rott/kf_sources/KFMod/Classes/KFPawn.uc
2026-07-14 20:27:09 +07:00

4398 lines
142 KiB
Ucode

//=============================================================================
// KFPawn
//=============================================================================
class KFPawn extends xPawn
dependsOn(xPawnGibGroup);
#exec OBJ LOAD FILE=Inf_Weapons.uax
#exec OBJ LOAD FILE=Inf_Player.uax
// From XPawn
var(Gib) class<xPawnGibGroup> GibGroupClass;
var(Gib) int GibCountCalf;
var(Gib) int GibCountForearm;
var(Gib) int GibCountHead;
var(Gib) int GibCountTorso;
var(Gib) int GibCountUpperArm;
var string KFBSkin;
var string KFFSkin;
var mesh KFSMesh;
var bool bCanBeHealed;
var float healthToGive, lastHealTime;
var bool bResetingAnimAct;
var float NextBileTime, BileFrequency, AnimActResetTime;
var int BileCount;
var Pawn BileInstigator;
var class<DamTypeVomit> LastBileDamagedByType;
var name ClientIdleWeaponAnim;
var bool bThrowingNade; // ARE WE ALREADY THROWING ONE?
var Inventory SecondaryItem;
// Player Health Bar textures
var Texture TeamBeaconTexture, NoEntryTexture;
var Material TeamBeaconBorderMaterial;
var class<DamageType> LastHitDamType; // records the last kind of damge you took (for siren hack)
var (Global) Mesh SafeMesh;
// Fire Related
var int BurnDown ; // Number of times our zombie must suffer Fire Damage.
var bool bAshen; // is our Zed crispy yet?
var class<Emitter> BurnEffect; // The appearance of the flames we are attaching to our Zed.
var int LastBurnDamage; // Record the last amount of Fire damage the pawn suffered.
var Emitter ItBUURRNNNS;
var bool bBurnified;
var bool bBurnApplied;
var pawn LastDamagedBy,BurnInstigator;
var() globalconfig bool bDetailedShadows,bRealDeathType,bRealtimeShadows;
var KFLevelRules LevRls;
var PlayerReplicationInfo OwnerPRI;
var byte bIsQuickHealing;
/* Feet adjusters ================*/
var bool bHasFootAdjust;
var globalconfig bool bDoAdjustFeet;
var float MaxZHeight,MinZHeight,OldAdjust[2];
var KFPawnFootAdjuster Adjuster;
var Class<SPECIES_KFMaleHuman> FeetAdjSpec;
// Animations
const NUM_FIRE_ANIMS = 4;
var name FireAnims[NUM_FIRE_ANIMS];
var name FireAltAnims[NUM_FIRE_ANIMS];
var name FireCrouchAnims[NUM_FIRE_ANIMS];
var name FireCrouchAltAnims[NUM_FIRE_ANIMS];
var name HitAnims[4];
var name PostFireBlendStandAnim;
var name PostFireBlendCrouchAnim;
// Footstepping
var(Sounds) float FootStepSoundRadius; // The radius that footstep sounds can be heard
var(Sounds) float QuietFootStepVolume; // The amount to scale footstepsounds when the player is walking slowly
var(Sounds) sound SoundFootsteps[20]; // Indexed by ESurfaceTypes (sorry about the literal).
var(Bob) float BobSpeedModifier; // A general scalar for walkbob/footstep sound speed
var(Bob) float BobScaleModifier; // A general scalar for walkbob intensity
var bool bMovementDisabled; // The player can't move right now
var float StopDisabledTime; // When the player can move again;
// Gore
var SeveredAppendageAttachment SeveredLeftArm; // The meaty attachments that get attached when body parts are blown off
var SeveredAppendageAttachment SeveredRightArm; // The meaty attachments that get attached when body parts are blown off
var SeveredAppendageAttachment SeveredLeftLeg; // The meaty attachments that get attached when body parts are blown off
var SeveredAppendageAttachment SeveredRightLeg; // The meaty attachments that get attached when body parts are blown off
var SeveredAppendageAttachment SeveredHead; // The meaty attachments that get attached when body parts are blown off
var(Gore) float SeveredArmAttachScale; // The drawscale of the arm gore attachement
var(Gore) float SeveredLegAttachScale; // The drawscale of the leg gore attachement
var(Gore) float SeveredHeadAttachScale; // The drawscale of the head gore attachement
var class<DismembermentJetHead> NeckSpurtEmitterClass; // class of the chopped off head neck emitter
var class<DismembermentJetLimb> LimbSpurtEmitterClass; // class of the chopped off head neck emitter
var class<SeveredAppendageAttachment> SeveredArmAttachClass; // class of the severed arm for this role
var class<SeveredAppendageAttachment> SeveredLegAttachClass; // class of the severed arm for this role
var class<SeveredAppendageAttachment> SeveredHeadAttachClass; // class of the severed arm for this role
var class <ROBloodSpurt> BleedingEmitterClass; // class of the bleeding emitter
var class <ProjectileBloodSplat> ProjectileBloodSplatClass; // class of the wall bloodsplat from a projectile's impact
var class <SeveredAppendage> DetachedArmClass; // class of detached arm to spawn for this pawn. Modified by the RoleInfo to match the player model
var class <SeveredAppendage> DetachedLegClass; // class of detached arm to spawn for this pawn. Modified by the RoleInfo to match the player model
var bool bLeftArmGibbed; // LeftArm is already blown off
var bool bRightArmGibbed; // RightArm is already blown off
var bool bLeftLegGibbed; // LeftLeg is already blown off
var bool bRightLegGibbed; // RightLeg is already blown off
var class <Emitter> ObliteratedEffectClass; // class of detached arm to spawn for this pawn. Modified by the RoleInfo to match the player model
var(Sounds) sound DecapitationSound; //The sound of this players head exploding
var bool bDestroyNextTick; // Destroy this pawn next tick because destroying it now will cause problems
var float TimeSetDestroyNextTickTime; // The time we set the bDestroyNextTick flag
var float LastDropCashMessageTime;
var float DropCashMessageDelay;
var bool bDestroyAfterRagDollTick; // Wait until the ragdoll tick has happened and then destroy. Prevents crashes where we try and destroy the actor right after initializing ragdoll
var bool bProcessedRagTickDestroy; // Already called destroy for a bDestroyAfterRagDollTick setting
// Collision
var KFBulletWhipAttachment AuxCollisionCylinder; // Additional collision cylinder for detecting bullets passing by
var bool SavedAuxCollision; // Saved aux collision cylinder status
var float NadeThrowTimeout; // Little hack to timeout the grenade throwing flag on the client in case it gets stuck. At some point we should try and track down what is actually causing it to get stuck, this is just a quick fix - Ramm
var Emitter AttachedEmitter;
/* === Replicated Custom Animation Struct.
Used with ACTION_PlayKFReplicatedAnim Objects to
allow level designers to play replicated scripted
animations on pawns */
struct SScriptedAnimRepInfo
{
var name BaseAnim;
var float BlendInTime;
var float BlendOutTime;
var float AnimRate;
var byte AnimIterations;
var bool bLoopAnim;
var float StartFrame;
};
var SScriptedAnimRepInfo ScriptedAnimData;
// Hit detection debugging - Only use when debugging
/*var vector DrawLocation;
var rotator DrawRotation;
var int DrawIndex;
var vector HitStart;
var vector HitEnd;
var byte HitPointDebugByte;
var byte OldHitPointDebugByte;*/
replication
{
reliable if(Role == ROLE_Authority)
bBurnified,QuickHeal,ClientCurrentWeaponSold,ClientForceChangeWeapon;
reliable if(Role < ROLE_Authority)
ServerBuyPotato,ServerBuyWeapon,ServerSellWeapon,ServerBuyKevlar,ServerBuyFirstAid,ServerBuyAmmo,ServerSellAmmo;
reliable if(Role < ROLE_Authority)
SecondaryItem,TossCash;
reliable if ( bNetDirty && (Role == Role_Authority) && bNetOwner )
bMovementDisabled;
reliable if(Role == ROLE_Authority && bNetDirty && !bNetOwner)
ScriptedAnimData;
// Hit detection debugging - Only use when debugging
/*reliable if (Role == ROLE_Authority)
DrawLocation,DrawRotation,DrawIndex,HitPointDebugByte,HitStart,HitEnd;*/
}
simulated function PostBeginPlay()
{
Super(UnrealPawn).PostBeginPlay();
AssignInitialPose();
if( bActorShadows && bPlayerShadows && (Level.NetMode!=NM_DedicatedServer) )
{
if( bDetailedShadows )
PlayerShadow = Spawn(class'KFShadowProject',Self,'',Location);
else PlayerShadow = Spawn(class'ShadowProjector',Self,'',Location);
PlayerShadow.ShadowActor = self;
PlayerShadow.bBlobShadow = bBlobShadow;
PlayerShadow.LightDirection = Normal(vect(1,1,3));
PlayerShadow.InitShadow();
}
// Only need this on the server
if( Role == Role_Authority/*IsLocallyControlled() || Level.NetMode == NM_DedicatedServer || Level.NetMode == NM_ListenServer*/ )
{
if ( AuxCollisionCylinder == none )
{
AuxCollisionCylinder = Spawn(class 'KFBulletWhipAttachment',self);
//AttachToBone(AuxCollisionCylinder, 'CHR_Pelvis');
///AuxCollisionCylinder = Spawn(class 'ExtendedZCollision',self);
//MyExtCollision.SetCollisionSize(ColRadius,ColHeight);
AuxCollisionCylinder.bHardAttach = true;
//AttachPos = Location + (ColOffset >> Rotation);
AuxCollisionCylinder.SetLocation( Location );
AuxCollisionCylinder.SetPhysics( PHYS_None );
AuxCollisionCylinder.SetBase( self );
}
SavedAuxCollision = AuxCollisionCylinder.bCollideActors;
}
}
// Setters for extra collision cylinders
simulated function ToggleAuxCollision(bool newbCollision)
{
if ( !newbCollision )
{
SavedAuxCollision = AuxCollisionCylinder.bCollideActors;
AuxCollisionCylinder.SetCollision(false);
}
else
{
AuxCollisionCylinder.SetCollision(SavedAuxCollision);
}
}
function PossessedBy(Controller C)
{
Super.PossessedBy(C);
if ( C.PlayerReplicationInfo != None )
OwnerPRI = C.PlayerReplicationInfo;
}
simulated Function PostNetBeginPlay()
{
EnableChannelNotify(1,1);
EnableChannelNotify(2,1);
super.PostNetBeginPlay();
}
simulated function string GetDefaultCharacter()
{
return "Corporal_Lewis";
}
simulated function Setup(xUtil.PlayerRecord rec, optional bool bLoadNow)
{
local class<Emitter> AttachedEmitterClass;
local vector AttachOffset;
if( rec.Species==None || Class<SPECIES_KFMaleHuman>(rec.Species)==None )
rec = class'xUtil'.static.FindPlayerRecord(GetDefaultCharacter());
Species = rec.Species;
RagdollOverride = rec.Ragdoll;
if ( Species!=None && !Species.static.Setup(self,rec) )
{
rec = class'xUtil'.static.FindPlayerRecord(GetDefaultCharacter());
Species = rec.Species;
RagdollOverride = rec.Ragdoll;
if ( !Species.static.Setup(self,rec) )
return;
}
if( rec.AttachedEmitter != "" && AttachedEmitter == none && Level.NetMode != NM_DedicatedServer)
{
AttachedEmitterClass = class<Emitter>(DynamicLoadObject(rec.AttachedEmitter,class'Class'));
AttachedEmitter = Spawn(AttachedEmitterClass, self);
if( AttachToBone(AttachedEmitter, rec.BoneName ) )
{
AttachOffset.X = rec.XOffset;
AttachOffset.Y = rec.YOffset;
AttachOffset.Z = rec.ZOffset;
AttachedEmitter.SetRelativeLocation( AttachOffset );//vect(rec.XOffset, rec.YOffset, rec.ZOffset) );
}
}
if( Class<SPECIES_KFMaleHuman>(Species) != none )
{
DetachedArmClass = Class<SPECIES_KFMaleHuman>(Species).default.DetachedArmClass;
DetachedLegClass = Class<SPECIES_KFMaleHuman>(Species).default.DetachedLegClass;
}
ResetPhysicsBasedAnim();
// bHasFootAdjust = False;
// FeetAdjSpec = Class<SPECIES_KFMaleHuman>(rec.Species);
// if( !bDoAdjustFeet || FeetAdjSpec==None || Level.NetMode==NM_DedicatedServer )
// return;
// if( Adjuster!=None )
// Adjuster.Destroy();
// Adjuster = Spawn(Class'KFPawnFootAdjuster',,,vect(0,0,0),rot(0,0,0));
// Adjuster.AdjustingPawn = Self;
// Adjuster.SpecType = FeetAdjSpec;
// Adjuster.LinkMesh(Mesh);
}
// Clean up weapon inventory before level change since certain weapons
// (sniper scopes with 3d scopes) won't get properly garbage collected
// otherwise. This lead to the webadmin and memory leak issues - Ramm
simulated function PreTravelCleanUp()
{
local Inventory Inv;
local KFWeapon invWeapon;
local int count;
count=0;
// consider doing a check on count to make sure it doesn't get too high
// and force Unreal to crash with a run away loop
for ( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
{
invWeapon = KFWeapon(Inv);
if ( invWeapon != None )
{
invWeapon.PreTravelCleanUp();
}
count++;
if( count > 500 )
break;
}
}
//returns how exposed this player is to another actor
function float GetExposureTo(vector TestLocation)
{
local float PercentExposed;
if( FastTrace(GetBoneCoords(HeadBone).Origin,TestLocation))
{
PercentExposed += 0.5;
}
if( FastTrace(GetBoneCoords(RootBone).Origin,TestLocation))
{
PercentExposed += 0.5;
}
return PercentExposed;
}
// Update the shadow if the detail settings have changed in the detail menu
simulated function UpdateShadow()
{
if (bActorShadows && bPlayerShadows && (Level.NetMode != NM_DedicatedServer))
{
if (PlayerShadow != none)
PlayerShadow.Destroy();
if( bDetailedShadows )
PlayerShadow = Spawn(class'KFShadowProject',Self,'',Location);
else PlayerShadow = Spawn(class'ShadowProjector',Self,'',Location);
PlayerShadow.ShadowActor = self;
PlayerShadow.bBlobShadow = bBlobShadow;
PlayerShadow.LightDirection = Normal(vect(1,1,3));
PlayerShadow.InitShadow();
}
else if (PlayerShadow != none && Level.NetMode != NM_DedicatedServer)
{
PlayerShadow.Destroy();
PlayerShadow = none;
}
}
simulated function DoDerezEffect();
function SetScriptedAnimData(
name BaseAnim,
float BlendInTime,
float BlendOutTime,
float AnimRate,
byte AnimIterations,
bool bLoopAnim,
float StartFrame)
{
ScriptedAnimData.BaseAnim = BaseAnim;
ScriptedAnimData.BlendInTime = BlendInTime;
ScriptedAnimData.BlendOutTime = BlendOutTime;
ScriptedAnimdata.AnimRate = AnimRate;
ScriptedAnimData.AnimIterations = AnimIterations;
ScriptedAnimData.bLoopAnim = bLoopAnim;
ScriptedAnimData.StartFrame = StartFrame;
/* Play the anim on the server too*/
if(Role == Role_Authority)
{
PlayScriptedAnim(ScriptedAnimData);
}
}
simulated function PlayScriptedAnim( SScriptedAnimRepInfo AnimData)
{
if(AnimData.bLoopAnim)
{
LoopAnim(AnimData.BaseAnim, AnimData.AnimRate, AnimData.BlendInTime);
}
else
{
PlayAnim(AnimData.baseAnim,AnimData.AnimRate,AnimData.BlendInTime);
}
if( AnimData.StartFrame > 0.0 )
SetAnimFrame(AnimData.StartFrame, 0, 1);
}
simulated event PostNetReceive()
{
if( ScriptedAnimData.BaseAnim != '')
{
PlayScriptedAnim(ScriptedAnimData);
ScriptedAnimData.BaseAnim = '';
}
if ( PlayerReplicationInfo != None )
{
Setup(class'xUtil'.static.FindPlayerRecord(PlayerReplicationInfo.CharacterName));
bNetNotify = false;
}
else if ( (DrivenVehicle != None) && (DrivenVehicle.PlayerReplicationInfo != None) )
{
Setup(class'xUtil'.static.FindPlayerRecord(DrivenVehicle.PlayerReplicationInfo.CharacterName));
bNetNotify = false;
}
}
// Don't let this pawn move for a certain amount of time
function DisableMovement(float DisableDuration)
{
StopDisabledTime = Level.TimeSeconds + DisableDuration;
bMovementDisabled = true;
}
// Modify the velocity of the pawn
simulated event ModifyVelocity(float DeltaTime, vector OldVelocity)
{
if( Role == ROLE_Authority )
{
if( bMovementDisabled )
{
if( Level.TimeSeconds > StopDisabledTime )
{
bMovementDisabled = false;
}
}
}
if( bMovementDisabled && Physics == PHYS_Walking )
{
Velocity.X = 0;
Velocity.Y = 0;
Velocity.Z = 0;
}
if ( KFGameReplicationInfo(Level.GRI).BaseDifficulty >= 5 && bMovementDisabled && Velocity.Z > 0 )
{
Velocity.Z = 0;
}
}
function TakeFallingDamage()
{
local float Shake, EffectiveSpeed;
local float UsedMaxFallSpeed;
UsedMaxFallSpeed = MaxFallSpeed;
// Higher max fall speed in low grav so that weapons that push you around
// don't cause you to die
if( Instigator != none && Instigator.PhysicsVolume.Gravity.Z > class'PhysicsVolume'.default.Gravity.Z )
{
UsedMaxFallSpeed *= 2.0;
}
if (Velocity.Z < -0.5 * UsedMaxFallSpeed)
{
if ( Role == ROLE_Authority )
{
MakeNoise(1.0);
if (Velocity.Z < -1 * UsedMaxFallSpeed)
{
EffectiveSpeed = Velocity.Z;
if ( TouchingWaterVolume() )
EffectiveSpeed = FMin(0, EffectiveSpeed + 100);
if ( EffectiveSpeed < -1 * UsedMaxFallSpeed )
TakeDamage(-100 * (EffectiveSpeed + UsedMaxFallSpeed)/UsedMaxFallSpeed, None, Location, vect(0,0,0), class'Fell');
}
}
if ( Controller != None )
{
Shake = FMin(1, -1 * Velocity.Z/MaxFallSpeed);
Controller.DamageShake(Shake);
}
}
else if (Velocity.Z < -1.4 * JumpZ)
MakeNoise(0.5);
}
exec function TestEye()
{
local Vector X,Y,Z;
if( !class'ROEngine.ROLevelInfo'.static.RODebugMode() )
return;
ClearStayingDebugLines();
DrawDebugSphere( EyePosition() + Location, 12, 12, 0, 255, 0);
GetAxes( Controller.rotation, X, Y, Z );
DrawStayingDebugLine((EyePosition() + Location), (EyePosition() + Location)+500* X, 0,0,255);
DrawStayingDebugLine((EyePosition() + Location), (EyePosition() + Location)+200* Y, 0,255,0);
Spawn(class 'ROEngine.RODebugTracer',self,,(EyePosition() + Location),Rotation);
}
/* DisplayDebug()
list important actor variable on canvas. Also show the pawn's controller and weapon info
*/
simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos)
{
local int i;
local name Sequence;
local float Frame, Rate;
Super.DisplayDebug(Canvas, YL, YPos);
for( i = 0; i < 16; i++ )
{
if( IsAnimating( i ) )
{
GetAnimParams( i, Sequence, Frame, Rate );
Canvas.DrawText("Anim:: Channel("@i@") Frame("@Frame@") Rate("@Rate@") Name("@Sequence@")");
YPos += YL;
Canvas.SetPos(4,YPos);
}
}
}
simulated function DoDamageFX( Name boneName, int Damage, class<DamageType> DamageType, Rotator r )
{
local float DismemberProbability;
local int RandBone;
local bool bDidSever;
//log("DamageFX bonename = "$boneName$" "$Level.TimeSeconds$" Damage "$Damage);
if ( FRand() > 0.3f || Damage > 30 || Health <= 0 )
{
HitFX[HitFxTicker].damtype = DamageType;
if( Health <= 0 )
{
switch( boneName )
{
case 'neck':
boneName = HeadBone;
break;
case 'lfoot':
case 'lleg':
boneName = 'lthigh';
break;
case 'rfoot':
case 'rleg':
boneName = 'rthigh';
break;
case 'righthand':
case 'rshoulder':
case 'rarm':
boneName = 'rfarm';
break;
case 'lefthand':
case 'lshoulder':
case 'larm':
boneName = 'lfarm';
break;
case 'None':
case 'spine':
boneName = FireRootBone;
break;
}
if( DamageType.default.bAlwaysSevers || (Damage == 1000) )
{
HitFX[HitFxTicker].bSever = true;
bDidSever = true;
if ( boneName == 'None' )
{
boneName = FireRootBone;
}
}
else if( DamageType.Default.GibModifier > 0.0 )
{
DismemberProbability = Abs( (Health - Damage*DamageType.Default.GibModifier) / 130.0f );
if( FRand() < DismemberProbability )
{
HitFX[HitFxTicker].bSever = true;
bDidSever = true;
}
}
}
if ( DamageType.default.bNeverSevers || class'GameInfo'.static.UseLowGore()
|| (Level.Game != none && Level.Game.PreventSever(self, boneName, Damage, DamageType)) )
{
HitFX[HitFxTicker].bSever = false;
bDidSever = false;
}
if ( HitFX[HitFxTicker].bSever )
{
if( !DamageType.default.bLocationalHit && (boneName == 'None' || boneName == FireRootBone ||
boneName == 'Spine' ))
{
RandBone = Rand(4);
switch( RandBone )
{
case 0:
boneName = 'lthigh';
break;
case 1:
boneName = 'rthigh';
break;
case 2:
boneName = 'lfarm';
break;
case 3:
boneName = 'rfarm';
break;
case 4:
boneName = HeadBone;
break;
default:
boneName = 'lthigh';
}
}
}
if( Health < 0 && Damage > DamageType.default.HumanObliterationThreshhold && Damage != 1000 )
{
boneName = 'obliterate';
}
HitFX[HitFxTicker].bone = boneName;
HitFX[HitFxTicker].rotDir = r;
HitFxTicker = HitFxTicker + 1;
if( HitFxTicker > ArrayCount(HitFX)-1 )
HitFxTicker = 0;
// If this was a really hardcore damage from an explosion, randomly spawn some arms and legs
if ( bDidSever && !DamageType.default.bLocationalHit && Damage > 200 && Damage != 1000 )
{
if ((Damage > 400 && FRand() < 0.3) || FRand() < 0.1 )
{
DoDamageFX(HeadBone,1000,DamageType,r);
DoDamageFX('lthigh',1000,DamageType,r);
DoDamageFX('rthigh',1000,DamageType,r);
DoDamageFX('lfarm',1000,DamageType,r);
DoDamageFX('rfarm',1000,DamageType,r);
}
if ( FRand() < 0.25 )
{
DoDamageFX('lthigh',1000,DamageType,r);
DoDamageFX('rthigh',1000,DamageType,r);
if ( FRand() < 0.5 )
{
DoDamageFX('lfarm',1000,DamageType,r);
}
else
{
DoDamageFX('rfarm',1000,DamageType,r);
}
}
else if ( FRand() < 0.35 )
DoDamageFX('lthigh',1000,DamageType,r);
else if ( FRand() < 0.5 )
DoDamageFX('rthigh',1000,DamageType,r);
else if ( FRand() < 0.75 )
{
if ( FRand() < 0.5 )
{
DoDamageFX('lfarm',1000,DamageType,r);
}
else
{
DoDamageFX('rfarm',1000,DamageType,r);
}
}
}
}
}
//Stops the green shit when a player dies.
simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
local float frame, rate;
local name seq;
local LavaDeath LD;
local MiscEmmiter BE;
if( Adjuster!=None )
Adjuster.Destroy();
bHasFootAdjust = False;
AmbientSound = None;
bCanTeleport = false; // sjs - fix karma going crazy when corpses land on teleporters
bReplicateMovement = false;
bTearOff = true;
bPlayedDeath = true;
//bFrozenBody = true;
SafeMesh = Mesh;
if (CurrentCombo != None)
CurrentCombo.Destroy();
HitDamageType = DamageType; // these are replicated to other clients
TakeHitLocation = HitLoc;
if ( DamageType != None )
{
if ( DamageType.default.bSkeletize )
{
SetOverlayMaterial(DamageType.Default.DamageOverlayMaterial, 4.0, true);
if (!bSkeletized)
{
if ( (Level.NetMode != NM_DedicatedServer) && (SkeletonMesh != None) )
{
if ( DamageType.default.bLeaveBodyEffect )
{
BE = spawn(class'MiscEmmiter',self);
if ( BE != None )
{
BE.DamageType = DamageType;
BE.HitLoc = HitLoc;
bFrozenBody = true;
}
}
GetAnimParams( 0, seq, frame, rate );
LinkMesh(SkeletonMesh, true);
Skins.Length = 0;
PlayAnim(seq, 0, 0);
SetAnimFrame(frame);
}
if (Physics == PHYS_Walking)
Velocity = Vect(0,0,0);
SetTearOffMomemtum(GetTearOffMomemtum() * 0.25);
bSkeletized = true;
if ( (Level.NetMode != NM_DedicatedServer) && (DamageType == class'FellLava') )
{
LD = spawn(class'LavaDeath', , , Location + vect(0, 0, 10), Rotation );
if ( LD != None )
LD.SetBase(self);
PlaySound( sound'Inf_Weapons.F1.f1_explode01', SLOT_None, 1.5*TransientSoundVolume ); // KFTODO: Replace this sound
}
}
}
else if ( DamageType.Default.DeathOverlayMaterial != None )
SetOverlayMaterial(DamageType.Default.DeathOverlayMaterial, DamageType.default.DeathOverlayTime, true);
else if ( (DamageType.Default.DamageOverlayMaterial != None) && (Level.DetailMode != DM_Low) && !Level.bDropDetail )
SetOverlayMaterial(DamageType.Default.DamageOverlayMaterial, 2*DamageType.default.DamageOverlayTime, true);
}
// stop shooting
AnimBlendParams(1, 0.0);
FireState = FS_None;
//LifeSpan = RagdollLifeSpan;
GotoState('Dying');
if ( BE != None )
return;
PlayDyingAnimation(DamageType, HitLoc);
}
function PlayDyingAnimation(class<DamageType> DamageType, vector HitLoc)
{
local vector shotDir, hitLocRel, deathAngVel, shotStrength;
local float maxDim;
local string RagSkelName;
local KarmaParamsSkel skelParams;
local bool PlayersRagdoll;
local PlayerController pc;
if ( Level.NetMode != NM_DedicatedServer )
{
// Is this the local player's ragdoll?
if(OldController != None)
pc = PlayerController(OldController);
if( pc != none && pc.ViewTarget == self )
PlayersRagdoll = true;
// In low physics detail, if we were not just controlling this pawn,
// and it has not been rendered in 3 seconds, just destroy it.
if( Level.PhysicsDetailLevel!=PDL_High && !PlayersRagdoll && (Level.TimeSeconds-LastRenderTime)>3 )
{
GoTo'NonRagdoll';
return;
}
// Try and obtain a rag-doll setup. Use optional 'override' one out of player record first, then use the species one.
if( RagdollOverride != "")
RagSkelName = RagdollOverride;
else if(Species != None)
RagSkelName = Species.static.GetRagSkelName( GetMeshName() );
else RagSkelName = "Male1"; // Otherwise assume it is Male1 ragdoll were after here.
KMakeRagdollAvailable();
if( KIsRagdollAvailable() && RagSkelName != "" )
{
skelParams = KarmaParamsSkel(KParams);
skelParams.KSkeleton = RagSkelName;
// Stop animation playing.
StopAnimating(true);
if( DamageType != None )
{
if ( DamageType.default.bLeaveBodyEffect )
TearOffMomentum = vect(0,0,0);
if( DamageType.default.bKUseOwnDeathVel )
{
RagDeathVel = DamageType.default.KDeathVel;
RagDeathUpKick = DamageType.default.KDeathUpKick;
}
}
// Set the dude moving in direction he was shot in general
shotDir = Normal(GetTearOffMomemtum());
shotStrength = RagDeathVel * shotDir;
// Calculate angular velocity to impart, based on shot location.
hitLocRel = TakeHitLocation - Location;
// We scale the hit location out sideways a bit, to get more spin around Z.
hitLocRel.X *= RagSpinScale;
hitLocRel.Y *= RagSpinScale;
// If the tear off momentum was very small for some reason, make up some angular velocity for the pawn
if( VSize(GetTearOffMomemtum()) < 0.01 )
{
//Log("TearOffMomentum magnitude of Zero");
deathAngVel = VRand() * 18000.0;
}
else deathAngVel = RagInvInertia * (hitLocRel Cross shotStrength);
// Set initial angular and linear velocity for ragdoll.
// Scale horizontal velocity for characters - they run really fast!
if ( DamageType.Default.bRubbery )
skelParams.KStartLinVel = vect(0,0,0);
if ( Damagetype.default.bKUseTearOffMomentum )
skelParams.KStartLinVel = GetTearOffMomemtum() + Velocity;
else
{
skelParams.KStartLinVel.X = 0.6 * Velocity.X;
skelParams.KStartLinVel.Y = 0.6 * Velocity.Y;
skelParams.KStartLinVel.Z = 1.0 * Velocity.Z;
skelParams.KStartLinVel += shotStrength;
}
// If not moving downwards - give extra upward kick
if( !DamageType.default.bLeaveBodyEffect && !DamageType.Default.bRubbery && (Velocity.Z > -10) )
skelParams.KStartLinVel.Z += RagDeathUpKick;
if ( DamageType.Default.bRubbery )
{
Velocity = vect(0,0,0);
skelParams.KStartAngVel = vect(0,0,0);
}
else
{
skelParams.KStartAngVel = deathAngVel;
// Set up deferred shot-bone impulse
maxDim = Max(CollisionRadius, CollisionHeight);
skelParams.KShotStart = TakeHitLocation - (1 * shotDir);
skelParams.KShotEnd = TakeHitLocation + (2*maxDim*shotDir);
skelParams.KShotStrength = RagShootStrength;
}
// If this damage type causes convulsions, turn them on here.
if(DamageType != None && DamageType.default.bCauseConvulsions)
{
RagConvulseMaterial=DamageType.default.DamageOverlayMaterial;
skelParams.bKDoConvulsions = true;
}
// Turn on Karma collision for ragdoll.
KSetBlockKarma(true);
// Set physics mode to ragdoll.
// This doesn't actaully start it straight away, it's deferred to the first tick.
SetPhysics(PHYS_KarmaRagdoll);
// If viewing this ragdoll, set the flag to indicate that it is 'important'
if( PlayersRagdoll )
skelParams.bKImportantRagdoll = true;
skelParams.bRubbery = DamageType.Default.bRubbery;
bRubbery = DamageType.Default.bRubbery;
skelParams.KActorGravScale = RagGravScale;
return;
}
// jag
}
NonRagdoll:
// non-ragdoll death fallback
Velocity += GetTearOffMomemtum();
BaseEyeHeight = Default.BaseEyeHeight;
SetTwistLook(0, 0);
SetInvisibility(0.0);
PlayDirectionalDeath(HitLoc);
SetPhysics(PHYS_Falling);
}
// jag
// Called when in Ragdoll when we hit something over a certain threshold velocity
// Used to play impact sounds.
event KImpact(actor other, vector pos, vector impactVel, vector impactNorm)
{
local float VelocitySquared;
local float RagHitVolume;
if(Level.TimeSeconds > RagLastSoundTime + RagImpactSoundInterval)
{
VelocitySquared = VSizeSquared(impactVel);
//log("Ragimpact velocity: "$VSize(impactVel)$" VelocitySquared: "$VelocitySquared);
RagHitVolume = FMin(2.0,(VelocitySquared/40000));
//log("RagHitVolume = "$RagHitVolume);
PlaySound(RagImpactSounds[0], SLOT_None, RagHitVolume);
RagLastSoundTime = Level.TimeSeconds;
}
}
//jag
simulated function bool ForceDefaultCharacter()
{
return false;
}
simulated function ProcessHitFX()
{
local Coords boneCoords;
local class<xEmitter> HitEffects[4];
local int i,j;
local float GibPerterbation;
if( (Level.NetMode == NM_DedicatedServer) || bSkeletized || (Mesh == SkeletonMesh) )
{
SimHitFxTicker = HitFxTicker;
return;
}
for ( SimHitFxTicker = SimHitFxTicker; SimHitFxTicker != HitFxTicker; SimHitFxTicker = (SimHitFxTicker + 1) % ArrayCount(HitFX) )
{
j++;
if ( j > 30 )
{
SimHitFxTicker = HitFxTicker;
return;
}
if( (HitFX[SimHitFxTicker].damtype == None) || (Level.bDropDetail && (Level.TimeSeconds - LastRenderTime > 3) && !IsHumanControlled()) )
continue;
//log("Processing effects for damtype "$HitFX[SimHitFxTicker].damtype);
if( HitFX[SimHitFxTicker].bone == 'obliterate' && !class'GameInfo'.static.UseLowGore())
{
SpawnGibs( HitFX[SimHitFxTicker].rotDir, 0);
bGibbed = true;
// Wait a tick on a listen server so the obliteration can replicate before the pawn is destroyed
if( Level.NetMode == NM_ListenServer )
{
bDestroyNextTick = true;
TimeSetDestroyNextTickTime = Level.TimeSeconds;
}
else
{
Destroy();
}
return;
}
boneCoords = GetBoneCoords( HitFX[SimHitFxTicker].bone );
if ( !Level.bDropDetail && !class'GameInfo'.static.NoBlood() && !bSkeletized )
{
//AttachEmitterEffect( BleedingEmitterClass, HitFX[SimHitFxTicker].bone, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir );
HitFX[SimHitFxTicker].damtype.static.GetHitEffects( HitEffects, Health );
if( !PhysicsVolume.bWaterVolume ) // don't attach effects under water
{
for( i = 0; i < ArrayCount(HitEffects); i++ )
{
if( HitEffects[i] == None )
continue;
AttachEffect( HitEffects[i], HitFX[SimHitFxTicker].bone, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir );
}
}
}
if ( class'GameInfo'.static.UseLowGore() )
HitFX[SimHitFxTicker].bSever = false;
if( HitFX[SimHitFxTicker].bSever )
{
GibPerterbation = HitFX[SimHitFxTicker].damtype.default.GibPerterbation;
bFlaming = HitFX[SimHitFxTicker].DamType.Default.bFlaming;
switch( HitFX[SimHitFxTicker].bone )
{
case 'obliterate':
break;
case 'lthigh':
if( !bLeftLegGibbed )
{
SpawnSeveredGiblet( DetachedLegClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation );
bLeftLegGibbed=true;
}
break;
case 'rthigh':
if( !bRightLegGibbed )
{
SpawnSeveredGiblet( DetachedLegClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation );
bRightLegGibbed=true;
}
break;
case 'lfarm':
if( !bLeftArmGibbed )
{
SpawnSeveredGiblet( DetachedArmClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation );
bLeftArmGibbed=true;
}
break;
case 'rfarm':
if( !bRightArmGibbed )
{
SpawnSeveredGiblet( DetachedArmClass, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation );
bRightArmGibbed=true;
}
break;
case 'head':
SpawnGiblet( GetGibClass(EGT_Head), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation );
break;
}
if (LastHitDamType == class 'SirenScreamDamage')
HideBone(HeadBone);
else if( HitFX[SimHitFXTicker].bone != 'Spine' && HitFX[SimHitFXTicker].bone != FireRootBone )
HideBone(HitFX[SimHitFxTicker].bone);
}
}
}
simulated function SpawnSeveredGiblet( class<SeveredAppendage> GibClass, Vector Location, Rotator Rotation, float GibPerterbation )
{
local SeveredAppendage Giblet;
local Vector Direction, Dummy;
if( (GibClass == None) || class'GameInfo'.static.UseLowGore() )
return;
Instigator = self;
Giblet = Spawn( GibClass,,, Location, Rotation );
if( Giblet == None )
return;
Giblet.SpawnTrail();
GibPerterbation *= 32768.0;
Rotation.Pitch += ( FRand() * 2.0 * GibPerterbation ) - GibPerterbation;
Rotation.Yaw += ( FRand() * 2.0 * GibPerterbation ) - GibPerterbation;
Rotation.Roll += ( FRand() * 2.0 * GibPerterbation ) - GibPerterbation;
GetAxes( Rotation, Dummy, Dummy, Direction );
Giblet.Velocity = Velocity + Normal(Direction) * (Giblet.MaxSpeed + (Giblet.MaxSpeed/2) * FRand());
//Giblet.LifeSpan = self.RagdollLifeSpan;
}
function class<Gib> GetGibClass(xPawnGibGroup.EGibType gibType)
{
return GibGroupClass.static.GetGibClass(gibType);
}
simulated function HideBone(name boneName)
{
local int BoneScaleSlot;
local coords boneCoords;
if( boneName == 'lthigh' )
{
boneScaleSlot = 0;
if( SeveredLeftLeg == none )
{
SeveredLeftLeg = Spawn(SeveredLegAttachClass,self);
SeveredLeftLeg.SetDrawScale(SeveredLegAttachScale);
boneCoords = GetBoneCoords( 'lleg' );
AttachEmitterEffect( LimbSpurtEmitterClass, 'lleg', boneCoords.Origin, rot(0,0,0) );
AttachToBone(SeveredLeftLeg, 'lleg');
}
}
else if ( boneName == 'rthigh' )
{
boneScaleSlot = 1;
if( SeveredRightLeg == none )
{
SeveredRightLeg = Spawn(SeveredLegAttachClass,self);
SeveredRightLeg.SetDrawScale(SeveredLegAttachScale);
boneCoords = GetBoneCoords( 'rleg' );
AttachEmitterEffect( LimbSpurtEmitterClass, 'rleg', boneCoords.Origin, rot(0,0,0) );
AttachToBone(SeveredRightLeg, 'rleg');
}
}
else if( boneName == 'rfarm' )
{
boneScaleSlot = 2;
if( SeveredRightArm == none )
{
SeveredRightArm = Spawn(SeveredArmAttachClass,self);
SeveredRightArm.SetDrawScale(SeveredArmAttachScale);
boneCoords = GetBoneCoords( 'rarm' );
AttachEmitterEffect( LimbSpurtEmitterClass, 'rarm', boneCoords.Origin, rot(0,0,0) );
AttachToBone(SeveredRightArm, 'rarm');
}
}
else if ( boneName == 'lfarm' )
{
boneScaleSlot = 3;
if( SeveredLeftArm == none )
{
SeveredLeftArm = Spawn(SeveredArmAttachClass,self);
SeveredLeftArm.SetDrawScale(SeveredArmAttachScale);
boneCoords = GetBoneCoords( 'larm' );
AttachEmitterEffect( LimbSpurtEmitterClass, 'larm', boneCoords.Origin, rot(0,0,0) );
AttachToBone(SeveredLeftArm, 'larm');
}
}
else if ( boneName == HeadBone )
{
boneScaleSlot = 4;
if( SeveredHead == none )
{
SeveredHead = Spawn(SeveredHeadAttachClass,self);
SeveredHead.SetDrawScale(SeveredHeadAttachScale);
boneCoords = GetBoneCoords( 'neck' );
AttachEmitterEffect( NeckSpurtEmitterClass, 'neck', boneCoords.Origin, rot(0,0,0) );
AttachToBone(SeveredHead, 'neck');
}
}
else if ( boneName == 'spine' )
boneScaleSlot = 5;
SetBoneScale(BoneScaleSlot, 0.0, BoneName);
}
function PlayDyingSound()
{
if( Level.NetMode!=NM_Client )
{
if ( bGibbed )
{
PlaySound(GibGroupClass.static.GibSound(), SLOT_Pain,2.0,true,525);
return;
}
if ( HeadVolume.bWaterVolume )
{
PlaySound(GetSound(EST_Drown), SLOT_Pain,2.5*TransientSoundVolume,true,500);
return;
}
PlaySound(SoundGroupClass.static.GetDeathSound(), SLOT_Pain,2.5*TransientSoundVolume, true,500);
}
}
// Maybe spawn some chunks when the player gets obliterated
simulated function SpawnGibs(Rotator HitRotation, float ChunkPerterbation)
{
bGibbed = true;
PlayDyingSound();
if ( class'GameInfo'.static.UseLowGore() )
return;
if ( ItBUURRNNNS != none )
{
ItBUURRNNNS.Emitters[0].SkeletalMeshActor = none;
ItBUURRNNNS.Destroy();
}
if( ObliteratedEffectClass != none )
Spawn( ObliteratedEffectClass,,, Location, HitRotation );
super.SpawnGibs(HitRotation,ChunkPerterbation);
if ( FRand() < 0.1 )
{
SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation );
SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation );
SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation );
SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation );
}
else if ( FRand() < 0.25 )
{
SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation );
SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation );
if ( FRand() < 0.5 )
{
SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation );
}
}
else if ( FRand() < 0.35 )
SpawnSeveredGiblet( DetachedLegClass, Location, HitRotation, ChunkPerterbation );
else if ( FRand() < 0.5 )
{
SpawnSeveredGiblet( DetachedArmClass, Location, HitRotation, ChunkPerterbation );
}
}
simulated function StartDeRes()
{
if( Level.NetMode == NM_DedicatedServer )
return;
AmbientGlow=0;
MaxLights=5;
// DeResFX = Spawn(class'DeResPart', self, , Location);
//Skins[0] = DeResMat0;
//Skins[1] = DeResMat1;
if( Physics == PHYS_KarmaRagdoll )
{
// Remove flames
RemoveFlamingEffects();
// Turn off any overlays
SetOverlayMaterial(None, 0.0f, true);
}
}
// Remove Shield Sounds , Randomize for Human Pain sound.
function int ShieldAbsorb(int dam)
{
local float Interval, damage, Remaining;
//local int PainSound;
damage = dam;
if ( ShieldStrength == 0 )
return damage;
if ( KFPlayerReplicationInfo(PlayerReplicationInfo) != none && KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
{
damage *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetBodyArmorDamageModifier(KFPlayerReplicationInfo(PlayerReplicationInfo));
}
// Super.ShieldAbsorb(dam);
//SetOverlayMaterial( ShieldHitMat, ShieldHitMatTime, false );
// Randomize Painsounds on Armor hit
// PainSound = rand(6);
// if (PainSound == 0)
// PlaySound(sound'KFPlayerSound.hpain3', SLOT_Pain,2*TransientSoundVolume,,400);
// else if (PainSound == 1)
// PlaySound(sound'KFPlayerSound.hpain2', SLOT_Pain,2*TransientSoundVolume,,400);
// else if (PainSound == 2)
// PlaySound(sound'KFPlayerSound.hpain1', SLOT_Pain,2*TransientSoundVolume,,400);
// else if (PainSound == 3)
// PlaySound(sound'KFPlayerSound.hpain3', SLOT_Pain,2*TransientSoundVolume,,400);
// else if (PainSound == 4)
// PlaySound(sound'KFPlayerSound.hpain2', SLOT_Pain,2*TransientSoundVolume,,400);
// else if (PainSound == 5)
// PlaySound(sound'KFPlayerSound.hpain1', SLOT_Pain,2*TransientSoundVolume,,400);
if ( ShieldStrength > SmallShieldStrength )
{
Interval = ShieldStrength - SmallShieldStrength;
if ( Interval >= 0.75 * damage )
{
ShieldStrength -= 0.75 * damage;
if ( ShieldStrength < SmallShieldStrength )
SmallShieldStrength = ShieldStrength;
return (0.25 * Damage);
}
else
{
ShieldStrength = SmallShieldStrength;
damage -= Interval;
Remaining = 0.33 * Interval;
if ( Remaining <= damage )
return damage;
damage -= Remaining;
}
}
if ( ShieldStrength >= 0.5 * damage )
{
ShieldStrength -= damage ;
SmallShieldStrength = ShieldStrength;
return Remaining + (0.25 * damage); // 0.5
}
else
{
damage -= ShieldStrength;
ShieldStrength = 0;
SmallShieldStrength = 0;
}
return damage + Remaining;
}
// Play the pawn firing animations
simulated function StartFiringX(bool bAltFire, bool bRapid)
{
local name FireAnim;
local int AnimIndex;
if ( HasUDamage() && (Level.TimeSeconds - LastUDamageSoundTime > 0.25) )
{
LastUDamageSoundTime = Level.TimeSeconds;
PlaySound(UDamageSound, SLOT_None, 1.5*TransientSoundVolume,,700);
}
if (Physics == PHYS_Swimming)
return;
AnimIndex = Rand(4);
if (bAltFire)
{
if( bIsCrouched )
{
FireAnim = FireCrouchAltAnims[AnimIndex];
}
else
{
FireAnim = FireAltAnims[AnimIndex];
}
}
else
{
if( bIsCrouched )
{
FireAnim = FireCrouchAnims[AnimIndex];
}
else
{
FireAnim = FireAnims[AnimIndex];
}
}
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
if (bRapid)
{
if (FireState != FS_Looping)
{
LoopAnim(FireAnim,, 0.0, 1);
FireState = FS_Looping;
}
}
else
{
PlayAnim(FireAnim,, 0.0, 1);
FireState = FS_PlayOnce;
}
IdleTime = Level.TimeSeconds;
}
simulated function StopFiring()
{
if (FireState == FS_Looping)
FireState = FS_PlayOnce;
IdleTime = Level.TimeSeconds;
}
simulated function AnimEnd(int Channel)
{
if (Channel == 1)
{
if (FireState == FS_Ready)
{
AnimBlendToAlpha(1, 0.0, 0.12);
FireState = FS_None;
}
else if (FireState == FS_PlayOnce)
{
if( bIsCrouched )
{
PlayAnim(PostFireBlendCrouchAnim,, 0.1, 1);
}
else
{
PlayAnim(PostFireBlendStandAnim,, 0.1, 1);
}
FireState = FS_Ready;
IdleTime = Level.TimeSeconds;
}
else
AnimBlendToAlpha(1, 0.0, 0.12);
}
else if ( bKeepTaunting && (Channel == 0) )
PlayVictoryAnimation();
}
function RemoveInventorySP( class<inventory> ItemClass )
{
// If this item is in our inventory chain, unlink it.
local actor Link;
local int Count;
local inventory Item ;
Item = spawn(ItemClass) ;
if ( ItemClass == Weapon.class )
Weapon = None;
if ( ItemClass == SelectedItem.class )
SelectedItem = None;
for( Link = Self; Link!=None; Link=Link.Inventory )
{
if( Link.Inventory.class == ItemClass )
{
Link.Inventory = Item.Inventory;
Item.Inventory = None;
Link.NetUpdateTime = Level.TimeSeconds - 1;
Item.NetUpdateTime = Level.TimeSeconds - 1;
break;
}
if ( Level.NetMode == NM_Client )
{
Count++;
if ( Count > 1000 )
break;
}
}
Item.SetOwner(None);
}
// another one cut-n-pasted to remove must-have-ammo fetish
exec function SwitchToLastWeapon()
{
if ( (Weapon != None) && (Weapon.OldWeapon != None) ) // && Weapon.OldWeapon.HasAmmo() )
{
PendingWeapon = Weapon.OldWeapon;
Weapon.PutDown();
}
}
// TODO: GetWeapon
simulated function AddHealth()
{
local int tempHeal ;
if((level.TimeSeconds - lastHealTime) >= 0.1)
{
if(Health < HealthMax)
{
tempHeal = int(10 * (level.TimeSeconds - lastHealTime)) ;
if(tempHeal>0)
lastHealTime = level.TimeSeconds ;
Health = Min(Health+tempHeal, HealthMax);
HealthToGive -= tempHeal ;
}
else
{
lastHealTime = level.timeSeconds ;
// if we are all healed, there's gonna be no more healing
HealthToGive = 0 ;
}
}
}
function bool GiveHealth(int HealAmount, int HealMax)
{
// Taking this out for now because it nerfs the high level medic perks - Ramm
// if(healAmount >= 50)
// healAmount = 50;
// If someone gets healed while burning, reduce the burn length/damage
if( BurnDown > 0 )
{
if( BurnDown > 1 )
{
BurnDown *= 0.5;
}
LastBurnDamage *= 0.5;
}
// Don't let them heal more than the max health
if( (healAmount + HealthToGive + Health) > HealthMax)
{
healAmount = HealthMax - (Health + HealthToGive);
if( healAmount == 0 )
{
return false;
}
}
if( Health<HealMax )
{
HealthToGive+=HealAmount;
lastHealTime = level.timeSeconds;
return true;
}
Return False;
}
function ThrowGrenade()
{
local inventory inv;
local Frag aFrag;
for ( inv = inventory; inv != none; inv = inv.Inventory )
{
aFrag = Frag(inv);
if ( aFrag != none && aFrag.HasAmmo() && !bThrowingNade )
{
if ( KFWeapon(Weapon) == none || Weapon.GetFireMode(0).NextFireTime - Level.TimeSeconds > 0.1 ||
(KFWeapon(Weapon).bIsReloading && !KFWeapon(Weapon).InterruptReload()) )
{
return;
}
//TODO: cache this without setting SecItem yet
//SecondaryItem = aFrag;
KFWeapon(Weapon).ClientGrenadeState = GN_TempDown;
Weapon.PutDown();
break;
//aFrag.StartThrow();
}
}
}
function WeaponDown()
{
local inventory inv;
local Frag aFrag;
for(inv=inventory; inv!=none; inv=inv.Inventory)
{
aFrag=Frag(inv);
if(aFrag!=none && aFrag.HasAmmo() )
{
SecondaryItem = aFrag;
aFrag.StartThrow();
}
}
}
simulated function HandleNadeThrowAnim()
{
if( Weapon != none )
{
if( AK47AssaultRifle(Weapon) != none )
{
SetAnimAction('Frag_AK47');
}
else if( Bullpup(Weapon) != none || SeekerSixRocketLauncher(Weapon) != none)
{
SetAnimAction('Frag_Bullpup');
}
else if( Crossbow(Weapon) != none )
{
SetAnimAction('Frag_Crossbow');
}
else if( Deagle(Weapon) != none || Magnum44Pistol(Weapon) != none || MK23Pistol(Weapon) != none)
{
SetAnimAction('Frag_Single9mm');
}
else if( KFWeapon(Weapon) != none && KFWeapon(Weapon).bDualWeapon )
{
SetAnimAction('Frag_Dual9mm');
}
else if( FlameThrower(Weapon) != none )
{
SetAnimAction('Frag_Flamethrower');
}
else if( Axe(Weapon) != none || DwarfAxe(Weapon) != none )
{
SetAnimAction('Frag_Axe');
}
else if( Chainsaw(Weapon) != none )
{
SetAnimAction('Frag_Chainsaw');
}
else if( Katana(Weapon) != none || ClaymoreSword(Weapon) != none )
{
SetAnimAction('Frag_Katana');
}
else if( Knife(Weapon) != none )
{
SetAnimAction('Frag_Knife');
}
else if( Machete(Weapon) != none )
{
SetAnimAction('Frag_Knife');
}
else if( Syringe(Weapon) != none )
{
SetAnimAction('Frag_Syringe');
}
else if( Welder(Weapon) != none )
{
SetAnimAction('Frag_Syringe');
}
else if( BoomStick(Weapon) != none )
{
SetAnimAction('Frag_HuntingShotgun');
}
else if( LAW(Weapon) != none )
{
SetAnimAction('Frag_LAW');
}
else if( Shotgun(Weapon) != none || BenelliShotgun(Weapon) != none || Trenchgun(Weapon) != none)
{
SetAnimAction('Frag_Shotgun');
}
else if( Winchester(Weapon) != none )
{
SetAnimAction('Frag_Winchester');
}
else if( Single(Weapon) != none )
{
SetAnimAction('Frag_Single9mm');
}
else if( M14EBRBattleRifle(Weapon) != none || SPSniperRifle(Weapon) != none )
{
SetAnimAction('Frag_M14');
}
else if( SCARMK17AssaultRifle(Weapon) != none )
{
SetAnimAction('Frag_SCAR');
}
else if( AA12AutoShotgun(Weapon) != none || FNFAL_ACOG_AssaultRifle(Weapon) != none
|| SPAutoShotgun(Weapon) != none )
{
SetAnimAction('Frag_AA12');
}
else if( MP5MMedicGun(Weapon) != none || KSGShotgun(Weapon) != none )
{
SetAnimAction('Frag_MP5');
}
else if( MP7MMedicGun(Weapon) != none )
{
SetAnimAction('Frag_MP7');
}
else if( M7A3MMedicGun(Weapon) != none || KrissMMedicGun(Weapon) != none )
{
SetAnimAction('Frag_Kriss');
}
else if( PipeBombExplosive(Weapon) != none )
{
SetAnimAction('Frag_PipeBomb');
}
else if( M79GrenadeLauncher(Weapon) != none || ZEDMKIIWeapon(Weapon) != none )
{
SetAnimAction('Frag_M79');
}
else if( M32GrenadeLauncher(Weapon) != none )
{
SetAnimAction('Frag_M32_MGL');
}
else if( SealSquealHarpoonBomber(Weapon) != none )
{
SetAnimAction('Frag_IJC_SealSqueal');
}
else if( M4203AssaultRifle(Weapon) != none || M99SniperRifle(Weapon) != none )
{
SetAnimAction('Frag_M4203');
}
else if( M4AssaultRifle(Weapon) != none || MKb42AssaultRifle(Weapon) != none)
{
SetAnimAction('Frag_M4');
}
else if( HuskGun(Weapon) != none )
{
SetAnimAction('Frag_HuskGun');
}
else if( ZEDGun(Weapon) != none )
{
SetAnimAction('Frag_Zed');
}
else if( NailGun(Weapon) != none )
{
SetAnimAction('Frag_Bullpup');
}
else if( SPThompsonSMG(Weapon) != none || ThompsonDrumSMG(Weapon) != none)
{
SetAnimAction('Frag_IJC_spThompson_Drum');
}
else if( ThompsonSMG(Weapon) != none )
{
SetAnimAction('Frag_Thompson');
}
else if( Scythe(Weapon) != none )
{
SetAnimAction('Frag_Scythe');
}
else if( Crossbuzzsaw(Weapon) != none )
{
SetAnimAction('Frag_Cheetah');
}
else if( FlareRevolver(Weapon) != none )
{
SetAnimAction('Frag_Single9mm');
}
}
else
{
SetAnimAction('Frag_Knife');
}
}
simulated function ThrowGrenadeFinished()
{
SecondaryItem = none;
KFWeapon(Weapon).ClientGrenadeState = GN_BringUp;
Weapon.BringUp();
bThrowingNade = false;
}
simulated function SetNadeTimeOut(float NewTimeOut)
{
NadeThrowTimeout = NewTimeOut;
}
/* Feet height adjusting functions ======================================================*/
simulated function SetFootHeight( float HeightMulti, byte iNum )
{
// local rotator R;
//
// OldAdjust[iNum] = (HeightMulti-OldAdjust[iNum])*0.5+OldAdjust[iNum];
// if( Abs(OldAdjust[iNum]-HeightMulti)<0.1 )
// OldAdjust[iNum] = HeightMulti;
// HeightMulti = OldAdjust[iNum];
// HeightMulti = 1.f-HeightMulti; // Invert this value.
// switch( FeetAdjSpec.Default.TorseRotType )
// {
// case BRot_Yaw:
// R.Yaw = FeetAdjSpec.Default.MaxTorsoTurn*HeightMulti;
// break;
// case BRot_Roll:
// R.Roll = FeetAdjSpec.Default.MaxTorsoTurn*HeightMulti;
// break;
// default:
// R.Pitch = FeetAdjSpec.Default.MaxTorsoTurn*HeightMulti;
// }
// SetBoneRotation(FeetAdjSpec.Default.TorsoBones[iNum],R);
// R = rot(0,0,0);
// switch( FeetAdjSpec.Default.KneeRotType )
// {
// case BRot_Yaw:
// R.Yaw = FeetAdjSpec.Default.MaxKneeTurn*HeightMulti;
// break;
// case BRot_Roll:
// R.Roll = FeetAdjSpec.Default.MaxKneeTurn*HeightMulti;
// break;
// default:
// R.Pitch = FeetAdjSpec.Default.MaxKneeTurn*HeightMulti;
// }
// SetBoneRotation(FeetAdjSpec.Default.KneeBones[iNum],R);
}
simulated function UpdateFeetCoords()
{
// local Coords C;
// local byte i;
// local vector X,Y,Z,HL,Pos;
//
// GetAxes(Rotation,X,Y,Z);
// Pos = Location+PrePivot;
// for( i=0; i<2; i++ )
// {
// C = GetBoneCoords(FeetAdjSpec.Default.FeetBones[i]);
// C.Origin = (C.Origin-Pos)<<Rotation;
// C.Origin = X*C.Origin.X+Y*C.Origin.Y+Pos-Z*MinZHeight*DrawScale;
// C.XAxis = C.Origin-Z*MaxZHeight*DrawScale;
// if( Trace(HL,C.YAxis,C.XAxis,C.Origin,true)==None )
// SetFootHeight(1,i);
// else SetFootHeight(FClamp(VSize(HL-C.Origin)/DrawScale/MaxZHeight,0.f,1.f),i);
// }
}
/* End of feet height adjusting functions ======================================================*/
simulated function Tick(float DeltaTime)
{
// local float DMult;
if( Role < ROLE_Authority && bThrowingNade )
{
if( NadeThrowTimeout > 0 )
{
NadeThrowTimeout -= DeltaTime;
}
// This is a hack to clear this flag on the client after a bit of time. This fixes a bug where you could get stuck unable to use weapons
if( NadeThrowTimeout <= 0 )
{
NadeThrowTimeout = 0;
ThrowGrenadeFinished();
}
}
// IN other words - we're moving, we've got a piece, but we're not firing or reloading, or jumping / falling Faust:Perhaps we need that later: VSize(Acceleration) != 0 &&
if (level.NetMode != NM_DEDICATEDSERVER)
{
if(bBurnified && !bBurnApplied)
{
if ( !bGibbed )
{
StartBurnFX();
}
}
else if(!bBurnified && bBurnApplied)
StopBurnFX();
}
// CheckFlashLightAnims();
if( bResetingAnimAct && (AnimActResetTime<Level.TimeSeconds) ) // Reset replication.
{
bResetingAnimAct = False;
AnimAction = '';
}
if(healthToGive > 0 && health > 0) //
AddHealth() ;
else if(healthToGive < 0)
healthToGive = 0 ;
if(BileCount>0 && NextBileTime<level.TimeSeconds)
{
--BileCount;
NextBileTime+=BileFrequency;
TakeBileDamage();
}
// if( bHasFootAdjust && (Level.TimeSeconds-LastRenderTime)<1 )
// {
// UpdateFeetCoords();
// if( Level.NetMode!=NM_ListenServer )
// {
// if( Physics!=PHYS_Walking )
// DMult = 1;
// else DMult = OldAdjust[0]+OldAdjust[1];
// if( DMult<1.65 && PrePivot.Z<0 )
// {
// PrePivot.Z+=DeltaTime*60f;
// SetDrawScale(DrawScale);
// }
// else if( DMult>1.85 && PrePivot.Z>-35 )
// {
// PrePivot.Z-=DeltaTime*60f;
// SetDrawScale(DrawScale);
// }
// }
// }
// KFTODO: Maybe take this out because we're using notifies for footsteps in third person now
// if( Level.Netmode != NM_DedicatedServer )
// {
// // do footsteps for nonlocal pawns and bots
// if( !IsLocallyControlled() || (Level.Netmode == NM_Standalone && !IsHumanControlled()))
// {
// CheckFootSteps(DeltaTime);
// }
// }
if( Physics == PHYS_KarmaRagdoll && bDestroyAfterRagDollTick &&
!bProcessedRagTickDestroy && GetRagDollFrames() > 0 )
{
bProcessedRagTickDestroy = true;
Destroy();
}
// If we've flagged this character to be destroyed next tick, handle that
else if( bDestroyNextTick && TimeSetDestroyNextTickTime < Level.TimeSeconds )
{
Destroy();
}
Super.Tick(deltaTime);
}
// Blend the upper body back to full body animation.
// Called by the native code when AnimBlendTime counts down to zero
simulated event AnimBlendTimer()
{
AnimBlendToAlpha(1, 0.0, 0.12);
// Force a new idle anim to play, since we likely just switched weapons
bIsIdle=false;
IdleTime = Level.TimeSeconds;
}
simulated event SetAnimAction(name NewAction)
{
local float UsedBlendOutTime;
if( NewAction=='' )
Return;
if (!bWaitForAnim)
{
AnimAction = NewAction;
if ( AnimAction == 'Weapon_Switch' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
// Set the timer to blend out the upper body animation
if( HasAnim( AnimAction ) )
{
UsedBlendOutTime = GetAnimDuration(NewAction, 1.0);
}
else
{
UsedBlendOutTime = 0.2;
}
AnimBlendTime = UsedBlendOutTime + 0.1;
}
else if ( AnimAction == IdleWeaponAnim )
{
PlayAnim(AnimAction,,0.1);
AnimBlendToAlpha(1,0.0,0.05);
}
else if ( AnimAction == 'Reload' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
}
else if ( AnimAction == 'AxeAttack' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
}
else if ( AnimAction == 'ChainSawAttack' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
}
else if ( AnimAction == 'DeagleHold' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
LoopAnim(NewAction,, 0.0, 1);
}
else if ( AnimAction == 'DualiesHold' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
LoopAnim(NewAction,, 0.0, 1);
}
else if ( AnimAction == 'Frag_AK47' || AnimAction == 'Frag_Bullpup'
|| AnimAction == 'Frag_Crossbow' || AnimAction == 'Frag_Single9mm'
|| AnimAction == 'Frag_Dual9mm' || AnimAction == 'Frag_Flamethrower'
|| AnimAction == 'Frag_Axe' || AnimAction == 'Frag_Chainsaw'
|| AnimAction == 'Frag_Katana' || AnimAction == 'Frag_Knife'
|| AnimAction == 'Frag_Syringe' || AnimAction == 'Frag_HuntingShotgun'
|| AnimAction == 'Frag_LAW' || AnimAction == 'Frag_Shotgun'
|| AnimAction == 'Frag_M14' || AnimAction == 'Frag_SCAR'
|| AnimAction == 'Frag_AA12' || AnimAction == 'Frag_MP7'
|| AnimAction == 'Frag_PipeBomb' || AnimAction == 'Frag_M79'
|| AnimAction == 'Frag_M32_MGL' || AnimAction == 'Frag_M4'
|| AnimAction == 'Frag_M4203' || AnimAction == 'Frag_MP5'
|| AnimAction == 'Frag_HuskGun' || AnimAction == 'Frag_Kriss'
|| AnimAction == 'Frag_Thompson' || AnimAction == 'Frag_scythe'
|| AnimAction == 'Frag_Cheetah' || AnimAction == 'Frag_Zed'
|| AnimAction == 'Frag_IJC_spThompson_Drum' || AnimAction == 'Frag_IJC_SealSqueal')
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
bThrowingNade = true;
}
else if ( AnimAction == 'ShotgunFire' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
}
else if ( AnimAction == 'DeagleBlast' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.0, 1);
} // Reloads
else if ( AnimAction == 'Reload1' || AnimAction == 'Reload_BullPup'
|| AnimAction == 'Reload_Single9mm' || AnimAction == 'Reload_Winchester'
|| AnimAction == 'Reload_Crossbow' || AnimAction == 'Reload_Dual9mm'
|| AnimAction == 'Reload_Flamethrower' || AnimAction == 'Reload_HuntingShotgun'
|| AnimAction == 'Reload_LAW' || AnimAction == 'Reload_Shotgun'
|| AnimAction == 'Reload_Winchester' || AnimAction == 'Reload_AK47'
|| AnimAction == 'Reload_M14' || AnimAction == 'Reload_SCAR'
|| AnimAction == 'Reload_MP7' || AnimAction == 'Reload_AA12'
|| AnimAction == 'Reload_Secondary_M4203' || AnimAction == 'Reload_Fal_Acog'
|| AnimAction == 'Reload_Fal_Acog' || AnimAction == 'Reload_M7A3'
|| AnimAction == 'Reload_KSG' || AnimAction == 'Reload_Flare'
|| AnimAction == 'Reload_DualFlare' || AnimAction == 'Reload_Cheetah'
|| AnimAction == 'Reload_Thompson' || AnimAction == 'Reload_Kriss'
|| AnimAction == 'Reload_Zed' || AnimAction == 'Reload_IJC_spJackHammer'
|| AnimAction == 'Reload_spSinper' || AnimAction == 'Reload_IJC_spThompson_Drum'
|| AnimAction == 'Reload_IJC_SealSqueal' || AnimAction == 'Reload_M32_MGL'
|| AnimAction == 'Reload_IJC_SeekerSix' || AnimAction == 'Reload_IJC_ZEDV2' )
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.1, 1);
FireState = FS_Ready;
}
else if ( ((Physics == PHYS_None)|| ((Level.Game != None) && Level.Game.IsInState('MatchOver'))) && (DrivenVehicle == None) )
{
PlayAnim(AnimAction,,0.1);
AnimBlendToAlpha(1,0.0,0.05);
}
else if ( (DrivenVehicle != None) || (Physics == PHYS_Falling) || ((Physics == PHYS_Walking) && (Velocity.Z != 0)) )
{
if ( CheckTauntValid(AnimAction) )
{
if (FireState == FS_None || FireState == FS_Ready)
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.1, 1);
FireState = FS_Ready;
}
}
else if ( HasAnim(AnimAction) && PlayAnim(AnimAction) )
{
if ( Physics != PHYS_None )
bWaitForAnim = true;
}
else AnimAction = NewAction;
}
else if (bIsIdle && !bIsCrouched && (Bot(Controller) == None) ) // standing taunt
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(AnimAction,,0.1,1);
}
else if (FireState == FS_None || FireState == FS_Ready)
{
AnimBlendParams(1, 1.0, 0.0, 0.2, FireRootBone);
PlayAnim(NewAction,, 0.1, 1);
FireState = FS_Ready;
}
}
if( Level.NetMode!=NM_Client )
{
// Reset to fix replication.
bResetingAnimAct = True;
AnimActResetTime = Level.TimeSeconds+0.45;
}
}
simulated function StartBurnFX()
{
if( bDeleteMe )
{
return;
}
if( ItBUURRNNNS==None )
{
ItBUURRNNNS = Spawn(BurnEffect);
ItBUURRNNNS.SetBase(Self);
ItBUURRNNNS.Emitters[0].SkeletalMeshActor = self;
ItBUURRNNNS.Emitters[0].UseSkeletalLocationAs = PTSU_SpawnOffset;
}
bBurnApplied = True;
}
simulated function StopBurnFX()
{
RemoveFlamingEffects();
if( ItBUURRNNNS!=None )
ItBUURRNNNS.Kill();
bBurnApplied = False;
}
// Process a precision hit
function ProcessLocationalDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class<DamageType> damageType, array<int> PointsHit )
{
local int actualDamage, originalDamage, cumulativeDamage, totalDamage, i;
local int HighestDamagePoint, HighestDamageAmount;
local bool bHeadShot;
// Hit detection debugging
// local coords CO;
// local vector HeadLoc;
// local bool bFirstHit;
originalDamage = damage;
// If someone else has killed this player , return
if( bDeleteMe || PointsHit.Length < 1 || Health <= 0 )
return;
// Don't process locational damage if we're not going to damage a friendly anyway
if( TeamGame(Level.Game)!=None && TeamGame(Level.Game).FriendlyFireScale==0 && instigatedBy!=None && instigatedBy!=Self
&& instigatedBy.GetTeamNum()==GetTeamNum() )
{
Return;
}
for(i=0; i<PointsHit.Length; i++)
{
// If someone else has killed this player , return
if( bDeleteMe || Health <= 0 )
return;
actualDamage = originalDamage;
actualDamage *= Hitpoints[PointsHit[i]].DamageMultiplier;
totalDamage += actualDamage;
actualDamage = Level.Game.ReduceDamage(actualDamage, self, instigatedBy, HitLocation, Momentum, DamageType);
cumulativeDamage += actualDamage;
if( actualDamage > HighestDamageAmount )
{
HighestDamageAmount = actualDamage;
HighestDamagePoint = PointsHit[i];
}
// Store if one of the shots was a headshot
if( Hitpoints[PointsHit[i]].HitPointType == PHP_Head && class<KFWeaponDamageType>(damageType)!=none &&
class<KFWeaponDamageType>(damageType).default.bCheckForHeadShots)
{
bHeadShot = true;
}
//log("We hit "$GetEnum(enum'EPawnHitPointType',Hitpoints[PointsHit[i]].HitPointType));
// Hit detection debugging
/*if( PointsHit[i] != 0 && !bFirstHit )
{
CO = GetBoneCoords(Hitpoints[PointsHit[i]].PointBone);
HeadLoc = CO.Origin;
HeadLoc = HeadLoc + (Hitpoints[PointsHit[i]].PointOffset >> GetBoneRotation(Hitpoints[PointsHit[i]].PointBone));
DrawLocation = HeadLoc;
DrawRotation = GetBoneRotation(Hitpoints[PointsHit[i]].PointBone);
DrawIndex = PointsHit[i];
HitPointDebugByte++;
bFirstHit = true;
}*/
// Lets exit out if one of the shots killed the player
if ( cumulativeDamage >= Health )
{
// Play a sound when someone gets a headshot - KFTODO: Replace this with a better bullet hitting a helmet sound
if( bHeadShot )
{
PlaySound(sound'ProjectileSounds.impact_metal09', SLOT_None,2.0,true,500);
}
TakeDamage(totalDamage, instigatedBy, hitlocation, momentum, damageType, HighestDamagePoint);
}
}
if( totalDamage > 0 )
{
// If someone else has killed this player , return
if( bDeleteMe || Health <= 0 )
return;
// Play a sound when someone gets a headshot
if( bHeadShot )
{
// Play a sound when someone gets a headshot - KFTODO: Replace this with a better bullet hitting a helmet sound
PlaySound(sound'ProjectileSounds.impact_metal09', SLOT_None,2.0,true,500);
}
TakeDamage(totalDamage, instigatedBy, hitlocation, momentum, damageType, HighestDamagePoint);
}
}
// Hit detection debugging - Only use when debugging
/*
simulated function DrawBoneLocation()
{
local vector X, Y, Z;
GetAxes(DrawRotation, X,Y,Z);
ClearStayingDebugLines();
DrawStayingDebugLine(HitStart, HitEnd, 0,255,0);
Spawn(class 'ROEngine.RODebugTracer',self,,HitStart,Rotator(Normal(HitEnd-HitStart)));
DrawDebugCylinder(DrawLocation,Z,Y,X,Hitpoints[DrawIndex].PointRadius * Hitpoints[DrawIndex].PointScale,Hitpoints[DrawIndex].PointHeight * Hitpoints[DrawIndex].PointScale,10,0, 255, 0);
}
simulated function DrawDebugCylinder(vector Base,vector X, vector Y,vector Z, FLOAT Radius,float HalfHeight,int NumSides, byte R, byte G, byte B)
{
local float AngleDelta;
local vector LastVertex, Vertex;
local int SideIndex;
AngleDelta = 2.0f * PI / NumSides;
LastVertex = Base + X * Radius;
for(SideIndex = 0;SideIndex < NumSides;SideIndex++)
{
Vertex = Base + (X * Cos(AngleDelta * (SideIndex + 1)) + Y * Sin(AngleDelta * (SideIndex + 1))) * Radius;
DrawStayingDebugLine( LastVertex - Z * HalfHeight,Vertex - Z * HalfHeight,R,G,B);
DrawStayingDebugLine( LastVertex + Z * HalfHeight,Vertex + Z * HalfHeight,R,G,B);
DrawStayingDebugLine( LastVertex - Z * HalfHeight,LastVertex + Z * HalfHeight,R,G,B);
LastVertex = Vertex;
}
}*/
function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class<DamageType> damageType, optional int HitIdx )
{
local KFPlayerReplicationInfo KFPRI;
LastHitDamType = damageType;
LastDamagedBy = instigatedBy;
super.TakeDamage(Damage, instigatedBy, hitLocation, momentum, damageType);
healthtoGive-=5;
KFPRI = KFPlayerReplicationInfo(PlayerReplicationInfo);
// Just return if this wouldn't even damage us. Prevents us from catching on fire for high level perks that dont take fire damage
if( KFPRI != none && KFPRI.ClientVeteranSkill != none )
{
if( KFPRI.ClientVeteranSkill.Static.ReduceDamage(KFPRI, self, instigatedBy, Damage, DamageType) <= 0 )
{
return;
}
}
if ( class<DamTypeBurned>(damageType) != none || class<DamTypeFlamethrower>(damageType) != none)
{
if( TeamGame(Level.Game)!=None && TeamGame(Level.Game).FriendlyFireScale==0 && instigatedBy!=None && instigatedBy!=Self
&& instigatedBy.GetTeamNum()==GetTeamNum() )
{
Return;
}
// Do burn damage if the damage was significant enough
if( Damage > 2 )
{
// If we are already burning, and this damage is more than our current burn amount, add more burn time
if( BurnDown > 0 && Damage > LastBurnDamage )
{
BurnDown = 5;
BurnInstigator = instigatedBy;
}
LastBurnDamage = Damage;
if (BurnDown <= 0 )
{
bBurnified = true;
BurnDown = 5;
BurnInstigator = instigatedBy;
SetTimer(1.5,true);
}
}
}
if(class<DamTypeVomit>(DamageType)!=none)
{
BileCount=7;
BileInstigator = instigatedBy;
LastBileDamagedByType=class<DamTypeVomit>(DamageType);
if(NextBileTime< Level.TimeSeconds )
NextBileTime = Level.TimeSeconds+BileFrequency;
if ( Level.Game != none && Level.Game.GameDifficulty >= 4.0 && KFPlayerController(Controller) != none &&
!KFPlayerController(Controller).bVomittedOn)
{
KFPlayerController(Controller).bVomittedOn = true;
KFPlayerController(Controller).VomittedOnTime = Level.TimeSeconds;
if ( Controller.TimerRate == 0.0 )
{
Controller.SetTimer(10.0, false);
}
}
}
else if ( class<SirenScreamDamage>(DamageType) != none )
{
if ( Level.Game != none && Level.Game.GameDifficulty >= 4.0 && KFPlayerController(Controller) != none &&
!KFPlayerController(Controller).bScreamedAt)
{
KFPlayerController(Controller).bScreamedAt = true;
KFPlayerController(Controller).ScreamTime = Level.TimeSeconds;
if ( Controller.TimerRate == 0.0 )
{
Controller.SetTimer(10.0, false);
}
}
}
}
function TakeBileDamage()
{
Super.TakeDamage(2+Rand(3), BileInstigator, Location, vect(0,0,0), LastBileDamagedByType);
healthtoGive-=5;
}
function bool AddShieldStrength(int ShieldAmount)
{
if(ShieldStrength >= 100)
return false;
ShieldStrength+=ShieldAmount;
if(ShieldStrength > 100)
ShieldStrength = 100;
return true ;
}
function TakeFireDamage(int Damage, pawn BInstigator)
{
if( Damage > 0 )
{
TakeDamage(Damage, BInstigator, Location, vect(0,0,0), class'DamTypeBurned');
if (BurnDown > 0)
{
BurnDown --; // Decrement the number of FireDamage calls left before our Zombie is extinguished :)
}
if(BurnDown==0)
{
bBurnified = false;
}
}
else
{
BurnDown = 0;
bBurnified = false;
}
}
function PlayHit(float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum, optional int HI )
{
local Vector HitNormal;
local Vector HitRay;
local Name HitBone;
local float HitBoneDist;
local PlayerController PC;
local bool bShowEffects, bRecentHit;
local ProjectileBloodSplat BloodHit;
local rotator SplatRot;
bRecentHit = Level.TimeSeconds - LastPainTime < 0.2;
// Take you out of ironsights when taking momentum from damage
if( VSize(Momentum) > 0 && KFWeapon(Weapon) != none )
{
KFWeapon(Weapon).bForceLeaveIronsights = true;
}
if ( Damage <= 0 )
return;
// Call the modified version of the original Pawn playhit
OldPlayHit(Damage,InstigatedBy,HitLocation,DamageType,Momentum);
PC = PlayerController(Controller);
bShowEffects = ( (Level.NetMode != NM_Standalone) || (Level.TimeSeconds - LastRenderTime < 2.5)
|| ((InstigatedBy != None) && (PlayerController(InstigatedBy.Controller) != None))
|| (PC != None) );
if ( !bShowEffects )
return;
if ( BurnDown > 0 && !bBurnified )
bBurnified = true;
HitRay = vect(0,0,0);
if( InstigatedBy != None )
HitRay = Normal(HitLocation-(InstigatedBy.Location+(vect(0,0,1)*InstigatedBy.EyeHeight)));
if( DamageType.default.bLocationalHit )
{
CalcHitLoc( HitLocation, HitRay, HitBone, HitBoneDist );
}
else
{
HitLocation = Location;
HitBone = FireRootBone;
HitBoneDist = 0.0f;
}
if( DamageType.default.bAlwaysSevers && DamageType.default.bSpecial )
HitBone = 'head';
if( InstigatedBy != None )
HitNormal = Normal( Normal(InstigatedBy.Location-HitLocation) + VRand() * 0.2 + vect(0,0,2.8) );
else
HitNormal = Normal( Vect(0,0,1) + VRand() * 0.2 + vect(0,0,2.8) );
//log("HitLocation "$Hitlocation) ;
if ( DamageType.Default.bCausesBlood && (!bRecentHit || (bRecentHit && (FRand() > 0.8))))
{
if ( !class'GameInfo'.static.NoBlood() )
{
if ( Momentum != vect(0,0,0) )
SplatRot = rotator(Normal(Momentum));
else
{
if ( InstigatedBy != None )
SplatRot = rotator(Normal(Location - InstigatedBy.Location));
else
SplatRot = rotator(Normal(Location - HitLocation));
}
BloodHit = Spawn(ProjectileBloodSplatClass,InstigatedBy,, HitLocation, SplatRot);
}
}
// hack for siren
if ( (DamageType.name == 'SirenScreamDamage') && (Health < 0) )
{
if( (InstigatedBy != None) && (VSize(InstigatedBy.Location - Location) < 200) )
{
DoDamageFX( 'obliterate', 5000 * Damage, DamageType, Rotator(HitNormal) );
}
else
{
DoDamageFX( HeadBone, 5000 * Damage, DamageType, Rotator(HitNormal) );
PlaySound(DecapitationSound, SLOT_Misc,1.30,true,525);
}
}
else
DoDamageFX( HitBone, Damage, DamageType, Rotator(HitNormal) );
if (DamageType.default.DamageOverlayMaterial != None && Damage > 0 ) // additional check in case shield absorbed
SetOverlayMaterial( DamageType.default.DamageOverlayMaterial, DamageType.default.DamageOverlayTime, false );
}
// Modified version of the original Pawn playhit. Set up because we want our blood puffs to be directional based
// On the momentum of the bullet, not out from the center of the player
function OldPlayHit(float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum, optional int HitIndex)
{
local PlayerController Hearer;
if ( DamageType == None )
return;
if ( (Damage <= 0) && ((Controller == None) || !Controller.bGodMode) )
return;
if (Damage > DamageType.Default.DamageThreshold) //spawn some blood
{
SpawnHitEmitter( Damage, InstigatedBy, HitLocation, damageType, Momentum );
}
if ( Health <= 0 )
{
if ( PhysicsVolume.bDestructive && (PhysicsVolume.ExitActor != None) )
Spawn(PhysicsVolume.ExitActor);
return;
}
if ( Level.TimeSeconds - LastPainTime > 0.1 )
{
if ( InstigatedBy != None && (DamageType != None) && DamageType.default.bDirectDamage )
Hearer = PlayerController(InstigatedBy.Controller);
if ( Hearer != None )
Hearer.bAcuteHearing = true;
PlayTakeHit(HitLocation,Damage,damageType);
if ( Hearer != None )
Hearer.bAcuteHearing = false;
LastPainTime = Level.TimeSeconds;
}
}
function SpawnHitEmitter( float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum )
{
local Vector HitNormal;
local class<Effects> DesiredEffect;
local class<Emitter> DesiredEmitter;
local vector BloodOffset, Mo;
// Play any set effect
if ( EffectIsRelevant(Location,true) )
{
HitNormal = Normal(HitLocation - Location);
DesiredEffect = DamageType.static.GetPawnDamageEffect(HitLocation, Damage, Momentum, self, (Level.bDropDetail || Level.DetailMode == DM_Low));
if ( DesiredEffect != None )
{
BloodOffset = 0.2 * CollisionRadius * HitNormal;
BloodOffset.Z = BloodOffset.Z * 0.5;
Mo = Momentum;
if ( Mo.Z > 0 )
Mo.Z *= 0.5;
spawn(DesiredEffect,self,,HitLocation + BloodOffset, rotator(Mo));
}
// Spawn any preset emitter
DesiredEmitter = DamageType.Static.GetPawnDamageEmitter(HitLocation, Damage, Momentum, self, (Level.bDropDetail || Level.DetailMode == DM_Low));
if (DesiredEmitter != None)
{
if( InstigatedBy != none )
HitNormal = Normal((InstigatedBy.Location+(vect(0,0,1)*InstigatedBy.EyeHeight))-HitLocation);
spawn(DesiredEmitter,,,HitLocation+HitNormal + (-HitNormal * CollisionRadius), Rotator(HitNormal));
}
}
}
simulated function AttachEffect( class<xEmitter> EmitterClass, Name BoneName, Vector Location, Rotator Rotation )
{
local Actor a;
local int i;
if( bSkeletized || (BoneName == 'None') )
return;
for( i = 0; i < Attached.Length; i++ )
{
if( Attached[i] == None )
continue;
if( Attached[i].AttachmentBone != BoneName )
continue;
if( ClassIsChildOf( EmitterClass, Attached[i].Class ) )
return;
}
a = Spawn( EmitterClass,,, Location, Rotation );
if (a == none)
return;
if( !AttachToBone( a, BoneName ) )
{
log( "Couldn't attach "$EmitterClass$" to "$BoneName, 'Error' );
a.Destroy();
return;
}
for( i = 0; i < Attached.length; i++ )
{
if( Attached[i] == a )
break;
}
a.SetRelativeRotation( Rotation );
}
simulated function SpawnGiblet( class<Gib> GibClass, Vector Location, Rotator Rotation, float GibPerterbation )
{
local Gib Giblet;
local Vector Direction, Dummy;
if( (GibClass == None) || class'GameInfo'.static.UseLowGore() )
return;
Instigator = self;
Giblet = Spawn( GibClass,,, Location, Rotation );
if( Giblet == None )
return;
Giblet.bFlaming = bFlaming;
Giblet.SpawnTrail();
GibPerterbation *= 32768.0;
Rotation.Pitch += ( FRand() * 2.0 * GibPerterbation ) - GibPerterbation;
Rotation.Yaw += ( FRand() * 2.0 * GibPerterbation ) - GibPerterbation;
Rotation.Roll += ( FRand() * 2.0 * GibPerterbation ) - GibPerterbation;
GetAxes( Rotation, Dummy, Dummy, Direction );
Giblet.Velocity = Velocity + Normal(Direction) * (250 + 260 * FRand());
Giblet.LifeSpan = Giblet.LifeSpan + 2 * FRand() - 1;
}
State Dying
{
simulated function AnimEnd( int Channel );
simulated function bool SpecialCalcView( out Actor ViewActor, out vector CameraLocation, out rotator CameraRotation )
{
local Coords Co;
local vector HL,HN;
ViewActor = Self;
Co = GetBoneCoords('CHR_Head');
CameraLocation = Co.Origin+Co.XAxis*8;
// Make sure camera dosent show through world geometry.
if( Trace(HL,HN,CameraLocation+vect(0,0,25),CameraLocation,False)!=None )
CameraLocation+=HN*25;
if( Trace(HL,HN,CameraLocation-vect(0,0,25),CameraLocation,False)!=None )
CameraLocation+=HN*25;
if( Trace(HL,HN,CameraLocation+vect(25,0,0),CameraLocation,False)!=None )
CameraLocation+=HN*25;
if( Trace(HL,HN,CameraLocation-vect(25,0,0),CameraLocation,False)!=None )
CameraLocation+=HN*25;
if( Trace(HL,HN,CameraLocation+vect(0,25,0),CameraLocation,False)!=None )
CameraLocation+=HN*25;
if( Trace(HL,HN,CameraLocation-vect(0,25,0),CameraLocation,False)!=None )
CameraLocation+=HN*25;
GetAxes(GetBoneRotation('CHR_Head'),Co.XAxis,Co.YAxis,Co.ZAxis);
CameraRotation = OrthoRotation(-Co.YAxis,Co.ZAxis,Co.XAxis); // Turns the camera by 90 degrees.
Return True;
}
event FellOutOfWorld(eKillZType KillType)
{
local LavaDeath LD;
// If we fall past a lava killz while dead- burn off skin.
if( KillType == KILLZ_Lava )
{
if ( !bSkeletized )
{
if ( SkeletonMesh != None )
{
LinkMesh(SkeletonMesh, true);
Skins.Length = 0;
}
bSkeletized = true;
LD = spawn(class'LavaDeath', , , Location + vect(0, 0, 10), Rotation );
if ( LD != None )
LD.SetBase(self);
// This should destroy itself once its finished.
PlaySound( sound'Inf_Weapons.F1.f1_explode01', SLOT_None, 1.5*TransientSoundVolume ); // KFTODO: Replace this sound
}
return;
}
Super.FellOutOfWorld(KillType);
}
simulated function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HI )
{
local emitter BloodHit;
Health -= Damage;
if (Health <= -200)
{
// Gibbed
BloodHit = Spawn(class'KFMod.FeedingSpray',InstigatedBy,,Location,Rotation);
// KFTODO: Replace this spawn giblet with
// SpawnGiblet(class 'ClotGibHead',HitLocation, self.Rotation, 0.06 ) ;
//
// SpawnGiblet(class 'ClotGibTorso',HitLocation, self.Rotation, 0.06) ;
// SpawnGiblet(class 'ClotGibLowerTorso',HitLocation, self.Rotation, 0.06 ) ;
//
// SpawnGiblet(class 'ClotGibArm',HitLocation, self.Rotation, 0.06 ) ;
// SpawnGiblet(class 'ClotGibArm',HitLocation, self.Rotation, 0.06 ) ;
//
// SpawnGiblet(class 'ClotGibThigh',HitLocation, self.Rotation, 0.06 ) ;
// SpawnGiblet(class 'ClotGibThigh',HitLocation, self.Rotation, 0.06 ) ;
//
// SpawnGiblet(class 'ClotGibLeg',HitLocation, self.Rotation, 0.06 ) ;
// SpawnGiblet(class 'ClotGibLeg',HitLocation, self.Rotation, 0.06 ) ;
if( Physics == PHYS_KarmaRagdoll )
{
bDestroyAfterRagDollTick = true;
}
else
{
Destroy();
}
}
}
simulated function BeginState()
{
local int i;
bSpecialCalcView = Class'KFPawn'.Default.bRealDeathType;
if ( Controller != None )
{
if ( Controller.bIsPlayer )
Controller.PawnDied(self);
else Controller.Destroy();
}
for (i = 0; i < Attached.length; i++)
if (Attached[i] != None)
Attached[i].PawnBaseDied();
AmbientSound = None;
if( Level.NetMode==NM_DedicatedServer )
SetTimer(1,False);
SetTimer(5,False);
}
simulated function Timer()
{
if( Level.NetMode==NM_DedicatedServer )
{
Destroy();
Return;
}
if( Physics!=PHYS_None )
{
if( VSize(Velocity)>10 )
{
SetTimer(1,False);
Return;
}
SetPhysics(PHYS_None);
SetTimer(30,False);
if(PlayerShadow != None)
PlayerShadow.bShadowActive = false;
}
else if( (Level.TimeSeconds-LastRenderTime)>40 || Level.bDropDetail )
Destroy();
else SetTimer(5,False);
}
// We shorten the lifetime when the guys comes to rest.
// Alex: No , you dont.
event KVelDropBelow()
{
}
}
simulated event Destroyed()
{
local int i;
// Make attached explosives blow up when this pawn dies
for( i=0; i<Attached.length; i++ )
{
if( SealSquealProjectile(Attached[i])!=None )
{
SealSquealProjectile(Attached[i]).HandleBasePawnDestroyed();
}
}
if ( ItBUURRNNNS != none )
{
ItBUURRNNNS.Emitters[0].SkeletalMeshActor = none;
ItBUURRNNNS.Destroy();
}
if( Adjuster!=None )
Adjuster.Destroy();
if( SeveredLeftArm != none )
{
SeveredLeftArm.Destroy();
}
if( SeveredRightArm != none )
{
SeveredRightArm.Destroy();
}
if( SeveredRightLeg != none )
{
SeveredRightLeg.Destroy();
}
if( SeveredLeftLeg != none )
{
SeveredLeftLeg.Destroy();
}
if( SeveredHead != none )
{
SeveredHead.Destroy();
}
if ( AuxCollisionCylinder != none )
{
AuxCollisionCylinder.Destroy();
}
if ( AttachedEmitter != none )
{
AttachedEmitter.Destroy();
}
Super.Destroyed();
}
function Died(Controller Killer, class<DamageType> damageType, vector HitLocation)
{
local Vector TossVel;
local Trigger T;
local NavigationPoint N;
local PlayerDeathMark D;
local Projectile PP;
local FakePlayerPawn FP;
local int i;
if ( bDeleteMe || Level.bLevelChange || Level.Game == None )
return; // already destroyed, or level is being cleaned up
if ( DamageType.default.bCausedByWorld && (Killer == None || Killer == Controller) && LastHitBy != None )
Killer = LastHitBy;
// mutator hook to prevent deaths
// WARNING - don't prevent bot suicides - they suicide when really needed
if ( Level.Game.PreventDeath(self, Killer, damageType, HitLocation) )
{
Health = max(Health, 1); //mutator should set this higher
return;
}
// Turn off the auxilary collision when the player dies
if ( AuxCollisionCylinder != none )
{
AuxCollisionCylinder.SetCollision(false,false,false);
}
// Hack fix for team-killing.
if( KFPlayerReplicationInfo(PlayerReplicationInfo)!=None )
{
FP = KFPlayerReplicationInfo(PlayerReplicationInfo).GetBlamePawn();
if( FP!=None )
{
ForEach DynamicActors(Class'Projectile',PP)
{
if( PP.Instigator==Self )
PP.Instigator = FP;
}
}
}
D = Spawn(Class'PlayerDeathMark');
if( D!=None )
D.Velocity = Velocity;
Health = Min(0, Health);
if ( Weapon != None && (DrivenVehicle == None || DrivenVehicle.bAllowWeaponToss) )
{
if ( Controller != None )
Controller.LastPawnWeapon = Weapon.Class;
Weapon.HolderDied();
TossVel = Vector(GetViewRotation());
TossVel = TossVel * ((Velocity Dot TossVel) + 500) + Vect(0,0,200);
TossWeapon(TossVel);
}
if ( DrivenVehicle != None )
{
Velocity = DrivenVehicle.Velocity;
DrivenVehicle.DriverDied();
}
if ( Controller != None )
{
Controller.WasKilledBy(Killer);
Level.Game.Killed(Killer, Controller, self, damageType);
}
else Level.Game.Killed(Killer, Controller(Owner), self, damageType);
DrivenVehicle = None;
if ( Killer != None )
TriggerEvent(Event, self, Killer.Pawn);
else TriggerEvent(Event, self, None);
// make sure to untrigger any triggers requiring player touch
if ( IsPlayerPawn() || WasPlayerPawn() )
{
PhysicsVolume.PlayerPawnDiedInVolume(self);
ForEach TouchingActors(class'Trigger',T)
T.PlayerToucherDied(self);
// event for HoldObjectives
ForEach TouchingActors(class'NavigationPoint', N)
if ( N.bReceivePlayerToucherDiedNotify )
N.PlayerToucherDied( Self );
}
// remove powerup effects, etc.
RemovePowerups();
Velocity.Z *= 1.3;
// Make attached explosives blow up when this pawn dies
for( i=0; i<Attached.length; i++ )
{
if( SealSquealProjectile(Attached[i])!=None )
{
SealSquealProjectile(Attached[i]).HandleBasePawnDestroyed();
}
}
if ( IsHumanControlled() )
PlayerController(Controller).ForceDeathUpdate();
NetUpdateFrequency = Default.NetUpdateFrequency;
PlayDying(DamageType, HitLocation);
if ( !bPhysicsAnimUpdate && !IsLocallyControlled() )
ClientDying(DamageType, HitLocation);
}
simulated function ChunkUp( Rotator HitRotation, float ChunkPerterbation )
{
/*
if ( (Level.NetMode != NM_Client) && (Controller != None) )
{
if ( Controller.bIsPlayer )
Controller.PawnDied(self);
else
Controller.Destroy();
}
bTearOff = true;
HitDamageType = class'Gibbed'; // make sure clients gib also
if ( (Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer) )
GotoState('TimingOut');
if ( Level.NetMode == NM_DedicatedServer )
return;
if ( class'GameInfo'.static.UseLowGore() )
{
Destroy();
return;
}
SpawnGibs(HitRotation,ChunkPerterbation);
if ( Level.NetMode != NM_ListenServer )
Destroy();
*/
}
// toss some of your cash away. (to help a cash-strapped ally or perhaps just to party like its 1994)
exec function TossCash( int Amount )
{
local Vector X,Y,Z;
local CashPickup CashPickup ;
local Vector TossVel;
local Actor A;
if( Amount<=0 )
Amount = 50;
Controller.PlayerReplicationInfo.Score = int(Controller.PlayerReplicationInfo.Score); // To fix issue with throwing 0 pounds.
if( Controller.PlayerReplicationInfo.Score<=0 || Amount<=0 )
return;
Amount = Min(Amount,int(Controller.PlayerReplicationInfo.Score));
GetAxes(Rotation,X,Y,Z);
TossVel = Vector(GetViewRotation());
TossVel = TossVel * ((Velocity Dot TossVel) + 500) + Vect(0,0,200);
CashPickup = Spawn(class'CashPickup',,, Location + 0.8 * CollisionRadius * X - 0.5 * CollisionRadius * Y);
if(CashPickup != none)
{
CashPickup.CashAmount = Amount;
CashPickup.bDroppedCash = true;
CashPickup.RespawnTime = 0; // Dropped cash doesnt respawn. For obvious reasons.
CashPickup.Velocity = TossVel;
CashPickup.DroppedBy = Controller;
CashPickup.InitDroppedPickupFor(None);
Controller.PlayerReplicationInfo.Score -= Amount;
if ( Level.Game.NumPlayers > 1 && Level.TimeSeconds - LastDropCashMessageTime > DropCashMessageDelay )
{
PlayerController(Controller).Speech('AUTO', 4, "");
}
// Hack to get Slot machines to accept dosh that's thrown inside their collision cylinder.
ForEach CashPickup.TouchingActors(class 'Actor', A)
{
if(A.IsA('KF_Slot_Machine'))
{
A.Touch(Cashpickup);
}
}
}
}
// Used to attach an emitter instead of an xemitter
simulated function AttachEmitterEffect( class<Emitter> EmitterClass, Name BoneName, Vector Location, Rotator Rotation )
{
local Actor a;
local int i;
if( bSkeletized || (BoneName == 'None') )
return;
for( i = 0; i < Attached.Length; i++ )
{
if( Attached[i] == None )
continue;
if( Attached[i].AttachmentBone != BoneName )
continue;
if( ClassIsChildOf( EmitterClass, Attached[i].Class ) )
return;
}
a = Spawn( EmitterClass,,, Location, Rotation );
if( !AttachToBone( a, BoneName ) )
{
log( "Couldn't attach "$EmitterClass$" to "$BoneName, 'Error' );
a.Destroy();
return;
}
for( i = 0; i < Attached.length; i++ )
{
if( Attached[i] == a )
break;
}
a.SetRelativeRotation( Rotation );
}
simulated function RemoveFlamingEffects()
{
local int i;
if( Level.NetMode == NM_DedicatedServer )
return;
for( i=0; i<Attached.length; i++ )
{
if( Attached[i].IsA('xEmitter') && !Attached[i].IsA('BloodJet'))
{
xEmitter(Attached[i]).mRegen = false;
}
if( Attached[i].IsA('KFMonsterFlame'))
{
Attached[i].LifeSpan = 0.1;
}
}
}
simulated function class<KFVeterancyTypes> GetVeteran()
{
if( KFPlayerReplicationInfo(PlayerReplicationInfo) != none && KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
{
return KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill;
}
return class'KFVeterancyTypes'; // The base neutral class.
}
function bool CanCarry( float Weight )
{
Return True;
}
// Validate that client is not hacking.
function bool CanBuyNow()
{
local ShopVolume Sh;
if( KFGameType(Level.Game)==None || KFGameType(Level.Game).bWaveInProgress || PlayerReplicationInfo==None )
return False;
foreach TouchingActors(Class'ShopVolume',Sh)
Return True;
Return False;
}
function bool ItemIsBuyable( Class<Pickup> IC )
{
local int i;
if( LevRls==None )
{
ForEach DynamicActors(Class'KFLevelRules',LevRls)
Break;
if( LevRls==None )
Return False;
}
For( i=0; i<25; i++ )
{
if( LevRls.ItemForSale[i]==IC )
Return True;
}
Return False;
}
simulated function ClientCurrentWeaponSold()
{
local Inventory I;
local int Count;
for ( I = Inventory; I != none && Count < 50; I = I.Inventory)
{
if ( I != Weapon && I != PendingWeapon && Weapon(I) != none )
{
PendingWeapon = Weapon(I);
break;
}
Count++;
}
ChangedWeapon();
}
simulated function ClientForceChangeWeapon(Inventory NewWeapon)
{
PendingWeapon = Weapon(NewWeapon);
ChangedWeapon();
}
function ServerBuyPotato()
{
local Controller C;
for ( C = Level.ControllerList; C != none; C = C.NextController )
{
if ( PlayerController(C) != none && PlayerController(C).SteamStatsAndAchievements != none )
{
PlayerController(C).SteamStatsAndAchievements.SetSteamAchievementCompleted(132);
}
}
PlayerReplicationInfo.Score -= 70000;
}
function ServerBuyWeapon( Class<Weapon> WClass, float ItemWeight )
{
local Inventory I, J;
local float Price;
local bool bIsDualWeapon, bHasDual9mms, bHasDualHCs, bHasDualRevolvers;
if ( !CanBuyNow() || Class<KFWeapon>(WClass) == none || Class<KFWeaponPickup>(WClass.Default.PickupClass) == none )
{
return;
}
if ( Class<KFWeapon>(WClass).Default.AppID > 0 && Class<KFWeapon>(WClass).Default.UnlockedByAchievement != -1 )
{
if ( KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements) == none ||
(!KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements).PlayerOwnsWeaponDLC(Class<KFWeapon>(WClass).Default.AppID) &&
KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements).Achievements[Class<KFWeapon>(WClass).Default.UnlockedByAchievement].bCompleted != 1 ))
{
return;
}
}
else if ( Class<KFWeapon>(WClass).Default.AppID > 0 )
{
if ( KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements) == none ||
!KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements).PlayerOwnsWeaponDLC(Class<KFWeapon>(WClass).Default.AppID))
{
return;
}
}
else if ( Class<KFWeapon>(WClass).Default.UnlockedByAchievement != -1 )
{
if ( KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements) == none ||
KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements).Achievements[Class<KFWeapon>(WClass).Default.UnlockedByAchievement].bCompleted != 1 )
{
return;
}
}
Price = class<KFWeaponPickup>(WClass.Default.PickupClass).Default.Cost;
if ( KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
{
Price *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), WClass.Default.PickupClass);
}
for ( I=Inventory; I!=None; I=I.Inventory )
{
if( I.Class==WClass )
{
Return; // Already has weapon.
}
if ( I.Class == class'Dualies' )
{
bHasDual9mms = true;
}
else if ( I.Class == class'DualDeagle' || I.Class == class'GoldenDualDeagle' )
{
bHasDualHCs = true;
}
else if ( I.Class == class'Dual44Magnum' )
{
bHasDualRevolvers = true;
}
}
if ( WClass == class'DualDeagle' )
{
for ( J = Inventory; J != None; J = J.Inventory )
{
if ( J.class == class'Deagle' )
{
Price = Price / 2;
break;
}
}
bIsDualWeapon = true;
bHasDualHCs = true;
}
if ( WClass == class'GoldenDualDeagle' )
{
for ( J = Inventory; J != None; J = J.Inventory )
{
if ( J.class == class'GoldenDeagle' )
{
Price = Price / 2;
break;
}
}
bIsDualWeapon = true;
bHasDualHCs = true;
}
if ( WClass == class'Dual44Magnum' )
{
for ( J = Inventory; J != None; J = J.Inventory )
{
if ( J.class == class'Magnum44Pistol' )
{
Price = Price / 2;
break;
}
}
bIsDualWeapon = true;
bHasDualRevolvers = true;
}
if ( WClass == class'DualMK23Pistol' )
{
for ( J = Inventory; J != None; J = J.Inventory )
{
if ( J.class == class'MK23Pistol' )
{
Price = Price / 2;
break;
}
}
bIsDualWeapon = true;
}
if ( WClass == class'DualFlareRevolver' )
{
for ( J = Inventory; J != None; J = J.Inventory )
{
if ( J.class == class'FlareRevolver' )
{
Price = Price / 2;
break;
}
}
bIsDualWeapon = true;
}
bIsDualWeapon = bIsDualWeapon || WClass == class'Dualies';
if ( !CanCarry(ItemWeight) )
{
Return;
}
if ( PlayerReplicationInfo.Score < Price )
{
Return; // Not enough CASH.
}
I = Spawn(WClass);
if ( I != none )
{
if ( KFGameType(Level.Game) != none )
{
KFGameType(Level.Game).WeaponSpawned(I);
}
KFWeapon(I).UpdateMagCapacity(PlayerReplicationInfo);
KFWeapon(I).FillToInitialAmmo();
KFWeapon(I).SellValue = Price * 0.75;
I.GiveTo(self);
PlayerReplicationInfo.Score -= Price;
if ( bIsDualWeapon )
{
KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements).OnDualsAddedToInventory(bHasDual9mms, bHasDualHCs, bHasDualRevolvers);
}
ClientForceChangeWeapon(I);
}
SetTraderUpdate();
}
function ServerSellWeapon( Class<Weapon> WClass )
{
local Inventory I;
local Single NewSingle;
local Deagle NewDeagle;
local Magnum44Pistol New44Magnum;
local MK23Pistol NewMK23;
local FlareRevolver NewFlare;
local float Price;
if ( !CanBuyNow() || Class<KFWeapon>(WClass) == none || Class<KFWeaponPickup>(WClass.Default.PickupClass) == none )
{
SetTraderUpdate();
Return;
}
for ( I = Inventory; I != none; I = I.Inventory )
{
if ( I.Class == WClass )
{
if ( KFWeapon(I) != none && KFWeapon(I).SellValue != -1 )
{
Price = KFWeapon(I).SellValue;
}
else
{
Price = int(class<KFWeaponPickup>(WClass.default.PickupClass).default.Cost * 0.75);
if ( KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
{
Price *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), WClass.Default.PickupClass);
}
}
if ( Dualies(I) != none && DualDeagle(I) == none && Dual44Magnum(I) == none
&& DualMK23Pistol(I) == none && DualFlareRevolver(I) == none )
{
NewSingle = Spawn(class'Single');
NewSingle.GiveTo(self);
}
if ( DualDeagle(I) != none )
{
if( GoldenDualDeagle(I) != none )
{
NewDeagle = Spawn(class'GoldenDeagle');
}
else
{
NewDeagle = Spawn(class'Deagle');
}
NewDeagle.GiveTo(self);
Price = Price / 2;
NewDeagle.SellValue = Price;
}
if ( Dual44Magnum(I) != none )
{
New44Magnum = Spawn(class'Magnum44Pistol');
New44Magnum.GiveTo(self);
Price = Price / 2;
New44Magnum.SellValue = Price;
}
if ( DualMK23Pistol(I) != none )
{
NewMK23 = Spawn(class'MK23Pistol');
NewMK23.GiveTo(self);
Price = Price / 2;
NewMK23.SellValue = Price;
}
if ( DualFlareRevolver(I) != none )
{
NewFlare = Spawn(class'FlareRevolver');
NewFlare.GiveTo(self);
Price = Price / 2;
NewFlare.SellValue = Price;
}
if ( I == Weapon || I == PendingWeapon )
{
ClientCurrentWeaponSold();
}
PlayerReplicationInfo.Score += Price;
I.Destroyed();
I.Destroy();
SetTraderUpdate();
if ( KFGameType(Level.Game) != none )
{
KFGameType(Level.Game).WeaponDestroyed(WClass);
}
return;
}
}
}
function ServerBuyKevlar()
{
local float Cost;
local int UnitsAffordable;
Cost = class'Vest'.default.ItemCost * ((100.0 - ShieldStrength) / 100.0);
if ( KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none)
{
Cost *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), class'Vest');
}
if ( !CanBuyNow() || ShieldStrength==100 )
{
SetTraderUpdate();
Return;
}
if ( PlayerReplicationInfo.Score >= Cost )
{
PlayerReplicationInfo.Score -= Cost;
ShieldStrength = 100;
}
else if ( ShieldStrength > 0 )
{
Cost = class'Vest'.default.ItemCost;
if ( KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none)
{
Cost *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), class'Vest');
}
Cost /= 100.0;
UnitsAffordable = int(PlayerReplicationInfo.Score / Cost);
PlayerReplicationInfo.Score -= int(Cost * UnitsAffordable);
ShieldStrength += UnitsAffordable;
}
SetTraderUpdate();
}
function ServerBuyFirstAid()
{
local int Cost;
Cost = class'FirstAidKit'.default.ItemCost;
if( !CanBuyNow() || Health==100 )
{
SetTraderUpdate();
Return;
}
if( PlayerReplicationInfo.Score < Cost )
{
SetTraderUpdate();
Return;
}
PlayerReplicationInfo.Score -= Cost;
GiveHealth(100, 100);
SetTraderUpdate();
}
function bool ServerBuyAmmo( Class<Ammunition> AClass, bool bOnlyClip )
{
local Inventory I;
local float Price;
local Ammunition AM;
local KFWeapon KW;
local int c;
local float UsedMagCapacity;
local Boomstick DBShotty;
if ( !CanBuyNow() || AClass == None )
{
SetTraderUpdate();
return false;
}
for ( I=Inventory; I != none; I=I.Inventory )
{
if ( I.Class == AClass )
{
AM = Ammunition(I);
}
else if ( KW == None && KFWeapon(I) != None && (Weapon(I).AmmoClass[0] == AClass || Weapon(I).AmmoClass[1] == AClass) )
{
KW = KFWeapon(I);
}
}
if ( KW == none || AM == none )
{
SetTraderUpdate();
return false;
}
DBShotty = Boomstick(KW);
AM.MaxAmmo = AM.default.MaxAmmo;
if ( KFPlayerReplicationInfo(PlayerReplicationInfo) != none && KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
{
AM.MaxAmmo = int(float(AM.MaxAmmo) * KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(PlayerReplicationInfo), AClass));
}
if ( AM.AmmoAmount >= AM.MaxAmmo )
{
SetTraderUpdate();
return false;
}
Price = class<KFWeaponPickup>(KW.PickupClass).default.AmmoCost * KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetAmmoCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), KW.PickupClass); // Clip price.
if ( KW.bHasSecondaryAmmo && AClass == KW.FireModeClass[1].default.AmmoClass )
{
UsedMagCapacity = 1; // Secondary Mags always have a Mag Capacity of 1? KW.default.SecondaryMagCapacity;
}
else
{
UsedMagCapacity = KW.default.MagCapacity;
}
if( KW.PickupClass == class'HuskGunPickup' )
{
UsedMagCapacity = class<HuskGunPickup>(KW.PickupClass).default.BuyClipSize;
}
if ( bOnlyClip )
{
if ( KFPlayerReplicationInfo(PlayerReplicationInfo) != none && KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
{
if( KW.PickupClass == class'HuskGunPickup' )
{
c = UsedMagCapacity * KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(PlayerReplicationInfo), AM.Class);
}
else
{
c = UsedMagCapacity * KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetMagCapacityMod(KFPlayerReplicationInfo(PlayerReplicationInfo), KW);
}
}
else
{
c = UsedMagCapacity;
}
}
else
{
c = (AM.MaxAmmo-AM.AmmoAmount);
}
Price = int(float(c) / UsedMagCapacity * Price);
if ( PlayerReplicationInfo.Score < Price ) // Not enough CASH (so buy the amount you CAN buy).
{
c *= (PlayerReplicationInfo.Score/Price);
if ( c == 0 )
{
SetTraderUpdate();
return false; // Couldn't even afford 1 bullet.
}
AM.AddAmmo(c);
if( DBShotty != none )
{
DBShotty.AmmoPickedUp();
}
PlayerReplicationInfo.Score = Max(PlayerReplicationInfo.Score - (float(c) / UsedMagCapacity * Price), 0);
SetTraderUpdate();
return false;
}
PlayerReplicationInfo.Score = int(PlayerReplicationInfo.Score-Price);
AM.AddAmmo(c);
if( DBShotty != none )
{
DBShotty.AmmoPickedUp();
}
SetTraderUpdate();
return true;
}
function ServerSellAmmo( Class<Ammunition> AClass )
{
local Inventory I;
local float Price;
local Ammunition AM;
local KFWeapon KW;
local int c;
if( !CanBuyNow() || AClass==None )
Return;
For( I=Inventory; I!=None; I=I.Inventory )
{
if( I.Class==AClass )
AM = Ammunition(I);
else if( KW==None && KFWeapon(I)!=None && (Weapon(I).AmmoClass[0]==AClass || Weapon(I).AmmoClass[1]==AClass) )
KW = KFWeapon(I);
}
if( (AM==None && KW==None) || AM.AmmoAmount==AM.MaxAmmo )
Return;
Price = Class<KFWeaponPickup>(KW.PickupClass).Default.AmmoCost; // Clip price.
c = KW.Default.MagCapacity;
if( c>AM.AmmoAmount )
c = AM.AmmoAmount;
Price = float(c)/float(KW.Default.MagCapacity)*Price*0.75;
PlayerReplicationInfo.Score+=Price;
AM.AmmoAmount-=c;
SetTraderUpdate();
}
simulated function SetTraderUpdate()
{
if ( KFPlayerController(Controller) != none )
{
KFPlayerController(Controller).DoTraderUpdate();
}
}
// Allow players spawn on top of each other.
event bool EncroachingOn( actor Other )
{
if ( Other.bWorldGeometry || Other.bBlocksTeleport )
return true;
if ( (Vehicle(Other) != None) && (Weapon != None) && Weapon.IsA('Translauncher') )
return true;
return false;
}
event EncroachedBy( actor Other )
{
if ( Pawn(Other)!=None && Vehicle(Other)==None && KFPawn(Other)==None )
gibbedBy(Other);
}
function name GetWeaponBoneFor(Inventory I)
{
return 'WeaponR_Bone';
}
function name GetOffhandBoneFor(Inventory I)
{
return 'WeaponL_Bone';
}
simulated function SetWeaponAttachment(WeaponAttachment NewAtt)
{
local KFWeaponAttachment KFWeapAttach;
local DualiesAttachment DualiesAttach;
local int i;
WeaponAttachment = NewAtt;
KFWeapAttach = KFWeaponAttachment(WeaponAttachment);
DualiesAttach = DualiesAttachment(WeaponAttachment);
// For remote clients set the brother class for dualies
if( Level.NetMode == NM_Client && DualiesAttach != none )
{
for( i = 0; i < Attached.Length; i++ )
{
if( Attached[i] == None )
continue;
if( DualiesAttachment(Attached[i]) != none && DualiesAttach != Attached[i] )
{
DualiesAttach.brother = DualiesAttachment(Attached[i]);
DualiesAttachment(Attached[i]).brother = DualiesAttach;
break;
}
}
}
if( KFWeapAttach != none )
{
MovementAnims[0]= KFWeapAttach.MovementAnims[0];
MovementAnims[1]= KFWeapAttach.MovementAnims[1];
MovementAnims[2]= KFWeapAttach.MovementAnims[2];
MovementAnims[3]= KFWeapAttach.MovementAnims[3];
TurnLeftAnim = KFWeapAttach.TurnLeftAnim;
TurnRightAnim = KFWeapAttach.TurnRightAnim;
SwimAnims[0]= KFWeapAttach.SwimAnims[0];
SwimAnims[1]= KFWeapAttach.SwimAnims[1];
SwimAnims[2]= KFWeapAttach.SwimAnims[2];
SwimAnims[3]= KFWeapAttach.SwimAnims[3];
CrouchAnims[0]= KFWeapAttach.CrouchAnims[0];
CrouchAnims[1]= KFWeapAttach.CrouchAnims[1];
CrouchAnims[2]= KFWeapAttach.CrouchAnims[2];
CrouchAnims[3]= KFWeapAttach.CrouchAnims[3];
WalkAnims[0]= KFWeapAttach.WalkAnims[0];
WalkAnims[1]= KFWeapAttach.WalkAnims[1];
WalkAnims[2]= KFWeapAttach.WalkAnims[2];
WalkAnims[3]= KFWeapAttach.WalkAnims[3];
AirAnims[0]= KFWeapAttach.AirAnims[0];
AirAnims[1]= KFWeapAttach.AirAnims[1];
AirAnims[2]= KFWeapAttach.AirAnims[2];
AirAnims[3]= KFWeapAttach.AirAnims[3];
TakeoffAnims[0]= KFWeapAttach.TakeoffAnims[0];
TakeoffAnims[1]= KFWeapAttach.TakeoffAnims[1];
TakeoffAnims[2]= KFWeapAttach.TakeoffAnims[2];
TakeoffAnims[3]= KFWeapAttach.TakeoffAnims[3];
LandAnims[0]= KFWeapAttach.LandAnims[0];
LandAnims[1]= KFWeapAttach.LandAnims[1];
LandAnims[2]= KFWeapAttach.LandAnims[2];
LandAnims[3]= KFWeapAttach.LandAnims[3];
DoubleJumpAnims[0]= KFWeapAttach.DoubleJumpAnims[0];
DoubleJumpAnims[1]= KFWeapAttach.DoubleJumpAnims[1];
DoubleJumpAnims[2]= KFWeapAttach.DoubleJumpAnims[2];
DoubleJumpAnims[3]= KFWeapAttach.DoubleJumpAnims[3];
DodgeAnims[0]= KFWeapAttach.DodgeAnims[0];
DodgeAnims[1]= KFWeapAttach.DodgeAnims[1];
DodgeAnims[2]= KFWeapAttach.DodgeAnims[2];
DodgeAnims[3]= KFWeapAttach.DodgeAnims[3];
AirStillAnim = KFWeapAttach.AirStillAnim;
TakeoffStillAnim = KFWeapAttach.TakeoffStillAnim;
CrouchTurnRightAnim = KFWeapAttach.CrouchTurnRightAnim;
CrouchTurnLeftAnim = KFWeapAttach.CrouchTurnLeftAnim;
IdleCrouchAnim = KFWeapAttach.IdleCrouchAnim;
IdleSwimAnim = KFWeapAttach.IdleSwimAnim;
IdleWeaponAnim = KFWeapAttach.IdleWeaponAnim;
IdleRestAnim = KFWeapAttach.IdleRestAnim;
IdleChatAnim = KFWeapAttach.IdleChatAnim;
FireAnims[0]=KFWeapAttach.FireAnims[0];
FireAnims[1]=KFWeapAttach.FireAnims[1];
FireAnims[2]=KFWeapAttach.FireAnims[2];
FireAnims[3]=KFWeapAttach.FireAnims[3];
FireAltAnims[0]=KFWeapAttach.FireAltAnims[0];
FireAltAnims[1]=KFWeapAttach.FireAltAnims[1];
FireAltAnims[2]=KFWeapAttach.FireAltAnims[2];
FireAltAnims[3]=KFWeapAttach.FireAltAnims[3];
FireCrouchAnims[0]=KFWeapAttach.FireCrouchAnims[0];
FireCrouchAnims[1]=KFWeapAttach.FireCrouchAnims[1];
FireCrouchAnims[2]=KFWeapAttach.FireCrouchAnims[2];
FireCrouchAnims[3]=KFWeapAttach.FireCrouchAnims[3];
FireCrouchAltAnims[0]=KFWeapAttach.FireCrouchAltAnims[0];
FireCrouchAltAnims[1]=KFWeapAttach.FireCrouchAltAnims[1];
FireCrouchAltAnims[2]=KFWeapAttach.FireCrouchAltAnims[2];
FireCrouchAltAnims[3]=KFWeapAttach.FireCrouchAltAnims[3];
HitAnims[0]=KFWeapAttach.HitAnims[0];
HitAnims[1]=KFWeapAttach.HitAnims[1];
HitAnims[2]=KFWeapAttach.HitAnims[2];
HitAnims[3]=KFWeapAttach.HitAnims[3];
PostFireBlendStandAnim = KFWeapAttach.PostFireBlendStandAnim;
PostFireBlendCrouchAnim = KFWeapAttach.PostFireBlendCrouchAnim;
}
}
simulated function PlayDirectionalHit(Vector HitLoc)
{
local Vector X,Y,Z, Dir;
if ( DrivenVehicle != None )
return;
GetAxes(Rotation, X,Y,Z);
HitLoc.Z = Location.Z;
// random
if ( VSize(Location - HitLoc) < 1.0 )
{
Dir = VRand();
}
// hit location based
else
{
Dir = -Normal(Location - HitLoc);
}
if ( Dir Dot X > 0.7 || Dir == vect(0,0,0))
{
PlayAnim(HitAnims[0],, 0.1);
}
else if ( Dir Dot X < -0.7 )
{
PlayAnim(HitAnims[1],, 0.1);
}
else if ( Dir Dot Y > 0 )
{
PlayAnim(HitAnims[3],, 0.1);
}
else
{
PlayAnim(HitAnims[2],, 0.1);
}
}
//-----------------------------------------------------------------------------
// FootStepping - overriden to support custom footstep volumes
//-----------------------------------------------------------------------------
simulated function FootStepping(int Side)
{
local int SurfaceTypeID, i;
local actor A;
local material FloorMat;
local vector HL,HN,Start,End,HitLocation,HitNormal;
local float FootVolumeMod;
SurfaceTypeID = 0;
FootVolumeMod = 1.0;
for ( i=0; i<Touching.Length; i++ )
if ( ((PhysicsVolume(Touching[i]) != None) && PhysicsVolume(Touching[i]).bWaterVolume)
|| (FluidSurfaceInfo(Touching[i]) != None) )
{
PlaySound(sound'Inf_Player.FootStepWaterDeep', SLOT_Interact, FootstepVolume * 2,, FootStepSoundRadius);
// Play a water ring effect as you walk through the water
if ( !Level.bDropDetail && (Level.DetailMode != DM_Low) && (Level.NetMode != NM_DedicatedServer)
&& !Touching[i].TraceThisActor(HitLocation, HitNormal,Location - CollisionHeight*vect(0,0,1.1), Location) )
{
Spawn(class'WaterRingEmitter',,,HitLocation,rot(16384,0,0));
}
return;
}
// Lets still play the sounds when walking slow, just play them quieter
if ( bIsCrouched || bIsWalking )
{
FootVolumeMod = QuietFootStepVolume;
}
if ( (Base!=None) && (!Base.IsA('LevelInfo')) && (Base.SurfaceType!=0) )
{
SurfaceTypeID = Base.SurfaceType;
}
else
{
Start = Location - Vect(0,0,1)*CollisionHeight;
End = Start - Vect(0,0,16);
A = Trace(hl,hn,End,Start,false,,FloorMat);
if (FloorMat !=None)
SurfaceTypeID = FloorMat.SurfaceType;
}
PlaySound(SoundFootsteps[SurfaceTypeID], SLOT_Interact, (FootstepVolume * FootVolumeMod),,(FootStepSoundRadius * FootVolumeMod));
}
// Footstep sound checking for non local player or non player bots
// This function is only called on non owned network clients or bots
simulated function CheckFootSteps(float DeltaTime)
{
local float Speed2D;
local float OldBobTime;
local int m,n;
OldBobTime = BobTime;
if (Physics == PHYS_Walking )
{
Speed2D = VSize(Velocity);
if ( Speed2D < 10 )
BobTime += 0.2 * DeltaTime;
else
BobTime += DeltaTime * (0.3 + 0.7 * Speed2D/GroundSpeed);
}
else
{
BobTime = 0;
}
if ( (Physics != PHYS_Walking) || (VSize(Velocity) < 10) )
return;
m = int(0.5 * Pi + 9.0 * OldBobTime/Pi);
n = int(0.5 * Pi + 9.0 * BobTime/Pi);
if ( (m != n) && !bIsCrawling)
FootStepping(0);
}
function CheckBob(float DeltaTime, vector Y)
{
local float Speed2D;
local float OldBobTime;
local int m,n;
local float UsedBobScaleModifier;
OldBobTime = BobTime;
Bob = FClamp(Bob, -0.01, 0.01);
UsedBobScaleModifier = BobScaleModifier;
// Modify the amount of bob based on the movement state
if( bIsCrouched )
{
UsedBobScaleModifier = 2.5;
}
if (Physics == PHYS_Walking )
{
Speed2D = VSize(Velocity);
Speed2D *= BobSpeedModifier;
if ( Speed2D < 10 )
BobTime += 0.2 * DeltaTime;
else
BobTime += DeltaTime * (0.3 + 0.7 * Speed2D/GroundSpeed);
WalkBob = Y * (Bob * UsedBobScaleModifier) * Speed2D * sin(8 * BobTime);
AppliedBob = AppliedBob * (1 - FMin(1, 16 * deltatime));
WalkBob.Z = AppliedBob;
if ( Speed2D > 10 )
WalkBob.Z = WalkBob.Z + 0.75 * (Bob * UsedBobScaleModifier) * Speed2D * sin(16 * BobTime);
if ( LandBob > 0.01 )
{
AppliedBob += FMin(1, 16 * deltatime) * LandBob;
LandBob *= (1 - 8*Deltatime);
}
}
else if ( Physics == PHYS_Swimming )
{
Speed2D = Sqrt(Velocity.X * Velocity.X + Velocity.Y * Velocity.Y);
WalkBob = Y * Bob * 0.5 * Speed2D * sin(4.0 * Level.TimeSeconds);
WalkBob.Z = Bob * 1.5 * Speed2D * sin(8.0 * Level.TimeSeconds);
}
else
{
BobTime = 0;
WalkBob = WalkBob * (1 - FMin(1, 8 * deltatime));
}
if ( (Physics != PHYS_Walking) || (VSize(Velocity) < 10)
|| ((PlayerController(Controller) != None) && PlayerController(Controller).bBehindView) )
return;
m = int(0.5 * Pi + 9.0 * OldBobTime/Pi);
n = int(0.5 * Pi + 9.0 * BobTime/Pi);
if ( (m != n) )
FootStepping(0);
}
function Sound GetSound(xPawnSoundGroup.ESoundType soundType)
{
local int SurfaceTypeID;
local actor A;
local vector HL,HN,Start,End;
local material FloorMat;
if( SoundGroupClass == none )
{
return None;
}
if( soundType == EST_Land || soundType == EST_Jump )
{
if ( (Base!=None) && (!Base.IsA('LevelInfo')) && (Base.SurfaceType!=0) )
{
SurfaceTypeID = Base.SurfaceType;
}
else
{
Start = Location - Vect(0,0,1)*CollisionHeight;
End = Start - Vect(0,0,16);
A = Trace(hl,hn,End,Start,false,,FloorMat);
if (FloorMat !=None)
SurfaceTypeID = FloorMat.SurfaceType;
}
}
return SoundGroupClass.static.GetSound(soundType, SurfaceTypeID);
}
/* Quickly select syring, alt fire once, select old weapon again */
simulated exec function QuickHeal()
{
local Syringe S;
local Inventory I;
local byte C;
if ( Health>=HealthMax )
return;
for( I=Inventory; (I!=None && C++<250); I=I.Inventory )
{
S = Syringe(I);
if( S!=None )
break;
}
if ( S == none )
return;
if ( S.ChargeBar() < 0.95 )
{
if ( PlayerController(Controller) != none && HUDKillingFloor(PlayerController(Controller).myHud) != none )
{
HUDKillingFloor(PlayerController(Controller).myHud).ShowQuickSyringe();
}
return; // No can heal.
}
bIsQuickHealing = 1;
if ( Weapon==None )
{
PendingWeapon = S;
ChangedWeapon();
}
else if ( Weapon!=S )
{
PendingWeapon = S;
Weapon.PutDown();
}
else // Syringe already selected, just start healing.
{
bIsQuickHealing = 0;
S.HackClientStartFire();
}
}
simulated exec function ToggleFlashlight()
{
local KFWeapon KFWeap;
if ( Controller == none )
{
return;
}
if ( KFWeapon(Weapon) != none && KFWeapon(Weapon).bTorchEnabled )
{
Weapon.ClientStartFire(1);
}
else
{
KFWeap = KFWeapon(FindInventoryType(class'Shotgun'));
if ( KFWeap == none )
{
KFWeap = KFWeapon(FindInventoryType(class'BenelliShotgun'));
if ( KFWeap == none )
{
KFWeap = KFWeapon(FindInventoryType(class'Dualies'));
if ( KFWeap == none || DualDeagle(KFWeap) != none || Dual44Magnum(KFWeap) != none
|| DualMK23Pistol(KFWeap) != none || DualFlareRevolver(KFWeap) != none )
{
KFWeap = KFWeapon(FindInventoryType(class'Single'));
}
}
}
if ( KFWeap != none )
{
KFWeap.bPendingFlashlight = true;
PendingWeapon = KFWeap;
if ( Weapon != none )
{
Weapon.PutDown();
}
else
{
ChangedWeapon();
}
}
}
}
function GiveWeapon(string aClassName )
{
local class<Weapon> WeaponClass;
local Inventory I;
local Weapon NewWeapon;
local bool bHasDual9mms, bHasDualHCs, bHasDualRevolvers;
WeaponClass = class<Weapon>(DynamicLoadObject(aClassName, class'Class'));
for ( I = Inventory; I != none; I = I.Inventory )
{
if( I.Class == WeaponClass )
{
Return; // Already has weapon.
}
if ( I.Class == class'Dualies' )
{
bHasDual9mms = true;
}
else if ( I.Class == class'DualDeagle' || I.Class == class'GoldenDualDeagle' )
{
bHasDualHCs = true;
}
else if ( I.Class == class'Dual44Magnum' )
{
bHasDualRevolvers = true;
}
}
newWeapon = Spawn(WeaponClass);
if ( newWeapon != none )
{
newWeapon.GiveTo(self);
if ( WeaponClass == class'Dualies' || WeaponClass == class'DualDeagle' || WeaponClass == class'GoldenDualDeagle' || WeaponClass == class'Dual44Magnum' )
{
KFSteamStatsAndAchievements(PlayerReplicationInfo.SteamStatsAndAchievements).OnDualsAddedToInventory(bHasDual9mms, bHasDualHCs, bHasDualRevolvers);
}
if ( KFGameType(Level.Game) != none )
{
KFGameType(Level.Game).WeaponSpawned(newWeapon);
}
}
}
function bool DoJump( bool bUpdating )
{
if ( Super.DoJump(bUpdating) )
{
// Take you out of ironsights if you jump on a non-lowgrav map
if( KFWeapon(Weapon) != none && PhysicsVolume.Gravity.Z <= class'PhysicsVolume'.default.Gravity.Z )
{
KFWeapon(Weapon).ForceZoomOutTime = Level.TimeSeconds + 0.01;
}
return true;
}
return false;
}
function string GetPlayerName()
{
if( PlayerReplicationInfo != none )
{
return PlayerReplicationInfo.PlayerName;
}
return "";
}
defaultproperties
{
bCanBeHealed=true
BileFrequency=0.5 // 1.5
ClientIdleWeaponAnim=""
ShieldStrengthMax=100.000000
ShieldHitMat=None
GibGroupClass=Class'KFMod.KFHumanGibGroup'
SoundGroupClass=Class'KFMod.KFMaleSoundGroup'
TeleportFXClass=None
TransEffects(0)=None
TransEffects(1)=None
DeResTime=0.000000
DeResMat0=Texture'KFCharacters.KFDeRez'
DeResMat1=Texture'KFCharacters.KFDeRez'
DeResLiftVel=(Points=(,(InVal=0.000000,OutVal=0.000000),(InVal=0.000000,OutVal=0.000000)))
DeResLiftSoftness=(Points=((OutVal=0.000000),(InVal=0.000000,OutVal=0.000000),(InVal=0.000000,OutVal=0.000000)))
DeResLateralFriction=0.000000
RagdollLifeSpan=9999.000000
RagDeathVel=75.000000
RagShootStrength=6000.000000
RagDeathUpKick=100.000000
TransOutEffect(0)=None
TransOutEffect(1)=None
RequiredEquipment(0)="none"
RequiredEquipment(1)="none"
bScriptPostRender=True
MeleeRange=80.000000
GroundSpeed=240.000000
WaterSpeed=180.000000
AirSpeed=240.000000
JumpZ=300.000000
BaseEyeHeight=44.0//54.000000
EyeHeight=44.0//54.000000
DodgeSpeedFactor=1.000000
DodgeSpeedZ=0.000000
SwimAnims(0)="WalkF"
SwimAnims(1)="WalkB"
SwimAnims(2)="WalkL"
SwimAnims(3)="WalkR"
AmbientGlow=0
bClientAnim=True
CollisionRadius=20.0//26.000000
CollisionHeight=40.000000
CrouchRadius=20.0
bBlockKarma=True
Mass=400.000000
BurnEffect = class 'KFMonsterFlame'
bRealDeathType=True
bDoAdjustFeet=True
bDetailedShadows=True
MovementAnims(0)=JogF_Bullpup//RunF
MovementAnims(1)=JogB_Bullpup//RunB
MovementAnims(2)=JogL_Bullpup//RunL
MovementAnims(3)=JogR_Bullpup//RunR
// SwimAnims(0)=SwimF
// SwimAnims(1)=SwimB
// SwimAnims(2)=SwimL
// SwimAnims(3)=SwimR
CrouchAnims(0)=CHwalkF_BullPup
CrouchAnims(1)=CHwalkB_BullPup
CrouchAnims(2)=CHwalkL_BullPup
CrouchAnims(3)=CHwalkR_BullPup
WalkAnims(0)=WalkF_Bullpup
WalkAnims(1)=WalkB_Bullpup
WalkAnims(2)=WalkL_Bullpup
WalkAnims(3)=WalkR_Bullpup
AirStillAnim=JumpF_Mid
AirAnims(0)=JumpF_Mid
AirAnims(1)=JumpF_Mid
AirAnims(2)=JumpL_Mid
AirAnims(3)=JumpR_Mid
TakeoffStillAnim=JumpF_Takeoff
TakeoffAnims(0)=JumpF_Takeoff
TakeoffAnims(1)=JumpF_Takeoff
TakeoffAnims(2)=JumpL_Takeoff
TakeoffAnims(3)=JumpR_Takeoff
LandAnims(0)=JumpF_Land
LandAnims(1)=JumpF_Land
LandAnims(2)=JumpL_Land
LandAnims(3)=JumpR_Land
DoubleJumpAnims(0)=DoubleJumpF
DoubleJumpAnims(1)=DoubleJumpB
DoubleJumpAnims(2)=DoubleJumpL
DoubleJumpAnims(3)=DoubleJumpR
DodgeAnims(0)=JumpF_Takeoff
DodgeAnims(1)=JumpF_Takeoff
DodgeAnims(2)=JumpL_Takeoff
DodgeAnims(3)=JumpR_Takeoff
WallDodgeAnims(0)=WallDodgeF
WallDodgeAnims(1)=WallDodgeB
WallDodgeAnims(2)=WallDodgeL
WallDodgeAnims(3)=WallDodgeR
TurnRightAnim=TurnR
TurnLeftAnim=TurnL
CrouchTurnRightAnim=CH_TurnR
CrouchTurnLeftAnim=CH_TurnL
IdleRestAnim=Idle_Rifle//Idle_Rest
IdleCrouchAnim=CHIdle_BullPup
IdleSwimAnim=Swim_Tread
IdleWeaponAnim=Idle_Bullpup//Idle_Rifle
IdleHeavyAnim=Idle_Bullpup//Idle_Biggun
IdleRifleAnim=Idle_Bullpup//Idle_Rifle
IdleChatAnim=Idle_Chat
FireAnims(0)=Fire_Bullpup
FireAnims(1)=Fire_Bullpup
FireAnims(2)=Fire_Bullpup
FireAnims(3)=Fire_Bullpup
FireAltAnims(0)=Fire_Bullpup
FireAltAnims(1)=Fire_Bullpup
FireAltAnims(2)=Fire_Bullpup
FireAltAnims(3)=Fire_Bullpup
FireCrouchAnims(0)=CHFire_BullPup
FireCrouchAnims(1)=CHFire_BullPup
FireCrouchAnims(2)=CHFire_BullPup
FireCrouchAnims(3)=CHFire_BullPup
FireCrouchAltAnims(0)=CHFire_BullPup
FireCrouchAltAnims(1)=CHFire_BullPup
FireCrouchAltAnims(2)=CHFire_BullPup
FireCrouchAltAnims(3)=CHFire_BullPup
HitAnims(0)=HitF_Bullpup
HitAnims(1)=HitB_Bullpup
HitAnims(2)=HitL_Bullpup
HitAnims(3)=HitR_Bullpup
PostFireBlendStandAnim=Blend_Bullpup
PostFireBlendCrouchAnim=CHBlend_Bullpup
RootBone="CHR_Pelvis"
HeadBone="CHR_Head"
SpineBone1="CHR_Spine2"
SpineBone2="CHR_Spine3"
FireRootBone="CHR_Spine1"
PrePivot=(X=0.0,Y=0.0,Z=0.0);
Species=class'SPECIES_KFMaleHuman'
GruntVolume=0.5
FootstepVolume = 0.45
QuietFootStepVolume=0.40
FootStepSoundRadius=125
BobSpeedModifier=0.90
BobScaleModifier=1.0
RagImpactSounds(0)=Sound'KF_PlayerGlobalSnd.Player_BodyImpact'
SoundFootsteps(0)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootStepDirt'
SoundFootsteps(1)=Sound'KF_PlayerGlobalSnd.Player_StepDirt'//Sound'Inf_Player.FootstepGravel' // Rock
SoundFootsteps(2)=Sound'KF_PlayerGlobalSnd.Player_StepDirt'//Sound'Inf_Player.FootStepDirt' // Dirt
SoundFootsteps(3)=Sound'KF_PlayerGlobalSnd.Player_StepMetal'//Sound'Inf_Player.FootstepMetal' // Metal
SoundFootsteps(4)=Sound'KF_PlayerGlobalSnd.Player_StepWood'//Sound'Inf_Player.FootstepWoodenfloor' // Wood
SoundFootsteps(5)=Sound'KF_PlayerGlobalSnd.Player_StepGrass'//Sound'Inf_Player.FootstepGrass' // Plant
SoundFootsteps(6)=Sound'KF_PlayerGlobalSnd.Player_StepDirt'//Sound'Inf_Player.FootStepDirt' // Flesh
SoundFootsteps(7)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootstepSnowRough' // Ice
SoundFootsteps(8)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootstepSnowHard'
SoundFootsteps(9)=Sound'KF_PlayerGlobalSnd.Player_StepWater'//Sound'Inf_Player.FootstepWaterShallow' // Shallow Water
SoundFootsteps(10)=Sound'KF_PlayerGlobalSnd.Player_StepBrGlass'//Sound'Inf_Player.FootstepGravel' // Glass- Replaceme
SoundFootsteps(11)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootstepGravel' // Gravel
SoundFootsteps(12)=Sound'KF_PlayerGlobalSnd.Player_StepConc'//Sound'Inf_Player.FootstepAsphalt' // Concrete
SoundFootsteps(13)=Sound'KF_PlayerGlobalSnd.Player_StepWood'//Sound'Inf_Player.FootstepWoodenfloor' // HollowWood
SoundFootsteps(14)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootstepMud' // Mud
SoundFootsteps(15)=Sound'KF_PlayerGlobalSnd.Player_StepMetal'//Sound'Inf_Player.FootstepMetal' // MetalArmor
SoundFootsteps(16)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootstepAsphalt_P' // Paper
SoundFootsteps(17)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootStepDirt' // Cloth
SoundFootsteps(18)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootStepDirt' // Rubber
SoundFootsteps(19)=Sound'KF_PlayerGlobalSnd.Player_StepDefault'//Sound'Inf_Player.FootStepDirt' // Crap
SeveredHeadAttachScale=1.1
SeveredLegAttachScale=1.1
SeveredArmAttachScale=1.1
SeveredHeadAttachClass = class'SeveredHeadAttachment'
SeveredArmAttachClass = class'SeveredArmAttachment'
SeveredLegAttachClass = class'SeveredLegAttachment'
NeckSpurtEmitterClass=class'DismembermentJetHead'
LimbSpurtEmitterClass=class'DismembermentJetLimb'
ObliteratedEffectClass=class'PlayerObliteratedEmitter'
// These two are fallbacks. Should assign these in subclasses
DetachedArmClass=class'SeveredArmSoldier'
DetachedLegClass=class'SeveredLegSoldier'
ProjectileBloodSplatClass=class'ROEffects.ProjectileBloodSplat'
DecapitationSound=sound'KF_EnemyGlobalSnd.Generic_Decap'
DropCashMessageDelay=10.0
bBlockHitPointTraces=False
// whole body, do no further checks if we don't at least hit this
Hitpoints(MAINCOLLISIONINDEX)=(PointRadius=40,PointHeight=60.0,PointScale=1.0,PointBone=CHR_Pelvis,PointOffset=(X=0.0,Y=-10.0,Z=0.0),DamageMultiplier=0.0,HitPointType=PHP_None)
// head
Hitpoints(1)=(PointRadius=6.5,PointHeight=8.0,PointScale=1.0,PointBone=CHR_Head,PointOffset=(X=2.0,Y=-2.0,Z=0.0),DamageMultiplier=5.0,HitPointType=PHP_Head)
// body
Hitpoints(2)=(PointRadius=13.0,PointHeight=15.0,PointScale=1.0,PointBone=CHR_Spine3,PointOffset=(X=0.0,Y=-5.0,Z=0.0),DamageMultiplier=1.0,HitPointType=PHP_Torso)
Hitpoints(3)=(PointRadius=12.0,PointHeight=11.0,PointScale=1.0,PointBone=CHR_Spine1,PointOffset=(X=-3.0,Y=-3.0,Z=0.0),DamageMultiplier=1.0,HitPointType=PHP_Torso)
//
// // upper appendages
Hitpoints(4)=(PointRadius=7.0,PointHeight=12.0,PointScale=1.0,PointBone=CHR_LThigh,PointOffset=(X=18.0,Y=1.0,Z=0.0),DamageMultiplier=0.5,HitPointType=PHP_Leg)
Hitpoints(5)=(PointRadius=7.0,PointHeight=12.0,PointScale=1.0,PointBone=CHR_RThigh,PointOffset=(X=18.0,Y=1.0,Z=0.0),DamageMultiplier=0.5,HitPointType=PHP_Leg)
Hitpoints(6)=(PointRadius=5.0,PointHeight=11.0,PointScale=1.0,PointBone=CHR_LArmUpper,PointOffset=(X=8.0,Y=0.0,Z=1.0),DamageMultiplier=0.3,HitPointType=PHP_Arm)
Hitpoints(7)=(PointRadius=5.0,PointHeight=11.0,PointScale=1.0,PointBone=CHR_RArmUpper,PointOffset=(X=8.0,Y=0.0,Z=1.0),DamageMultiplier=0.3,HitPointType=PHP_Arm)
//
// // lower appendages
Hitpoints(8)=(PointRadius=6.0,PointHeight=18.0,PointScale=1.0,PointBone=CHR_LCalf,PointOffset=(X=15.0,Y=0.0,Z=0.0),DamageMultiplier=0.4,HitPointType=PHP_Leg)
Hitpoints(9)=(PointRadius=6.0,PointHeight=18.0,PointScale=1.0,PointBone=CHR_RCalf,PointOffset=(X=15.0,Y=0.0,Z=0.0),DamageMultiplier=0.4,HitPointType=PHP_Leg)
Hitpoints(10)=(PointRadius=4.0,PointHeight=10.0,PointScale=1.0,PointBone=CHR_LArmForeArm,PointOffset=(X=6.0,Y=0.0,Z=0.0),DamageMultiplier=0.2,HitPointType=PHP_Arm)
Hitpoints(11)=(PointRadius=4.0,PointHeight=10.0,PointScale=1.0,PointBone=CHR_RArmForeArm,PointOffset=(X=6.0,Y=0.0,Z=0.0),DamageMultiplier=0.2,HitPointType=PHP_Arm)
//
// // hands and feet
Hitpoints(12)=(PointRadius=4.0,PointHeight=4.0,PointScale=1.0,PointBone=CHR_LArmPalm,PointOffset=(X=5.0,Y=2.0,Z=0.0),DamageMultiplier=0.1,HitPointType=PHP_Hand)
Hitpoints(13)=(PointRadius=4.0,PointHeight=4.0,PointScale=1.0,PointBone=CHR_RArmPalm,PointOffset=(X=5.0,Y=2.0,Z=0.0),DamageMultiplier=0.1,HitPointType=PHP_Hand)
Hitpoints(14)=(PointRadius=4.0,PointHeight=8.0,PointScale=1.0,PointBone=CHR_LToe1,PointOffset=(X=0.0,Y=0.0,Z=0.0),DamageMultiplier=0.1,HitPointType=PHP_Foot)
Hitpoints(15)=(PointRadius=4.0,PointHeight=8.0,PointScale=1.0,PointBone=CHR_RToe1,PointOffset=(X=0.0,Y=0.0,Z=0.0),DamageMultiplier=0.1,HitPointType=PHP_Foot)
bForceSkelUpdate=true;
}