291 lines
11 KiB
Ucode
291 lines
11 KiB
Ucode
//==============================================================================
|
|
// NicePack / NiceMeleeFire
|
|
//==============================================================================
|
|
// Adjustment of vanilla melee fire class to NicePack.
|
|
//==============================================================================
|
|
// 'Nice pack' source
|
|
// Do whatever the fuck you want with it
|
|
// Author: dkanus
|
|
// E-mail: dkanus@gmail.com
|
|
//==============================================================================
|
|
class NiceMeleeFire extends NiceFire;
|
|
var float weaponRange;
|
|
var float damageDelay;
|
|
// How far to rot view?
|
|
var vector impactShakeRotMag;
|
|
// How fast to rot view?
|
|
var vector impactShakeRotRate;
|
|
// How much time to rot the instigator's view?
|
|
var float impactShakeRotTime;
|
|
// Max view offset vertically?
|
|
var vector impactShakeOffsetMag;
|
|
// How fast to offset view vertically?
|
|
var vector impactShakeOffsetRate;
|
|
// How much time to offset view?
|
|
var float impactShakeOffsetTime;
|
|
// Sound for this melee strike hitting a pawn (fleshy hits).
|
|
var array<sound> meleeHitSounds;
|
|
var float meleeHitVolume;
|
|
var array<name> fireAnims;
|
|
// The class to spawn for the hit effect for
|
|
// this melee weapon hitting the world (not pawns).
|
|
var class<KFMeleeHitEffect> hitEffectClass;
|
|
var array<string> meleeHitSoundRefs;
|
|
// The angle to do sweeping strikes in front of the player.
|
|
// If zero, - do no strikes.
|
|
var float wideDamageMinHitAngle;
|
|
static function PreloadAssets(LevelInfo level, optional KFFire spawned){
|
|
local int i;
|
|
local NiceMeleeFire niceFire;
|
|
super.PreloadAssets(level, spawned);
|
|
for(i = 0; i < default.meleeHitSoundRefs.length;i ++){
|
|
if(default.meleeHitSoundRefs[i] == "")
|
|
continue;
|
|
if( default.meleeHitSounds.length >= i + 1
|
|
&& default.meleeHitSounds[i] != none)
|
|
continue;
|
|
default.meleeHitSounds[i] = Sound(
|
|
DynamicLoadObject( default.meleeHitSoundRefs[i],
|
|
class'Sound', true));
|
|
}
|
|
niceFire = NiceMeleeFire(spawned);
|
|
if(niceFire != none)
|
|
for(i = 0; i < default.meleeHitSoundRefs.length;i ++)
|
|
niceFire.meleeHitSounds[i] = default.meleeHitSounds[i];
|
|
}
|
|
static function bool UnloadAssets(){
|
|
local int i;
|
|
super.UnloadAssets();
|
|
for(i = 0; i < default.meleeHitSoundRefs.length;i ++)
|
|
default.meleeHitSounds[i] = none;
|
|
return true;
|
|
}
|
|
simulated function DoBurst(optional bool bSkipFirstShot){}
|
|
function DoFireEffect(){}
|
|
function float MaxRange(){
|
|
local bool hasWindCutterSkill;
|
|
traceRange = weaponRange;
|
|
if(instigator == none) return traceRange;
|
|
hasWindCutterSkill = class'NiceVeterancyTypes'.static.
|
|
HasSkill( NicePlayerController(instigator.controller),
|
|
class'NiceSkillZerkWindCutter');
|
|
if(hasWindCutterSkill)
|
|
traceRange *= class'NiceSkillZerkWindCutter'.default.rangeBonus;
|
|
return traceRange;
|
|
}
|
|
simulated function bool AllowFire(){
|
|
local KFPawn kfPwn;
|
|
// Check pawn actions
|
|
kfPwn = KFPawn(instigator);
|
|
if(kfPwn == none || kfPwn.SecondaryItem != none || kfPwn.bThrowingNade)
|
|
return false;
|
|
return true;
|
|
}
|
|
function name GetCorrectAnim(bool bLoop, bool bAimed){
|
|
local int AnimToPlay;
|
|
if(fireAnims.length > 0){
|
|
AnimToPlay = rand(fireAnims.length);
|
|
fireAnim = fireAnims[AnimToPlay];
|
|
}
|
|
return FireAnim;
|
|
}
|
|
simulated function NiceMonster DealTargetMeleeDamage
|
|
(
|
|
NiceReplicationInfo niceRI,
|
|
class<NiceWeaponDamageType> niceDmgType
|
|
){
|
|
local float headSizeModifier;
|
|
local float headshotLevel;
|
|
local NiceMonster niceZed;
|
|
local Vector hitLocation, hitNormal;
|
|
local KFPlayerReplicationInfo KFPRI;
|
|
local class<NiceVeterancyTypes> niceVet;
|
|
if(niceRI == none || instigator == none) return none;
|
|
KFPRI = KFPlayerReplicationInfo(instigator.PlayerReplicationInfo);
|
|
if(KFPRI == none)
|
|
return none;
|
|
niceVet = class<NiceVeterancyTypes>(KFPRI.ClientVeteranSkill);
|
|
if(niceVet == none)
|
|
return none;
|
|
if(niceDmgType != none)
|
|
headSizeModifier = niceDmgType.default.headSizeModifier;
|
|
headSizeModifier = 1.0;
|
|
headSizeModifier *=
|
|
niceVet.static.GetHeadshotCheckMultiplier(KFPRI, niceDmgType);
|
|
headshotLevel = TraceZed(niceZed, hitLocation, hitNormal, headSizeModifier);
|
|
if(niceZed != none)
|
|
HitZed(niceZed, headshotLevel, niceRI, niceDmgType);
|
|
else
|
|
HitWall(niceRI, niceDmgType);
|
|
return niceZed;
|
|
}
|
|
function HitZed(NiceMonster niceZed,
|
|
float headshotLevel,
|
|
NiceReplicationInfo niceRI,
|
|
class<NiceWeaponDamageType> niceDmgType){
|
|
local Vector hitLocation, hitNormal;
|
|
local NiceMeleeWeapon niceWeap;
|
|
ImpactShakeView();
|
|
niceWeap = NiceMeleeWeapon(weapon);
|
|
if(niceWeap != none && niceWeap.BloodyMaterial != none)
|
|
niceWeap.Skins[niceWeap.BloodSkinSwitchArray] = niceWeap.BloodyMaterial;
|
|
niceRI.ServerDealMeleeDamage( niceZed, damageMax, instigator,
|
|
hitLocation, -hitNormal,
|
|
niceDmgType, true, headshotLevel);
|
|
}
|
|
function HitWall( NiceReplicationInfo niceRI,
|
|
class<NiceWeaponDamageType> niceDmgType){
|
|
local Actor wall;
|
|
local Vector hitLocation, hitNormal;
|
|
local Rotator rotation;
|
|
TraceWall(wall, hitLocation, hitNormal);
|
|
if(wall != none){
|
|
niceRI.ServerDealMeleeDamage( wall, damageMax, instigator,
|
|
hitLocation, -hitNormal, niceDmgType,
|
|
false);
|
|
rotation = Rotator
|
|
(
|
|
HitLocation - instigator.location - instigator.EyePosition()
|
|
);
|
|
instigator.spawn(hitEffectClass,,, hitLocation, rotation);
|
|
}
|
|
}
|
|
simulated function DealArcMeleeDamage
|
|
(
|
|
NiceMonster niceZed,
|
|
NiceReplicationInfo niceRI,
|
|
class<NiceWeaponDamageType> niceDmgType
|
|
){
|
|
local NiceMonster otherZed;
|
|
local float actualMinAngle, tempRadians;
|
|
local bool hasCleave;
|
|
if(weapon == none) return;
|
|
hasCleave = class'NiceVeterancyTypes'.static.
|
|
HasSkill( NicePlayerController(instigator.controller),
|
|
class'NiceSkillZerkCleave');
|
|
actualMinAngle = wideDamageMinHitAngle;
|
|
if(hasCleave){
|
|
tempRadians = acos(actualMinAngle);
|
|
tempRadians += class'NiceSkillZerkCleave'.default.bonusDegrees;
|
|
tempRadians = FMin(tempRadians, Pi);
|
|
actualMinAngle = cos(tempRadians);
|
|
}
|
|
foreach weapon.VisibleCollidingActors(
|
|
class'NiceMonster', otherZed, weaponRange * 2,
|
|
instigator.location + instigator.EyePosition()){
|
|
|
|
if(niceZed != none && otherZed == niceZed) continue;
|
|
if(otherZed == instigator || otherZed.Health <= 0) continue;
|
|
TryHitZedArc(actualMinAngle, otherZed, niceRI, niceDmgType);
|
|
}
|
|
}
|
|
function TryHitZedArc(float minAngle, NiceMonster niceZed,
|
|
NiceReplicationInfo niceRI,
|
|
class<NiceWeaponDamageType> niceDmgType){
|
|
local vector hitLocation, hitNormal;
|
|
local vector dir, lookDir;
|
|
local float diffAngle, victimDist;
|
|
victimDist = VSize(instigator.location - niceZed.location);
|
|
if(victimDist + niceZed.CollisionRadius > weaponRange * 1.1)
|
|
return;
|
|
lookDir = Normal(Vector(instigator.GetViewRotation()));
|
|
dir = Normal(niceZed.location - instigator.location);
|
|
diffAngle = lookDir dot dir;
|
|
if(diffAngle <= minAngle)
|
|
return;
|
|
hitLocation =
|
|
niceZed.location + niceZed.CollisionHeight * vect(0,0,0.7);
|
|
niceRI.ServerDealMeleeDamage( niceZed, damageMax * 0.5, instigator,
|
|
hitLocation, hitNormal, niceDmgType,
|
|
false, 0.0);
|
|
if(meleeHitSounds.Length > 0)
|
|
niceZed.PlaySound( meleeHitSounds[Rand(meleeHitSounds.length)],
|
|
SLOT_None, meleeHitVolume,,,, false);
|
|
}
|
|
simulated function Timer(){
|
|
local NiceMonster niceZed;
|
|
local NiceReplicationInfo niceRI;
|
|
local class<NiceWeaponDamageType> niceDmgType;
|
|
niceRI = GetNiceRI();
|
|
niceDmgType = class<NiceWeaponDamageType>(damageType);
|
|
if(niceRI == none || instigator == none || niceDmgType == none)
|
|
return;
|
|
niceZed = DealTargetMeleeDamage(niceRI, niceDmgType);
|
|
DealArcMeleeDamage(niceZed, niceRI, niceDmgType);
|
|
}
|
|
simulated function MDFEffectsClient(float newAmmoPerFire, float rec){
|
|
local float fireSpeedMod;
|
|
fireSpeedMod = GetFireSpeed();
|
|
super.MDFEffectsClient(newAmmoPerFire, rec);
|
|
SetTimer(damageDelay / fireSpeedMod, false);
|
|
}
|
|
function PlayFiring_animation(){
|
|
if(weapon == none) return;
|
|
if(weapon.Mesh == none) return;
|
|
if(fireCount <= 0){
|
|
weapon.PlayAnim(GetCorrectAnim(false, false), fireAnimRate, 0.0);
|
|
return;
|
|
}
|
|
if(weapon.HasAnim(FireLoopAnim))
|
|
weapon.PlayAnim(GetCorrectAnim(true, false), fireLoopAnimRate, 0.0);
|
|
else
|
|
weapon.PlayAnim(GetCorrectAnim(false, false), fireAnimRate, 0.0);
|
|
}
|
|
function PlayFiring(){
|
|
local float randPitch;
|
|
local bool shouldPlayStereo;
|
|
if(weapon == none) return;
|
|
if(weapon.instigator == none) return;
|
|
PlayFiring_animation();
|
|
if(bRandomPitchFireSound){
|
|
randPitch = FRand() * RandomPitchAdjustAmt;
|
|
if(FRand() < 0.5)
|
|
randPitch *= -1.0;
|
|
}
|
|
shouldPlayStereo = weapon.instigator.IsLocallyControlled()
|
|
&& weapon.instigator.IsFirstPerson()
|
|
&& StereoFireSound != none;
|
|
if(shouldPlayStereo){
|
|
weapon.PlayOwnedSound( StereoFireSound, SLOT_Interact,
|
|
TransientSoundVolume * 0.85,,
|
|
TransientSoundRadius, 1.0 + randPitch, false);
|
|
}
|
|
else{
|
|
weapon.PlayOwnedSound( FireSound, SLOT_Interact, TransientSoundVolume,,
|
|
TransientSoundRadius, 1.0 + randPitch, false);
|
|
}
|
|
ClientPlayForceFeedback(fireForce);
|
|
if(!currentContext.bIsBursting)
|
|
fireCount ++;
|
|
}
|
|
function ImpactShakeView(){
|
|
local NicePlayerController nicePlayer;
|
|
if(instigator == none) return;
|
|
nicePlayer = NicePlayerController(instigator.controller);
|
|
if(nicePlayer == none)
|
|
return;
|
|
nicePlayer.WeaponShakeView( impactShakeRotMag, impactShakeRotRate,
|
|
impactShakeRotTime, impactShakeOffsetMag,
|
|
impactShakeOffsetRate, impactShakeOffsetTime);
|
|
}
|
|
simulated function HandleRecoil(float Rec){}
|
|
|
|
defaultproperties
|
|
{
|
|
weaponRange=70.000000
|
|
damageDelay=0.300000
|
|
ImpactShakeRotMag=(X=50.000000,Y=50.000000,Z=50.000000)
|
|
ImpactShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000)
|
|
ImpactShakeRotTime=2.000000
|
|
ImpactShakeOffsetMag=(X=10.000000,Y=10.000000,Z=10.000000)
|
|
ImpactShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000)
|
|
ImpactShakeOffsetTime=2.000000
|
|
MeleeHitVolume=1.000000
|
|
HitEffectClass=Class'KFMod.KFMeleeHitEffect'
|
|
WideDamageMinHitAngle=1.000000
|
|
bFiringDoesntAffectMovement=True
|
|
FireEndAnim=
|
|
FireForce="ShockRifleFire"
|
|
aimerror=100.000000
|
|
}
|