// Ok, what this does is it basically checks to see if // every player on the server is in a certain area, and if // that is satisfied, it calls the volume's event. // This is useful for story based missions where you need to // gather your whole team before you can progress. // Alex class KFTeamProgressVolume extends PhysicsVolume; var int NumTouching; var() bool bOff; // Whatever if the volume should start disabled. // Configurable Variables var() bool bDisableAfterTriggered; // default true. Changes this if you'd like to the volume to continue checking player counts. var() bool bTimeOut; // default false. If true, the volume's event will fire even if not all players are inside. var() int TimeOutSeconds; // Number of seconds before timeout is called var() float PlayerThreshold; // Min percent of total players who HAVE to be in the volume before the timeout can go through. var() bool bTeleportWhenAbsent; // Teleport all players here that are not inside the volume (to in volume playerstarts). var() bool bRepawnDeadPlayers; // All fallen players will respawn here (to in volume playerstarts). var() enum EVolTriggerAct { VTR_ToggleDisabled, VTR_Untrigger, VTR_TurnOff, VTR_TurnOn, VTR_FinishEvent } VolumeTriggerAction; var array PSList; simulated function PostBeginPlay() { local NavigationPoint N; local PlayerStart PS; local int i; Super.PostBeginPlay(); if( Level.NetMode==NM_Client ) return; For( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint ) { PS = PlayerStart(N); if( PS!=None && PS.PhysicsVolume==Self ) { PS.bEnabled = False; PSList.Length = i+1; PSList[i] = PS; i++; } } } function PlayerStart PickRandomSpawnPoint() { Return PSList[Rand(PSList.Length)]; } function int CountAlivePlayers() { local Controller C; local int i; For( C=Level.ControllerList; C!=None; C=C.NextController ) { if( PlayerController(C)!=None && C.Pawn!=None && C.Pawn.Health>0 ) i++; } Return i; } simulated event PawnEnteredVolume(Pawn Other) { local vector HitLocation,HitNormal; local Actor SpawnedEntryActor; if ( bWaterVolume && (Level.TimeSeconds - Other.SplashTime > 0.3) && (PawnEntryActor != None) && !Level.bDropDetail && (Level.DetailMode != DM_Low) && EffectIsRelevant(Other.Location,false) ) { if ( !TraceThisActor(HitLocation, HitNormal, Other.Location - Other.CollisionHeight*vect(0,0,1), Other.Location + Other.CollisionHeight*vect(0,0,1)) ) { SpawnedEntryActor = Spawn(PawnEntryActor,Other,,HitLocation,rot(16384,0,0)); if( SpawnedEntryActor!=None ) SpawnedEntryActor.RemoteRole = ROLE_None; } } if( bOff || Level.NetMode==NM_Client || PlayerController(Other.Controller)==None ) return; NumTouching++; CheckActivity(); } function CheckActivity() { local int i; i = CountAlivePlayers(); if( i>=NumTouching ) { if( IsInState('TimingOut') ) GoToState(''); FinishedEvent(); } else if( NumTouching>0 && bTimeOut && (float(i)/float(NumTouching))>=PlayerThreshold ) { SetTimer(2,True); if( !IsInState('TimingOut') ) GoToState('TimingOut'); } else { if( IsInState('TimingOut') ) GoToState(''); if( NumTouching<=0 ) SetTimer(0,False); else SetTimer(2,True); } } function Timer() { CheckActivity(); } State TimingOut { Begin: Sleep(TimeOutSeconds); FinishedEvent(); } function FinishedEvent() { local Controller C; local PlayerStart P; if( bOff ) Return; if( PSList.Length>0 && KFSPGameType(Level.Game)!=None ) KFSPGameType(Level.Game).SpawnVolume = Self; if( bTeleportWhenAbsent ) { For( C=Level.ControllerList; C!=None; C=C.NextController ) { if( PlayerController(C)!=None && C.Pawn!=None && C.Pawn.Health>0 && C.Pawn.PhysicsVolume!=Self ) { P = PickRandomSpawnPoint(); if( P==None ) Continue; C.Pawn.PlayTeleportEffect(True,False); C.Pawn.SetLocation(P.Location); C.ClientSetRotation(P.Rotation); C.Pawn.PlayTeleportEffect(False,True); } } } if( bRepawnDeadPlayers ) { For( C=Level.ControllerList; C!=None; C=C.NextController ) { if( PlayerController(C)!=None && (C.Pawn==None || C.Pawn.Health<=0) && !C.PlayerReplicationInfo.bOnlySpectator ) { C.GotoState('PlayerWaiting'); C.PlayerReplicationInfo.bOutOfLives = false; C.PlayerReplicationInfo.NumLives = 0; C.ServerReStartPlayer(); PlayerController(C).ClientSetViewTarget(C.Pawn); PlayerController(C).SetViewTarget(C.Pawn); } } } TriggerEvent(Event,self,None); if(bDisableAfterTriggered) { SetTimer(0,False); bOff = true; } } simulated event PawnLeavingVolume(Pawn P) { if( bOff || Level.NetMode==NM_Client || PlayerController(P.Controller)==None ) return; NumTouching--; CheckActivity(); } function PlayerPawnDiedInVolume(Pawn Other) { if( bOff || Level.NetMode==NM_Client || PlayerController(Other.Controller)==None ) return; NumTouching --; CheckActivity(); } function Trigger( actor Other, pawn EventInstigator ) { Switch( VolumeTriggerAction ) { Case VTR_ToggleDisabled: bOff = !bOff; Return; Case VTR_Untrigger: if( NumTouching>0 ) UntriggerEvent(Event,self, EventInstigator ); Return; Case VTR_TurnOff: bOff = True; Return; Case VTR_TurnOn: bOff = False; Return; Case VTR_FinishEvent: bOff = False; FinishedEvent(); Return; } } defaultproperties { bDisableAfterTriggered=true; PlayerThreshold=0.75 // 75% players is enough to execute bTimeOut=false TimeOutSeconds=60 bStatic=False bNoDelete=True RemoteRole=ROLE_None }