Engine
Class Polyobj

source: c:\runehov\Engine\Classes\Polyobj.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Brush
         |
         +--Engine.Polyobj
Direct Known Subclasses:RunePolyobj

class Polyobj
extends Engine.Brush

//============================================================================= // Polyobj. //=============================================================================
Variables
 byte BrushRaytraceKey
           Raytrace the brush here.
 int BumpDamage
           Damage to do to an actor when bumped (one-time per bump)
 name BumpEvent
           Optional event to cause when any valid bumper bumps the mover.
 Actor CBase
           The polyobj should be dynamically lit
 float CDelay
           The polyobj should be dynamically lit
 vector CHeightVect
           The polyobj should be dynamically lit
 float CPrevV
           The polyobj should be dynamically lit
 float CPulse
           The polyobj should be dynamically lit
 rotator CRotator
           The polyobj should be dynamically lit
 vector CStartLocation
           The polyobj should be dynamically lit
 float CTimeCounter
           The polyobj should be dynamically lit
 float DamageThreshold
           minimum damage to trigger
 float DelayTime
           delay before starting to open
 enum EPolyObjBumpType
 enum EPolyObjEncroachType
 enum EPolyObjGlideType
 int EncroachDamage
           How much to damage encroached actors.
 name InterpolateEvent[16]
           RUNE: Events to call at each interpolation point
 byte KeyNum
           Current or destination keyframe.
 vector KeyPos[16]
           delay before starting to open
 rotator KeyRot[16]
           delay before starting to open
 float MoveTime[16]
           Time to spend moving between keyframes.
 byte NumKeys
           Number of keyframes in total (0-3).
 int OnMeCount
           For Sinkers
 Pawn OnMeList[4]
           For Sinkers
 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.
 bool SinkResting
           For Sinkers
 float StayOpenTime
           How long to remain open before closing.
 vector ThrustVector
           For PET_ThrustWhenEncroach
 byte WorldRaytraceKey
           Raytrace the world with the brush here.
 bool bCanRender
           Set to true after the poly has been lit and is renderable
 bool bDamageTriggered
           Triggered by taking damage
 bool bDynamicLightMover
           Apply dynamic lighting to mover.
 bool bDynamicLightPolyobj
           The polyobj should be dynamically lit
 bool bInitiallyOn
           used for rotators, smashing,
 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


Function Summary
 void Attach(Actor Other)
 void BeginEvent()
 
simulated
BeginPlay()
     
//-----------------------------------------------------------------------------
// Engine notifications
//-----------------------------------------------------------------------------
// When mover enters gameplay.
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void BeginState()
 void Bump(Actor Other)
 void Bump(Actor Other)
 void Bump(Actor Other)
 void DoClose()
     
// Close the mover.
 void DoOpen()
     
// Open the mover.
 bool EncroachingOn(Actor Other)
     
// Return true to abort, false to continue.
 void EndEvent()
 void Explode(vector Momentum)
     
// Override in destructible child classes to determine matter
 void FindTriggerActor()
 void FinishNotify()
     
// Notify AI that mover finished movement
 void FinishedClosing()
     
// Handle when the mover finishes closing.
 void FinishedOpening()
     
// Handle when the mover finishes opening.
 float GetCollisionRadius()
     
// Used for debris spawn locations and to calculate size of chunks
 Texture GetTexture()
     
// Get approximate collision sphere
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleDoor(Pawn Other)
     
// Open when stood on, wait, then close.
 bool HandleTriggerDoor(Pawn Other)
 void InterpolateEnd(Actor Other)
     
// Interpolation ended.
 void InterpolateTo(byte NewKeyNum, float Seconds)
     
// Interpolate to keyframe KeyNum in Seconds time.
 bool JointDamaged(int Damage, Pawn EventInstigator, vector HitLoc, vector Momentum, name DamageType, int joint)
 bool JointDamaged(int Damage, Pawn EventInstigator, vector HitLoc, vector Momentum, name DamageType, int joint)
 void MakeGroupReturn()
 void MakeGroupStop()
 void MakeOnMeList()
 void PolyobjDestroy()
     
//===================================================================
//
// PolyobjDestroy
//
// Polyobjs aren't actually destroyed: they hidden, made non-blocking 
// and non-thinking.
//
// This function should be called instead of the Destroy();
//===================================================================
 void PostBeginPlay()
     
// Immediately after entering gameplay.
 void SetKeyframe(byte NewKeyNum, vector NewLocation, rotator NewRotation)
     
// Set the specified keyframe.
 Actor SpecialHandling(Pawn Other)
 void Tick(float deltaTime)
 void Tick(float deltaTime)
 void Tick(float deltaTime)
 void Tick(float deltaTime)
 void Tick(float deltaTime)
 
simulated
Timer()
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void Trigger(Actor Other, Pawn EventInstigator)
 void UnTrigger(Actor Other, Pawn EventInstigator)
 void UnTrigger(Actor Other, Pawn EventInstigator)
 void UpdateSinkerZ(float deltaTime)
 bool UseTrigger(Actor Other)



Source Code


