diff options
Diffstat (limited to 'Northstar.Coop/scripts/vscripts/sp/_gauntlet.gnut')
-rw-r--r-- | Northstar.Coop/scripts/vscripts/sp/_gauntlet.gnut | 1054 |
1 files changed, 0 insertions, 1054 deletions
diff --git a/Northstar.Coop/scripts/vscripts/sp/_gauntlet.gnut b/Northstar.Coop/scripts/vscripts/sp/_gauntlet.gnut deleted file mode 100644 index 4cde3094..00000000 --- a/Northstar.Coop/scripts/vscripts/sp/_gauntlet.gnut +++ /dev/null @@ -1,1054 +0,0 @@ -global function Gauntlet_ServerInit -global function EnableAllGauntlets -global function DisableAllGauntlets -global function EnableGauntlet -global function DisableGauntlet -global function Gauntlet_HideLeaderboard -global function Gauntlet_ShowLeaderboard -global function Gauntlet_NPC_PostSpawn -global function ClientCommand_Gauntlet_PlayerRestartedFromMenu -global function Gauntlet_StartGhostPlayback -global function Gauntlet_StopGhostPlayback -global function Gauntlet_ChallengeLeaderboardGhosts -#if DEV -global function Gauntlet_Player_GhostRecordOrPlayback -#endif - -const float GAUNTLET_ENEMY_MISSED_TIME_PENALTY = 2.0 -const float GAUNTLET_TARGET_DISSOLVE_TIME = 1.0 -const float GAUNTLET_TARGET_DISSOLVE_TIME_MS = GAUNTLET_TARGET_DISSOLVE_TIME * 100 - -void function Gauntlet_ServerInit() -{ - AddClientCommandCallback( "Gauntlet_PlayerRestartedFromMenu", ClientCommand_Gauntlet_PlayerRestartedFromMenu ) - AddCallback_EntitiesDidLoad( Gauntlet_PostEntityLoadSetup ) - AddCallback_OnClientConnected( Gauntlet_PlayerConnected ) - AddCallback_OnLoadSaveGame( Gauntlet_OnLoadSaveGame ) - - RegisterSignal( "trigStart_OnStartTouch" ) - RegisterSignal( "trigStart_OnEndTouch" ) - RegisterSignal( "trigStart2_OnStartTouch" ) - RegisterSignal( "trigStart2_OnEndTouch" ) - - RegisterSignal( "Gauntlet_PlayerHitStartTrig" ) - RegisterSignal( "Gauntlet_PlayerWentBackwardsThroughStartTrig" ) - RegisterSignal( "Gauntlet_PlayerHitFinishTrig" ) - RegisterSignal( "Gauntlet_CheckpointHit" ) - RegisterSignal( "Gauntlet_ForceRestart" ) - RegisterSignal( "GhostAnimationPlayback_Start" ) - RegisterSignal( "GhostAnimationPlayback_Stop" ) - RegisterSignal( "Gauntlet_PlayerBeatChallengeGhost" ) - RegisterSignal( "Gauntlet_PlayerBeatAllChallengeGhosts" ) - #if DEV - RegisterSignal( "RecordAnimation_Start") - RegisterSignal( "Player_StartRecordingGhost_HintStart" ) - #endif -} - -void function Gauntlet_PostEntityLoadSetup() -{ - foreach ( gauntlet in GetGauntlets() ) - { - InitGauntlet( gauntlet ) - - if ( gauntlet.startEnabled ) - EnableGauntlet( gauntlet ) - } -} - -void function Gauntlet_PlayerConnected( entity player ) -{ - foreach ( gauntlet in GetGauntlets() ) - { - // send ghost duration data to client- only server can read the anim durations - foreach ( ghost in gauntlet.ghosts ) - Remote_CallFunction_Replay( player, "ScriptCallback_Gauntlet_SetGhostDuration", gauntlet.id, ghost.id, ghost.duration ) - - if ( gauntlet.showLeaderboard ) - { - Gauntlet_ShowLeaderboard( gauntlet ) - - if ( gauntlet.activeGhostID != -1 ) - Gauntlet_RefreshActiveGhostID( gauntlet ) - } - } -} - -void function Gauntlet_OnLoadSaveGame( entity player ) -{ - thread Gauntlet_OnLoadSaveGame_Thread( player ) -} - -void function Gauntlet_OnLoadSaveGame_Thread( entity player ) -{ - wait 1.0 - Gauntlet_PlayerConnected( player ) -} - -// turns on a particular gauntlet -void function EnableGauntlet( GauntletInfo gauntlet ) -{ - Assert( gauntlet.isInited, "Must run InitGauntlet before enabling" ) - - if ( gauntlet.isEnabled ) - return - - Gauntlet_CreateSignalEnt( gauntlet ) - - foreach ( player in GetPlayerArray() ) - Remote_CallFunction_Replay( player, "ScriptCallback_EnableGauntlet", gauntlet.id ) - - thread Gauntlet_Think( gauntlet ) - - gauntlet.isEnabled = true -} - -// turns off a particular gauntlet -void function DisableGauntlet( GauntletInfo gauntlet ) -{ - if ( !gauntlet.isEnabled ) - return - - gauntlet.signalEnt.Signal( "DisableGauntlet" ) - - Gauntlet_CleanupSignalEnt( gauntlet ) - Gauntlet_ClearSpawnedNPCs( gauntlet ) - thread ClearDroppedWeapons( GAUNTLET_TARGET_DISSOLVE_TIME + 0.1 ) // needs to be longer than gauntlet ghost dissolve time so weapons drop - - foreach ( player in GetPlayerArray() ) - Remote_CallFunction_Replay( player, "ScriptCallback_DisableGauntlet", gauntlet.id ) - - gauntlet.isEnabled = false -} - -void function Gauntlet_HideLeaderboard( GauntletInfo gauntlet ) -{ - Gauntlet_SetLeaderboardEnabled( gauntlet, false ) - - foreach ( player in GetPlayerArray() ) - Remote_CallFunction_Replay( player, "ScriptCallback_HideLeaderboard", gauntlet.id ) -} - -void function Gauntlet_ShowLeaderboard( GauntletInfo gauntlet ) -{ - Gauntlet_SetLeaderboardEnabled( gauntlet, true ) - - foreach ( player in GetPlayerArray() ) - Remote_CallFunction_Replay( player, "ScriptCallback_ShowLeaderboard", gauntlet.id ) -} - -void function Gauntlet_Checkpoints( GauntletInfo gauntlet ) -{ - if ( !gauntlet.checkpoints.len() ) - return - - foreach ( trig in gauntlet.checkpoints ) - thread Gauntlet_CheckpointTrig_WaitForPlayer( gauntlet, trig ) -} - -void function Gauntlet_CheckpointTrig_WaitForPlayer( GauntletInfo gauntlet, entity trig ) -{ - gauntlet.player.EndSignal( "OnDestroy" ) - gauntlet.player.EndSignal( "Gauntlet_RunStarted" ) - gauntlet.player.EndSignal( "Gauntlet_RunStopped" ) - trig.EndSignal( "OnDestroy" ) - - table result - entity activator - - while ( 1 ) - { - result = trig.WaitSignal( "OnStartTouch" ) - activator = expect entity( result.activator ) - - if ( !activator.IsPlayer() ) - continue - - if ( !IsAlive( activator ) ) - continue - - if ( activator.IsTitan() ) - continue - - break - } - - gauntlet.checkpointsHit++ - activator.Signal( "Gauntlet_CheckpointHit" ) -} - -void function Gauntlet_ClearSpawnedNPCs( GauntletInfo gauntlet ) -{ - foreach ( guy in gauntlet.spawned ) - { - if ( IsAlive( guy ) ) - { - Gauntlet_UnfreezeNPC( guy ) - guy.Die() - } - } - - gauntlet.spawned = [] -} - -void function Gauntlet_SpawnNPCs( GauntletInfo gauntlet ) -{ - Gauntlet_ClearSpawnedNPCs( gauntlet ) - - array<entity> spawned = SpawnFromSpawnerArray( gauntlet.spawners ) - foreach ( guy in spawned ) - thread Gauntlet_NPC_PostSpawn( guy, gauntlet ) - - gauntlet.spawned = spawned -} - -void function Gauntlet_NPC_PostSpawn( entity npc, GauntletInfo gauntlet ) -{ - if ( IsGrunt( npc ) ) - { - // TODO- pulse as player runs through course, so the effect highlights the different ranges where the enemies are - Highlight_SetEnemyHighlightWithParam1( npc, "gauntlet_target_highlight", npc.EyePosition() ) - - npc.SetHealth( 1 ) - - npc.SetCanBeMeleeExecuted( false ) - } - - npc.EndSignal( "OnDeath" ) - thread Gauntlet_NPC_DeathWait( npc, gauntlet ) - - AddEntityCallback_OnDamaged( npc, Gauntlet_NPC_Damaged ) - - npc.SetNoTarget( true ) - npc.SetEfficientMode( true ) - npc.SetHologram() - npc.SetDeathActivity( "ACT_DIESIMPLE" ) - - wait RandomFloatRange( 0.5, 1.0 ) // This is no good, too variable. TODO put in a pose instead - - npc.Freeze() -} - -void function Gauntlet_NPC_Damaged( entity npc, var damageInfo ) -{ - printt( "NPC Damaged!", npc.GetHealth() ) - - float dmg = DamageInfo_GetDamage( damageInfo ) - float finalHealth = npc.GetHealth() - dmg - - if ( finalHealth <= 0 ) - Gauntlet_UnfreezeNPC( npc ) -} - -void function Gauntlet_NPC_DeathWait( entity npc, GauntletInfo gauntlet ) -{ - gauntlet.signalEnt.EndSignal( "DisableGauntlet" ) - - npc.WaitSignal( "OnDeath" ) - - EmitSoundAtPosition( TEAM_UNASSIGNED, npc.GetOrigin(), "holopilot_impacts_training" ) - npc.Dissolve( ENTITY_DISSOLVE_PHASESHIFT, Vector( 0, 0, 0 ), GAUNTLET_TARGET_DISSOLVE_TIME_MS ) - - if ( !gauntlet.isActive ) - return - - if ( gauntlet.runFinished ) - return - - gauntlet.enemiesKilled++ - - Remote_CallFunction_Replay( gauntlet.player, "ScriptCallback_Gauntlet_SetEnemyInfo", gauntlet.id, gauntlet.spawners.len(), gauntlet.enemiesKilled ) -} - -void function Gauntlet_UnfreezeNPC( entity npc ) -{ - if ( !npc.IsFrozen() ) - return - - npc.Unfreeze() -} - -string function EnableAllGauntlets() -{ - foreach ( idx, gauntlet in GetGauntlets() ) - EnableGauntlet( gauntlet ) - - return( "All gauntlets enabled" ) -} - -string function DisableAllGauntlets() -{ - foreach ( idx, gauntlet in GetGauntlets() ) - DisableGauntlet( gauntlet ) - - return( "All gauntlets disabled" ) -} - -void function Gauntlet_Think( GauntletInfo gauntlet ) -{ - gauntlet.signalEnt.EndSignal( "DisableGauntlet" ) - - OnThreadEnd( - function() : ( gauntlet ) - { - Gauntlet_ResetTrackerStats( gauntlet ) - - if ( gauntlet.player && !gauntlet.runFinished ) - Gauntlet_AbortRun( gauntlet ) - } - ) - - while ( 1 ) - { - thread Gauntlet_StartTrigThink( gauntlet ) - - waitthread Gauntlet_WaitForPlayerToStart( gauntlet ) - - Gauntlet_ResetTrackerStats( gauntlet ) - - Gauntlet_StartRun( gauntlet ) - - thread Gauntlet_HandlePlayerForceRestart( gauntlet ) - - waitthread Gauntlet_WaitForStop( gauntlet ) - - waitthread Gauntlet_StopRun( gauntlet ) - } -} - -void function Gauntlet_StartRun( GauntletInfo gauntlet ) -{ - printt( "Gauntlet Run Started for player " + gauntlet.player ) - - RestockPlayerAmmo( gauntlet.player ) - EmitSoundOnEntityOnlyToPlayer( gauntlet.player, gauntlet.player, "training_scr_gaunlet_start" ) - - gauntlet.isActive = true - gauntlet.startTime = Time() - gauntlet.player.Signal( "Gauntlet_RunStarted" ) - gauntlet.signalEnt.Signal( "Gauntlet_RunStarted" ) - level.ui.playerRunningGauntlet = true - - Remote_CallFunction_Replay( gauntlet.player, "ScriptCallback_Gauntlet_StartRun", gauntlet.id ) - Remote_CallFunction_Replay( gauntlet.player, "ScriptCallback_Gauntlet_SetEnemyInfo", gauntlet.id, gauntlet.spawners.len(), 0 ) - - thread Gauntlet_SpawnNPCs( gauntlet ) - - thread Gauntlet_Checkpoints( gauntlet ) -} - -void function Gauntlet_StopRun( GauntletInfo gauntlet ) -{ - gauntlet.isActive = false - level.ui.playerRunningGauntlet = false - - string feedbackSound = "" - - ResetPlayerHealthAndStatus( gauntlet.player ) - - if ( !gauntlet.runFinished ) - { - Gauntlet_AbortRun( gauntlet ) - feedbackSound = "training_scr_gaunlet_abort" - } - else - { - Gauntlet_FinishRun( gauntlet ) - - if ( gauntlet.lastRunDefeatedGhost ) - feedbackSound = "training_scr_gaunlet_high_score" - else if ( gauntlet.lastRunBestTime ) - feedbackSound = "training_scr_gaunlet_high_score" - else - feedbackSound = "training_scr_gaunlet_end" - - if ( feedbackSound != "" && IsAlive( gauntlet.player ) ) - EmitSoundOnEntityOnlyToPlayer( gauntlet.player, gauntlet.player, feedbackSound ) - } - - wait 0.1 // let the gauntlet finish and count NPCs remaining before killing the remainder - Gauntlet_ClearSpawnedNPCs( gauntlet ) - thread ClearDroppedWeapons( GAUNTLET_TARGET_DISSOLVE_TIME + 0.1 ) // needs to be longer than gauntlet ghost dissolve time so weapons drop - - if ( IsValid( gauntlet.player ) ) - ClearActiveProjectilesForTeam( gauntlet.player.GetTeam() ) - - // need to wait before firing final signal, so this signal doesn't kill Gauntlet_HandlePlayerForceRestart - if ( IsValid( gauntlet.player ) ) - gauntlet.player.Signal( "Gauntlet_RunStopped" ) - - if ( IsValid( gauntlet.signalEnt ) ) - gauntlet.signalEnt.Signal( "Gauntlet_RunStopped" ) - - wait 0.1 // let other threads catch the signals and check the gauntlet struct before ResetTrackerStats -} - -void function ResetPlayerHealthAndStatus( entity player ) -{ - if ( !IsAlive( player ) ) - return - - player.SetHealth( player.GetMaxHealth() ) - - array<int> statusEffectsToStop = [] - statusEffectsToStop.append( eStatusEffect.emp ) - statusEffectsToStop.append( eStatusEffect.move_slow ) - statusEffectsToStop.append( eStatusEffect.turn_slow ) - - foreach ( statusEffect in statusEffectsToStop ) - { - if ( StatusEffect_Get( player, statusEffect ) > 0.0 ) - StatusEffect_StopAll( player, statusEffect ) // arc grenade stun - } -} - -void function Gauntlet_FinishRun( GauntletInfo gauntlet ) -{ - RestockPlayerAmmo( gauntlet.player ) - - float elapsedTime = Time() - gauntlet.startTime - printt( "Gauntlet Run Finished, elapsed time", elapsedTime ) - - // time penalties for missed enemies - float enemiesMissedTimePenalty = 0.0 - if ( gauntlet.spawners.len() > gauntlet.enemiesKilled ) - { - int numEnemiesRemaining = gauntlet.spawners.len() - gauntlet.enemiesKilled - enemiesMissedTimePenalty = ( numEnemiesRemaining.tofloat() * GAUNTLET_ENEMY_MISSED_TIME_PENALTY ) - - elapsedTime += enemiesMissedTimePenalty - } - - // check if new best time was set - gauntlet.lastRunTime = elapsedTime - if ( gauntlet.bestTime == -1.0 || elapsedTime < gauntlet.bestTime ) - { - printt( "New best time!" ) - gauntlet.bestTime = elapsedTime - gauntlet.lastRunBestTime = true - - // if there's a player ghost (for leaderboard), update its duration - if ( gauntlet.hasPlayerGhost ) - { - // update player ghost - GauntletGhost playerGhost = Gauntlet_GetPlayerGhost( gauntlet ) - Gauntlet_SetGhostDuration( gauntlet, playerGhost, gauntlet.bestTime ) - } - } - - // did player beat a ghost racer? - if ( Gauntlet_HasActiveGhost( gauntlet ) ) - { - GauntletGhost activeGhost = Gauntlet_GetActiveGhost( gauntlet ) - - if ( gauntlet.lastRunTime < activeGhost.duration ) - { - printt( "player beat active ghost!" ) - gauntlet.lastRunDefeatedGhost = true - } - } - - Remote_CallFunction_Replay( gauntlet.player, "ScriptCallback_Gauntlet_FinishRun", gauntlet.id, elapsedTime, gauntlet.bestTime, enemiesMissedTimePenalty ) -} - -void function Gauntlet_AbortRun( GauntletInfo gauntlet ) -{ - entity player = gauntlet.player - if ( !IsValid( player ) ) - return - - RestockPlayerAmmo_Silent( gauntlet.player ) - - EmitSoundOnEntityOnlyToPlayer( player, player, "training_scr_gaunlet_abort" ) - - Remote_CallFunction_Replay( player, "ScriptCallback_Gauntlet_AbortRun", gauntlet.id ) -} - -void function Gauntlet_WaitForPlayerToStart( GauntletInfo gauntlet ) -{ - WaitSignal( gauntlet.signalEnt, "Gauntlet_PlayerHitStartTrig" ) - Assert( IsValid( gauntlet.player ) ) -} - -entity function Gauntlet_StartTrigThink( GauntletInfo gauntlet ) -{ - entity trigStart = gauntlet.trigStart - entity trigStart2 = gauntlet.trigStart2 - - EndSignal( gauntlet.signalEnt, "OnDestroy" ) - EndSignal( trigStart, "OnDestroy" ) - EndSignal( trigStart2, "OnDestroy" ) - EndSignal( gauntlet.signalEnt, "Gauntlet_RunStopped" ) - - table result - string signal - entity player - - //printt( "WaitForPlayerToHitStartTrig started" ) - - // "trigStart_OnStartTouch", "trigStart_OnEndTouch", "trigStart2_OnStartTouch", "trigStart2_OnEndTouch" - thread Gauntlet_PlayerStartSignals( gauntlet, trigStart, "trigStart_" ) - thread Gauntlet_PlayerStartSignals( gauntlet, trigStart2, "trigStart2_" ) - - while ( 1 ) - { - entity alreadyTouchingEnt = null - foreach ( p in GetPlayerArray() ) - { - if ( trigStart.IsTouching( p ) && Gauntlet_EntCanActivateGauntletTrigger( p ) ) - { - alreadyTouchingEnt = p - break - } - } - - if ( IsValid( alreadyTouchingEnt ) ) - { - player = alreadyTouchingEnt - } - else - { - //printt( "Waiting for trigStart OnStartTouch" ) - - result = WaitSignal( trigStart, "OnStartTouch" ) - player = expect entity( result.activator ) - } - - if ( !Gauntlet_EntCanActivateGauntletTrigger( player ) ) - continue - - if ( !IsAlive( player ) ) - continue - - //printt( "WAITING for trigStart_OnEndTouch" ) - - while ( IsAlive( player ) ) - { - WaitSignal( player, "trigStart_OnEndTouch" ) - - //printt( "RECEIVED trigStart_OnEndTouch" ) - - // player exited start trig without running gauntlet - if ( !trigStart2.IsTouching( player ) ) - { - player.Signal( "Gauntlet_PlayerWentBackwardsThroughStartTrig" ) - continue - } - - //printt( "WAITING for trigStart_OnStartTouch or trigStart2_OnEndTouch" ) - - // player is now in trig2 - result = WaitSignal( player, "trigStart_OnStartTouch", "trigStart2_OnEndTouch" ) - signal = expect string( result.signal ) - if ( signal == "trigStart2_OnEndTouch" ) - { - //printt( "RECEIVED trigStart2_OnEndTouch" ) - - // player exited trig2 without touching trig1, so we know they started the gauntlet - if ( !trigStart.IsTouching( player ) ) - { - //printt( "SENDING Gauntlet_PlayerHitStartTrig" ) - gauntlet.signalEnt.Signal( "Gauntlet_PlayerHitStartTrig" ) - gauntlet.player = player - } - } - } - } -} - -void function Gauntlet_PlayerStartSignals( GauntletInfo gauntlet, entity trig, string signalPrefix ) -{ - EndSignal( trig, "OnDestroy" ) - EndSignal( gauntlet.signalEnt, "Gauntlet_RunStopped" ) - - /* - OnThreadEnd( - function() : ( ) - { - printt( "Gauntlet_PlayerStartSignals ENDED" ) - } - ) - - printt( "PlayerStartSignals started" ) - */ - - while ( 1 ) - { - table result = WaitSignal( trig, "OnStartTouch", "OnEndTouch" ) - string signal = expect string( result.signal ) - entity activator = expect entity( result.activator ) - - if ( !Gauntlet_EntCanActivateGauntletTrigger( activator ) ) - continue - - string outboundSignal = signalPrefix - if ( signal == "OnStartTouch" ) - outboundSignal += "OnStartTouch" - else if ( signal == "OnEndTouch" ) - outboundSignal += "OnEndTouch" - - Assert( outboundSignal != signalPrefix ) - - Signal( activator, outboundSignal ) - } -} - -void function Gauntlet_WaitForStop( GauntletInfo gauntlet ) -{ - gauntlet.player.EndSignal( "OnDeath" ) - gauntlet.player.EndSignal( "Gauntlet_PlayerWentBackwardsThroughStartTrig" ) - gauntlet.player.EndSignal( "Gauntlet_ForceRestart" ) - gauntlet.signalEnt.EndSignal( "DisableGauntlet" ) - - table result - entity activator - - while ( 1 ) - { - result = gauntlet.trigFinish.WaitSignal( "OnStartTouch" ) - activator = expect entity( result.activator ) - - if ( !activator.IsPlayer() ) - continue - - if ( activator != gauntlet.player ) - continue - - gauntlet.player.Signal( "Gauntlet_PlayerHitFinishTrig" ) - - gauntlet.runFinished = true - if ( gauntlet.checkpoints.len() && gauntlet.checkpointsHit < gauntlet.checkpoints.len() ) - gauntlet.runFinished = false - - break - } -} - -bool function Gauntlet_EntCanActivateGauntletTrigger( entity ent ) -{ - if ( !ent.IsPlayer() ) - return false - - if ( !IsAlive( ent ) ) - return false - - if ( ent.IsTitan() ) - return false - - return true -} - -void function Gauntlet_HandlePlayerForceRestart( GauntletInfo gauntlet ) -{ - gauntlet.player.EndSignal( "OnDestroy" ) - gauntlet.player.EndSignal( "Gauntlet_RunStopped" ) - - gauntlet.player.WaitSignal( "Gauntlet_ForceRestart" ) - - thread Gauntlet_TeleportPlayerToStart( gauntlet ) -} - -void function Gauntlet_TeleportPlayerToStart( GauntletInfo gauntlet ) -{ - entity player = gauntlet.player - entity startpoint = gauntlet.startpoint - - if ( !IsAlive( player ) ) - return - - if ( !IsValid( startpoint ) ) - return - - EndSignal( player, "OnDestroy" ) - - // wait for quick death to finish before continuing - printt( "player doing quick death (1)?", player.p.doingQuickDeath ) - while ( player.p.doingQuickDeath ) - wait 0.1 - - //printt( "starting reset fade" ) - - float fadeTime = 0.1 - float holdTime = 0.3 - ScreenFadeToBlack( player, fadeTime, holdTime ) - player.FreezeControlsOnServer() - player.SetVelocity( <0,0,0> ) - - OnThreadEnd( - function() : ( player, gauntlet ) - { - if ( IsValid( player ) ) - { - player.UnfreezeControlsOnServer() - player.UnforceStand() - thread Gauntlet_TeleportFailsafe( player, gauntlet ) - } - } - ) - - wait fadeTime - - // again, wait for quick death to finish before continuing since it could have started during fadeTime - printt( "player doing quick death (2)?", player.p.doingQuickDeath ) - while ( player.p.doingQuickDeath ) - wait 0.1 - - printt( "moving player back to start" ) - - player.FreezeControlsOnServer() // just in case they were unfrozen by quick death ending since we started waiting - player.SetOrigin( OriginToGround( startpoint.GetOrigin() + <0,0,1> ) ) - player.SetAngles( startpoint.GetAngles() ) - player.SetVelocity( <0,0,0> ) - player.ForceStand() - - wait holdTime -} - -// HACK this is in case the quick death teleport happens on the exact same server frame as the gauntlet restart teleport -void function Gauntlet_TeleportFailsafe( entity player, GauntletInfo gauntlet ) -{ - // HACK this breaks in other levels that don't have the flag trigger - // in the future set this up as a gauntlet setting - if ( GetMapName() != "sp_training" ) - return - - EndSignal( player, "OnDestroy" ) - - wait 0.5 - - if ( !gauntlet.isActive && !Flag( "PlayerInGauntletEntryway" ) ) - { - printt( "Gauntlet reset FAILSAFE!" ) - thread Gauntlet_TeleportPlayerToStart( gauntlet ) - } -} - -bool function ClientCommand_Gauntlet_PlayerRestartedFromMenu( entity player, array<string> args ) -{ - player.Signal( "Gauntlet_ForceRestart" ) - return true -} - -void function Gauntlet_CreateSignalEnt( GauntletInfo gauntlet ) -{ - Assert( !IsValid( gauntlet.signalEnt ) ) - - entity signalEnt = CreateEntity( "info_target" ) - DispatchSpawn( signalEnt ) - - gauntlet.signalEnt = signalEnt -} - -void function Gauntlet_CleanupSignalEnt( GauntletInfo gauntlet ) -{ - gauntlet.signalEnt.Destroy() - gauntlet.signalEnt = null -} - - -void function Gauntlet_ResetTrackerStats( GauntletInfo gauntlet ) -{ - gauntlet.startTime = -1 - gauntlet.runFinished = false - gauntlet.lastRunBestTime = false - gauntlet.lastRunDefeatedGhost = false - gauntlet.enemiesKilled = 0 -} - - -// ===== GHOST RECORDINGS ===== -void function Gauntlet_StartGhostPlayback( GauntletInfo gauntlet, string ghostFileName, string ghostDisplayName = "" )//, bool waitForPlayerToStartFirstRun = true ) -{ - gauntlet.signalEnt.Signal( "GhostAnimationPlayback_Start" ) - gauntlet.signalEnt.EndSignal( "GhostAnimationPlayback_Start" ) - gauntlet.signalEnt.EndSignal( "GhostAnimationPlayback_Stop" ) - gauntlet.signalEnt.EndSignal( "DisableGauntlet" ) - - GauntletGhost ghostInfo = Gauntlet_GetGhostByFileName( gauntlet, ghostFileName ) - var rec = LoadRecordedAnimation( ghostInfo.fileAsset ) - float duration = GetRecordedAnimationDuration( rec ) - printt( "duration is", duration ) - - Gauntlet_SetActiveGhostID( gauntlet, ghostInfo.id ) - - entity animRef = gauntlet.startpoint - - bool createdIdleRef = false - entity idleRef - if ( gauntlet.ghostAttractSpot != null ) - { - idleRef = gauntlet.ghostAttractSpot - } - else - { - createdIdleRef = true - idleRef = CreateScriptMover( animRef.GetOrigin(), animRef.GetAngles() ) - DropToGround( idleRef ) - } - - table<int,entity> g = {} - - OnThreadEnd( - function() : ( g, idleRef, createdIdleRef, gauntlet ) - { - if ( IsValid( g[0] ) ) - { - g[0].Anim_Stop() - StopSoundOnEntity( g[0], "PathHologram_Sustain_Loop_3P" ) - DissolveGhost( g[0] ) - } - - if ( createdIdleRef && IsValid( idleRef ) ) - idleRef.Destroy() - - Gauntlet_ClearActiveGhost( gauntlet ) - } - ) - - entity ghost - entity ghostWeapon - - bool isFirstRun = true - - while ( 1 ) - { - if ( IsValid( ghost ) ) - { - StopSoundOnEntity( ghost, "PathHologram_Sustain_Loop_3P" ) - DissolveGhost( ghost ) - } - - ghost = CreateGhost( idleRef.GetOrigin(), ghostDisplayName ) - g[0] <- ghost - //ghost.SetTitle( "Ghost Runner" ) - //ShowName( ghost ) // not working - - ghostWeapon = Ghost_GetWeaponEnt( ghost ) - ghostWeapon.kv.VisibilityFlags = ENTITY_VISIBLE_TO_NOBODY - - thread PlayAnimTeleport( ghost, "pt_OG_training_stand", idleRef ) - - if ( !gauntlet.isActive ) - gauntlet.signalEnt.WaitSignal( "Gauntlet_RunStarted" ) - - float startTime = Time() - - ghostWeapon.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE - - EmitSoundOnEntity( ghost, "PathHologram_Sustain_Loop_3P" ) - - ghost.Anim_Stop() - ghost.PlayRecordedAnimation( rec, <0,0,0>, <0,0,0>, DEFAULT_SCRIPTED_ANIMATION_BLEND_TIME, animRef ) - - thread GhostPlayback_HideGhostIfPlayerIsNear( ghost, ghostWeapon ) - - float ghostFadeTime = 1.2 - float waitBeforeFade = duration - ghostFadeTime - WaitSignalTimeout( gauntlet.signalEnt, waitBeforeFade, "Gauntlet_RunStopped" ) - - // ended prematurely - if ( Time() - startTime < waitBeforeFade ) - ghost.Anim_Stop() - - isFirstRun = false - } -} - -void function GhostPlayback_HideGhostIfPlayerIsNear( entity ghost, entity ghostWeapon ) -{ - EndSignal( ghost, "OnDestroy" ) - EndSignal( ghostWeapon, "OnDestroy" ) - - const float TICK_WAIT = 0.1 - - while ( 1 ) - { - wait TICK_WAIT - - entity nearbyPlayer - - array<entity> players = GetPlayerArray() - foreach ( player in players ) - { - if ( !IsAlive( player ) ) - continue - - if ( PlayerTooCloseToGhost( player, ghost ) ) - { - nearbyPlayer = player - break - } - } - - if ( IsValid( nearbyPlayer ) ) - { - ghost.kv.VisibilityFlags = ENTITY_VISIBLE_TO_NOBODY - ghostWeapon.kv.VisibilityFlags = ENTITY_VISIBLE_TO_NOBODY - - while ( PlayerTooCloseToGhost( nearbyPlayer, ghost ) ) - wait TICK_WAIT - - ghost.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE - ghostWeapon.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE - } - - } -} - -bool function PlayerTooCloseToGhost( entity player, entity ghost ) -{ - if ( !IsAlive( player ) ) - return false - - const float CLOSE_DIST = 64.0 - - if ( Distance( player.EyePosition(), ghost.GetOrigin() ) <= CLOSE_DIST ) - return true - - if ( Distance( player.EyePosition(), ghost.EyePosition() ) <= CLOSE_DIST ) - return true - - return false -} - -void function Gauntlet_StopGhostPlayback( GauntletInfo gauntlet ) -{ - gauntlet.signalEnt.Signal( "GhostAnimationPlayback_Stop" ) -} - - -// - Player climbs the leaderboard as her best run time improves -// - Skips challenging ghosts whose times are worse than the player's -void function Gauntlet_ChallengeLeaderboardGhosts( entity player, GauntletInfo gauntlet, string endFlag ) -{ - if ( Flag( endFlag ) ) - return - - FlagEnd( endFlag ) - - player.EndSignal( "OnDestroy" ) - gauntlet.signalEnt.EndSignal( "OnDestroy" ) - - GauntletGhost playerGhost = Gauntlet_GetPlayerGhost( gauntlet ) - - int currPlayerIdx = GAUNTLET_LEADERBOARD_MAX_ENTRIES - 1 - int nextGhostIdx = currPlayerIdx - 1 - - while ( currPlayerIdx > 0 ) - { - array<GauntletGhost> leaderboard = Gauntlet_GetLeaderboard( gauntlet ) - - // get current player leaderboard position - int maxLeaderboardIdx = leaderboard.len() - 1 - if ( currPlayerIdx >= maxLeaderboardIdx ) - currPlayerIdx = maxLeaderboardIdx - - foreach ( idx, leaderboardGhost in leaderboard ) - { - if ( leaderboardGhost.fileName == playerGhost.fileName ) - currPlayerIdx = idx - } - - // player is top of the leaderboard, stop racing ghosts - if ( currPlayerIdx <= 0 ) - break - - // if player is not top of leaderboard, cue the ghost above player leaderboard position - int nextGhostIdx = currPlayerIdx - 1 - GauntletGhost ghost = leaderboard[ nextGhostIdx ] - - Assert( ghost.fileName != GHOST_NAME_PLAYER, "Can't race against own player ghost- no anim recording asset" ) - - thread Gauntlet_StartGhostPlayback( gauntlet, ghost.fileName, ghost.displayName ) - - if ( !gauntlet.isActive ) - WaitSignal( player, "Gauntlet_RunStarted" ) - - // wait for run to stop - WaitSignal( player, "Gauntlet_RunStopped" ) - } - - Gauntlet_ClearActiveGhost( gauntlet ) - - gauntlet.allGhostsDefeated = true -} - -#if DEV -void function Gauntlet_Player_GhostRecordOrPlayback( entity player, GauntletInfo gauntlet, string ghostFileName ) -{ - if ( GetBugReproNum() == 55 ) - { - thread Gauntlet_Player_StartRecordingGhost( player, gauntlet, ghostFileName ) - } - else - { - thread Gauntlet_StartGhostPlayback( gauntlet, ghostFileName ) - - GauntletGhost ghost = Gauntlet_GetGhostByFileName( gauntlet, ghostFileName ) - Dev_PrintMessage( player, "Ghost Playback:", "TO RECORD, set bug_reproNum 55", 4.0 ) - wait 4.0 - Dev_PrintMessage( player, ghost.displayName, "TO RECORD, set bug_reproNum 55", 4.0 ) - } -} - -void function Gauntlet_Player_StartRecordingGhost( entity player, GauntletInfo gauntlet, string ghostFileName ) -{ - player.Signal( "RecordAnimation_Start" ) - player.EndSignal( "RecordAnimation_Start" ) - player.EndSignal( "OnDestroy" ) - - entity animRef = gauntlet.startpoint - GauntletGhost ghost = Gauntlet_GetGhostByFileName( gauntlet, ghostFileName ) - - thread Gauntlet_StartGhostPlayback( gauntlet, ghostFileName ) - - while ( 1 ) - { - #if PC_PROG - thread Gauntlet_Player_StartRecordingGhost_Hints( player, gauntlet, ghost ) - #endif - - printt( "READY TO RECORD:", ghost.fileName ) - - player.WaitSignal( "Gauntlet_RunStarted" ) - - player.StartRecordingAnimation( animRef.GetOrigin(), animRef.GetAngles() ) - printt( "RECORDING STARTED:", ghost.fileName ) - - player.WaitSignal( "Gauntlet_RunStopped" ) - - var recording = player.StopRecordingAnimation() - - if ( !gauntlet.runFinished ) - continue - - if ( gauntlet.enemiesKilled < gauntlet.spawners.len() ) - { - Dev_PrintMessage( player, "RECORDING NOT SAVED!", "Must kill all the enemies on your run to save.", 7.0 ) - printt( "!!!! RECORDED ANIM NOT SAVED!!!!" ) - continue - } - - #if PC_PROG - SaveRecordedAnimation( recording, ghost.fileName ) - Dev_PrintMessage( player, "Anim Data Saved", "BAKE and CLEAR BUG REPRO NUM and RELOAD LEVEL to play it back.", 5.5 ) - printt( "RECORDED ANIM SAVED:", ghost.fileName ) - - wait 5.5 - - thread Gauntlet_StartGhostPlayback( gauntlet, ghostFileName ) - #endif - } -} - -void function Gauntlet_Player_StartRecordingGhost_Hints( entity player, GauntletInfo gauntlet, GauntletGhost ghost ) -{ - player.Signal( "Player_StartRecordingGhost_HintStart" ) - player.EndSignal( "Player_StartRecordingGhost_HintStart" ) - player.EndSignal( "OnDestroy" ) - - Dev_PrintMessage( player, "Ready To Record Ghost:", "FINISH Gauntlet and kill ALL TARGETS to SAVE GHOST.", 3.0 ) - wait 3.0 - Dev_PrintMessage( player, ghost.displayName, "FINISH Gauntlet and kill ALL TARGETS to SAVE GHOST.", 5.0 ) -} -#endif //DEV
\ No newline at end of file |