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

520 lines
16 KiB
Ucode

//=============================================================================
// SRHumanPawn
//=============================================================================
class SRHumanPawn extends KFHumanPawn_Story;
var ClientPerkRepLink PerkLink;
var transient float CashTossTimer,LongTossCashTimer;
var transient byte LongTossCashCount;
// Override bad coding in StoryGame
simulated function Fire( optional float F )
{
Super(Pawn).Fire(F);
}
function AddDefaultInventory()
{
if( KFStoryGameInfo(Level.Game)!=none )
Super.AddDefaultInventory();
else Super(KFHumanPawn).AddDefaultInventory();
}
function ServerSellAmmo( Class<Ammunition> AClass );
final function bool HasWeaponClass( class<Inventory> IC, optional out Inventory Res )
{
local Inventory I;
for ( I=Inventory; I!=None; I=I.Inventory )
if( I.Class==IC )
{
Res = I;
return true;
}
return false;
}
final function ClientPerkRepLink FindStats()
{
local LinkedReplicationInfo L;
if( Controller==None || Controller.PlayerReplicationInfo==None )
return None;
for( L=Controller.PlayerReplicationInfo.CustomReplicationInfo; L!=None; L=L.NextReplicationInfo )
if( ClientPerkRepLink(L)!=None )
return ClientPerkRepLink(L);
return None;
}
function ServerBuyWeapon( Class<Weapon> WClass, float Weight )
{
local float Price;
local int OtherPrice;
local Inventory I,OI;
local class<KFWeapon> SecType;
if( !CanBuyNow() || Class<KFWeapon>(WClass)==None || Class<KFWeaponPickup>(WClass.Default.PickupClass)==None || HasWeaponClass(WClass) )
Return;
// Validate if allowed to buy that weapon.
if( PerkLink==None )
PerkLink = FindStats();
if( PerkLink!=None && !PerkLink.CanBuyPickup(Class<KFWeaponPickup>(WClass.Default.PickupClass)) )
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);
Weight = Class<KFWeapon>(WClass).Default.Weight;
if( class'DualWeaponsManager'.Static.IsDualWeapon(WClass,SecType) )
{
if( WClass!=class'Dualies' && HasWeaponClass(SecType,OI) )
{
Weight-=SecType.Default.Weight;
Price*=0.5f;
OtherPrice = KFWeapon(OI).SellValue;
if( OtherPrice==-1 )
{
OtherPrice = class<KFWeaponPickup>(SecType.Default.PickupClass).Default.Cost * 0.75;
if ( KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none )
OtherPrice *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), SecType.Default.PickupClass);
}
}
}
else if( class'DualWeaponsManager'.Static.HasDualies(WClass,Inventory) )
return;
Price = int(Price); // Truncuate price.
if( Weight>0 && !CanCarry(Weight) )
{
ClientMessage("Error: "$WClass.Name$" is too heavy ("$CurrentWeight$"+"$Weight$">"$MaxCarryWeight$")");
return;
}
if ( PlayerReplicationInfo.Score<Price )
{
ClientMessage("Error: "$WClass.Name$" is too expensive ("$int(Price)$">"$int(PlayerReplicationInfo.Score)$")");
Return;
}
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;
if( OtherPrice>0 )
KFWeapon(I).SellValue+=OtherPrice;
I.GiveTo(self);
PlayerReplicationInfo.Score -= Price;
ClientForceChangeWeapon(I);
}
else ClientMessage("Error: "$WClass.Name$" failed to spawn.");
SetTraderUpdate();
}
function ServerSellWeapon( Class<Weapon> WClass )
{
local Inventory I;
local KFWeapon NewWep;
local float Price;
local class<KFWeapon> SecType;
if ( !CanBuyNow() || Class<KFWeapon>(WClass) == none || Class<KFWeaponPickup>(WClass.Default.PickupClass)==none
|| Class<KFWeapon>(WClass).Default.bKFNeverThrow )
{
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 = (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( class'DualWeaponsManager'.Static.IsDualWeapon(WClass,SecType) )
{
NewWep = Spawn(SecType);
if( WClass!=class'Dualies' )
{
Price *= 0.5f;
NewWep.SellValue = Price;
}
NewWep.GiveTo(self);
}
if ( I==Weapon || I==PendingWeapon )
{
ClientCurrentWeaponSold();
}
PlayerReplicationInfo.Score += int(Price);
I.Destroy();
SetTraderUpdate();
if ( KFGameType(Level.Game)!=none )
KFGameType(Level.Game).WeaponDestroyed(WClass);
return;
}
}
}
simulated function AddBlur(Float BlurDuration, float Intensity)
{
if( KFPC!=none && Viewport(KFPC.Player)!=None )
Super.AddBlur(BlurDuration,Intensity);
}
simulated function DoHitCamEffects(vector HitDirection, float JarrScale, float BlurDuration, float JarDurationScale )
{
if( KFPC!=none && Viewport(KFPC.Player)!=None )
Super.DoHitCamEffects(HitDirection,JarrScale,BlurDuration,JarDurationScale);
}
simulated function StopHitCamEffects()
{
if( KFPC!=none && Viewport(KFPC.Player)!=None )
Super.StopHitCamEffects();
}
exec function TossCash( int Amount )
{
// To fix cash tossing exploit.
if( CashTossTimer<Level.TimeSeconds && (LongTossCashTimer<Level.TimeSeconds || LongTossCashCount<20) )
{
Super.TossCash(Max(Amount,50));
CashTossTimer = Level.TimeSeconds+0.1f;
if( LongTossCashTimer<Level.TimeSeconds )
{
LongTossCashTimer = Level.TimeSeconds+5.f;
LongTossCashCount = 0;
}
else ++LongTossCashCount;
}
}
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( !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
LifeSpan = 0.2f;
}
function float AssessThreatTo(KFMonsterController Monster, optional bool CheckDistance)
{
local float ThreatRating;
local Inventory CurInv;
local KF_StoryInventoryItem StoryInv;
ThreatRating = FMax(Super(KFHumanPawn).AssessThreatTo(Monster,CheckDistance),0.1f);
/* Factor in story Items which adjust your desirability to ZEDs */
for ( CurInv = Inventory; CurInv != none; CurInv = CurInv.Inventory )
{
StoryInv = KF_StoryInventoryItem(CurInv);
if(StoryInv != none)
ThreatRating *= StoryInv.AIThreatModifier;
}
return ThreatRating;
}
simulated final function int GetFloorSurface()
{
local int SurfaceTypeID;
local actor A;
local vector HL,HN,Start,End;
local material FloorMat;
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 SurfaceTypeID;
}
simulated function Sound GetSound(xPawnSoundGroup.ESoundType soundType)
{
local int SurfaceTypeID;
if( SoundGroupClass==None )
SoundGroupClass = Class'KFMaleSoundGroup';
if( soundType == EST_Land || soundType == EST_Jump )
SurfaceTypeID = GetFloorSurface();
return SoundGroupClass.static.GetSound(soundType, SurfaceTypeID);
}
// The player wants to switch to weapon group number F.
simulated function SwitchWeapon(byte F)
{
local Weapon DesiredWeap;
local bool AllowSwitch;
// Fixed script warnings.
if( Weapon!=None && Weapon.Inventory!=None )
DesiredWeap = Weapon.Inventory.WeaponChange(F, false);
if(DesiredWeap == none && Inventory!=None )
DesiredWeap = Inventory.WeaponChange(F, true);
if(DesiredWeap != none)
AllowSwitch = AllowHoldWeapon(DesiredWeap);
if( AllowSwitch )
Super(KFPawn).SwitchWeapon(F);
}
simulated function tick(float DeltaTime)
{
local KF_StoryPRI PRI;
super(KFPawn).Tick(DeltaTime);
if( IsLocallyControlled() && !bUsingHitBlur && BlurFadeOutTime > 0 )
{
BlurFadeOutTime -= DeltaTime;
DeltaTime = BlurFadeOutTime/StartingBlurFadeOutTime * CurrentBlurIntensity;
if( BlurFadeOutTime <= 0 )
{
BlurFadeOutTime = 0;
StopHitCamEffects();
}
else if( bUseBlurEffect && KFPC!=none && !KFPC.PostFX_IsReady() )
{
if( CameraEffectFound != none )
UnderWaterBlur(CameraEffectFound).BlurAlpha = Lerp( DeltaTime, 255, UnderWaterBlur(CameraEffectFound).default.BlurAlpha );
else KFPC.SetBlur(DeltaTime);
}
}
/* Replicated Location stuff - for tracking this pawn's position to display icons when its not relevant */
PRI = KF_StoryPRI(PlayerReplicationInfo);
if(PRI != none && PRI.GetFloatingIconMat() != none)
{
if(Role == Role_Authority) // server authoritative
{
if(PRI.GetOwnerPawn() != self)
{
PRI.SetOwnerPawn(self);
PRI.NetUpdateTime = Level.TimeSeconds - 1;
}
KF_StoryPRI(PlayerReplicationInfo).SetReplicatedPawnLoc(GetHoverIconPosition());
}
else if(bDeleteMe || bPendingDelete) // simulated proxy.
{
PRI.SetOwnerPawn(none);
PRI.NetUpdateTime = Level.TimeSeconds - 1;
}
}
}
simulated function SetWeaponAttachment(WeaponAttachment NewAtt)
{
local byte i;
Super.SetWeaponAttachment(NewAtt);
if( KFWeaponAttachment(WeaponAttachment)!=None )
{
// Veryify valid animations.
for( i=0; i<4; ++i )
{
DoubleJumpAnims[i] = TakeoffAnims[i];
if( !HasAnim(MovementAnims[i]) )
MovementAnims[i] = Default.MovementAnims[i];
if( !HasAnim(WalkAnims[i]) )
MovementAnims[i] = Default.WalkAnims[i];
}
if( !HasAnim(IdleWeaponAnim) )
MovementAnims[i] = Default.IdleWeaponAnim;
if( !HasAnim(IdleRestAnim) )
MovementAnims[i] = Default.IdleRestAnim;
if( !HasAnim(IdleChatAnim) )
MovementAnims[i] = Default.IdleChatAnim;
}
}
defaultproperties
{
InvisMaterial=Shader'KF_Specimens_Trip_T.patriarch_invisible'
WallDodgeAnims(0)="JumpF_Takeoff"
WallDodgeAnims(1)="JumpL_Takeoff"
WallDodgeAnims(2)="JumpL_Takeoff"
WallDodgeAnims(3)="JumpR_Takeoff"
MovementAnims(0)="JogF_Pipe"
MovementAnims(1)="JogB_Pipe"
MovementAnims(2)="JogL_Pipe"
MovementAnims(3)="JogR_Pipe"
SwimAnims(0)="WalkF_Flamethrower"
SwimAnims(1)="WalkB_Flamethrower"
SwimAnims(2)="WalkL_Flamethrower"
SwimAnims(3)="WalkR_Flamethrower"
CrouchAnims(0)="CHwalkF_Pipe"
CrouchAnims(1)="CHwalkB_Pipe"
CrouchAnims(2)="CHwalkL_Pipe"
CrouchAnims(3)="CHwalkR_Pipe"
WalkAnims(0)="WalkF_Flamethrower"
WalkAnims(1)="WalkB_Flamethrower"
WalkAnims(2)="WalkL_Flamethrower"
WalkAnims(3)="WalkR_Flamethrower"
DoubleJumpAnims(0)="JumpF_Takeoff"
DoubleJumpAnims(1)="JumpL_Takeoff"
DoubleJumpAnims(2)="JumpL_Takeoff"
DoubleJumpAnims(3)="JumpR_Takeoff"
IdleWeaponAnim="Idle_Pipe"
IdleRestAnim="Idle_Pipe"
IdleChatAnim="Idle_Pipe"
}