00001	//=============================================================================
00002	// Polyobj.
00003	//=============================================================================
00004	class Polyobj expands Brush
00005		native;
00006	//	nativereplication;
00007	
00008	//-----------------------------------------------------------------------------
00009	// Mover Stuff
00010	//-----------------------------------------------------------------------------
00011	
00012	// How to react when it encroaches an actor.
00013	var() enum EPolyObjEncroachType
00014	{
00015		PET_StopWhenEncroach,	// Stop when we hit an actor.
00016		PET_ReturnWhenEncroach,	// Return to previous position when we hit an actor.
00017	   	PET_CrushWhenEncroach,   // Crush the poor helpless actor.
00018	   	PET_IgnoreWhenEncroach,  // Ignore encroached actors.
00019	} PolyObjEncroachType;
00020	
00021	// How to move from one position to another.
00022	var() enum EPolyObjGlideType
00023	{
00024		PGT_MoveByTime,			// Move linearly.
00025		PGT_GlideByTime,			// Move with smooth acceleration.
00026	} PolyObjGlideType;
00027	
00028	// What classes can bump trigger me
00029	var() enum EPolyObjBumpType
00030	{
00031		PBT_PlayerBump,		// Can only be bumped by player.
00032		PBT_PawnBump,		// Can be bumped by any pawn
00033		PBT_CreatureBump,	// Can be bumped by any NON-player pawn
00034		PBT_AnyBump,			// Cany be bumped by any solid actor
00035	} PolyObjBumpType;
00036	
00037	// Keyframe numbers.
00038	var() byte       KeyNum;           // Current or destination keyframe.
00039	var byte         PrevKeyNum;       // Previous keyframe.
00040	var() const byte NumKeys;          // Number of keyframes in total (0-3).
00041	var() const byte WorldRaytraceKey; // Raytrace the world with the brush here.
00042	var() const byte BrushRaytraceKey; // Raytrace the brush here.
00043	
00044	// Movement parameters.
00045	var() float      MoveTime[16];         // Time to spend moving between keyframes.
00046	var() float      StayOpenTime;     // How long to remain open before closing.
00047	var() float      OtherTime;        // TriggerPound stay-open time.
00048	var() int        EncroachDamage;   // How much to damage encroached actors.
00049	var() name		 InterpolateEvent[16];	// RUNE:  Events to call at each interpolation point
00050	var() int		 BumpDamage;		// Damage to do to an actor when bumped (one-time per bump)
00051	
00052	// Mover state.
00053	var() bool       bTriggerOnceOnly; // Go dormant after first trigger.
00054	var() bool       bSlave;           // This brush is a slave.
00055	var() bool		 bUseTriggered;		// Triggered by player grab
00056	var() bool		 bDamageTriggered;	// Triggered by taking damage
00057	var() bool       bDynamicLightMover; // Apply dynamic lighting to mover.
00058	var() name       PlayerBumpEvent;  // Optional event to cause when the player bumps the mover.
00059	var() name       BumpEvent;			// Optional event to cause when any valid bumper bumps the mover.
00060	var   actor      SavedTrigger;      // Who we were triggered by.
00061	var() float		 DamageThreshold;	// minimum damage to trigger
00062	var	  int		 numTriggerEvents;	// number of times triggered ( count down to untrigger )
00063	var	  Polyobj	 Leader;			// for having multiple movers return together
00064	var	  Polyobj	 Follower;
00065	var() name		 ReturnGroup;		// if none, same as tag
00066	var() float		 DelayTime;			// delay before starting to open
00067	
00068	// Audio.
00069	var(Sounds) sound      OpeningSound;     // When start opening.
00070	var(Sounds) sound      OpenedSound;      // When finished opening.
00071	var(Sounds) sound      ClosingSound;     // When start closing.
00072	var(Sounds) sound      ClosedSound;      // When finish closing.
00073	var(Sounds) sound      MoveAmbientSound; // Optional ambient sound when moving.
00074	
00075	// Internal.
00076	var vector       KeyPos[16];
00077	var rotator      KeyRot[16];
00078	var vector       BasePos, OldPos, OldPrePivot, SavedPos;
00079	var rotator      BaseRot, OldRot, SavedRot;
00080	
00081	// AI related
00082	var       NavigationPoint  myMarker;
00083	var		  Actor			TriggerActor;
00084	var		  Actor         TriggerActor2;
00085	var		  Pawn			WaitingPawn;
00086	var		  bool			bOpening, bDelaying, bClientPause;
00087	var		  bool			bPlayerOnly;
00088	var		  Trigger		RecommendedTrigger;
00089	
00090	// for client side replication
00091	var		vector			SimOldPos;
00092	var		int				SimOldRotPitch, SimOldRotYaw, SimOldRotRoll;
00093	var		vector			SimInterpolate;
00094	var		vector			RealPosition;
00095	var     rotator			RealRotation;
00096	var		int				ClientUpdate;
00097	
00098	//-----------------------------------------------------------------------------
00099	// PolyObj stuff
00100	//-----------------------------------------------------------------------------
00101	var const bool bCanRender;			// Set to true after the poly has been lit and is renderable
00102	var() bool bDynamicLightPolyobj;	// The polyobj should be dynamically lit
00103	
00104	var vector	CStartLocation;
00105	var vector	CHeightVect;
00106	var rotator	CRotator;
00107	var float	CTimeCounter;
00108	var float	CPrevV;
00109	var float	CPulse;
00110	var float	CDelay;
00111	var actor	CBase;
00112	
00113	var(PolyObjSpecial) float CCycleTime;
00114	var(PolyObjSpecial) float CPhase;
00115	var(PolyObjSpecial) float CHeight;
00116	var(PolyObjSpecial) float CSize;
00117	var(PolyObjSpecial) float CSpeed;
00118	var(PolyObjSpecial) sound CSound;
00119	var(PolyObjSpecial) bool flag1;
00120	var(PolyObjSpecial) bool flag2;
00121	var(PolyObjSpecial) name CBaseName;
00122	
00123	const CCUTOFF = 0.3;
00124	
00125	var int OnMeCount;							// For Sinkers
00126	var Pawn OnMeList[4];						// For Sinkers
00127	var bool SinkResting;						// For Sinkers
00128	
00129	var() bool bInitiallyOn;		// used for rotators, smashing, 
00130	
00131	var() vector ThrustVector;	// For PET_ThrustWhenEncroach
00132	
00133	var(PolyObjDestroyable) EMatterType matter;			// Used to tell if damaged in lieu of being texture based
00134	var(PolyObjDestroyable) class<Debris> DebrisType;
00135	var(PolyObjDestroyable) bool bDestroyable;			// An alternate way of marking as destroyable (to combine with other states)
00136	var(PolyObjDestroyable) int NumDebrisChunks;
00137	var(PolyObjDestroyable) float DebrisSpawnRadius;	// Used for debris spawn locations and to calculate size of chunks
00138	var(PolyObjDestroyable) Texture DebrisTexture;
00139	
00140	
00141	native(668) final function float GetCollisionRadius();		// Get approximate collision sphere
00142	native(669) final function Texture GetTexture();			// Get one of the textures
00143	
00144	
00145	replication
00146	{
00147		// Things the server should send to the client.
00148		reliable if( Role==ROLE_Authority )
00149			SimOldPos, SimOldRotPitch, SimOldRotYaw, SimOldRotRoll, SimInterpolate, RealPosition, RealRotation;
00150	}
00151	
00152	
00153	
00154	//-----------------------------------------------------------------------------
00155	// Functions
00156	//-----------------------------------------------------------------------------
00157	
00158	// Override in destructible child classes to determine matter
00159	function Explode(vector Momentum)
00160	{
00161		local Debris D;
00162		local Actor A;
00163		local int i,numchunks;
00164		local float scale;
00165		local vector loc;
00166	
00167		// Trigger any events.
00168		FireEvent(Event);
00169	
00170		// DebrisType is specified by LD, for automatic use RunePolyobj
00171	
00172		// Spawn debris
00173		if (DebrisType != None)
00174		{
00175			if (DebrisSpawnRadius == 0)
00176				DebrisSpawnRadius = GetCollisionRadius();
00177	
00178			// Find appropriate size of chunks
00179	//		scale = (CollisionRadius*CollisionRadius*CollisionHeight) / (NumDebrisChunks*500);
00180			scale = (DebrisSpawnRadius*DebrisSpawnRadius*DebrisSpawnRadius) / (NumDebrisChunks*500);
00181			scale = scale ** 0.3333333;
00182			scale = FClamp(scale, 0.2, 5);
00183	
00184			numchunks = NumDebrisChunks*Level.Game.DebrisPercentage;
00185			for (i=0; i<numchunks; i++)
00186			{
00187				loc = Location;
00188				loc.X += (FRand()*2-1)*DebrisSpawnRadius;
00189				loc.Y += (FRand()*2-1)*DebrisSpawnRadius;
00190				loc.Z += (FRand()*2-1)*DebrisSpawnRadius;
00191				D = Spawn(DebrisType,,,loc);
00192				if (D != None)
00193				{
00194					D.SetSize(scale);
00195					if (DebrisTexture==None)
00196						D.SetTexture(GetTexture());
00197					else
00198						D.SetTexture(DebrisTexture);
00199					D.SetMomentum(Momentum);
00200				}
00201			}
00202		}
00203	}
00204	
00205	
00206	function FindTriggerActor()
00207	{
00208		local Actor A;
00209	
00210		TriggerActor = None;
00211		TriggerActor2 = None;
00212		ForEach AllActors(class 'Actor', A)
00213			if ( (A.Event == Tag) && (A.IsA('Trigger') || A.IsA('Polyobj')) )
00214			{
00215				if ( A.IsA('Counter') || A.IsA('Pawn') )
00216				{
00217					bPlayerOnly = true;
00218					return; //FIXME - handle counters
00219				}
00220				if (TriggerActor == None)
00221					TriggerActor = A;
00222				else if ( TriggerActor2 == None )
00223					TriggerActor2 = A;
00224			}
00225	
00226		if ( TriggerActor == None )
00227		{
00228			bPlayerOnly = (PolyObjBumpType == PBT_PlayerBump);
00229			return;
00230		}
00231	
00232		bPlayerOnly = ( TriggerActor.IsA('Trigger') && (Trigger(TriggerActor).TriggerType == TT_PlayerProximity) );
00233		if ( bPlayerOnly && ( TriggerActor2 != None) )
00234		{
00235			bPlayerOnly = ( TriggerActor2.IsA('Trigger') && (Trigger(TriggerActor).TriggerType == TT_PlayerProximity) );
00236			if ( !bPlayerOnly )
00237			{
00238				A = TriggerActor;
00239				TriggerActor = TriggerActor2;
00240				TriggerActor2 = A;
00241			}
00242		}
00243	}
00244	
00245	// set specialgoal/movetarget or special pause if necessary
00246	// if mover can't be affected by this pawn, return false
00247	// Each mover state should implement the appropriate version
00248	function bool HandleDoor(pawn Other)
00249	{
00250		return false;
00251	}
00252	
00253	function bool HandleTriggerDoor(pawn Other)
00254	{
00255		local bool bOne, bTwo;
00256		local float DP1, DP2, Dist1, Dist2;
00257	
00258		if ( bOpening || bDelaying )
00259		{
00260			WaitingPawn = Other;
00261			Other.SpecialPause = 2.5;
00262			return true;
00263		}
00264		if ( bPlayerOnly && !Other.bIsPlayer )
00265			return false;
00266		if ( bUseTriggered )
00267		{
00268			WaitingPawn = Other;
00269			Other.SpecialPause = 2.5;
00270			Trigger(Other, Other);
00271			return true;
00272		}
00273		if ( (BumpEvent == tag) || (Other.bIsPlayer && (PlayerBumpEvent == tag)) )
00274		{
00275			WaitingPawn = Other;
00276			Other.SpecialPause = 2.5;
00277			if ( Other.Base == Self )
00278				Trigger(Other, Other);
00279			return true;
00280		}
00281		if ( bDamageTriggered )
00282		{
00283			WaitingPawn = Other;
00284			Other.SpecialGoal = self;
00285			if ( !Other.bCanDoSpecial || (Other.Weapon == None) )
00286				return false;
00287	
00288			Other.Target = self;
00289			Other.bShootSpecial = true;
00290			Trigger(Self, Other);
00291			Other.bFire = 0;
00292			Other.bAltFire = 0;
00293			return true;
00294		}
00295	
00296		if ( RecommendedTrigger != None )
00297		{
00298			Other.SpecialGoal = RecommendedTrigger;
00299			Other.MoveTarget = RecommendedTrigger;
00300			return True;
00301		}
00302	
00303		bOne = ( (TriggerActor != None) 
00304				&& (!TriggerActor.IsA('Trigger') || Trigger(TriggerActor).IsRelevant(Other)) );
00305		bTwo = ( (TriggerActor2 != None) 
00306				&& (!TriggerActor2.IsA('Trigger') || Trigger(TriggerActor2).IsRelevant(Other)) );
00307		
00308		if ( bOne && bTwo )
00309		{
00310			// Dotp, dist
00311			Dist1 = VSize(TriggerActor.Location - Other.Location);
00312			Dist2 = VSize(TriggerActor2.Location - Other.Location);
00313			if ( Dist1 < Dist2 )
00314			{
00315				if ( (Dist1 < 500) && Other.ActorReachable(TriggerActor) )
00316					bTwo = false;
00317			}
00318			else if ( (Dist2 < 500) && Other.ActorReachable(TriggerActor2) )
00319				bOne = false;
00320			
00321			if ( bOne && bTwo )
00322			{
00323				DP1 = Normal(Location - Other.Location) Dot (TriggerActor.Location - Other.Location)/Dist1;
00324				DP2 = Normal(Location - Other.Location) Dot (TriggerActor2.Location - Other.Location)/Dist2;
00325				if ( (DP1 > 0) && (DP2 < 0) )
00326					bOne = false;
00327				else if ( (DP1 < 0) && (DP2 > 0) )
00328					bTwo = false;
00329				else if ( Dist1 < Dist2 )
00330					bTwo = false;
00331				else 
00332					bOne = false;
00333			}
00334		}
00335	
00336		if ( bOne )
00337		{
00338			Other.SpecialGoal = TriggerActor;
00339			Other.MoveTarget = TriggerActor;
00340			return True;
00341		}
00342		else if ( bTwo )
00343		{
00344			Other.SpecialGoal = TriggerActor2;
00345			Other.MoveTarget = TriggerActor2;
00346			return True;
00347		}
00348		return false;
00349	}
00350	
00351	function Actor SpecialHandling(Pawn Other)
00352	{
00353		if ( bDamageTriggered )	
00354		{
00355			if ( !Other.bCanDoSpecial || (Other.Weapon == None) )
00356				return None;
00357	
00358			Other.Target = self;
00359			Other.bShootSpecial = true;
00360	//		Other.FireWeapon();
00361			Other.bFire = 0;
00362			Other.bAltFire = 0;
00363			return self;
00364		}
00365	
00366		if ( PolyObjBumpType == PBT_PlayerBump && !Other.bIsPlayer )
00367			return None;
00368	
00369		return self;
00370	}
00371	
00372	//-----------------------------------------------------------------------------
00373	// Movement functions.
00374	//-----------------------------------------------------------------------------
00375	
00376	// Interpolate to keyframe KeyNum in Seconds time.
00377	final function InterpolateTo( byte NewKeyNum, float Seconds )
00378	{
00379		local Actor A;
00380	
00381		NewKeyNum = Clamp( NewKeyNum, 0, ArrayCount(KeyPos)-1 );
00382		if( NewKeyNum==PrevKeyNum && KeyNum!=PrevKeyNum )
00383		{
00384			// Reverse the movement smoothly.
00385			PhysAlpha = 1.0 - PhysAlpha;
00386			OldPos    = BasePos + KeyPos[KeyNum];
00387			OldRot    = BaseRot + KeyRot[KeyNum];
00388		}
00389		else
00390		{
00391			// Start a new movement.
00392			OldPos    = Location;
00393			OldRot    = Rotation;
00394			PhysAlpha = 0.0;
00395		}
00396	
00397		// Setup physics.
00398		SetPhysics(PHYS_MovingBrush);
00399		bInterpolating   = true;
00400		PrevKeyNum       = KeyNum;
00401		KeyNum			 = NewKeyNum;
00402		PhysRate         = 1.0 / FMax(Seconds, 0.005);
00403	
00404		ClientUpdate++;
00405		SimOldPos = OldPos;
00406		SimOldRotYaw = OldRot.Yaw;
00407		SimOldRotPitch = OldRot.Pitch;
00408		SimOldRotRoll = OldRot.Roll;
00409		SimInterpolate.X = 100 * PhysAlpha;
00410		SimInterpolate.Y = 100 * FMax(0.01, PhysRate);
00411		SimInterpolate.Z = 256 * PrevKeyNum + KeyNum;
00412		
00413		// Call events at each interpolation point	
00414		if(InterpolateEvent[PrevKeyNum] != 'None')
00415		{ // Call the event on this interpolation point
00416			foreach AllActors(class 'Actor', A, InterpolateEvent[PrevKeyNum])
00417			{
00418				A.Trigger(self, None);
00419			}
00420		}
00421	}
00422	
00423	// Set the specified keyframe.
00424	final function SetKeyframe( byte NewKeyNum, vector NewLocation, rotator NewRotation )
00425	{
00426		KeyNum         = Clamp( NewKeyNum, 0, ArrayCount(KeyPos)-1 );
00427		KeyPos[KeyNum] = NewLocation;
00428		KeyRot[KeyNum] = NewRotation;
00429	}
00430	
00431	// Interpolation ended.
00432	function InterpolateEnd( actor Other )
00433	{
00434		local byte OldKeyNum;
00435		local Actor A;
00436	
00437		OldKeyNum  = PrevKeyNum;
00438		PrevKeyNum = KeyNum;
00439		PhysAlpha  = 0;
00440		ClientUpdate--;
00441	
00442		// If more than two keyframes, chain them.
00443		if( KeyNum>0 && KeyNum<OldKeyNum )
00444		{
00445			// Chain to previous.
00446			InterpolateTo(KeyNum-1,MoveTime[KeyNum-1]);
00447		}
00448		else if( KeyNum<NumKeys-1 && KeyNum>OldKeyNum )
00449		{
00450			// Chain to next.
00451			InterpolateTo(KeyNum+1,MoveTime[KeyNum]);
00452		}
00453		else
00454		{
00455			// Call events at each interpolation point (end point)
00456			if(InterpolateEvent[PrevKeyNum] != 'None')
00457			{ // Call the event on this interpolation point
00458				foreach AllActors(class 'Actor', A, InterpolateEvent[PrevKeyNum])
00459				{
00460					A.Trigger(self, None);
00461				}
00462			}
00463	
00464			// Finished interpolating.
00465			AmbientSound = None;
00466			if ( (ClientUpdate == 0) && (Level.NetMode != NM_Client) )
00467			{
00468				RealPosition = Location;
00469				RealRotation = Rotation;
00470			}
00471		}
00472	}
00473	
00474	//-----------------------------------------------------------------------------
00475	// Mover functions.
00476	//-----------------------------------------------------------------------------
00477	
00478	// Notify AI that mover finished movement
00479	function FinishNotify()
00480	{
00481		local Pawn P;
00482	
00483		if ( StandingCount > 0 )
00484			for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00485				if ( P.Base == self )
00486				{
00487					P.StopWaiting();
00488					if ( (P.SpecialGoal == self) || (P.SpecialGoal == myMarker) )
00489						P.SpecialGoal = None; 
00490					if ( P == WaitingPawn )
00491						WaitingPawn = None;
00492				}
00493	
00494		if ( WaitingPawn != None )
00495		{
00496			WaitingPawn.StopWaiting();
00497			if ( (WaitingPawn.SpecialGoal == self) || (WaitingPawn.SpecialGoal == myMarker) )
00498				WaitingPawn.SpecialGoal = None; 
00499			WaitingPawn = None;
00500		}
00501	}
00502	
00503	// Handle when the mover finishes closing.
00504	function FinishedClosing()
00505	{
00506		// Update sound effects.
00507		PlaySound( ClosedSound, SLOT_None );
00508	
00509		// Notify our triggering actor that we have completed.
00510		if( SavedTrigger != None )
00511			SavedTrigger.EndEvent();
00512		SavedTrigger = None;
00513		Instigator = None;
00514		FinishNotify(); 
00515	}
00516	
00517	// Handle when the mover finishes opening.
00518	function FinishedOpening()
00519	{
00520		local actor A;
00521	
00522		// Update sound effects.
00523		PlaySound( OpenedSound, SLOT_None );
00524		
00525		// Trigger any chained movers.
00526	//	FireEvent(Event);
00527	
00528		if(ThrustVector != vect(0, 0, 0))
00529		{
00530			foreach AllActors(class'Actor', A)
00531				if(A.Base == self)
00532					A.AddVelocity(ThrustVector);
00533		}
00534	
00535		FinishNotify();
00536	
00537	}
00538	
00539	// Open the mover.
00540	function DoOpen()
00541	{
00542		bOpening = true;
00543		bDelaying = false;
00544		
00545		InterpolateTo( 1, MoveTime[0] );	
00546		PlaySound( OpeningSound, SLOT_None );
00547		AmbientSound = MoveAmbientSound;
00548	}
00549	
00550	// Close the mover.
00551	function DoClose()
00552	{
00553		local actor A;
00554	
00555		bOpening = false;
00556		bDelaying = false;
00557		InterpolateTo( Max(0,KeyNum-1), MoveTime[Max(0, KeyNum-1)]);
00558		PlaySound( ClosingSound, SLOT_None );
00559	//	FireEvent(Event);
00560		AmbientSound = MoveAmbientSound;
00561	}
00562	
00563	//===================================================================
00564	//
00565	// PolyobjDestroy
00566	//
00567	// Polyobjs aren't actually destroyed: they hidden, made non-blocking 
00568	// and non-thinking.
00569	//
00570	// This function should be called instead of the Destroy();
00571	//===================================================================
00572	
00573	function PolyobjDestroy()
00574	{
00575		local actor A;
00576	
00577		bHidden = true;
00578		bSweepable = false;
00579		SetCollision(false, false, false);
00580		Disable('Tick');
00581		SetTimer(0.0, false);
00582	
00583		if(StandingCount > 0)
00584		{
00585			foreach AllActors(class'Actor', A)
00586				if(A.Base == self)
00587				{
00588					A.SetBase(None);
00589				}
00590		}
00591	
00592		GotoState('');
00593	}
00594	
00595	//-----------------------------------------------------------------------------
00596	// Engine notifications
00597	//-----------------------------------------------------------------------------
00598	// When mover enters gameplay.
00599	simulated function BeginPlay()
00600	{
00601		local rotator R;
00602	
00603		Enable('Tick');
00604	
00605		// timer updates real position every second in network play
00606		if ( Level.NetMode != NM_Standalone )
00607		{
00608			if ( Level.NetMode == NM_Client )
00609				settimer(4.0, true);
00610			else
00611				settimer(1.0, true);
00612			if ( Role < ROLE_Authority )
00613				return;
00614		}
00615	
00616		if ( Level.NetMode != NM_Client )
00617		{
00618			RealPosition = Location;
00619			RealRotation = Rotation;
00620		}
00621	
00622		// Init key info.
00623		Super.BeginPlay();
00624		KeyNum         = Clamp( KeyNum, 0, ArrayCount(KeyPos)-1 );
00625		PhysAlpha      = 0.0;
00626	
00627		// Set initial location.
00628		Move( BasePos + KeyPos[KeyNum] - Location );
00629	
00630		// Initial rotation.
00631		SetRotation( BaseRot + KeyRot[KeyNum] );
00632	
00633		// find movers in same group
00634		if ( ReturnGroup == '' )
00635			ReturnGroup = tag;
00636	}
00637	
00638	// Immediately after entering gameplay.
00639	function PostBeginPlay()
00640	{
00641		local polyobj M;
00642	
00643		//brushes can't be deleted, so if not relevant, make it invisible and non-colliding
00644		if ( !Level.Game.IsRelevant(self) )
00645		{
00646			SetCollision(false, false, false);
00647			SetLocation(Location + vect(0,0,20000)); // temp since still in bsp
00648			bHidden = true;
00649		}
00650		else
00651		{
00652			FindTriggerActor();
00653			// Initialize all slaves.
00654			if( !bSlave )
00655			{
00656				foreach AllActors( class 'Polyobj', M, Tag )
00657				{
00658					if( M.bSlave )
00659					{
00660						M.GotoState('');
00661						M.SetBase( Self );
00662					}
00663				}
00664			}
00665			if ( Leader == None )
00666			{	
00667				Leader = self;
00668				ForEach AllActors( class'Polyobj', M )
00669					if ( (M != self) && (M.ReturnGroup == ReturnGroup) )
00670					{
00671						M.Leader = self;
00672						M.Follower = Follower;
00673						Follower = M;
00674					}
00675			}
00676		}
00677	}
00678	
00679	simulated function Timer()
00680	{
00681		if ( Velocity != vect(0,0,0) )
00682		{
00683			bClientPause = false;
00684			return;		
00685		}
00686		if ( Level.NetMode == NM_Client )
00687		{
00688			if ( ClientUpdate == 0 ) // not doing a move
00689			{
00690				if ( bClientPause )
00691				{
00692					if ( VSize(RealPosition - Location) > 3 )
00693						SetLocation(RealPosition);
00694					else
00695						RealPosition = Location;
00696					SetRotation(RealRotation);
00697					bClientPause = false;
00698				}
00699				else if ( RealPosition != Location )
00700					bClientPause = true;
00701			}
00702			else
00703				bClientPause = false;
00704		}
00705		else
00706		{
00707			RealPosition = Location;
00708			RealRotation = Rotation;
00709		}
00710	}
00711	
00712	function MakeGroupStop()
00713	{
00714		// Stop moving immediately.
00715		bInterpolating = false;
00716		AmbientSound = None;
00717		GotoState( , '' );
00718	
00719		if ( Follower != None )
00720			Follower.MakeGroupStop();
00721	}
00722	
00723	function MakeGroupReturn()
00724	{
00725		// Abort move and reverse course.
00726		bInterpolating = false;
00727		AmbientSound = None;
00728		if( KeyNum<PrevKeyNum )
00729			GotoState( , 'Open' );
00730		else
00731			GotoState( , 'Close' );
00732	
00733		if ( Follower != None )
00734			Follower.MakeGroupReturn();
00735	}
00736			
00737	// Return true to abort, false to continue.
00738	function bool EncroachingOn( actor Other )
00739	{
00740		local Pawn P;
00741		if ( Other.IsA('Carcass') || Other.IsA('Decoration') )
00742		{
00743			Other.JointDamaged(10000, Instigator, Other.Location, vect(0,0,0), 'Crushed', 0);
00744			return false;
00745		}
00746		if ( Other.IsA('Fragment') || (Other.IsA('Inventory') && (Other.Owner == None)) )
00747		{
00748			Other.Destroy();
00749			return false;
00750		}
00751	
00752		// Damage the encroached actor.
00753		if( EncroachDamage != 0 )
00754		{
00755			Other.JointDamaged( EncroachDamage, Instigator, Other.Location, vect(0,0,0), 'Crushed', 0);
00756		}
00757	
00758		// If we have a bump-player event, and Other is a pawn, do the bump thing.
00759		P = Pawn(Other);
00760		if( P!=None && P.bIsPlayer)
00761		{
00762			if ( PlayerBumpEvent!='' )
00763				Bump( Other );
00764			/*
00765			if ( (MyMarker != None) && (P.Base != self) 
00766				&& (P.Location.Z < MyMarker.Location.Z - P.CollisionHeight - 0.7 * MyMarker.CollisionHeight) )
00767				// pawn is under lift - tell him to move
00768			{
00769				P.UnderLift(self);
00770			}
00771			*/
00772		}
00773	
00774		// Stop, return, or whatever.
00775		if( PolyObjEncroachType == PET_StopWhenEncroach )
00776		{
00777			Leader.MakeGroupStop();
00778			return true;
00779		}
00780		else if( PolyObjEncroachType == PET_ReturnWhenEncroach )
00781		{
00782			Leader.MakeGroupReturn();
00783			return true;
00784		}
00785		else if( PolyObjEncroachType == PET_CrushWhenEncroach )
00786		{
00787			// Kill it.
00788			Other.KilledBy( Instigator );
00789			return false;
00790		}
00791		else if( PolyObjEncroachType == PET_IgnoreWhenEncroach )
00792		{
00793			// Ignore it.
00794			return false;
00795		}
00796	}
00797	
00798	// When bumped by player.
00799	function Bump( actor Other )
00800	{
00801		local actor A;
00802		local pawn  P;
00803	
00804		// Apply bump damage (if applicable)
00805		if(BumpDamage > 0)
00806		{
00807			Other.JointDamaged(BumpDamage, Other.Instigator, Other.Location, vect(0, 0, 0), 'blunt', 0);
00808		}
00809	
00810		P = Pawn(Other);
00811		if ( (PolyObjBumpType != PBT_AnyBump) && (P == None) )
00812			return;
00813		if ( (PolyObjBumpType == PBT_PlayerBump) && !P.bIsPlayer )
00814			return;
00815		if ( (PolyObjBumpType == PBT_PawnBump) && (Other.Mass < 10) )
00816			return;
00817		if((PolyObjBumpType == PBT_CreatureBump) && (Other.Mass < 10 || P.bIsPlayer))
00818			return; // RUNE:  Non-player pawn bump
00819	
00820		if( BumpEvent!='' )
00821			foreach AllActors( class 'Actor', A, BumpEvent )
00822				A.Trigger( Self, P );
00823	
00824		if ( P != None )
00825		{
00826			if( P.bIsPlayer && (PlayerBumpEvent!='') )
00827					foreach AllActors( class 'Actor', A, PlayerBumpEvent )
00828							A.Trigger( Self, P );
00829	
00830			if ( P.SpecialGoal == self )
00831				P.SpecialGoal = None;
00832		}
00833	}
00834	
00835	function bool UseTrigger(Actor Other)
00836	{
00837		if ( bUseTriggered )
00838		{
00839			self.Trigger(self, Pawn(Other));
00840			return true;
00841		}
00842		return false;
00843	}
00844	
00845	function bool JointDamaged(int Damage, Pawn EventInstigator, vector HitLoc, vector Momentum, name DamageType, int joint)
00846	{
00847		local bool bDamage;
00848	
00849		if ( bDamageTriggered && (Damage >= DamageThreshold) )
00850			self.Trigger(self, EventInstigator);
00851	
00852		if ( bDestroyable )
00853		{
00854			DamageThreshold -= Damage;
00855			if (DamageThreshold <= 0)
00856			{
00857				Explode(Momentum);
00858				PolyobjDestroy();
00859			}
00860	
00861	/* Commented out so that all weapons will cause damage to all breakable objects -- cjr
00862			switch(DamageType)
00863			{
00864				case 'sever':		// Sword
00865					bDamage = (matter==MATTER_FLESH);
00866					break;
00867				case 'bluntsever':	// Axe
00868					bDamage = (matter==MATTER_FLESH || matter==MATTER_WOOD);
00869					break;
00870				case 'blunt':		// Hammer
00871					bDamage = (matter==MATTER_FLESH || matter==MATTER_WOOD || matter==MATTER_STONE);
00872					break;
00873				default:
00874					bDamage = false;
00875					break;
00876			}
00877	
00878			if (bDamage)
00879			{
00880				DamageThreshold -= Damage;
00881				if (DamageThreshold <= 0)
00882				{
00883					Explode(Momentum);
00884					PolyobjDestroy();
00885				}
00886			}
00887	*/
00888		}
00889	
00890		return false;
00891	}
00892	
00893	
00894	
00895	//-----------------------------------------------------------------------------
00896	// States
00897	//-----------------------------------------------------------------------------
00898	state() Rotating
00899	{
00900		function BeginState()
00901		{
00902			if (!bInitiallyOn)
00903				bFixedRotationDir=False;
00904		}
00905	
00906		function Trigger( Actor other, Pawn EventInstigator )
00907		{
00908			if (bInitiallyOn)
00909			{
00910				PlaySound( OpenedSound, SLOT_None );
00911				bFixedRotationDir=False;
00912				bInitiallyOn = false;
00913			}
00914			else
00915			{
00916				PlaySound( OpeningSound, SLOT_None );
00917				AmbientSound = MoveAmbientSound;
00918				bFixedRotationDir=True;
00919				bInitiallyOn = true;
00920			}
00921		}
00922	Open:
00923	Close:
00924	}
00925	
00926	
00927	state() Prop
00928	{
00929		function BeginState()
00930		{
00931			if (!bInitiallyOn)
00932				Disable('Tick');
00933	
00934			foreach AllActors( class 'Actor', Target, CBaseName )
00935				CBase = Target;
00936			CRotator = Rotation;
00937			if(CSpeed < 0.01)
00938				CSpeed = 1.0;
00939		}
00940	
00941		function Tick(float deltaTime)
00942		{
00943			CRotator.roll += DeltaTime * 20000 * CSpeed;
00944			SetLocation(CBase.Location);
00945			SetRotation(CRotator + CBase.Rotation);
00946		}
00947	
00948		function Trigger( Actor other, Pawn EventInstigator )
00949		{
00950			if (bInitiallyOn)
00951			{
00952				Disable('Tick');
00953				bInitiallyOn = false;
00954			}
00955			else
00956			{
00957				Enable('Tick');
00958				bInitiallyOn = true;
00959			}
00960		}
00961	}
00962	
00963	state() Smashing
00964	{
00965		function BeginState()
00966		{
00967			if (!bInitiallyOn)
00968				Disable('Tick');
00969	
00970			CStartLocation = Location;
00971			CStartLocation.z -= CCUTOFF * CHeight;
00972			CTimeCounter = CPhase;
00973			CCycleTime = 2 * Pi / CCycleTime;
00974			CHeightVect = Vect( 0, 0, 0 );
00975			CHeightVect.z = CHeight;
00976			CPrevV = 0;
00977			if(CSpeed < 0.01)
00978				CSpeed = 1.0;
00979		}
00980	
00981		function Trigger( Actor other, Pawn EventInstigator )
00982		{
00983			if (bInitiallyOn)
00984			{
00985				Disable('Tick');
00986				bInitiallyOn = false;
00987			}
00988			else
00989			{
00990				Enable('Tick');
00991				bInitiallyOn = true;
00992			}
00993		}
00994	
00995		function Tick( float DeltaTime )
00996		{
00997			local float v, v2;
00998			local vector PosVect;
00999	
01000			if(CDelay > 0.01)
01001			{
01002				CDelay -= DeltaTime;
01003				return;
01004			}
01005			CTimeCounter += DeltaTime;
01006			v = ( 1.0 + sin( CTimeCounter * CCycleTime ) ) / 2.0;
01007			v2 = v;
01008			if( v < CCUTOFF )
01009			{
01010				if( CPrevV >= CCUTOFF )
01011				{
01012					if( Event != '' )
01013					{
01014						foreach AllActors( class 'Actor', Target, Event )
01015							Target.Trigger( Self, None );
01016					}
01017					if( CSound != None )
01018					{
01019						PlaySound( CSound );
01020					}
01021				}
01022				v2 = CCUTOFF + ( CCUTOFF - v ) * 0.04;
01023			}
01024			else if ( CPrevV < CCUTOFF )
01025			{
01026				CDelay = CSpeed;
01027				CPrevV = CCUTOFF;
01028				return;
01029			}
01030			PosVect = CHeightVect * v2;
01031			CPrevV = v;
01032			SetLocation( CStartLocation + PosVect );
01033		}
01034	}
01035	
01036	state() Shaking
01037	{
01038		function BeginState()
01039		{
01040			if (!bInitiallyOn)
01041				Disable('Tick');
01042	
01043			CRotator = Rotation;
01044			CTimeCounter = CPhase;
01045			CPulse = 0.0;
01046			if(CCycleTime < 0.01)
01047				CCycleTime = 1.0;
01048			if(CSpeed < 0.01)
01049				CSpeed = 1.0;
01050			if(CSize < 0.01)
01051				CSize = 1.0;
01052		}
01053	
01054		function Trigger( Actor other, Pawn EventInstigator )
01055		{
01056			if (bInitiallyOn)
01057			{
01058				Disable('Tick');
01059				bInitiallyOn = false;
01060			}
01061			else
01062			{
01063				Enable('Tick');
01064				bInitiallyOn = true;
01065			}
01066			CPulse = CCycleTime;
01067		}
01068	
01069		function Tick(float deltaTime)
01070		{
01071			local float wScale;
01072			local rotator tRot;
01073	
01074			CPulse -= deltaTime;
01075			if(CPulse < 0.001)
01076			{
01077				SetRotation(CRotator);
01078				return;
01079			}
01080	
01081			wScale = CPulse/CCycleTime;
01082	
01083			CTimeCounter += deltaTime * (1.5-wScale);
01084	
01085			tRot.pitch = sin(CTimeCounter*19*CSpeed) * 900 * wScale *CSize;
01086			tRot.roll = sin(CTimeCounter*17*CSpeed) * 900 * wScale *CSize;
01087			tRot.yaw = 0.0;
01088			SetRotation(CRotator + tRot);
01089		}
01090	}
01091	
01092	state() Wobbling
01093	{
01094		function BeginState()
01095		{
01096			if (!bInitiallyOn)
01097				Disable('Tick');
01098			if(CSize < 0.01)
01099				CSize = 1.0;
01100			CTimeCounter = CPhase;
01101			CStartLocation = Location;
01102			CRotator = Rotation;
01103			CRotator.pitch = CPhase;
01104			CRotator.yaw = CPhase;
01105			CRotator.roll = CPhase;
01106		}
01107	
01108		function Trigger( Actor other, Pawn EventInstigator )
01109		{
01110			if (bInitiallyOn)
01111			{
01112				Disable('Tick');
01113				bInitiallyOn = false;
01114			}
01115			else
01116			{
01117				Enable('Tick');
01118				bInitiallyOn = true;
01119			}
01120		}
01121	
01122		function Tick(float deltaTime)
01123		{
01124			local vector wob;
01125			local float wScale;
01126	
01127			CTimeCounter += deltaTime;
01128	
01129			wob.x = sin( CTimeCounter * 2.0 );
01130			wob.y = sin( CTimeCounter * 3.0 );
01131			wob.z = sin( CTimeCounter * 4.0 );
01132			SetLocation( CStartLocation + (wob*70*CSize) );
01133	
01134			if(flag1)
01135				wScale = 1.6 + sin(CTimeCounter*2.5)*0.7;
01136			else
01137				wScale = 0.6;
01138			CRotator.pitch += deltaTime * 15000 * wScale;
01139			CRotator.yaw += deltaTime * 10000 * wScale;
01140			CRotator.roll += deltaTime * 18000 * wScale;
01141			SetRotation(CRotator);
01142		}
01143	}
01144	
01145	state() Splining
01146	{
01147		function BeginState()
01148		{
01149			Disable('Tick');
01150			CTimeCounter = 0;
01151			if(CSize < 0.1)
01152				CSize = 1.0;
01153		}
01154	
01155		function Trigger(actor other, pawn eventInstigator)
01156		{
01157			local InterpolationPoint i;
01158	
01159			foreach AllActors(class 'InterpolationPoint', i, Event)
01160			{
01161				if(i.Position == 0)
01162				{ // Found a matching path
01163					//SetCollision(true, false, false);
01164					//bCollideWorld = False;
01165					Target = i;
01166					SetPhysics(PHYS_Interpolating);
01167					PhysRate = 1.0;
01168					PhysAlpha = 0.0;
01169					bInterpolating = true;
01170					//Enable('Tick');
01171					return;
01172				}
01173			}
01174		}
01175	
01176		function Tick(float deltaTime)
01177		{
01178		}
01179	}
01180	
01181	state() Sinker
01182	{
01183		function BeginState()
01184		{
01185			OnMeCount = 0;
01186			CStartLocation = Location;
01187			CTimeCounter = FRand()*100;
01188			SinkResting = true;
01189		}
01190	
01191		function MakeOnMeList()
01192		{
01193			local int i, j;
01194			local Pawn p;
01195	
01196			OnMeCount = 0;
01197			for(i = 0; i < StandingCount; i++)
01198			{
01199				foreach RadiusActors(class'Pawn', p, 150)
01200				{
01201					if(p.Base == self)
01202					{
01203						//for(j = 0; j < OnMeCount; j++)
01204						//	if(p.Name == OnMeList[j].Name)
01205						//		continue;
01206						OnMeList[OnMeCount] = p;
01207						OnMeCount++;
01208					}
01209				}
01210				if(OnMeCount == 4)
01211					break;
01212			}
01213	
01214			//slog("OnMe Actors: " $ OnMeCount);
01215			//for(i = 0; i < OnMeCount; i++)
01216			//{
01217			//	slog("  name: " $ OnMeList[i].Name);
01218			//}
01219	
01220			if(OnMeCount == 0)
01221			{
01222				DesiredRotation = Rot(0,0,0);
01223				RotationRate = Rot(1000,1000,1000);
01224			}
01225		}
01226	
01227		event Attach(actor other)
01228		{
01229			MakeOnMeList();
01230		}
01231	
01232		event Detach(actor other)
01233		{
01234			MakeOnMeList();
01235		}
01236	
01237		event Tick(float deltaTime)
01238		{
01239			local vector pos;
01240			local vector onMe;
01241			local float xdiff, ydiff;
01242			local rotator dRot, tRot;
01243			local float wScale;
01244	
01245			CTimeCounter += deltaTime;
01246			if(OnMeCount > 0)
01247			{
01248				pos = vect(0,0,0);
01249				pos.z = -6*deltaTime;
01250				Move(pos);
01251	
01252				pos = Location;
01253				onMe = OnMeList[0].Location;
01254				drot.yaw = 0;
01255				xdiff = onMe.x - pos.x;
01256				ydiff = onMe.y - pos.y;
01257				drot.pitch = -xdiff*40;
01258				drot.roll = ydiff*40;
01259				DesiredRotation = dRot;
01260				RotationRate = Rot(4000,4000,4000);
01261				bRotateToDesired = true;
01262				SinkResting = false;
01263			}
01264			else if(SinkResting == true)
01265			{
01266				wScale = 0.5 + cos(CTimeCounter*2.5)*0.5;
01267				tRot.pitch = wScale*(sin(CTimeCounter*1.3)*275);
01268				wScale = 0.5 + sin(CTimeCounter*2.0)*0.5;
01269				tRot.roll = wScale*(cos(CTimeCounter*0.9)*290);
01270				tRot.yaw = 0.0;
01271				SetRotation(tRot);
01272				UpdateSinkerZ(deltaTime);
01273			}
01274			else
01275			{
01276				DesiredRotation = Rot(0, 0, 0);
01277				RotationRate = Rot(3000, 3000, 3000);
01278				if(Rotation == Rot(0, 0, 0))
01279				{
01280					SinkResting = true;
01281					bRotateToDesired = false;
01282				}
01283				UpdateSinkerZ(deltaTime);
01284			}
01285		}
01286	
01287		function UpdateSinkerZ(float deltaTime)
01288		{
01289			local vector pos;
01290			local float zDiff;
01291	
01292			pos = Location;
01293			zDiff = CStartLocation.z - pos.z;
01294			if(zDiff > 0)
01295			{
01296				pos.z += (1+FClamp(zDiff, 0, 30)*0.5)*deltaTime;
01297				SetLocation(pos);
01298			}
01299		}
01300	}
01301	
01302	
01303	// Triggering or doing damage to it destroys it based on DamageThreshold
01304	State() Destructible
01305	{
01306		function Trigger(actor other, pawn eventInstigator)
01307		{
01308			DamageThreshold = 0;
01309			Explode(vect(0,0,0));
01310			PolyobjDestroy();
01311		}
01312	
01313		function bool JointDamaged(int Damage, Pawn EventInstigator, vector HitLoc, vector Momentum, name DamageType, int joint)
01314		{
01315	
01316			DamageThreshold -= Damage;
01317			if (DamageThreshold <= 0)
01318			{
01319				Explode(vect(0,0,0));
01320				PolyobjDestroy();
01321			}
01322	
01323	/* Commented out so that all weapons will cause damage to all breakable objects -- cjr
01324			local bool bDamage;
01325	
01326			switch(DamageType)
01327			{
01328				case 'sever':		// Sword
01329					bDamage = (matter==MATTER_FLESH);
01330					break;
01331				case 'bluntsever':	// Axe
01332					bDamage = (matter==MATTER_FLESH || matter==MATTER_WOOD);
01333					break;
01334				case 'blunt':		// Hammer
01335					bDamage = (matter==MATTER_FLESH || matter==MATTER_WOOD || matter==MATTER_STONE);
01336					break;
01337				default:
01338					bDamage = false;
01339					break;
01340			}
01341			if (bDamage)
01342			{
01343				DamageThreshold -= Damage;
01344				if (DamageThreshold <= 0)
01345				{
01346					Explode(vect(0,0,0));
01347					PolyobjDestroy();
01348				}
01349			}
01350	*/
01351		}
01352	Open:
01353	Close:
01354	}
01355	
01356	
01357	
01358	//-----------------------------------------------------------------------------
01359	// Mover States
01360	//-----------------------------------------------------------------------------
01361	
01362	
01363	// When triggered, open, wait, then close.
01364	state() TriggerOpenTimed
01365	{
01366		function bool HandleDoor(pawn Other)
01367		{
01368			return HandleTriggerDoor(Other);
01369		}
01370	
01371		function Trigger( actor Other, pawn EventInstigator )
01372		{
01373			SavedTrigger = Other;
01374			Instigator = EventInstigator;
01375			if ( SavedTrigger != None )
01376				SavedTrigger.BeginEvent();
01377			GotoState( 'TriggerOpenTimed', 'Open' );
01378		}
01379	
01380		function BeginState()
01381		{
01382			bOpening = false;
01383		}
01384	
01385	Open:
01386		Disable( 'Trigger' );
01387		if ( DelayTime > 0 )
01388		{
01389			bDelaying = true;
01390			Sleep(DelayTime);
01391		}
01392		DoOpen();
01393		FinishInterpolation();
01394		FinishedOpening();
01395		Sleep( StayOpenTime );
01396		if( bTriggerOnceOnly )
01397			GotoState('');
01398	Close:
01399		DoClose();
01400		FinishInterpolation();
01401		FinishedClosing();
01402		Enable( 'Trigger' );
01403	}
01404	
01405	// Toggle when triggered.
01406	state() TriggerToggle
01407	{
01408		function bool HandleDoor(pawn Other)
01409		{
01410			return HandleTriggerDoor(Other);
01411		}
01412		
01413		function Trigger( actor Other, pawn EventInstigator )
01414		{
01415			SavedTrigger = Other;
01416			Instigator = EventInstigator;
01417			if ( SavedTrigger != None )
01418				SavedTrigger.BeginEvent();
01419			if( KeyNum==0 || KeyNum<PrevKeyNum )
01420				GotoState( 'TriggerToggle', 'Open' );
01421			else
01422				GotoState( 'TriggerToggle', 'Close' );
01423		}
01424	Open:
01425		if ( DelayTime > 0 )
01426		{
01427			bDelaying = true;
01428			Sleep(DelayTime);
01429		}
01430		DoOpen();
01431		FinishInterpolation();
01432		FinishedOpening();
01433		if ( SavedTrigger != None )
01434			SavedTrigger.EndEvent();
01435		if( bTriggerOnceOnly )
01436			GotoState('');
01437		Stop;
01438	Close:		
01439		DoClose();
01440		FinishInterpolation();
01441		FinishedClosing();
01442	}
01443	
01444	// Open when triggered, close when get untriggered.
01445	state() TriggerControl
01446	{
01447		function bool HandleDoor(pawn Other)
01448		{
01449			return HandleTriggerDoor(Other);
01450		}
01451	
01452		function Trigger( actor Other, pawn EventInstigator )
01453		{
01454			numTriggerEvents++;
01455			SavedTrigger = Other;
01456			Instigator = EventInstigator;
01457			if ( SavedTrigger != None )
01458				SavedTrigger.BeginEvent();
01459			GotoState( 'TriggerControl', 'Open' );
01460		}
01461		function UnTrigger( actor Other, pawn EventInstigator )
01462		{
01463			numTriggerEvents--;
01464			if ( numTriggerEvents <=0 )
01465			{
01466				numTriggerEvents = 0;
01467				SavedTrigger = Other;
01468				Instigator = EventInstigator;
01469				SavedTrigger.BeginEvent();
01470				GotoState( 'TriggerControl', 'Close' );
01471			}
01472		}
01473	
01474		function BeginState()
01475		{
01476			numTriggerEvents = 0;
01477		}
01478	
01479	Open:
01480		if ( DelayTime > 0 )
01481		{
01482			bDelaying = true;
01483			Sleep(DelayTime);
01484		}
01485		DoOpen();
01486		FinishInterpolation();
01487		FinishedOpening();
01488		SavedTrigger.EndEvent();
01489		if( bTriggerOnceOnly )
01490			GotoState('');
01491		Stop;
01492	Close:		
01493		DoClose();
01494		FinishInterpolation();
01495		FinishedClosing();
01496	}
01497	
01498	// Start pounding when triggered.
01499	state() TriggerPound
01500	{
01501		function bool HandleDoor(pawn Other)
01502		{
01503			return HandleTriggerDoor(Other);
01504		}
01505	
01506		function Trigger( actor Other, pawn EventInstigator )
01507		{
01508			numTriggerEvents++;
01509			SavedTrigger = Other;
01510			Instigator = EventInstigator;
01511			GotoState( 'TriggerPound', 'Open' );
01512		}
01513		function UnTrigger( actor Other, pawn EventInstigator )
01514		{
01515			numTriggerEvents--;
01516			if ( numTriggerEvents <= 0 )
01517			{
01518				numTriggerEvents = 0;
01519				SavedTrigger = None;
01520				Instigator = None;
01521				GotoState( 'TriggerPound', 'Close' );
01522			}
01523		}
01524		function BeginState()
01525		{
01526			numTriggerEvents = 0;
01527		}
01528	
01529	Open:
01530		if ( DelayTime > 0 )
01531		{
01532			bDelaying = true;
01533			Sleep(DelayTime);
01534		}
01535		DoOpen();
01536		FinishInterpolation();
01537		Sleep(OtherTime);
01538	Close:
01539		DoClose();
01540		FinishInterpolation();
01541		Sleep(StayOpenTime);
01542		if( bTriggerOnceOnly )
01543			GotoState('');
01544		if( SavedTrigger != None )
01545			goto 'Open';
01546	}
01547	
01548	
01549	// Open when bumped, wait, then close.
01550	state() BumpOpenTimed
01551	{
01552		function bool HandleDoor(pawn Other)
01553		{
01554			if ( (PolyObjBumpType == PBT_PlayerBump) && !Other.bIsPlayer )
01555				return false;
01556	
01557			Bump(Other);
01558			WaitingPawn = Other;
01559			Other.SpecialPause = 2.5;
01560			return true;
01561		}
01562	
01563		function Bump( actor Other )
01564		{
01565			// Apply bump damage (if applicable)
01566			if(BumpDamage > 0)
01567			{
01568				Other.JointDamaged(BumpDamage, Other.Instigator, Other.Location, vect(0, 0, 0), 'blunt', 0);
01569			}
01570	
01571			if ( (PolyObjBumpType != PBT_AnyBump) && (Pawn(Other) == None) )
01572				return;
01573			if ( (PolyObjBumpType == PBT_PlayerBump) && !Pawn(Other).bIsPlayer )
01574				return;
01575			if ( (PolyObjBumpType == PBT_PawnBump) && (Other.Mass < 10) )
01576				return;
01577			if((PolyObjBumpType == PBT_CreatureBump) && (Other.Mass < 10 || Pawn(Other).bIsPlayer))
01578				return; // RUNE:  Non-player pawn bump
01579	
01580			Global.Bump( Other );
01581			SavedTrigger = None;
01582			Instigator = Pawn(Other);
01583			GotoState( 'BumpOpenTimed', 'Open' );
01584		}
01585	Open:
01586		Disable( 'Bump' );
01587		if ( DelayTime > 0 )
01588		{
01589			bDelaying = true;
01590			Sleep(DelayTime);
01591		}
01592		DoOpen();
01593		FinishInterpolation();
01594		FinishedOpening();
01595		Sleep( StayOpenTime );
01596		if( bTriggerOnceOnly )
01597			GotoState('');
01598	Close:
01599		DoClose();
01600		FinishInterpolation();
01601		FinishedClosing();
01602		Enable( 'Bump' );
01603	}
01604	
01605	// Open when bumped, close when reset.
01606	state() BumpButton
01607	{
01608		function bool HandleDoor(pawn Other)
01609		{
01610			if ( (PolyObjBumpType == PBT_PlayerBump) && !Other.bIsPlayer )
01611				return false;
01612	
01613			Bump(Other);
01614			return false; //let pawn try to move around this button
01615		}
01616	
01617		function Bump( actor Other )
01618		{
01619			// Apply bump damage (if applicable)
01620			if(BumpDamage > 0)
01621			{
01622				Other.JointDamaged(BumpDamage, None, Other.Location, vect(0, 0, 0), 'blunt', 0);
01623			}
01624	
01625			if ( (PolyObjBumpType != PBT_AnyBump) && (Pawn(Other) == None) )
01626				return;
01627			if ( (PolyObjBumpType == PBT_PlayerBump) && !Pawn(Other).bIsPlayer )
01628				return;
01629			if ( (PolyObjBumpType == PBT_PawnBump) && (Other.Mass < 10) )
01630				return;
01631			if((PolyObjBumpType == PBT_CreatureBump) && (Other.Mass < 10 || Pawn(Other).bIsPlayer))
01632				return; // RUNE:  Non-player pawn bump
01633	
01634			Global.Bump( Other );
01635			SavedTrigger = Other;
01636			Instigator = Pawn( Other );
01637			GotoState( 'BumpButton', 'Open' );
01638		}
01639		function BeginEvent()
01640		{
01641			bSlave=true;
01642		}
01643		function EndEvent()
01644		{
01645			bSlave     = false;
01646			Instigator = None;
01647			GotoState( 'BumpButton', 'Close' );
01648		}
01649	Open:
01650		Disable( 'Bump' );
01651		if ( DelayTime > 0 )
01652		{
01653			bDelaying = true;
01654			Sleep(DelayTime);
01655		}
01656		DoOpen();
01657		FinishInterpolation();
01658		FinishedOpening();
01659		if( bTriggerOnceOnly )
01660			GotoState('');
01661		if( bSlave )
01662			Stop;
01663	Close:
01664		DoClose();
01665		FinishInterpolation();
01666		FinishedClosing();
01667		Enable( 'Bump' );
01668	}
01669	
01670	
01671	// Open when stood on, wait, then close.
01672	state() StandOpenTimed
01673	{
01674		function bool HandleDoor(pawn Other)
01675		{
01676			if ( bPlayerOnly && !Other.bIsPlayer )
01677				return false;
01678			Other.SpecialPause = 2.5;
01679			WaitingPawn = Other;
01680			if ( Other.Base == self )
01681				Attach(Other);
01682			return true;
01683		}
01684	
01685		function Attach( actor Other )
01686		{
01687			local pawn  P;
01688	
01689			P = Pawn(Other);
01690			if ( (PolyObjBumpType != PBT_AnyBump) && (P == None) )
01691				return;
01692			if ( (PolyObjBumpType == PBT_PlayerBump) && !P.bIsPlayer )
01693				return;
01694			if ( (PolyObjBumpType == PBT_PawnBump) && (Other.Mass < 10) )
01695				return;
01696			if((PolyObjBumpType == PBT_CreatureBump) && (Other.Mass < 10 || P.bIsPlayer))
01697				return; // RUNE:  Non-player pawn bump
01698	
01699			SavedTrigger = None;
01700			GotoState( 'StandOpenTimed', 'Open' );
01701		}
01702	Open:
01703		Disable( 'Attach' );
01704		if ( DelayTime > 0 )
01705		{
01706			bDelaying = true;
01707			Sleep(DelayTime);
01708		}
01709		DoOpen();
01710		FinishInterpolation();
01711		FinishedOpening();
01712		Sleep( StayOpenTime );
01713		if( bTriggerOnceOnly )
01714			GotoState('');
01715	Close:
01716		DoClose();
01717		FinishInterpolation();
01718		FinishedClosing();
01719		Enable( 'Attach' );
01720	}
01721	
01722	defaultproperties
01723	{
01724	     PolyObjEncroachType=PET_ReturnWhenEncroach
01725	     PolyObjGlideType=PGT_GlideByTime
01726	     NumKeys=2
01727	     MoveTime(0)=1.000000
01728	     MoveTime(1)=1.000000
01729	     MoveTime(2)=1.000000
01730	     MoveTime(3)=1.000000
01731	     MoveTime(4)=1.000000
01732	     MoveTime(5)=1.000000
01733	     MoveTime(6)=1.000000
01734	     MoveTime(7)=1.000000
01735	     MoveTime(8)=1.000000
01736	     MoveTime(9)=1.000000
01737	     MoveTime(10)=1.000000
01738	     MoveTime(11)=1.000000
01739	     MoveTime(12)=1.000000
01740	     MoveTime(13)=1.000000
01741	     MoveTime(14)=1.000000
01742	     MoveTime(15)=1.000000
01743	     StayOpenTime=4.000000
01744	     matter=MATTER_STONE
01745	     NumDebrisChunks=10
01746	     bStatic=False
01747	     bIsMover=True
01748	     bAlwaysRelevant=True
01749	     Physics=PHYS_MovingBrush
01750	     RemoteRole=ROLE_SimulatedProxy
01751	     InitialState=BumpOpenTimed
01752	     bCollideActors=True
01753	     bBlockActors=True
01754	     bBlockPlayers=True
01755	     bSweepable=True
01756	     NetPriority=2.700000
01757	}

End Source Code