369 lines
9.1 KiB
Ucode
369 lines
9.1 KiB
Ucode
//=============================================================================
|
|
// 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<actor> 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> 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
|
|
}
|