Engine
Class Mover

source: e:\games\UnrealTournament\Engine\Classes\Mover.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Brush
         |
         +--Engine.Mover
Direct Known Subclasses:ElevatorMover, GradualMover, LoopMover, MixMover, AssertMover, AttachMover, RotatingMover

class Mover
extends Engine.Brush

//============================================================================= // The moving brush class. // This is a built-in Unreal class and it shouldn't be modified. //=============================================================================
Variables
 byte BrushRaytraceKey
           Raytrace the brush here.
 name BumpEvent
           Optional event to cause when any valid bumper bumps the mover.
 float DamageThreshold
           minimum damage to trigger
 float DelayTime
           delay before starting to open
 enum EBumpType
 enum EMoverEncroachType
 enum EMoverGlideType
 int EncroachDamage
           How much to damage encroached actors.
 byte KeyNum
           Current or destination keyframe.
 vector KeyPos[8]
           delay before starting to open
 rotator KeyRot[8]
           delay before starting to open
 float MoveTime
           Time to spend moving between keyframes.
 byte NumKeys
           Number of keyframes in total (0-3).
 float OtherTime
           TriggerPound stay-open time.
 name PlayerBumpEvent
           Optional event to cause when the player bumps the mover.
 byte PrevKeyNum
           Previous keyframe.
 rotator RealRotation
           delay before starting to open
 name ReturnGroup
           if none, same as tag
 OldPrePivot, SavedPos
           delay before starting to open
 OldRot, SavedRot
           delay before starting to open
 Actor SavedTrigger
           Who we were triggered by.
 float StayOpenTime
           How long to remain open before closing.
 byte WorldRaytraceKey
           Raytrace the world with the brush here.
 bool bDamageTriggered
           Triggered by taking damage
 bool bDynamicLightMover
           Apply dynamic lighting to mover.
 bool bSlave
           This brush is a slave.
 bool bTriggerOnceOnly
           Go dormant after first trigger.
 bool bUseTriggered
           Triggered by player grab
 NavigationPoint myMarker
           delay before starting to open

States
should

Function Summary
 void FindTriggerActor()
 
simulated
Timer()


State should Function Summary
 void Attach(Actor Other)
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 void EndEvent()
 void BeginEvent()
 void Bump(Actor Other)
 bool HandleDoor(Pawn Other)
     
// Open when bumped, close when reset.
 void Bump(Actor Other)
 bool HandleDoor(Pawn Other)
     
// Open when bumped, wait, then close.
 void BeginState()
 void UnTrigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 bool HandleDoor(Pawn Other)
     
// Start pounding when triggered.
 void BeginState()
 void UnTrigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 bool HandleDoor(Pawn Other)
     
// Open when triggered, close when get untriggered.
 void Trigger(Actor Other, Pawn EventInstigator)
 bool HandleDoor(Pawn Other)
     
// Toggle when triggered.
 void BeginState()
 void Trigger(Actor Other, Pawn EventInstigator)
 bool HandleDoor(Pawn Other)
     
// When triggered, open, wait, then close.
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
     
// When damaged
 void Bump(Actor Other)
     
// When bumped by player.
 bool EncroachingOn(Actor Other)
     
// Return true to abort, false to continue.
 void MakeGroupReturn()
 void MakeGroupStop()
 void PostBeginPlay()
     
// Immediately after mover enters gameplay.
 void DoClose()
     
// Close the mover.
 void DoOpen()
     
// Open the mover.
 void FinishedOpening()
     
// Handle when the mover finishes opening.
 void FinishedClosing()
     
// Handle when the mover finishes closing.
 void FinishNotify()
     
// Notify AI that mover finished movement
 void InterpolateEnd(Actor Other)
     
// Interpolation ended.
 void SetKeyframe(byte NewKeyNum, vector NewLocation, rotator NewRotation)
     
// Set the specified keyframe.
 void InterpolateTo(byte NewKeyNum, float Seconds)
     
// Interpolate to keyframe KeyNum in Seconds time.
 Actor SpecialHandling(Pawn Other)
 bool HandleTriggerDoor(Pawn Other)
 bool HandleDoor(Pawn Other)
     
implement the appropriate version
*/



Source Code


