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

1493 lines
34 KiB
Ucode

//=============================================================================
// The moving brush class.
// This is a built-in Unreal class and it shouldn't be modified.
// Note that movers by default have bNoDelete==true. This makes movers and their default properties
// remain on the client side. If a mover subclass has bNoDelete=false, then its default properties must
// be replicated
//=============================================================================
class Mover extends Actor
native
nativereplication;
// How the mover should react when it encroaches an actor.
var() enum EMoverEncroachType
{
ME_StopWhenEncroach, // Stop when we hit an actor.
ME_ReturnWhenEncroach, // Return to previous position when we hit an actor.
ME_CrushWhenEncroach, // Crush the poor helpless actor.
ME_IgnoreWhenEncroach, // Ignore encroached actors.
} MoverEncroachType;
// How the mover moves from one position to another.
var() enum EMoverGlideType
{
MV_MoveByTime, // Move linearly.
MV_GlideByTime, // Move with smooth acceleration.
} MoverGlideType;
// What classes can bump trigger this mover
var() enum EBumpType
{
BT_PlayerBump, // Can only be bumped by player.
BT_PawnBump, // Can be bumped by any pawn
BT_AnyBump, // Can be bumped by any solid actor
} BumpType;
//-----------------------------------------------------------------------------
// Keyframe numbers.
var() byte KeyNum; // Current or destination keyframe.
var byte PrevKeyNum; // Previous keyframe.
var() const byte NumKeys; // Number of keyframes in total (0-3).
var() const byte WorldRaytraceKey; // Raytrace the world with the brush here.
var() const byte BrushRaytraceKey; // Raytrace the brush here.
var byte StartKeyNum;
//-----------------------------------------------------------------------------
// Movement parameters.
var() float MoveTime; // Time to spend moving between keyframes.
var() float StayOpenTime; // How long to remain open before closing.
var() float OtherTime; // TriggerPound stay-open time.
var() int EncroachDamage; // How much to damage encroached actors.
//-----------------------------------------------------------------------------
// Mover state.
var() bool bToggleDirection;
var() bool bTriggerOnceOnly; // Go dormant after first trigger.
var() bool bSlave; // This brush is a slave.
var() bool bUseTriggered; // Triggered by player grab
var() bool bDamageTriggered; // Triggered by taking damage
var() bool bDynamicLightMover; // Apply dynamic lighting to mover.
var() bool bUseShortestRotation; // rot by -90 instead of +270 and so on.
var(ReturnGroup) bool bIsLeader;
var() name PlayerBumpEvent; // Optional event to cause when the player bumps the mover.
var() name BumpEvent; // Optional event to cause when any valid bumper bumps the mover.
var actor SavedTrigger; // Who we were triggered by.
var() float DamageThreshold; // minimum damage to trigger
var int numTriggerEvents; // number of times triggered ( count down to untrigger )
var Mover Leader; // for having multiple movers return together
var Mover Follower;
var(ReturnGroup) name ReturnGroup; // if none, same as tag
var() float DelayTime; // delay before starting to open
//-----------------------------------------------------------------------------
// Audio.
var(MoverSounds) sound OpeningSound; // When start opening.
var(MoverSounds) sound OpenedSound; // When finished opening.
var(MoverSounds) sound ClosingSound; // When start closing.
var(MoverSounds) sound ClosedSound; // When finish closing.
var(MoverSounds) sound MoveAmbientSound; // Optional ambient sound when moving.
var(MoverSounds) sound LoopSound; // Played on Loop
//-----------------------------------------------------------------------------
// Events
var(MoverEvents) name OpeningEvent; // Event to cause when opening
var(MoverEvents) name OpenedEvent; // Event to cause when opened
var(MoverEvents) name ClosingEvent; // Event to cause when closing
var(MoverEvents) name ClosedEvent; // Event to cause when closed
var(MoverEvents) name LoopEvent; // Event to cause when the mover loops
//-----------------------------------------------------------------------------
// Other stuff
//-----------------------------------------------------------------------------
// Internal.
var vector KeyPos[24];
var rotator KeyRot[24];
var vector BasePos, OldPos, OldPrePivot, SavedPos;
var rotator BaseRot, OldRot, SavedRot;
var float PhysAlpha; // Interpolating position, 0.0-1.0.
var float PhysRate; // Interpolation rate per second.
// AI related
var NavigationPoint myMarker;
var bool bOpening, bDelaying, bClientPause;
var bool bClosed; // mover is in closed position, and no longer moving
var bool bPlayerOnly;
var(AI) bool bAutoDoor; // automatically setup Door NavigationPoint for this mover
var(AI) bool bNoAIRelevance; // don't warn about this mover during path review
var bool bJumpLift;
var() bool bOscillatingLoop; // Goes from 0 up to X then back down to 0
// for client side replication
var byte ClientStop;
var vector SimOldPos;
var int SimOldRotPitch, SimOldRotYaw, SimOldRotRoll;
var vector SimInterpolate;
var vector RealPosition;
var rotator RealRotation;
var int ClientUpdate;
var byte StoppedPosition;
// Used for Oscillation
var int StepDirection; // 1 = Moving forward, -1 moving Backward
// Used for controlling antiportals
var array<AntiPortalActor> AntiPortals;
var() name AntiPortalTag;
// Resetting
var bool bResetting, BACKUP_bHidden;
var name Backup_InitialState;
replication
{
// Things the server should send to the client.
reliable if( Role==ROLE_Authority )
SimOldPos, SimOldRotPitch, SimOldRotYaw, SimOldRotRoll, SimInterpolate, RealPosition, RealRotation, StoppedPosition;
}
function bool SelfTriggered()
{
return true;
}
function Actor SpecialHandling(Pawn Other)
{
local Actor A;
if ( myMarker != None )
{
A = MyMarker.SpecialHandling(Other);
if ( A == None )
return MyMarker;
return A;
}
return self;
}
/* StartInterpolation()
when this function is called, the actor will start moving along an interpolation path
beginning at Dest
*/
simulated function StartInterpolation()
{
GotoState('');
bInterpolating = true;
SetPhysics(PHYS_None);
}
simulated function Timer()
{
if ( Velocity != vect(0,0,0) )
{
if ( bClientPause )
bClientPause = false;
return;
}
if ( Level.NetMode == NM_Client && !bClientAuthoritative )
{
if ( ClientUpdate == 0 ) // not doing a move
{
if ( bClientPause )
{
if ( VSize(RealPosition - Location) > 3 )
SetLocation(RealPosition);
else
RealPosition = Location;
SetRotation(RealRotation);
bClientPause = false;
}
else if ( RealPosition != Location )
bClientPause = true;
}
else
bClientPause = false;
}
else
{
if ( bCollideActors )
{
if ( RealRotation != Rotation )
RealRotation = Rotation;
if ( RealPosition != Location )
RealPosition = Location;
}
}
}
//-----------------------------------------------------------------------------
// Movement functions.
// Interpolate to keyframe KeyNum in Seconds time.
simulated final function InterpolateTo( byte NewKeyNum, float Seconds )
{
local Mover M;
ForEach BasedActors(class'Mover', M)
M.BaseStarted();
NewKeyNum = Clamp( NewKeyNum, 0, ArrayCount(KeyPos)-1 );
if( NewKeyNum==PrevKeyNum && KeyNum!=PrevKeyNum )
{
// Reverse the movement smoothly.
PhysAlpha = 1.0 - PhysAlpha;
OldPos = BasePos + KeyPos[KeyNum];
OldRot = BaseRot + KeyRot[KeyNum];
}
else
{
// Start a new movement.
OldPos = Location;
OldRot = Rotation;
PhysAlpha = 0.0;
}
if ( bResetting ) // resetting mover, do it at max speed
Seconds = 0.005;
// Setup physics.
SetPhysics(PHYS_MovingBrush);
bInterpolating = true;
PrevKeyNum = KeyNum;
KeyNum = NewKeyNum;
PhysRate = 1.0 / FMax(Seconds, 0.005);
ClientUpdate++;
SimOldPos = OldPos;
SimOldRotYaw = OldRot.Yaw;
SimOldRotPitch = OldRot.Pitch;
SimOldRotRoll = OldRot.Roll;
SimInterpolate.X = 100 * PhysAlpha;
SimInterpolate.Y = 100 * FMax(0.01, PhysRate);
SimInterpolate.Z = 256 * PrevKeyNum + KeyNum;
NetUpdateTime = Level.TimeSeconds - 1;
}
// Set the specified keyframe.
final function SetKeyframe( byte NewKeyNum, vector NewLocation, rotator NewRotation )
{
KeyNum = Clamp( NewKeyNum, 0, ArrayCount(KeyPos)-1 );
KeyPos[KeyNum] = NewLocation;
KeyRot[KeyNum] = NewRotation;
}
// Interpolation ended.
simulated event KeyFrameReached()
{
local byte OldKeyNum;
local Mover M;
OldKeyNum = PrevKeyNum;
PrevKeyNum = KeyNum;
PhysAlpha = 0;
ClientUpdate--;
// If more than two keyframes, chain them.
if( KeyNum>0 && KeyNum<OldKeyNum )
{
// Chain to previous.
InterpolateTo(KeyNum-1,MoveTime);
}
else if( KeyNum<NumKeys-1 && KeyNum>OldKeyNum )
{
// Chain to next.
InterpolateTo(KeyNum+1,MoveTime);
}
else
{
// Finished interpolating.
AmbientSound = None;
NetUpdateTime = Level.TimeSeconds - 1;
if ( bJumpLift && (KeyNum == 1) )
FinishNotify();
if ( (ClientUpdate == 0) && ((Level.NetMode != NM_Client) || bClientAuthoritative) )
{
RealPosition = Location;
RealRotation = Rotation;
ForEach BasedActors(class'Mover', M)
M.BaseFinished();
}
}
}
//-----------------------------------------------------------------------------
// Mover functions.
// Notify AI that mover finished movement
function FinishNotify()
{
local Controller C;
for ( C=Level.ControllerList; C!=None; C=C.nextController )
if ( (C.Pawn != None) && (C.PendingMover == self) )
C.MoverFinished();
}
// Handle when the mover finishes closing.
function FinishedClosing()
{
local Mover M;
// Update sound effects.
PlaySound( ClosedSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
// Handle Events
TriggerEvent( ClosedEvent, Self, Instigator );
// Notify our triggering actor that we have completed.
if( SavedTrigger != None )
SavedTrigger.EndEvent();
SavedTrigger = None;
Instigator = None;
If ( MyMarker != None )
MyMarker.MoverClosed();
bClosed = true;
FinishNotify();
for ( M=Leader; M!=None; M=M.Follower )
if ( !M.bClosed )
return;
UnTriggerEvent(OpeningEvent, Self, Instigator);
}
// Handle when the mover finishes opening.
function FinishedOpening()
{
// Update sound effects.
PlaySound( OpenedSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
// Trigger any chained movers / Events
TriggerEvent(Event, Self, Instigator);
TriggerEvent(OpenedEvent, Self, Instigator);
If ( MyMarker != None )
MyMarker.MoverOpened();
FinishNotify();
}
// Open the mover.
function DoOpen()
{
bOpening = true;
bDelaying = false;
InterpolateTo( 1, MoveTime );
MakeNoise(1.0);
PlaySound( OpeningSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
AmbientSound = MoveAmbientSound;
TriggerEvent(OpeningEvent, Self, Instigator);
if ( Follower != None )
Follower.DoOpen();
}
// Close the mover.
function DoClose()
{
bOpening = false;
bDelaying = false;
InterpolateTo( Max(0,KeyNum-1), MoveTime );
MakeNoise(1.0);
PlaySound( ClosingSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
UntriggerEvent(Event, self, Instigator);
AmbientSound = MoveAmbientSound;
TriggerEvent(ClosingEvent,Self,Instigator);
if ( Follower != None )
Follower.DoClose();
}
//-----------------------------------------------------------------------------
// Engine notifications.
// When mover enters gameplay.
simulated function BeginPlay()
{
local AntiPortalActor AntiPortalA;
if(AntiPortalTag != '')
{
foreach AllActors(class'AntiPortalActor',AntiPortalA,AntiPortalTag)
{
AntiPortals.Length = AntiPortals.Length + 1;
AntiPortals[AntiPortals.Length - 1] = AntiPortalA;
}
}
// timer updates real position every second in network play
if ( Level.NetMode != NM_Standalone )
{
if ( Level.NetMode == NM_Client && bClientAuthoritative )
settimer(4.0, true);
else
settimer(1.0, true);
if ( Role < ROLE_Authority )
return;
}
RealPosition = Location;
RealRotation = Rotation;
// Init key info.
Super.BeginPlay();
KeyNum = Clamp( KeyNum, 0, ArrayCount(KeyPos)-1 );
PhysAlpha = 0.0;
StartKeyNum = KeyNum;
// Set initial location.
Move( BasePos + KeyPos[KeyNum] - Location );
// Initial rotation.
SetRotation( BaseRot + KeyRot[KeyNum] );
// find movers in same group
if ( ReturnGroup == '' )
ReturnGroup = tag;
Leader = None;
Follower = None;
}
// Immediately after mover enters gameplay.
function PostBeginPlay()
{
local mover M;
RealRotation = Rotation;
RealPosition = Location;
Backup_InitialState = InitialState;
BACKUP_bHidden = bHidden;
// Initialize all slaves.
if( !bSlave )
{
foreach DynamicActors( class 'Mover', M, Tag )
{
if( M.bSlave )
{
M.GotoState('');
M.SetBase( Self );
}
}
}
if ( bIsLeader )
{
Leader = self;
ForEach DynamicActors( class'Mover', M )
if ( (M != self) && (M.ReturnGroup == ReturnGroup) )
{
M.Leader = self;
M.Follower = Follower;
Follower = M;
}
}
else if ( Leader == None )
{
// if no one in returngroup, I am the leader anyway
ForEach DynamicActors( class'Mover', M )
{
if ( (M != self) && (M.ReturnGroup == ReturnGroup) )
return;
}
Leader = self;
}
}
function SetResetStatus( bool bNewStatus )
{
NetUpdateTime = Level.TimeSeconds - 1;
bHidden = BACKUP_bHidden;
bResetting = bNewStatus;
if ( Follower != None )
Follower.SetResetStatus( bNewStatus );
}
function Reset()
{
SetResetStatus( true );
DoClose();
SetResetStatus( false );
EnableTrigger();
GotoState(Backup_InitialState, '');
}
function MakeGroupStop()
{
// Stop moving immediately.
bInterpolating = false;
NetUpdateTime = Level.TimeSeconds - 1;
AmbientSound = None;
GotoState( , '' );
if ( Follower != None )
Follower.MakeGroupStop();
}
function MakeGroupReturn()
{
// Abort move and reverse course.
bInterpolating = false;
NetUpdateTime = Level.TimeSeconds - 1;
AmbientSound = None;
if(bIsLeader || Leader==Self)
{
if( KeyNum<PrevKeyNum )
GotoState( , 'Open' );
else
GotoState( , 'Close' );
}
if ( Follower != None )
Follower.MakeGroupReturn();
}
// Return true to abort, false to continue.
function bool EncroachingOn( actor Other )
{
local Pawn P;
if ( Other == None )
return false;
if ( ((Pawn(Other) != None) && (Pawn(Other).Controller == None)) || Other.IsA('Decoration') )
{
Other.TakeDamage(10000, None, Other.Location, vect(0,0,0), class'Crushed');
return false;
}
if ( Other.IsA('Pickup') )
{
if ( !Other.bAlwaysRelevant && (Other.Owner == None) )
Other.Destroy();
return false;
}
if ( Other.IsA('Fragment') || Other.IsA('SeveredAppendage') || Other.IsA('Projectile') )
{
Other.Destroy();
return false;
}
// Damage the encroached actor.
if( EncroachDamage != 0 )
Other.TakeDamage( EncroachDamage, Instigator, Other.Location, vect(0,0,0), class'Crushed' );
// If we have a bump-player event, and Other is a pawn, do the bump thing.
P = Pawn(Other);
if( P!=None && (P.Controller != None) && P.IsPlayerPawn() )
{
if ( PlayerBumpEvent!='' )
Bump( Other );
if ( (P != None) && (P.Controller != None) && (P.Base != self) && (P.Controller.PendingMover == self) )
P.Controller.UnderLift(self); // pawn is under lift - tell him to move
}
if ( Leader == None )
Leader = self;
// Stop, return, or whatever.
if( MoverEncroachType == ME_StopWhenEncroach )
{
Leader.MakeGroupStop();
return true;
}
else if( MoverEncroachType == ME_ReturnWhenEncroach )
{
Leader.MakeGroupReturn();
if ( Other.IsA('Pawn') )
Pawn(Other).PlayMoverHitSound();
return true;
}
else if( MoverEncroachType == ME_CrushWhenEncroach )
{
// Kill it.
Other.KilledBy( Instigator );
return false;
}
else if( MoverEncroachType == ME_IgnoreWhenEncroach )
{
// Ignore it.
return false;
}
}
// When bumped by player.
function Bump( actor Other )
{
local pawn P;
P = Pawn(Other);
if ( bUseTriggered && (P != None) && !P.IsHumanControlled() && P.IsPlayerPawn() && !bDelaying && !bOpening )
{
Trigger(P,P);
P.Controller.WaitForMover(self);
}
if ( (BumpType != BT_AnyBump) && (P == None) )
return;
if ( (BumpType == BT_PlayerBump) && !P.IsPlayerPawn() )
return;
if ( (BumpType == BT_PawnBump) && P.bAmbientCreature )
return;
TriggerEvent(BumpEvent, self, P);
if ( (P != None) && P.IsPlayerPawn() )
TriggerEvent(PlayerBumpEvent, self, P);
}
// When damaged
function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
Vector momentum, class<DamageType> damageType, optional int HitIndex)
{
if ( bDamageTriggered && (Damage >= DamageThreshold) )
{
if ( (AIController(instigatedBy.Controller) != None)
&& (instigatedBy.Controller.Focus == self) )
instigatedBy.Controller.StopFiring();
self.Trigger(self, instigatedBy);
if ( (AIController(instigatedBy.Controller) != None) && (instigatedBy.Controller.Target == self) )
instigatedBy.Controller.StopFiring();
}
}
//========================================================================
// Master State for OpenTimed mover states (for movers that open and close)
// Laurent -- Moved out of state for reset
function DisableTrigger();
function EnableTrigger();
state OpenTimedMover
{
function bool ShouldReTrigger()
{
return( false );
}
function Reset()
{
SetResetStatus( true );
GotoState(Backup_InitialState, 'Close');
}
function BeginState()
{
EnableTrigger();
}
Open:
if ( bTriggerOnceOnly )
Disable('Trigger');
bClosed = false;
DisableTrigger();
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
DoOpen();
FinishInterpolation();
FinishedOpening();
Sleep( StayOpenTime );
if ( bTriggerOnceOnly )
GotoState('WasOpenTimedMover', '');
Close:
DoClose();
FinishInterpolation();
FinishedClosing();
EnableTrigger();
if ( bResetting )
{
SetResetStatus( false );
GotoState( Backup_InitialState, '' );
Stop;
}
Sleep( StayOpenTime );
if( ShouldReTrigger() )
{
SavedTrigger = None;
GotoState( 'StandOpenTimed', 'Open' );
}
}
state WasOpenTimedMover
{
function Reset()
{
SetResetStatus( true );
GotoState(Backup_InitialState, 'Close');
}
}
// Open when stood on, wait, then close.
state() StandOpenTimed extends OpenTimedMover
{
function bool ShouldReTrigger()
{
local int i;
for( i = 0; i < Attached.Length; i++ )
if( CanTrigger( Attached[i] ) )
return( true );
return( false );
}
function bool CanTrigger( Actor Other )
{
local pawn P;
P = Pawn(Other);
if ( (BumpType != BT_AnyBump) && (P == None) )
return (false);
if ( (BumpType == BT_PlayerBump) && !P.IsPlayerPawn() )
return (false);
if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
return (false);
TriggerEvent(BumpEvent, self, P); // gam -- this _might_ cause problems. Blame Goose.
return( true );
}
function Attach( actor Other )
{
if( !CanTrigger( Other ) )
return;
SavedTrigger = None;
GotoState( 'StandOpenTimed', 'Open' );
}
function DisableTrigger()
{
Disable( 'Attach' );
}
function EnableTrigger()
{
Enable('Attach');
}
}
// Open when bumped, wait, then close.
state() BumpOpenTimed extends OpenTimedMover
{
function Bump( actor Other )
{
if ( (BumpType != BT_AnyBump) && (Pawn(Other) == None) )
return;
if ( (BumpType == BT_PlayerBump) && !Pawn(Other).IsPlayerPawn() )
return;
if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
return;
Global.Bump( Other );
SavedTrigger = None;
Instigator = Pawn(Other);
Instigator.Controller.WaitForMover(self);
GotoState( 'BumpOpenTimed', 'Open' );
}
function DisableTrigger()
{
Disable( 'Bump' );
}
function EnableTrigger()
{
Enable('Bump');
}
}
// When triggered, open, wait, then close.
state() TriggerOpenTimed extends OpenTimedMover
{
function bool SelfTriggered()
{
return false;
}
function Trigger( actor Other, pawn EventInstigator )
{
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
GotoState( 'TriggerOpenTimed', 'Open' );
}
function DisableTrigger()
{
Disable('Trigger');
}
function EnableTrigger()
{
Enable('Trigger');
}
}
state() LoopMove
{
function bool SelfTriggered()
{
return false;
}
event Trigger( actor Other, pawn EventInstigator )
{
Disable ('Trigger');
Enable ('UnTrigger');
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
bOpening = true;
PlaySound( OpeningSound, SLOT_None );
AmbientSound = MoveAmbientSound;
GotoState( 'LoopMove', 'Running' );
}
event UnTrigger( actor Other, pawn EventInstigator )
{
Disable ('UnTrigger');
Enable ('Trigger');
SavedTrigger = Other;
Instigator = EventInstigator;
GotoState( 'LoopMove', 'Stopping' );
}
event KeyFrameReached()
{
}
function BeginState()
{
bOpening = false;
bDelaying = false;
}
Running:
FinishInterpolation();
InterpolateTo( (KeyNum + 1) % NumKeys, MoveTime );
GotoState( 'LoopMove', 'Running' );
Stopping:
FinishInterpolation();
FinishedOpening();
UnTriggerEvent(Event, self, Instigator);
bOpening = false;
Stop;
}
//=================================================================
// Other Mover States
// Toggle when triggered.
state() TriggerToggle
{
function bool SelfTriggered()
{
return false;
}
function Reset()
{
super.Reset();
if ( bOpening || bDelaying )
{
// Reset instantly
SetResetStatus( true );
GotoState( 'TriggerToggle', 'Close' );
}
}
function Trigger( actor Other, pawn EventInstigator )
{
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
if( KeyNum==0 || KeyNum<PrevKeyNum )
GotoState( 'TriggerToggle', 'Open' );
else
{
if( EventInstigator.Controller != none && AIController(EventInstigator.Controller) == none )
GotoState( 'TriggerToggle', 'Close' );
// KFO Mod
else
{
GotoState( 'TriggerToggle', 'Close' );
}
// END KFO
//else
// log("Don't let bots close doors!!! bClosed = "$bClosed);
}
}
Open:
bClosed = false;
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
DoOpen();
FinishInterpolation();
FinishedOpening();
if ( SavedTrigger != None )
SavedTrigger.EndEvent();
Stop;
Close:
DoClose();
FinishInterpolation();
FinishedClosing();
SetResetStatus( false );
}
// Open when triggered, close when get untriggered.
state() TriggerControl
{
function bool SelfTriggered()
{
return false;
}
function Reset()
{
super.Reset();
if ( numTriggerEvents > 0 )
{
// Reset instantly
SetResetStatus( true );
numTriggerEvents = 0;
UnTrigger(None, None);
}
}
function Trigger( actor Other, pawn EventInstigator )
{
numTriggerEvents++;
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
if ( !bOpening )
GotoState( 'TriggerControl', 'Open' );
}
function UnTrigger( actor Other, pawn EventInstigator )
{
numTriggerEvents--;
if ( numTriggerEvents <=0 )
{
numTriggerEvents = 0;
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
GotoState( 'TriggerControl', 'Close' );
}
}
function BeginState()
{
numTriggerEvents = 0;
}
Open:
bClosed = false;
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
if ( !bOpening )
DoOpen();
FinishInterpolation();
FinishedOpening();
if ( SavedTrigger != None )
SavedTrigger.EndEvent();
if( bTriggerOnceOnly )
GotoState('WasTriggerControl');
Stop;
Close:
if ( bOpening )
DoClose();
FinishInterpolation();
FinishedClosing();
SetResetStatus( false );
}
state WasTriggerControl
{
function bool SelfTriggered()
{
return false;
}
function Reset()
{
super.Reset();
// Reset instantly
SetResetStatus( true );
GotoState('TriggerControl','Close');
}
}
// Start pounding when triggered.
state() TriggerPound
{
function bool SelfTriggered()
{
return false;
}
function Reset()
{
super.Reset();
if ( numTriggerEvents > 0 )
{
// Reset instantly
SetResetStatus( true );
numTriggerEvents = 0;
UnTrigger(None,None);
}
}
function Trigger( actor Other, pawn EventInstigator )
{
numTriggerEvents++;
SavedTrigger = Other;
Instigator = EventInstigator;
GotoState( 'TriggerPound', 'Open' );
}
function UnTrigger( actor Other, pawn EventInstigator )
{
numTriggerEvents--;
if ( numTriggerEvents <= 0 )
{
numTriggerEvents = 0;
SavedTrigger = None;
Instigator = None;
GotoState( 'TriggerPound', 'Close' );
}
}
function BeginState()
{
numTriggerEvents = 0;
}
Open:
if ( bTriggerOnceOnly )
Disable('Trigger');
bClosed = false;
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
DoOpen();
FinishInterpolation();
Sleep(OtherTime);
Close:
DoClose();
FinishInterpolation();
Sleep(StayOpenTime);
SetResetStatus( false );
if( bTriggerOnceOnly )
GotoState('WasTriggerPound');
if( SavedTrigger != None )
goto 'Open';
}
state WasTriggerPound
{
function Reset()
{
super.Reset();
// Reset instantly
SetResetStatus( true );
GotoState('TriggerPound','Open');
}
}
function SetStoppedPosition(byte NewPos)
{
NetUpdateTime = Level.TimeSeconds - 1;
StoppedPosition = NewPos;
}
// Open when triggered, stop when untriggered, close when reset.
state() TriggerAdvance
{
function bool SelfTriggered()
{
return false;
}
function Reset()
{
super.Reset();
// Reset instantly
SetResetStatus( true );
numTriggerEvents = 0;
GotoState('TriggerAdvance','Close');
}
function Trigger( actor Other, pawn EventInstigator )
{
numTriggerEvents++;
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
SetStoppedPosition(0);
SetPhysics(PHYS_MovingBrush);
AmbientSound = MoveAmbientSound;
if ( !bOpening )
GotoState( 'TriggerAdvance', 'Open' );
}
function UnTrigger( actor Other, pawn EventInstigator )
{
numTriggerEvents--;
if ( numTriggerEvents <=0 )
{
AmbientSound = None;
numTriggerEvents = 0;
SavedTrigger = Other;
Instigator = EventInstigator;
if ( SavedTrigger != None )
SavedTrigger.BeginEvent();
SetStoppedPosition(1);
SetPhysics(PHYS_None);
}
}
function BeginState()
{
numTriggerEvents = 0;
}
function EndState()
{
AmbientSound = None;
}
Open:
if ( Physics == PHYS_None ) // Check if Mover has been UnTriggered since
GotoState( 'TriggerAdvance', '' );
bClosed = false;
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
if ( Physics == PHYS_None ) // Check if Mover has been UnTriggered since
GotoState( 'TriggerAdvance', '' );
SetStoppedPosition(0);
DoOpen();
FinishInterpolation();
FinishedOpening();
if ( SavedTrigger != None )
SavedTrigger.EndEvent();
GotoState('WasTriggerAdvance');
Stop;
Close:
SetStoppedPosition(0);
SetPhysics(PHYS_MovingBrush);
DoClose();
FinishInterpolation();
FinishedClosing();
SetResetStatus( false );
Stop;
}
state WasTriggerAdvance
{
function bool SelfTriggered()
{
return false;
}
function Reset()
{
super.Reset();
// Reset instantly
SetResetStatus( true );
GotoState('TriggerAdvance','Close');
}
}
//-----------------------------------------------------------------------------
// Bump states.
// Open when bumped, close when reset.
state() BumpButton
{
function Bump( actor Other )
{
if ( (BumpType != BT_AnyBump) && (Pawn(Other) == None) )
return;
if ( (BumpType == BT_PlayerBump) && !Pawn(Other).IsPlayerPawn() )
return;
if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
return;
Global.Bump( Other );
SavedTrigger = Other;
Instigator = Pawn( Other );
Instigator.Controller.WaitForMover(self);
GotoState( 'BumpButton', 'Open' );
}
function BeginEvent()
{
bSlave=true;
}
function EndEvent()
{
bSlave = false;
Instigator = None;
GotoState( 'BumpButton', 'Close' );
}
Open:
if ( bTriggerOnceOnly )
Disable('Trigger');
bClosed = false;
Disable( 'Bump' );
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
DoOpen();
FinishInterpolation();
FinishedOpening();
if( bTriggerOnceOnly )
GotoState('WasBumpButton');
if( bSlave )
Stop;
Close:
DoClose();
FinishInterpolation();
FinishedClosing();
SetResetStatus( false );
Enable( 'Bump' );
}
state WasBumpButton
{
function Reset()
{
super.Reset();
// Reset instantly
SetResetStatus( true );
GotoState('BumpButton','Close');
}
}
function MoverLooped() // Cause the LoopEvent and play the Loop Sound
{
// Event and sound
TriggerEvent(LoopEvent, Self, Instigator);
If (LoopSound!=None)
PlaySound( LoopSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
}
// -----------------------------
// Loop this mover from the moment we begin
state() ConstantLoop
{
event KeyFrameReached()
{
if (bOscillatingLoop)
{
if ( (KeyNum==0) || (KeyNum==NumKeys-1) ) // Flip
{
StepDirection*= -1;
MoverLooped();
}
KeyNum += StepDirection;
InterpolateTo( KeyNum, MoveTime );
}
else
{
InterpolateTo( (KeyNum + 1) % NumKeys, MoveTime );
if (KeyNum==0)
MoverLooped();
}
}
function BeginState()
{
bOpening = false;
bDelaying = false;
}
Begin:
InterpolateTo( 1, MoveTime );
Running:
FinishInterpolation();
GotoState( 'ConstantLoop', 'Running' );
}
// --------
// LeadInOutLooper - A Looping move that goes from 0 to 1 when trigger, loops 1-x then returns to 0 when triggered again
state() LeadInOutLooper
{
function Trigger( actor Other, pawn EventInstigator )
{
// Sanity check
if (NumKeys<3)
{
log("LeadInOutLooper detected with <3 movement keys");
return;
}
InterpolateTo(1,MoveTime);
}
event KeyFrameReached()
{
if (KeyNum!=0)
{
InterpolateTo(2,MoveTime);
gotoState('LeadInOutLooping');
}
}
function BeginState()
{
bOpening = false;
bDelaying = false;
}
}
state LeadInOutLooping
{
function Trigger(actor Other, pawn EventInstigator)
{
InterpolateTo(0,MoveTime);
GotoState('LeadInOutLooper');
}
event KeyFrameReached()
{
if (bOscillatingLoop)
{
if ( (KeyNum==1) || (KeyNum==NumKeys-1) ) // Flip
{
StepDirection*= -1;
MoverLooped();
}
KeyNum += StepDirection;
InterpolateTo( KeyNum, MoveTime );
}
else
{
KeyNum++;
if (KeyNum==NumKeys)
{
KeyNum=1;
MoverLooped();
}
InterpolateTo( KeyNum, MoveTime );
}
}
}
function BaseStarted();
function BaseFinished();
// toggles between rotation directions when triggered, stops rotating when untriggered
state() RotatingMover
{
simulated function BaseStarted()
{
local actor OldBase;
bFixedRotationDir = true;
OldBase = Base;
SetPhysics(PHYS_Rotating);
SetBase(OldBase);
}
simulated function BaseFinished()
{
local actor OldBase;
OldBase = Base;
SetPhysics(PHYS_None);
SetBase(OldBase);
if ( bToggleDirection )
{
RotationRate.Yaw *= -1;
RotationRate.Pitch *= -1;
RotationRate.Roll *= -1;
}
}
simulated function BeginState()
{
SetTimer(0.0,false);
}
}
simulated function UpdatePrecacheStaticMeshes()
{
if ( (DrawType == DT_StaticMesh) && StaticMesh != None )
Level.AddPrecacheStaticMesh( StaticMesh );
}
defaultproperties
{
bNoDelete=true
bPathColliding=true
MoverEncroachType=ME_ReturnWhenEncroach
MoverGlideType=MV_GlideByTime
NumKeys=2
BrushRaytraceKey=0
MoveTime=+00001.000000
StayOpenTime=+00004.000000
bStatic=False
bDynamicLightMover=False
bHidden=false
CollisionRadius=+00160.000000
CollisionHeight=+00160.000000
bCollideActors=True
bBlockActors=True
Physics=PHYS_MovingBrush
InitialState=BumpOpenTimed
TransientSoundVolume=+00001.000000
SoundVolume=228
NetPriority=2.7
bAlwaysRelevant=true
RemoteRole=ROLE_SimulatedProxy
bClosed=true
bToggleDirection=true
bShadowCast=true
bEdShouldSnap=true
bAcceptsProjectors=true
StepDirection=1
bOnlyDirtyReplication=true
NetUpdateFrequency=1
bUseDynamicLights=true
}