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

122 lines
3.5 KiB
Ucode

/*=============================================================================
// LadderVolumes, when touched, cause ladder supporting actors to use Phys_Ladder.
// note that underwater ladders won't be waterzones (no breathing problems)
============================================================================= */
class LadderVolume extends PhysicsVolume
native;
var() name ClimbingAnimation, TopAnimation; // name of animation to play when climbing this ladder
var() rotator WallDir;
var vector LookDir;
var vector ClimbDir; // pawn can move in this direction (or reverse)
var const Ladder LadderList; // list of Ladder actors associated with this LadderVolume
var() bool bNoPhysicalLadder; // if true, won't push into/keep player against geometry in lookdir
var() bool bAutoPath; // add top and bottom ladders automatically
var() bool bAllowLadderStrafing; // if true, players on ladder can strafe sideways
var Pawn PendingClimber;
simulated function PostBeginPlay()
{
local Ladder L, M;
local vector Dir;
Super.PostBeginPlay();
LookDir = vector(WallDir);
if ( !bAutoPath && (LookDir.Z != 0) )
{
ClimbDir = vect(0,0,1);
for ( L=LadderList; L!=None; L=L.LadderList )
for ( M=LadderList; M!=None; M=M.LadderList )
if ( M != L )
{
Dir = Normal(M.Location - L.Location);
if ( (Dir dot ClimbDir) < 0 )
Dir *= -1;
ClimbDir += Dir;
}
ClimbDir = Normal(ClimbDir);
if ( (ClimbDir Dot vect(0,0,1)) < 0 )
ClimbDir *= -1;
}
}
function bool InUse(Pawn Ignored)
{
local Pawn StillClimbing;
ForEach TouchingActors(class'Pawn',StillClimbing)
{
if ( (StillClimbing != Ignored) && StillClimbing.bCollideActors && StillClimbing.bBlockActors )
return true;
}
if ( PendingClimber != None )
{
if ( (PendingClimber.Controller == None)
|| !PendingClimber.bCollideActors || !PendingClimber.bBlockActors
|| (Ladder(PendingClimber.Controller.MoveTarget) == None)
|| (Ladder(PendingClimber.Controller.MoveTarget).MyLadder != self) )
PendingClimber = None;
}
return ( (PendingClimber != None) && (PendingClimber != Ignored) );
}
simulated event PawnEnteredVolume(Pawn P)
{
local rotator PawnRot;
Super.PawnEnteredVolume(P);
if ( !P.CanGrabLadder() )
return;
PawnRot = P.Rotation;
PawnRot.Pitch = 0;
if ( (vector(PawnRot) Dot LookDir > 0.9)
|| ((AIController(P.Controller) != None) && (Ladder(P.Controller.MoveTarget) != None)) )
P.ClimbLadder(self);
else if ( !P.bDeleteMe && (P.Controller != None) )
spawn(class'PotentialClimbWatcher',P);
}
simulated event PawnLeavingVolume(Pawn P)
{
local Controller C;
if ( P.OnLadder != self )
return;
Super.PawnLeavingVolume(P);
P.OnLadder = None;
P.EndClimbLadder(self);
if ( P == PendingClimber )
PendingClimber = None;
// tell all waiting pawns, if not in use
if ( !InUse(P) )
{
for ( C=Level.ControllerList; C!=None; C=C.NextController )
if ( C.bPreparingMove && (Ladder(C.MoveTarget) != None)
&&(Ladder(C.MoveTarget).MyLadder == self) )
{
C.bPreparingMove = false;
PendingClimber = C.Pawn;
return;
}
}
}
simulated event PhysicsChangedFor(Actor Other)
{
if ( (Other.Physics == PHYS_Falling) || (Other.Physics == PHYS_Ladder) || Other.bDeleteMe || (Pawn(Other) == None) || (Pawn(Other).Controller == None) )
return;
spawn(class'PotentialClimbWatcher',Other);
}
defaultproperties
{
RemoteRole=ROLE_SimulatedProxy
ClimbDir=(X=+0.0,Y=+0.0,Z=+1.0)
bAutoPath=true
}