//============================================================================= // Trigger: senses things happening in its proximity and generates // sends Trigger/UnTrigger to actors whose names match 'EventName'. //============================================================================= class Trigger extends Triggers native; #exec Texture Import File=Textures\Trigger.pcx Name=S_Trigger Mips=Off MASKED=1 //----------------------------------------------------------------------------- // Trigger variables. // Trigger type. var() enum ETriggerType { TT_PlayerProximity, // Trigger is activated by player proximity. TT_PawnProximity, // Trigger is activated by any pawn's proximity TT_ClassProximity, // Trigger is activated by actor of ClassProximityType only TT_AnyProximity, // Trigger is activated by any actor in proximity. TT_Shoot, // Trigger is activated by player shooting it. TT_HumanPlayerProximity, // Trigger activated by human player (not bot) TT_LivePlayerProximity, // Trigger only activated by live player, untriggered if player dies while touching } TriggerType; // Human readable triggering message. var() localized string Message; // Only trigger once and then go dormant. var() bool bTriggerOnceOnly; // For triggers that are activated/deactivated by other triggers. var() bool bInitiallyActive; var() class ClassProximityType; var() float RepeatTriggerTime; //if > 0, repeat trigger message at this interval is still touching other var() float ReTriggerDelay; //minimum time before trigger can be triggered again var float TriggerTime; var() float DamageThreshold; //minimum damage to trigger if TT_Shoot // AI vars var actor TriggerActor; // actor that triggers this trigger var actor TriggerActor2; // store for reset var bool bSavedInitialCollision; var bool bSavedInitialActive; /* ToucherDied() called when Pawn P dies, to untrigger player only triggers */ function PlayerToucherDied(Pawn P) { if ( bInitiallyActive && (TriggerType == TT_LivePlayerProximity) ) UntriggerEvent(event, self, P); } //============================================================================= // AI related functions function bool SelfTriggered() { return bInitiallyActive; } function PreBeginPlay() { Super.PreBeginPlay(); if ( (TriggerType == TT_PlayerProximity) || (TriggerType == TT_PawnProximity) || (TriggerType == TT_HumanPlayerProximity) || (TriggerType == TT_LivePlayerProximity) || ((TriggerType == TT_ClassProximity) && ClassIsChildOf(ClassProximityType,class'Pawn')) ) OnlyAffectPawns(true); } function PostBeginPlay() { if ( !bInitiallyActive ) FindTriggerActor(); if ( TriggerType == TT_Shoot ) { bHidden = false; bProjTarget = true; SetDrawType(DT_None); } bSavedInitialActive = bInitiallyActive; bSavedInitialCollision = bCollideActors; Super.PostBeginPlay(); } /* Reset() reset actor to initial state - used when restarting level without reloading. */ function Reset() { Super.Reset(); // collision, bInitiallyactive bInitiallyActive = bSavedInitialActive; SetCollision(bSavedInitialCollision, bBlockActors ); } function FindTriggerActor() { local Actor A; TriggerActor = None; TriggerActor2 = None; ForEach AllActors(class 'Actor', A) if ( A.Event == Tag) { if (TriggerActor == None) TriggerActor = A; else { TriggerActor2 = A; return; } } } function Actor SpecialHandling(Pawn Other) { local Actor A; if ( bTriggerOnceOnly && !bCollideActors ) return None; if ( (TriggerType == TT_HumanPlayerProximity) && !Other.IsHumanControlled() ) return None; if ( (TriggerType == TT_PlayerProximity) && !Other.IsPlayerPawn() ) return None; if ( !bInitiallyActive ) { if ( TriggerActor == None ) FindTriggerActor(); if ( TriggerActor == None ) return None; if ( (TriggerActor2 != None) && (VSize(TriggerActor2.Location - Other.Location) < VSize(TriggerActor.Location - Other.Location)) ) return TriggerActor2; else return TriggerActor; } // is this a shootable trigger? if ( TriggerType == TT_Shoot ) { if ( Other.CanAttack(self) ) return Other.ShootSpecial(self); return self; } // can other trigger it right away? if ( IsRelevant(Other) ) { ForEach TouchingActors(class'Actor', A) if ( A == Other ) Touch(Other); return self; } return self; } // when trigger gets turned on, check its touch list function CheckTouchList() { local Actor A; ForEach TouchingActors(class'Actor', A) Touch(A); } //============================================================================= // Trigger states. // Trigger is always active. state() NormalTrigger { } // Other trigger toggles this trigger's activity. state() OtherTriggerToggles { function Trigger( actor Other, pawn EventInstigator ) { bInitiallyActive = !bInitiallyActive; if ( bInitiallyActive ) CheckTouchList(); } } // Other trigger turns this on. state() OtherTriggerTurnsOn { function Trigger( actor Other, pawn EventInstigator ) { local bool bWasActive; bWasActive = bInitiallyActive; bInitiallyActive = true; if ( !bWasActive ) CheckTouchList(); } } // Other trigger turns this off. state() OtherTriggerTurnsOff { function Trigger( actor Other, pawn EventInstigator ) { bInitiallyActive = false; } } //============================================================================= // Trigger logic. // // See whether the other actor is relevant to this trigger. // function bool IsRelevant( actor Other ) { local Actor Inst; Inst = FindInstigator( Other ); if( !bInitiallyActive ) return false; switch( TriggerType ) { case TT_HumanPlayerProximity: return (Pawn(Other) != None) && Pawn(Other).IsHumanControlled(); case TT_PlayerProximity: return (Pawn(Other) != None) && (Pawn(Other).IsPlayerPawn() || Pawn(Other).WasPlayerPawn()); case TT_LivePlayerProximity: return (Pawn(Other) != None) && Pawn(Other).IsPlayerPawn(); case TT_PawnProximity: return (Pawn(Other) != None) && Pawn(Other).CanTrigger(self); case TT_ClassProximity: return ClassIsChildOf(Other.Class, ClassProximityType) && ( !ClassIsChildOf(ClassProximityType, class'Vehicle') || Pawn(Inst).IsPlayerPawn() ); // Force Pawns to be controlled case TT_AnyProximity: return true; case TT_Shoot: return ( (Projectile(Other) != None) && (Projectile(Other).Damage >= DamageThreshold) ); } } function Actor FindInstigator( Actor Other ) { // Hack if player is in turret and not controlling vehicle... if ( Vehicle(Other) != None && Vehicle(Other).Controller == None ) return Vehicle(Other).GetInstigator(); return Other; } // // Called when something touches the trigger. // function Touch( actor Other ) { local int i; if( IsRelevant( Other ) ) { Other = FindInstigator( Other ); if ( ReTriggerDelay > 0 ) { if ( Level.TimeSeconds - TriggerTime < ReTriggerDelay ) return; TriggerTime = Level.TimeSeconds; } // Broadcast the Trigger message to all matching actors. TriggerEvent(Event, self, Other.Instigator); if ( (Pawn(Other) != None) && (Pawn(Other).Controller != None) ) { for ( i=0;i<4;i++ ) if ( Pawn(Other).Controller.GoalList[i] == self ) { Pawn(Other).Controller.GoalList[i] = None; break; } } if( (Message != "") && (Other.Instigator != None) ) // Send a string message to the toucher. Other.Instigator.ClientMessage( Message ); if( bTriggerOnceOnly ) // Ignore future touches. SetCollision(False); else if ( RepeatTriggerTime > 0 ) SetTimer(RepeatTriggerTime, false); } } function Timer() { local bool bKeepTiming; local Actor A; bKeepTiming = false; ForEach TouchingActors(class'Actor', A) if ( IsRelevant(A) ) { bKeepTiming = true; Touch(A); } if ( bKeepTiming ) SetTimer(RepeatTriggerTime, false); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class damageType, optional int HitIndex) { if ( bInitiallyActive && (TriggerType == TT_Shoot) && (Damage >= DamageThreshold) && (instigatedBy != None) ) { if ( ReTriggerDelay > 0 ) { if ( Level.TimeSeconds - TriggerTime < ReTriggerDelay ) return; TriggerTime = Level.TimeSeconds; } // Broadcast the Trigger message to all matching actors. TriggerEvent(Event, self, instigatedBy); if( Message != "" ) // Send a string message to the toucher. instigatedBy.Instigator.ClientMessage( Message ); if( bTriggerOnceOnly ) // Ignore future touches. SetCollision(False); if ( (AIController(instigatedBy.Controller) != None) && (instigatedBy.Controller.Target == self) ) instigatedBy.Controller.StopFiring(); } } // // When something untouches the trigger. // function UnTouch( actor Other ) { if( IsRelevant( Other ) ) UntriggerEvent(event, self, Other.Instigator); } defaultproperties { Texture=S_Trigger bInitiallyActive=True InitialState=NormalTrigger }