00001	//=============================================================================
00002	// The moving brush class.
00003	// This is a built-in Unreal class and it shouldn't be modified.
00004	//=============================================================================
00005	class Mover extends Brush
00006		native
00007		nativereplication;
00008	
00009	// How the mover should react when it encroaches an actor.
00010	var() enum EMoverEncroachType
00011	{
00012		ME_StopWhenEncroach,	// Stop when we hit an actor.
00013		ME_ReturnWhenEncroach,	// Return to previous position when we hit an actor.
00014	   	ME_CrushWhenEncroach,   // Crush the poor helpless actor.
00015	   	ME_IgnoreWhenEncroach,  // Ignore encroached actors.
00016	} MoverEncroachType;
00017	
00018	// How the mover moves from one position to another.
00019	var() enum EMoverGlideType
00020	{
00021		MV_MoveByTime,			// Move linearly.
00022		MV_GlideByTime,			// Move with smooth acceleration.
00023	} MoverGlideType;
00024	
00025	// What classes can bump trigger this mover
00026	var() enum EBumpType
00027	{
00028		BT_PlayerBump,		// Can only be bumped by player.
00029		BT_PawnBump,		// Can be bumped by any pawn
00030		BT_AnyBump,			// Cany be bumped by any solid actor
00031	} BumpType;
00032	
00033	//-----------------------------------------------------------------------------
00034	// Keyframe numbers.
00035	var() byte       KeyNum;           // Current or destination keyframe.
00036	var byte         PrevKeyNum;       // Previous keyframe.
00037	var() const byte NumKeys;          // Number of keyframes in total (0-3).
00038	var() const byte WorldRaytraceKey; // Raytrace the world with the brush here.
00039	var() const byte BrushRaytraceKey; // Raytrace the brush here.
00040	
00041	//-----------------------------------------------------------------------------
00042	// Movement parameters.
00043	var() float      MoveTime;         // Time to spend moving between keyframes.
00044	var() float      StayOpenTime;     // How long to remain open before closing.
00045	var() float      OtherTime;        // TriggerPound stay-open time.
00046	var() int        EncroachDamage;   // How much to damage encroached actors.
00047	
00048	//-----------------------------------------------------------------------------
00049	// Mover state.
00050	var() bool       bTriggerOnceOnly; // Go dormant after first trigger.
00051	var() bool       bSlave;           // This brush is a slave.
00052	var() bool		 bUseTriggered;		// Triggered by player grab
00053	var() bool		 bDamageTriggered;	// Triggered by taking damage
00054	var() bool       bDynamicLightMover; // Apply dynamic lighting to mover.
00055	var() name       PlayerBumpEvent;  // Optional event to cause when the player bumps the mover.
00056	var() name       BumpEvent;			// Optional event to cause when any valid bumper bumps the mover.
00057	var   actor      SavedTrigger;      // Who we were triggered by.
00058	var() float		 DamageThreshold;	// minimum damage to trigger
00059	var	  int		 numTriggerEvents;	// number of times triggered ( count down to untrigger )
00060	var	  Mover		 Leader;			// for having multiple movers return together
00061	var	  Mover		 Follower;
00062	var() name		 ReturnGroup;		// if none, same as tag
00063	var() float		 DelayTime;			// delay before starting to open
00064	
00065	//-----------------------------------------------------------------------------
00066	// Audio.
00067	var(MoverSounds) sound      OpeningSound;     // When start opening.
00068	var(MoverSounds) sound      OpenedSound;      // When finished opening.
00069	var(MoverSounds) sound      ClosingSound;     // When start closing.
00070	var(MoverSounds) sound      ClosedSound;      // When finish closing.
00071	var(MoverSounds) sound      MoveAmbientSound; // Optional ambient sound when moving.
00072	
00073	//-----------------------------------------------------------------------------
00074	// Internal.
00075	var vector       KeyPos[8];
00076	var rotator      KeyRot[8];
00077	var vector       BasePos, OldPos, OldPrePivot, SavedPos;
00078	var rotator      BaseRot, OldRot, SavedRot;
00079	
00080	// AI related
00081	var       NavigationPoint  myMarker;
00082	var		  Actor			TriggerActor;
00083	var		  Actor         TriggerActor2;
00084	var		  Pawn			WaitingPawn;
00085	var		  bool			bOpening, bDelaying, bClientPause;
00086	var		  bool			bPlayerOnly;
00087	var		  Trigger		RecommendedTrigger;
00088	
00089	// for client side replication
00090	var		vector			SimOldPos;
00091	var		int				SimOldRotPitch, SimOldRotYaw, SimOldRotRoll;
00092	var		vector			SimInterpolate;
00093	var		vector			RealPosition;
00094	var     rotator			RealRotation;
00095	var		int				ClientUpdate;
00096	
00097	replication
00098	{
00099		// Things the server should send to the client.
00100		reliable if( Role==ROLE_Authority )
00101			SimOldPos, SimOldRotPitch, SimOldRotYaw, SimOldRotRoll, SimInterpolate, RealPosition, RealRotation;
00102	}
00103	
00104	simulated function Timer()
00105	{
00106		if ( Velocity != vect(0,0,0) )
00107		{
00108			bClientPause = false;
00109			return;		
00110		}
00111		if ( Level.NetMode == NM_Client )
00112		{
00113			if ( ClientUpdate == 0 ) // not doing a move
00114			{
00115				if ( bClientPause )
00116				{
00117					if ( VSize(RealPosition - Location) > 3 )
00118						SetLocation(RealPosition);
00119					else
00120						RealPosition = Location;
00121					SetRotation(RealRotation);
00122					bClientPause = false;
00123				}
00124				else if ( RealPosition != Location )
00125					bClientPause = true;
00126			}
00127			else
00128				bClientPause = false;
00129		}
00130		else 
00131		{
00132			RealPosition = Location;
00133			RealRotation = Rotation;
00134		}
00135	}
00136			
00137	function FindTriggerActor()
00138	{
00139		local Actor A;
00140	
00141		TriggerActor = None;
00142		TriggerActor2 = None;
00143		ForEach AllActors(class 'Actor', A)
00144			if ( (A.Event == Tag) && (A.IsA('Trigger') || A.IsA('Mover')) )
00145			{
00146				if ( A.IsA('Counter') || A.IsA('Pawn') )
00147				{
00148					bPlayerOnly = true;
00149					return; //FIXME - handle counters
00150				}
00151				if (TriggerActor == None)
00152					TriggerActor = A;
00153				else if ( TriggerActor2 == None )
00154					TriggerActor2 = A;
00155			}
00156	
00157		if ( TriggerActor == None )
00158		{
00159			bPlayerOnly = (BumpType == BT_PlayerBump);
00160			return;
00161		}
00162	
00163		bPlayerOnly = ( TriggerActor.IsA('Trigger') && (Trigger(TriggerActor).TriggerType == TT_PlayerProximity) );
00164		if ( bPlayerOnly && ( TriggerActor2 != None) )
00165		{
00166			bPlayerOnly = ( TriggerActor2.IsA('Trigger') && (Trigger(TriggerActor).TriggerType == TT_PlayerProximity) );
00167			if ( !bPlayerOnly )
00168			{
00169				A = TriggerActor;
00170				TriggerActor = TriggerActor2;
00171				TriggerActor2 = A;
00172			}
00173		}
00174	}
00175	
00176	/* set specialgoal/movetarget or special pause if necessary
00177	if mover can't be affected by this pawn, return false
00178	Each mover state should implement the appropriate version
00179	*/
00180	function bool HandleDoor(pawn Other)
00181	{
00182		return false;
00183	}
00184	
00185	function bool HandleTriggerDoor(pawn Other)
00186	{
00187		local bool bOne, bTwo;
00188		local float DP1, DP2, Dist1, Dist2;
00189	
00190		if ( bOpening || bDelaying )
00191		{
00192			WaitingPawn = Other;
00193			Other.SpecialPause = 2.5;
00194			return true;
00195		}
00196		if ( bPlayerOnly && !Other.bIsPlayer )
00197			return false;
00198		if ( bUseTriggered )
00199		{
00200			WaitingPawn = Other;
00201			Other.SpecialPause = 2.5;
00202			Trigger(Other, Other);
00203			return true;
00204		}
00205		if ( (BumpEvent == tag) || (Other.bIsPlayer && (PlayerBumpEvent == tag)) )
00206		{
00207			WaitingPawn = Other;
00208			Other.SpecialPause = 2.5;
00209			if ( Other.Base == Self )
00210				Trigger(Other, Other);
00211			return true;
00212		}
00213		if ( bDamageTriggered )
00214		{
00215			WaitingPawn = Other;
00216			Other.SpecialGoal = self;
00217			if ( !Other.bCanDoSpecial || (Other.Weapon == None) )
00218				return false;
00219	
00220			Other.Target = self;
00221			Other.bShootSpecial = true;
00222			Other.FireWeapon();
00223			Trigger(Self, Other);
00224			Other.bFire = 0;
00225			Other.bAltFire = 0;
00226			return true;
00227		}
00228	
00229		if ( RecommendedTrigger != None )
00230		{
00231			Other.SpecialGoal = RecommendedTrigger;
00232			Other.MoveTarget = RecommendedTrigger;
00233			return True;
00234		}
00235	
00236		bOne = ( (TriggerActor != None) 
00237				&& (!TriggerActor.IsA('Trigger') || Trigger(TriggerActor).IsRelevant(Other)) );
00238		bTwo = ( (TriggerActor2 != None) 
00239				&& (!TriggerActor2.IsA('Trigger') || Trigger(TriggerActor2).IsRelevant(Other)) );
00240		
00241		if ( bOne && bTwo )
00242		{
00243			// Dotp, dist
00244			Dist1 = VSize(TriggerActor.Location - Other.Location);
00245			Dist2 = VSize(TriggerActor2.Location - Other.Location);
00246			if ( Dist1 < Dist2 )
00247			{
00248				if ( (Dist1 < 500) && Other.ActorReachable(TriggerActor) )
00249					bTwo = false;
00250			}
00251			else if ( (Dist2 < 500) && Other.ActorReachable(TriggerActor2) )
00252				bOne = false;
00253			
00254			if ( bOne && bTwo )
00255			{
00256				DP1 = Normal(Location - Other.Location) Dot (TriggerActor.Location - Other.Location)/Dist1;
00257				DP2 = Normal(Location - Other.Location) Dot (TriggerActor2.Location - Other.Location)/Dist2;
00258				if ( (DP1 > 0) && (DP2 < 0) )
00259					bOne = false;
00260				else if ( (DP1 < 0) && (DP2 > 0) )
00261					bTwo = false;
00262				else if ( Dist1 < Dist2 )
00263					bTwo = false;
00264				else 
00265					bOne = false;
00266			}
00267		}
00268	
00269		if ( bOne )
00270		{
00271			Other.SpecialGoal = TriggerActor;
00272			Other.MoveTarget = TriggerActor;
00273			return True;
00274		}
00275		else if ( bTwo )
00276		{
00277			Other.SpecialGoal = TriggerActor2;
00278			Other.MoveTarget = TriggerActor2;
00279			return True;
00280		}
00281		return false;
00282	}
00283	
00284	function Actor SpecialHandling(Pawn Other)
00285	{
00286		if ( bDamageTriggered )	
00287		{
00288			if ( !Other.bCanDoSpecial || (Other.Weapon == None) )
00289				return None;
00290	
00291			Other.Target = self;
00292			Other.bShootSpecial = true;
00293			Other.FireWeapon();
00294			Other.bFire = 0;
00295			Other.bAltFire = 0;
00296			return self;
00297		}
00298	
00299		if ( BumpType == BT_PlayerBump && !Other.bIsPlayer )
00300			return None;
00301	
00302		return self;
00303	}
00304	
00305	//-----------------------------------------------------------------------------
00306	// Movement functions.
00307	
00308	// Interpolate to keyframe KeyNum in Seconds time.
00309	final function InterpolateTo( byte NewKeyNum, float Seconds )
00310	{
00311		NewKeyNum = Clamp( NewKeyNum, 0, ArrayCount(KeyPos)-1 );
00312		if( NewKeyNum==PrevKeyNum && KeyNum!=PrevKeyNum )
00313		{
00314			// Reverse the movement smoothly.
00315			PhysAlpha = 1.0 - PhysAlpha;
00316			OldPos    = BasePos + KeyPos[KeyNum];
00317			OldRot    = BaseRot + KeyRot[KeyNum];
00318		}
00319		else
00320		{
00321			// Start a new movement.
00322			OldPos    = Location;
00323			OldRot    = Rotation;
00324			PhysAlpha = 0.0;
00325		}
00326	
00327		// Setup physics.
00328		SetPhysics(PHYS_MovingBrush);
00329		bInterpolating   = true;
00330		PrevKeyNum       = KeyNum;
00331		KeyNum			 = NewKeyNum;
00332		PhysRate         = 1.0 / FMax(Seconds, 0.005);
00333	
00334		ClientUpdate++;
00335		SimOldPos = OldPos;
00336		SimOldRotYaw = OldRot.Yaw;
00337		SimOldRotPitch = OldRot.Pitch;
00338		SimOldRotRoll = OldRot.Roll;
00339		SimInterpolate.X = 100 * PhysAlpha;
00340		SimInterpolate.Y = 100 * FMax(0.01, PhysRate);
00341		SimInterpolate.Z = 256 * PrevKeyNum + KeyNum;
00342	}
00343	
00344	// Set the specified keyframe.
00345	final function SetKeyframe( byte NewKeyNum, vector NewLocation, rotator NewRotation )
00346	{
00347		KeyNum         = Clamp( NewKeyNum, 0, ArrayCount(KeyPos)-1 );
00348		KeyPos[KeyNum] = NewLocation;
00349		KeyRot[KeyNum] = NewRotation;
00350	}
00351	
00352	// Interpolation ended.
00353	function InterpolateEnd( actor Other )
00354	{
00355		local byte OldKeyNum;
00356	
00357		OldKeyNum  = PrevKeyNum;
00358		PrevKeyNum = KeyNum;
00359		PhysAlpha  = 0;
00360		ClientUpdate--;
00361	
00362		// If more than two keyframes, chain them.
00363		if( KeyNum>0 && KeyNum<OldKeyNum )
00364		{
00365			// Chain to previous.
00366			InterpolateTo(KeyNum-1,MoveTime);
00367		}
00368		else if( KeyNum<NumKeys-1 && KeyNum>OldKeyNum )
00369		{
00370			// Chain to next.
00371			InterpolateTo(KeyNum+1,MoveTime);
00372		}
00373		else
00374		{
00375			// Finished interpolating.
00376			AmbientSound = None;
00377			if ( (ClientUpdate == 0) && (Level.NetMode != NM_Client) )
00378			{
00379				RealPosition = Location;
00380				RealRotation = Rotation;
00381			}
00382		}
00383	}
00384	
00385	//-----------------------------------------------------------------------------
00386	// Mover functions.
00387	
00388	// Notify AI that mover finished movement
00389	function FinishNotify()
00390	{
00391		local Pawn P;
00392	
00393		if ( StandingCount > 0 )
00394			for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00395				if ( P.Base == self )
00396				{
00397					P.StopWaiting();
00398					if ( (P.SpecialGoal == self) || (P.SpecialGoal == myMarker) )
00399						P.SpecialGoal = None; 
00400					if ( P == WaitingPawn )
00401						WaitingPawn = None;
00402				}
00403	
00404		if ( WaitingPawn != None )
00405		{
00406			WaitingPawn.StopWaiting();
00407			if ( (WaitingPawn.SpecialGoal == self) || (WaitingPawn.SpecialGoal == myMarker) )
00408				WaitingPawn.SpecialGoal = None; 
00409			WaitingPawn = None;
00410		}
00411	}
00412	
00413	// Handle when the mover finishes closing.
00414	function FinishedClosing()
00415	{
00416		// Update sound effects.
00417		PlaySound( ClosedSound, SLOT_None );
00418	
00419		// Notify our triggering actor that we have completed.
00420		if( SavedTrigger != None )
00421			SavedTrigger.EndEvent();
00422		SavedTrigger = None;
00423		Instigator = None;
00424		FinishNotify(); 
00425	}
00426	
00427	// Handle when the mover finishes opening.
00428	function FinishedOpening()
00429	{
00430		local actor A;
00431	
00432		// Update sound effects.
00433		PlaySound( OpenedSound, SLOT_None );
00434		
00435		// Trigger any chained movers.
00436		if( Event != '' )
00437			foreach AllActors( class 'Actor', A, Event )
00438				A.Trigger( Self, Instigator );
00439	
00440		FinishNotify();
00441	}
00442	
00443	// Open the mover.
00444	function DoOpen()
00445	{
00446		bOpening = true;
00447		bDelaying = false;
00448		InterpolateTo( 1, MoveTime );
00449		PlaySound( OpeningSound, SLOT_None );
00450		AmbientSound = MoveAmbientSound;
00451	}
00452	
00453	// Close the mover.
00454	function DoClose()
00455	{
00456		local actor A;
00457	
00458		bOpening = false;
00459		bDelaying = false;
00460		InterpolateTo( Max(0,KeyNum-1), MoveTime );
00461		PlaySound( ClosingSound, SLOT_None );
00462		if( Event != '' )
00463			foreach AllActors( class 'Actor', A, Event )
00464				A.UnTrigger( Self, Instigator );
00465		AmbientSound = MoveAmbientSound;
00466	}
00467	
00468	//-----------------------------------------------------------------------------
00469	// Engine notifications.
00470	
00471	// When mover enters gameplay.
00472	simulated function BeginPlay()
00473	{
00474		local rotator R;
00475	
00476		// timer updates real position every second in network play
00477		if ( Level.NetMode != NM_Standalone )
00478		{
00479			if ( Level.NetMode == NM_Client )
00480				settimer(4.0, true);
00481			else
00482				settimer(1.0, true);
00483			if ( Role < ROLE_Authority )
00484				return;
00485		}
00486	
00487		if ( Level.NetMode != NM_Client )
00488		{
00489			RealPosition = Location;
00490			RealRotation = Rotation;
00491		}
00492	
00493		// Init key info.
00494		Super.BeginPlay();
00495		KeyNum         = Clamp( KeyNum, 0, ArrayCount(KeyPos)-1 );
00496		PhysAlpha      = 0.0;
00497	
00498		// Set initial location.
00499		Move( BasePos + KeyPos[KeyNum] - Location );
00500	
00501		// Initial rotation.
00502		SetRotation( BaseRot + KeyRot[KeyNum] );
00503	
00504		// find movers in same group
00505		if ( ReturnGroup == '' )
00506			ReturnGroup = tag;
00507	}
00508	
00509	// Immediately after mover enters gameplay.
00510	function PostBeginPlay()
00511	{
00512		local mover M;
00513	
00514		//brushes can't be deleted, so if not relevant, make it invisible and non-colliding
00515		if ( !Level.Game.IsRelevant(self) )
00516		{
00517			SetCollision(false, false, false);
00518			SetLocation(Location + vect(0,0,20000)); // temp since still in bsp
00519			bHidden = true;
00520		}
00521		else
00522		{
00523			FindTriggerActor();
00524			// Initialize all slaves.
00525			if( !bSlave )
00526			{
00527				foreach AllActors( class 'Mover', M, Tag )
00528				{
00529					if( M.bSlave )
00530					{
00531						M.GotoState('');
00532						M.SetBase( Self );
00533					}
00534				}
00535			}
00536			if ( Leader == None )
00537			{	
00538				Leader = self;
00539				ForEach AllActors( class'Mover', M )
00540					if ( (M != self) && (M.ReturnGroup == ReturnGroup) )
00541					{
00542						M.Leader = self;
00543						M.Follower = Follower;
00544						Follower = M;
00545					}
00546			}
00547		}
00548	}
00549	
00550	function MakeGroupStop()
00551	{
00552		// Stop moving immediately.
00553		bInterpolating = false;
00554		AmbientSound = None;
00555		GotoState( , '' );
00556	
00557		if ( Follower != None )
00558			Follower.MakeGroupStop();
00559	}
00560	
00561	function MakeGroupReturn()
00562	{
00563		// Abort move and reverse course.
00564		bInterpolating = false;
00565		AmbientSound = None;
00566		if( KeyNum<PrevKeyNum )
00567			GotoState( , 'Open' );
00568		else
00569			GotoState( , 'Close' );
00570	
00571		if ( Follower != None )
00572			Follower.MakeGroupReturn();
00573	}
00574			
00575	// Return true to abort, false to continue.
00576	function bool EncroachingOn( actor Other )
00577	{
00578		local Pawn P;
00579		if ( Other.IsA('Carcass') || Other.IsA('Decoration') )
00580		{
00581			Other.TakeDamage(10000, None, Other.Location, vect(0,0,0), 'Crushed');
00582			return false;
00583		}
00584		if ( Other.IsA('Fragment') || (Other.IsA('Inventory') && (Other.Owner == None)) )
00585		{
00586			Other.Destroy();
00587			return false;
00588		}
00589	
00590		// Damage the encroached actor.
00591		if( EncroachDamage != 0 )
00592			Other.TakeDamage( EncroachDamage, Instigator, Other.Location, vect(0,0,0), 'Crushed' );
00593	
00594		// If we have a bump-player event, and Other is a pawn, do the bump thing.
00595		P = Pawn(Other);
00596		if( P!=None && P.bIsPlayer )
00597		{
00598			if ( PlayerBumpEvent!='' )
00599				Bump( Other );
00600			if ( (MyMarker != None) && (P.Base != self) 
00601				&& (P.Location.Z < MyMarker.Location.Z - P.CollisionHeight - 0.7 * MyMarker.CollisionHeight) )
00602				// pawn is under lift - tell him to move
00603				P.UnderLift(self);
00604		}
00605	
00606		// Stop, return, or whatever.
00607		if( MoverEncroachType == ME_StopWhenEncroach )
00608		{
00609			Leader.MakeGroupStop();
00610			return true;
00611		}
00612		else if( MoverEncroachType == ME_ReturnWhenEncroach )
00613		{
00614			Leader.MakeGroupReturn();
00615			if ( Other.IsA('Pawn') )
00616			{
00617				if ( Pawn(Other).bIsPlayer )
00618					Pawn(Other).PlaySound(Pawn(Other).Land, SLOT_Talk);
00619				else
00620					Pawn(Other).PlaySound(Pawn(Other).HitSound1, SLOT_Talk);
00621			}	
00622			return true;
00623		}
00624		else if( MoverEncroachType == ME_CrushWhenEncroach )
00625		{
00626			// Kill it.
00627			Other.KilledBy( Instigator );
00628			return false;
00629		}
00630		else if( MoverEncroachType == ME_IgnoreWhenEncroach )
00631		{
00632			// Ignore it.
00633			return false;
00634		}
00635	}
00636	
00637	// When bumped by player.
00638	function Bump( actor Other )
00639	{
00640		local actor A;
00641		local pawn  P;
00642	
00643		P = Pawn(Other);
00644		if ( (BumpType != BT_AnyBump) && (P == None) )
00645			return;
00646		if ( (BumpType == BT_PlayerBump) && !P.bIsPlayer )
00647			return;
00648		if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
00649			return;
00650		if( BumpEvent!='' )
00651			foreach AllActors( class 'Actor', A, BumpEvent )
00652				A.Trigger( Self, P );
00653	
00654		if ( P != None )
00655		{
00656			if( P.bIsPlayer && (PlayerBumpEvent!='') )
00657					foreach AllActors( class 'Actor', A, PlayerBumpEvent )
00658							A.Trigger( Self, P );
00659	
00660			if ( P.SpecialGoal == self )
00661				P.SpecialGoal = None;
00662		}
00663	}
00664	
00665	// When damaged
00666	function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
00667							Vector momentum, name damageType)
00668	{
00669		if ( bDamageTriggered && (Damage >= DamageThreshold) )
00670			self.Trigger(self, instigatedBy);
00671	}
00672	
00673	//-----------------------------------------------------------------------------
00674	// Trigger states.
00675	
00676	// When triggered, open, wait, then close.
00677	state() TriggerOpenTimed
00678	{
00679		function bool HandleDoor(pawn Other)
00680		{
00681			return HandleTriggerDoor(Other);
00682		}
00683	
00684		function Trigger( actor Other, pawn EventInstigator )
00685		{
00686			SavedTrigger = Other;
00687			Instigator = EventInstigator;
00688			if ( SavedTrigger != None )
00689				SavedTrigger.BeginEvent();
00690			GotoState( 'TriggerOpenTimed', 'Open' );
00691		}
00692	
00693		function BeginState()
00694		{
00695			bOpening = false;
00696		}
00697	
00698	Open:
00699		Disable( 'Trigger' );
00700		if ( DelayTime > 0 )
00701		{
00702			bDelaying = true;
00703			Sleep(DelayTime);
00704		}
00705		DoOpen();
00706		FinishInterpolation();
00707		FinishedOpening();
00708		Sleep( StayOpenTime );
00709		if( bTriggerOnceOnly )
00710			GotoState('');
00711	Close:
00712		DoClose();
00713		FinishInterpolation();
00714		FinishedClosing();
00715		Enable( 'Trigger' );
00716	}
00717	
00718	// Toggle when triggered.
00719	state() TriggerToggle
00720	{
00721		function bool HandleDoor(pawn Other)
00722		{
00723			return HandleTriggerDoor(Other);
00724		}
00725		
00726		function Trigger( actor Other, pawn EventInstigator )
00727		{
00728			SavedTrigger = Other;
00729			Instigator = EventInstigator;
00730			if ( SavedTrigger != None )
00731				SavedTrigger.BeginEvent();
00732			if( KeyNum==0 || KeyNum<PrevKeyNum )
00733				GotoState( 'TriggerToggle', 'Open' );
00734			else
00735				GotoState( 'TriggerToggle', 'Close' );
00736		}
00737	Open:
00738		if ( DelayTime > 0 )
00739		{
00740			bDelaying = true;
00741			Sleep(DelayTime);
00742		}
00743		DoOpen();
00744		FinishInterpolation();
00745		FinishedOpening();
00746		if ( SavedTrigger != None )
00747			SavedTrigger.EndEvent();
00748		Stop;
00749	Close:		
00750		DoClose();
00751		FinishInterpolation();
00752		FinishedClosing();
00753	}
00754	
00755	// Open when triggered, close when get untriggered.
00756	state() TriggerControl
00757	{
00758		function bool HandleDoor(pawn Other)
00759		{
00760			return HandleTriggerDoor(Other);
00761		}
00762	
00763		function Trigger( actor Other, pawn EventInstigator )
00764		{
00765			numTriggerEvents++;
00766			SavedTrigger = Other;
00767			Instigator = EventInstigator;
00768			if ( SavedTrigger != None )
00769				SavedTrigger.BeginEvent();
00770			GotoState( 'TriggerControl', 'Open' );
00771		}
00772		function UnTrigger( actor Other, pawn EventInstigator )
00773		{
00774			numTriggerEvents--;
00775			if ( numTriggerEvents <=0 )
00776			{
00777				numTriggerEvents = 0;
00778				SavedTrigger = Other;
00779				Instigator = EventInstigator;
00780				SavedTrigger.BeginEvent();
00781				GotoState( 'TriggerControl', 'Close' );
00782			}
00783		}
00784	
00785		function BeginState()
00786		{
00787			numTriggerEvents = 0;
00788		}
00789	
00790	Open:
00791		if ( DelayTime > 0 )
00792		{
00793			bDelaying = true;
00794			Sleep(DelayTime);
00795		}
00796		DoOpen();
00797		FinishInterpolation();
00798		FinishedOpening();
00799		SavedTrigger.EndEvent();
00800		if( bTriggerOnceOnly )
00801			GotoState('');
00802		Stop;
00803	Close:		
00804		DoClose();
00805		FinishInterpolation();
00806		FinishedClosing();
00807	}
00808	
00809	// Start pounding when triggered.
00810	state() TriggerPound
00811	{
00812		function bool HandleDoor(pawn Other)
00813		{
00814			return HandleTriggerDoor(Other);
00815		}
00816	
00817		function Trigger( actor Other, pawn EventInstigator )
00818		{
00819			numTriggerEvents++;
00820			SavedTrigger = Other;
00821			Instigator = EventInstigator;
00822			GotoState( 'TriggerPound', 'Open' );
00823		}
00824		function UnTrigger( actor Other, pawn EventInstigator )
00825		{
00826			numTriggerEvents--;
00827			if ( numTriggerEvents <= 0 )
00828			{
00829				numTriggerEvents = 0;
00830				SavedTrigger = None;
00831				Instigator = None;
00832				GotoState( 'TriggerPound', 'Close' );
00833			}
00834		}
00835		function BeginState()
00836		{
00837			numTriggerEvents = 0;
00838		}
00839	
00840	Open:
00841		if ( DelayTime > 0 )
00842		{
00843			bDelaying = true;
00844			Sleep(DelayTime);
00845		}
00846		DoOpen();
00847		FinishInterpolation();
00848		Sleep(OtherTime);
00849	Close:
00850		DoClose();
00851		FinishInterpolation();
00852		Sleep(StayOpenTime);
00853		if( bTriggerOnceOnly )
00854			GotoState('');
00855		if( SavedTrigger != None )
00856			goto 'Open';
00857	}
00858	
00859	//-----------------------------------------------------------------------------
00860	// Bump states.
00861	
00862	// Open when bumped, wait, then close.
00863	state() BumpOpenTimed
00864	{
00865		function bool HandleDoor(pawn Other)
00866		{
00867			if ( (BumpType == BT_PlayerBump) && !Other.bIsPlayer )
00868				return false;
00869	
00870			Bump(Other);
00871			WaitingPawn = Other;
00872			Other.SpecialPause = 2.5;
00873			return true;
00874		}
00875	
00876		function Bump( actor Other )
00877		{
00878			if ( (BumpType != BT_AnyBump) && (Pawn(Other) == None) )
00879				return;
00880			if ( (BumpType == BT_PlayerBump) && !Pawn(Other).bIsPlayer )
00881				return;
00882			if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
00883				return;
00884			Global.Bump( Other );
00885			SavedTrigger = None;
00886			Instigator = Pawn(Other);
00887			GotoState( 'BumpOpenTimed', 'Open' );
00888		}
00889	Open:
00890		Disable( 'Bump' );
00891		if ( DelayTime > 0 )
00892		{
00893			bDelaying = true;
00894			Sleep(DelayTime);
00895		}
00896		DoOpen();
00897		FinishInterpolation();
00898		FinishedOpening();
00899		Sleep( StayOpenTime );
00900		if( bTriggerOnceOnly )
00901			GotoState('');
00902	Close:
00903		DoClose();
00904		FinishInterpolation();
00905		FinishedClosing();
00906		Enable( 'Bump' );
00907	}
00908	
00909	// Open when bumped, close when reset.
00910	state() BumpButton
00911	{
00912		function bool HandleDoor(pawn Other)
00913		{
00914			if ( (BumpType == BT_PlayerBump) && !Other.bIsPlayer )
00915				return false;
00916	
00917			Bump(Other);
00918			return false; //let pawn try to move around this button
00919		}
00920	
00921		function Bump( actor Other )
00922		{
00923			if ( (BumpType != BT_AnyBump) && (Pawn(Other) == None) )
00924				return;
00925			if ( (BumpType == BT_PlayerBump) && !Pawn(Other).bIsPlayer )
00926				return;
00927			if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
00928				return;
00929			Global.Bump( Other );
00930			SavedTrigger = Other;
00931			Instigator = Pawn( Other );
00932			GotoState( 'BumpButton', 'Open' );
00933		}
00934		function BeginEvent()
00935		{
00936			bSlave=true;
00937		}
00938		function EndEvent()
00939		{
00940			bSlave     = false;
00941			Instigator = None;
00942			GotoState( 'BumpButton', 'Close' );
00943		}
00944	Open:
00945		Disable( 'Bump' );
00946		if ( DelayTime > 0 )
00947		{
00948			bDelaying = true;
00949			Sleep(DelayTime);
00950		}
00951		DoOpen();
00952		FinishInterpolation();
00953		FinishedOpening();
00954		if( bTriggerOnceOnly )
00955			GotoState('');
00956		if( bSlave )
00957			Stop;
00958	Close:
00959		DoClose();
00960		FinishInterpolation();
00961		FinishedClosing();
00962		Enable( 'Bump' );
00963	}
00964	
00965	//-----------------------------------------------------------------------------
00966	// Stand states.
00967	
00968	// Open when stood on, wait, then close.
00969	state() StandOpenTimed
00970	{
00971		function bool HandleDoor(pawn Other)
00972		{
00973			if ( bPlayerOnly && !Other.bIsPlayer )
00974				return false;
00975			Other.SpecialPause = 2.5;
00976			WaitingPawn = Other;
00977			if ( Other.Base == self )
00978				Attach(Other);
00979			return true;
00980		}
00981	
00982		function Attach( actor Other )
00983		{
00984			local pawn  P;
00985	
00986			P = Pawn(Other);
00987			if ( (BumpType != BT_AnyBump) && (P == None) )
00988				return;
00989			if ( (BumpType == BT_PlayerBump) && !P.bIsPlayer )
00990				return;
00991			if ( (BumpType == BT_PawnBump) && (Other.Mass < 10) )
00992				return;
00993			SavedTrigger = None;
00994			GotoState( 'StandOpenTimed', 'Open' );
00995		}
00996	Open:
00997		Disable( 'Attach' );
00998		if ( DelayTime > 0 )
00999		{
01000			bDelaying = true;
01001			Sleep(DelayTime);
01002		}
01003		DoOpen();
01004		FinishInterpolation();
01005		FinishedOpening();
01006		Sleep( StayOpenTime );
01007		if( bTriggerOnceOnly )
01008			GotoState('');
01009	Close:
01010		DoClose();
01011		FinishInterpolation();
01012		FinishedClosing();
01013		Enable( 'Attach' );
01014	}
01015	
01016	defaultproperties
01017	{
01018	     MoverEncroachType=ME_ReturnWhenEncroach
01019	     MoverGlideType=MV_GlideByTime
01020	     NumKeys=2
01021	     MoveTime=1.000000
01022	     StayOpenTime=4.000000
01023	     bStatic=False
01024	     bHidden=False
01025	     bIsMover=True
01026	     bAlwaysRelevant=True
01027	     Physics=PHYS_MovingBrush
01028	     RemoteRole=ROLE_SimulatedProxy
01029	     InitialState=BumpOpenTimed
01030	     SoundVolume=228
01031	     TransientSoundVolume=3.000000
01032	     CollisionRadius=160.000000
01033	     CollisionHeight=160.000000
01034	     bCollideActors=True
01035	     bBlockActors=True
01036	     bBlockPlayers=True
01037	     NetPriority=2.700000
01038	}

End Source Code