aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut')
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut1183
1 files changed, 0 insertions, 1183 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut
deleted file mode 100644
index c9d986bcc..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut
+++ /dev/null
@@ -1,1183 +0,0 @@
-untyped
-
-global function ReplacementTitans_Init
-
-global function EmptyTitanPlaysAnim
-global function TryReplacementTitanReadyAnnouncement
-
-global function IsReplacementTitanAvailable
-
-global function SetTitanRespawnTimer
-global function GetTitanRespawnTimer
-global function DecrementBuildTimer
-global function ReplacementTitanTimerFinished
-global function GetAttachmentAtTimeFromModel
-global function TryETATitanReadyAnnouncement
-global function TryUpdateTitanRespawnTimerForNewTitanSelection
-global function IsReplacementDropInProgress
-
-global function req
-global function ReplacementTitan
-global function TryAnnounceTitanfallWarningToEnemyTeam
-global function GetTitanForPlayer
-
-
-global function ShouldSetTitanRespawnTimer
-
-global function PauseTitanTimers
-global function PauseTitansThink
-
-global function IsReplacementTitanAvailableForGameState
-
-global function SetReplacementTitanGamemodeRules
-global function SetRequestTitanGamemodeRules
-
-global function CreateTitanForPlayerAndHotdrop
-
-struct {
- array<int> ETATimeThresholds = [ 120, 60, 30, 15 ]
- float ETA2MinUpperBound = 123
- float ETA2MinLowerBound = 115
- float ETA60sUpperBound = 63
- float ETA60sLowerBound = 55
- float ETA30sUpperBound = 33
- float ETA30sLowerBound = 25
- float ETA15sUpperBound = 18
- float ETA15sLowerBound = 12
- float ETAAnnouncementAllowanceTime = 6.0
-
- bool buildTimerDisabled = false
-
- table warpFallDebounce = {}
-
- bool functionref( entity ) ReplacementTitanGamemodeRules
- bool functionref( entity, vector ) RequestTitanGamemodeRules
-
-} file
-
-const nagInterval = 40
-
-global const float WARPFALL_SOUND_DELAY = 1.1
-global const float WARPFALL_FX_DELAY = 0.9
-
-function ReplacementTitans_Init()
-{
- ReplacementTitansDrop_Init()
-
- RegisterSignal( "titan_impact" )
-
- RegisterSignal( "SetTitanRespawnTimer" )
- RegisterSignal( "CalledInReplacementTitan" )
-
- PrecacheEffect( TURBO_WARP_FX )
- PrecacheEffect( TURBO_WARP_COMPANY )
-
-
- AddCallback_OnClientConnecting( ReplacementTitan_InitPlayer )
- AddClientCommandCallback( "ClientCommand_RequestTitan", ClientCommand_RequestTitan )
- AddSoulDeathCallback( ResetTitanReplacementAnnouncements )
-
- level.maxTitansPerTeam <- 2
-
- if ( file.ReplacementTitanGamemodeRules == null )
- file.ReplacementTitanGamemodeRules = ReplacementTitanGamemodeRules_Default
- if ( file.RequestTitanGamemodeRules == null )
- file.RequestTitanGamemodeRules = RequestTitanGamemodeRules_Default
-
- FlagInit( "LevelHasRoof" )
-}
-
-
-void function ReplacementTitan_InitPlayer( entity player )
-{
- player.p.replacementTitanETATimer = GetTimeLimit_ForGameMode() * 60.0
-}
-
-
-bool function IsReplacementTitanAvailable( player, timeBuffer = 0 )
-{
- expect entity( player )
-
- if ( !IsReplacementTitanAvailableForGameState() )
- return false
-
- if ( player.IsTitan() )
- return false
-
- if ( IsAlive( player.GetPetTitan() ) )
- return false
-
- if ( player.isSpawning )
- return false
-
- if ( !file.ReplacementTitanGamemodeRules( player ) )
- return false
-
- switch ( Riff_TitanAvailability() )
- {
- case eTitanAvailability.Default:
- if ( player.titansBuilt == 0 )
- return true
- else
- break
-
- default:
- return Riff_IsTitanAvailable( player )
- }
-
- if ( player.IsBot() )
- return true
-
- return ReplacementTitanTimerFinished( player, timeBuffer )
-}
-
-function IsReplacementTitanAvailableForGameState()
-{
- #if HAS_GAMEMODES
- local currentGameState = GetGameState()
-
- switch ( currentGameState ) //need to add a new entry in here for every new game state we make
- {
- case eGameState.WaitingForCustomStart:
- case eGameState.WaitingForPlayers:
- case eGameState.PickLoadout:
- case eGameState.Prematch:
- case eGameState.SwitchingSides:
- case eGameState.Postmatch:
- return false
-
- case eGameState.Playing:
- case eGameState.SuddenDeath:
- return true
-
- case eGameState.WinnerDetermined:
- case eGameState.Epilogue:
- {
- if ( IsRoundBased() )
- {
- if ( !IsRoundBasedGameOver() )
- return false
-
- if ( !ShouldRunEvac() )
- return false
- }
-
- return true
- }
-
- default:
- Assert( false, "Unknown Game State: " + currentGameState )
- return false
- }
- #endif
-
- return true
-}
-
-void function SetReplacementTitanGamemodeRules( bool functionref( entity ) rules )
-{
- file.ReplacementTitanGamemodeRules = rules
-}
-
-void function SetRequestTitanGamemodeRules( bool functionref( entity, vector ) rules )
-{
- file.RequestTitanGamemodeRules = rules
-}
-
-bool function ReplacementTitanGamemodeRules_Default( entity player )
-{
- return true
-}
-
-bool function RequestTitanGamemodeRules_Default( entity player, vector origin )
-{
- return true
-}
-
-float function GetTitanRespawnTimer( entity player )
-{
- return player.GetNextTitanRespawnAvailable() - Time()
-}
-
-
-#if SP
-void function DecrementBuildTimer( entity player, float amount )
-{
- if ( !player.IsTitan() )
- return
- // core ability in use
- if ( TitanCoreInUse( player ) )
- return
-
- if ( !IsAlive( player ) )
- return
-
- SetTitanCoreTimer( player, GetTitanCoreTimer( player ) - amount )
-}
-#endif
-
-#if MP
-void function DecrementBuildTimer( entity player, float amount )
-{
- Assert( !TitanDamageRewardsTitanCoreTime() || !player.IsTitan() )
-
- amount = ModifyBuildTimeForPlayerBonuses( player, amount )
-
- bool shouldDecrementBuildTimer = true
-
- if ( player.IsTitan() )
- {
- // core ability in use
- if ( TitanCoreInUse( player ) )
- return
-
- if ( !IsAlive( player ) )
- return
- }
- else
- {
- //Don't decrement build time for Titan if already have Titan in map
- if ( player.GetPetTitan() )
- return
- }
-
- if ( player.IsTitan() )
- {
- SetTitanCoreTimer( player, GetTitanCoreTimer( player ) - amount )
- }
- else if ( shouldDecrementBuildTimer )
- {
- float remainingTime = GetTitanRespawnTimer( player )
- SetTitanRespawnTimer( player, remainingTime - amount )
- }
-}
-#endif
-
-float function ModifyBuildTimeForPlayerBonuses( entity player, float amount )
-{
- if ( PlayerHasServerFlag( player, SFLAG_FAST_BUILD2 ) )
- amount *= 2.0
- else if ( PlayerHasServerFlag( player, SFLAG_FAST_BUILD1 ) )
- amount *= 1.5
-
- return amount
-}
-
-
-void function TryUpdateTitanRespawnTimerForNewTitanSelection( entity player )
-{
- if ( GetCurrentPlaylistVarInt( "titan_build_time_use_set_file", 0 ) == 1 )
- {
- if ( ShouldSetTitanRespawnTimer( player ) )
- {
- if ( player.GetTitanBuildTime() != GetTitanBuildTime( player ) )
- {
- float timeElapsed = player.GetTitanBuildTime() - ( player.GetNextTitanRespawnAvailable() - Time() )
- ResetTitanBuildTime( player ) // update titan build time here
- float newTime = Time() + ( player.GetTitanBuildTime() - timeElapsed )
- player.SetNextTitanRespawnAvailable( max( 0, newTime ) )
- }
- }
- }
-}
-
-void function SetTitanRespawnTimer( entity player, float timeDiff )
-{
- //printt( "SetTitanRespawnTimer with timeDiff: " + timeDiff )
- if ( ShouldSetTitanRespawnTimer( player ) == false )
- return
-
- float newTime = Time() + timeDiff
- player.SetNextTitanRespawnAvailable( max( Time() - 1, newTime ) )
-
- thread WaitToAnnounceTitanETA( player, timeDiff )
-}
-
-bool function ShouldSetTitanRespawnTimer( player )
-{
- if ( Riff_TitanAvailability() == eTitanAvailability.Custom )
- return false
-
- if ( Riff_TitanAvailability() == eTitanAvailability.Default )
- return true
-
- if ( player.IsTitan() )
- return true
-
- if ( IsValid( player.GetPetTitan() ) )
- return true
-
- if ( player.GetNextTitanRespawnAvailable() < 0 )
- return false
-
- return true
-}
-
-
-
-function WaitToAnnounceTitanETA( entity player, timeDiff )
-{
- player.EndSignal( "OnDestroy" )
- player.Signal( "SetTitanRespawnTimer" )
- player.EndSignal( "SetTitanRespawnTimer" )
- player.EndSignal( "CalledInReplacementTitan" )
- player.EndSignal( "ChoseToSpawnAsTitan" )
-
- if ( timeDiff > 0 )
- wait GetTimeTillNextETAAnnouncement( player )
-
- TryETATitanReadyAnnouncement( player )
-}
-
-float function GetTimeTillNextETAAnnouncement( entity player )
-{
-// if ( !IsValid( player ) )
-// return 0
-
- float timeTillNextTitan = player.GetNextTitanRespawnAvailable() - Time()
- if ( timeTillNextTitan <= 0 )
- {
- //printt( "Waiting 0, Titan Ready" )
- return 0
- }
-
-// if ( !( "replacementTitanETATimer" in player.s ) )
-// return 0
-
- if ( timeTillNextTitan >= file.ETA2MinUpperBound && player.p.replacementTitanETATimer > 120 ) //Give some leadup time to conversation starting
- {
- //printt( "Waiting " + ( timeTillNextTitan - file.ETA2MinUpperBound ) + " till 2 min announcement" )
- return timeTillNextTitan - file.ETA2MinUpperBound
- }
-
- if ( timeTillNextTitan >= file.ETA2MinLowerBound && player.p.replacementTitanETATimer > 120 )
- {
- //printt( "Waiting 0 till 2 min announcement" )
- return 0 //Play 2 min ETA announcement immediately
- }
-
- if ( timeTillNextTitan >= file.ETA60sUpperBound && player.p.replacementTitanETATimer > 60 )
- {
- //printt( "Waiting " + ( timeTillNextTitan - file.ETA60sUpperBound ) + " till 60s announcement" )
- return timeTillNextTitan - file.ETA60sUpperBound
- }
-
- if ( timeTillNextTitan >= file.ETA60sLowerBound && player.p.replacementTitanETATimer > 60 )
- {
- //printt( "Waiting 0 till 60s announcement" )
- return 0
- }
-
- if ( timeTillNextTitan >= file.ETA30sUpperBound && player.p.replacementTitanETATimer > 30 )
- {
- //printt( "Waiting " + ( timeTillNextTitan - file.ETA30sUpperBound ) + " till 30s announcement" )
- return timeTillNextTitan - file.ETA30sUpperBound
- }
-
- if ( timeTillNextTitan >= file.ETA30sLowerBound && player.p.replacementTitanETATimer > 30 )
- {
- //printt( "Waiting 0 till 30 announcement" )
- return 0
- }
-
- if ( timeTillNextTitan >= file.ETA15sUpperBound && player.p.replacementTitanETATimer > 15 )
- {
- //printt( "Waiting " + ( timeTillNextTitan - file.ETA15sUpperBound ) + " till 15s announcement" )
- return timeTillNextTitan - file.ETA15sUpperBound
- }
-
- if ( timeTillNextTitan >= file.ETA15sLowerBound && player.p.replacementTitanETATimer > 15 )
- {
- //printt( "Waiting 0 till 15s announcement" )
- return 0
- }
-
- //printt( "Waiting " + timeTillNextTitan + " till next Titan" )
- return timeTillNextTitan
-
-
-}
-
-function TryETATitanReadyAnnouncement( entity player )
-{
- //printt( "TryETATitanReadyAnnouncement" )
- if ( !IsAlive( player ) )
- return
-
- if ( GetPlayerTitanInMap( player ) )
- return
-
- if ( player.GetNextTitanRespawnAvailable() < 0 )
- return
-
- if ( GetGameState() > eGameState.SuddenDeath )
- return
-
- if ( GameTime_PlayingTime() < 5.0 )
- return
-
- local timeTillNextTitan = player.GetNextTitanRespawnAvailable() - Time()
- //printt( "TryETATitanReadyAnnouncement timetillNextTitan: " + timeTillNextTitan )
- if ( floor(timeTillNextTitan) <= 0 )
- {
- //Titan is ready, let TryReplacementTitanReadyAnnouncement take care of it
- TryReplacementTitanReadyAnnouncement( player )
- return
- }
-
- //This entire loop is probably too complicated now for what it's doing. Simplify next game!
- //Loop might be pretty hard to read, a particular iteration of the loop is written in comments below
- for ( int i = 0; i < file.ETATimeThresholds.len(); ++i )
- {
- if ( fabs( timeTillNextTitan - file.ETATimeThresholds[ i ] ) < file.ETAAnnouncementAllowanceTime )
- {
- if ( player.p.replacementTitanETATimer > file.ETATimeThresholds[ i ] )
- {
- if ( player.titansBuilt )
- PlayConversationToPlayer( "TitanReplacementETA" + file.ETATimeThresholds[ i ] + "s" , player )
- else
- PlayConversationToPlayer( "FirstTitanETA" + file.ETATimeThresholds[ i ] + "s", player )
-
- player.p.replacementTitanETATimer = float ( file.ETATimeThresholds[ i ] )
- wait timeTillNextTitan - file.ETATimeThresholds[ i ]
- if ( IsAlive( player ) )
- SetTitanRespawnTimer( player, player.GetNextTitanRespawnAvailable() - Time() )
- return
- }
- }
- }
-
- /*if ( fabs( timeTillNextTitan - 120 ) < ETAAnnouncementAllowanceTime && player.p.replacementTitanETATimer > 120 )
- {
- if ( player.titansBuilt )
- PlayConversationToPlayer( "TitanReplacementETA120s", player )
- else
- PlayConversationToPlayer( "FirstTitanETA120s", player )
- player.p.replacementTitanETATimer = 120
- wait timeTillNextTitan - 120
- SetTitanRespawnTimer( player, player.GetNextTitanRespawnAvailable() - Time() )
- return
- }
- */
-
-}
-
-function TryReplacementTitanReadyAnnouncement( entity player )
-{
- while( true )
- {
- //printt( "TryReplacementTitanReadyAnnouncementLoop" )
- if ( !IsAlive( player ) )
- return
-
- if ( GetGameState() > eGameState.SuddenDeath )
- return
-
- if ( GetPlayerTitanInMap( player ) )
- return
-
- if ( level.nv.titanDropEnabledForTeam != TEAM_BOTH && level.nv.titanDropEnabledForTeam != player.GetTeam() )
- return
-
- if ( player.p.replacementTitanReady_lastNagTime == 0 || Time() - player.p.replacementTitanReady_lastNagTime >= nagInterval )
- {
- //Don't play Titan Replacement Announcements if you don't have it ready
- switch ( Riff_TitanAvailability() )
- {
- case eTitanAvailability.Default:
- break
-
- default:
- if ( !Riff_IsTitanAvailable( player ) )
- return
- }
-
- if ( player.titansBuilt )
- {
- PlayConversationToPlayer( "TitanReplacementReady", player )
- }
- else
- {
- PlayConversationToPlayer( "FirstTitanReady", player )
- }
- player.p.replacementTitanReady_lastNagTime = Time()
- }
-
- wait 5.0 // Once every 5 seconds should be fine
- }
-}
-
-void function ResetTitanReplacementAnnouncements( entity soul, var damageInfo )
-{
- entity player = soul.GetBossPlayer()
-
- if ( !IsValid( player ) )
- return
-
- player.p.replacementTitanETATimer = expect float( level.nv.gameEndTime )
-}
-
-function req()
-{
- ReplacementTitan( GetPlayerArray()[0] )
-}
-
-bool function ClientCommand_RequestTitan( entity player, array<string> args )
-{
- ReplacementTitan( player ) //Separate function because other functions will call ReplacementTitan
- return true
-}
-
-// This a baseline titan request function; the only things that prevent this from happening are
-// common cases; wrong gamestate, already has a titan, is currently dead, etc...
-bool function RequestTitan( entity player )
-{
- if ( !IsReplacementTitanAvailableForGameState() )
- return false
-
- if ( player.IsTitan() )
- return false
-
- if ( IsAlive( player.GetPetTitan() ) )
- return false
-
- if ( player.isSpawning )
- return false
-
- if ( !IsAlive( player ) )
- return false
-
- Point spawnPoint = GetTitanReplacementPoint( player, false )
- local origin = spawnPoint.origin
- Assert( origin )
-
- //Check titanfall request against any custom gamemode rules
- if ( !file.RequestTitanGamemodeRules( player, spawnPoint.origin ) )
- return false
-
- //if ( ShouldDoTitanfall() )
- thread CreateTitanForPlayerAndHotdrop( player, spawnPoint )
- //else
- // thread ForcePilotToBecomeTitan( player )
-
- return true
-}
-
-bool function ReplacementTitan( entity player )
-{
- if ( !IsAlive( player ) )
- {
- printt( "ReplacementTitan", player, player.entindex(), "failed", "IsAlive( player ) was false" )
- return false
- }
-
- if ( !IsReplacementTitanAvailable( player, 0 ) )
- {
- printt( "ReplacementTitan", player, player.entindex(), "failed", "IsReplacementTitanAvailable was false" )
- return false
- }
-
- entity titan = GetPlayerTitanInMap( player )
- if ( IsAlive( titan ) )
- {
- printt( "ReplacementTitan", player, player.entindex(), "failed", "GetPlayerTitanInMap was true" )
- return false
- }
-
- if ( player in file.warpFallDebounce )
- {
- if ( Time() - file.warpFallDebounce[ player ] < 3.0 )
- {
- printt( "ReplacementTitan", player, player.entindex(), "failed", "player in file.warpFallDebounce was true" )
- return false
- }
- }
-
- Point spawnPoint = GetTitanReplacementPoint( player, false )
- local origin = spawnPoint.origin
- Assert( origin )
-
- #if MP
- PIN_PlayerAbility( player, "titanfall", "titanfall", {pos = origin} )
- #endif
-
- //Check titanfall request against any custom gamemode rules
- if ( !file.RequestTitanGamemodeRules( player, spawnPoint.origin ) )
- return false
-
- #if SP
- thread CreateTitanForPlayerAndHotdrop( player, spawnPoint )
- #endif
-
- #if MP
- if ( ShouldDoTitanfall() )
- thread CreateTitanForPlayerAndHotdrop( player, spawnPoint )
- else
- thread ForcePilotToBecomeTitan( player )
- #endif
-
- return true
-}
-
-#if MP
-
-void function ForcePilotToBecomeTitan( entity player )
-{
- float fadeTime = 0.5
- float holdTime = 2.0
-
- player.EndSignal( "OnDeath" )
- player.EndSignal( "OnDestroy" )
-
- if ( GAMETYPE != SST )
- {
- #if FACTION_DIALOGUE_ENABLED
- PlayFactionDialogueToPlayer( "mp_titanInbound" , player )
- #else
- if ( player.titansBuilt )
- PlayConversationToPlayer( "TitanReplacement", player )
- else
- PlayConversationToPlayer( "FirstTitanInbound", player )
- #endif
- }
-
- player.Signal( "RodeoOver" )
- player.Signal( "ScriptAnimStop" )
-
- table<string,bool> e = {}
- e.settingsRestored <- false
-
- OnThreadEnd(
- function() : ( player, e )
- {
- if ( IsValid( player ) && !e.settingsRestored )
- {
- Rodeo_Allow( player )
- player.Show()
- player.MakeVisible()
- }
- }
- )
- Rodeo_Disallow( player )
-
- ScreenFadeToBlack( player, fadeTime, holdTime )
- player.DissolveNonLethal( ENTITY_DISSOLVE_CORE, Vector( 0, 0, 0 ), 500 )
-
- wait fadeTime
- player.SetInvulnerable()
- player.Hide()
-
- wait holdTime
- ScreenFadeFromBlack( player, 1.0, 0.5 )
- waitthread TitanPlayerHotDropsIntoLevel( player )
- e.settingsRestored = true
- Rodeo_Allow( player )
- player.Show()
- player.MakeVisible()
- player.ClearInvulnerable()
-}
-#endif
-
-bool function IsReplacementDropInProgress( entity player )
-{
- return expect bool( player.s.replacementDropInProgress )
-}
-
-void function CreateTitanForPlayerAndHotdrop( entity player, Point spawnPoint, TitanLoadoutDef ornull overrideLoadout = null )
-{
- Assert( IsValid( player ) )
-
- if ( player.isSpawning )
- {
- printt( "CreateTitanForPlayerAndHotdrop", player, player.entindex(), "failed", "player.isSpawning was true" )
- return
- }
-
- if ( player.s.replacementDropInProgress )
- {
- printt( "CreateTitanForPlayerAndHotdrop", player, player.entindex(), "failed", "player.s.replacementDropInProgress was true" )
- return
- }
-
- player.s.replacementDropInProgress = true
-
- entity titanFallDisablingEntity = CreateInfoTarget()
-
- OnThreadEnd(
- function() : ( player, titanFallDisablingEntity )
- {
- if ( IsValid( titanFallDisablingEntity ) ) //As a fail safe. Should have been cleaned up in OnThreadEnd of CleanupTitanFallDisablingEntity
- titanFallDisablingEntity.Destroy()
-
- if ( !IsValid( player ) )
- return
-
- player.s.replacementDropInProgress = false
- player.ClearHotDropImpactTime()
- }
- )
-
- player.EndSignal( "OnDestroy" )
-
- if ( GAMETYPE != SST )
- {
- #if FACTION_DIALOGUE_ENABLED
- PlayFactionDialogueToPlayer( "mp_titanInbound" , player )
- #else
- if ( player.titansBuilt )
- PlayConversationToPlayer( "TitanReplacement", player )
- else
- PlayConversationToPlayer( "FirstTitanInbound", player )
- #endif
- }
-
- vector origin = spawnPoint.origin
- vector angles
- if ( spawnPoint.angles != < 0.0, 0.0, 0.0 > )
- angles = spawnPoint.angles
- else
- angles = VectorToAngles( FlattenVector( player.GetViewVector() ) * -1 ) // face the player
-
- printt( "Dropping replacement titan at " + origin + " with angles " + angles )
-
- #if HAS_STATS
- UpdatePlayerStat( player, "misc_stats", "titanFalls" )
- #endif
- #if SERVER && MP
- PIN_AddToPlayerCountStat( player, "titanfalls" )
- #endif
-
- if ( !level.firstTitanfall )
- {
- AddPlayerScore( player, "FirstTitanfall", player )
-
- #if HAS_STATS
- UpdatePlayerStat( player, "misc_stats", "titanFallsFirst" )
- #endif
-
- level.firstTitanfall = true
- }
- else
- {
- AddPlayerScore( player, "Titanfall", player )
- }
-
-
- player.Signal( "CalledInReplacementTitan" )
-
- int playerTeam = player.GetTeam()
-
- TryAnnounceTitanfallWarningToEnemyTeam( playerTeam, origin )
-
- titanFallDisablingEntity.SetOrigin( origin )
- DisableTitanfallForLifetimeOfEntityNearOrigin( titanFallDisablingEntity, origin, TITANHOTDROP_DISABLE_ENEMY_TITANFALL_RADIUS )
-
- entity titan
- string animation
-
- string regularTitanfallAnim = "at_hotdrop_drop_2knee_turbo"
-
- TitanLoadoutDef loadout
- if ( overrideLoadout == null )
- {
- loadout = GetTitanLoadoutForPlayer( player )
- }
- else
- {
- loadout = expect TitanLoadoutDef( overrideLoadout )
- }
- bool hasWarpfall = loadout.passive3 == "pas_warpfall"
- if ( hasWarpfall || Flag( "LevelHasRoof" ) )
- {
- ClearTitanAvailable( player ) //Normally this is done when the Titan is spawned, but for warpfall the Titan isn't spawned instaneously after requesting it.
-
- file.warpFallDebounce[ player ] <- Time()
- animation = "at_hotdrop_drop_2knee_turbo_upgraded"
- string settings = loadout.setFile
- asset model = GetPlayerSettingsAssetForClassName( settings, "bodymodel" )
- Attachment warpAttach = GetAttachmentAtTimeFromModel( model, animation, "offset", origin, angles, 0 )
-
- entity fakeTitan = CreatePropDynamic( model )
- float impactTime = GetHotDropImpactTime( fakeTitan, animation )
-
- float diff = 0.0
-
- if ( !hasWarpfall ) // this means the level requested the warpfall
- {
- float regularImpactTime = GetHotDropImpactTime( fakeTitan, regularTitanfallAnim ) - (WARPFALL_SOUND_DELAY + WARPFALL_FX_DELAY)
- diff = ( regularImpactTime - impactTime )
- impactTime = regularImpactTime
- }
-
- fakeTitan.Kill_Deprecated_UseDestroyInstead()
-
- local impactStartTime = Time()
- impactTime += (WARPFALL_SOUND_DELAY + WARPFALL_FX_DELAY)
- player.SetHotDropImpactDelay( impactTime )
- Remote_CallFunction_Replay( player, "ServerCallback_ReplacementTitanSpawnpoint", origin.x, origin.y, origin.z, Time() + impactTime )
-
- EmitDifferentSoundsAtPositionForPlayerAndWorld( "Titan_1P_Warpfall_CallIn", "Titan_3P_Warpfall_CallIn", origin, player, playerTeam )
-
- wait diff
-
- wait WARPFALL_SOUND_DELAY
-
- // "Titan_1P_Warpfall_Start" - for first person warp calls, starting right on the button press
- // "Titan_3P_Warpfall_Start" - for any 3P other player or NPC when they call in a warp, starting right on their button press
- EmitSoundAtPositionOnlyToPlayer( playerTeam, origin, player, "Titan_1P_Warpfall_Start" )
- EmitSoundAtPositionExceptToPlayer( playerTeam, origin, player, "Titan_3P_Warpfall_Start" )
-
- PlayFX( TURBO_WARP_FX, warpAttach.position + Vector(0,0,-104), warpAttach.angle )
-
- wait WARPFALL_FX_DELAY
-
- titan = CreateAutoTitanForPlayer_FromTitanLoadout( player, loadout, origin, angles )
- DispatchSpawn( titan )
- thread PlayFXOnEntity( TURBO_WARP_COMPANY, titan, "offset" )
- }
- else
- {
- animation = regularTitanfallAnim
-
- titan = CreateAutoTitanForPlayer_FromTitanLoadout( player, loadout, origin, angles )
- DispatchSpawn( titan )
-
- float impactTime = GetHotDropImpactTime( titan, animation )
- player.SetHotDropImpactDelay( impactTime )
- Remote_CallFunction_Replay( player, "ServerCallback_ReplacementTitanSpawnpoint", origin.x, origin.y, origin.z, Time() + impactTime )
- }
-
- SetActiveTitanLoadoutIndex( player, GetPersistentSpawnLoadoutIndex( player, "titan" ) )
- #if MP
- SetActiveTitanLoadout( player )
- #endif
- if ( player in file.warpFallDebounce )
- delete file.warpFallDebounce[ player ]
-
- titan.EndSignal( "OnDeath" )
- Assert( IsAlive( titan ) )
-
- // dont let AI titan get enemies while dropping. Don't do trigger checks
- titan.SetEfficientMode( true )
- titan.SetTouchTriggers( false )
- titan.SetNoTarget( true )
- titan.SetAimAssistAllowed( false )
-
-#if R1_VGUI_MINIMAP
- thread PingMinimapDuringHotdrop( player, titan, origin )
-#endif
-
- thread CleanupTitanFallDisablingEntity( titanFallDisablingEntity, titan ) //needs to be here after titan is created
- waitthread PlayersTitanHotdrops( titan, origin, angles, player, animation ) //Note that this function returns after the titan has played the landing anim, not when the titan hits the ground
-
- titan.SetEfficientMode( false )
- titan.SetTouchTriggers( true )
- titan.SetAimAssistAllowed( true )
-
- player.Signal( "titan_impact" )
-
- thread TitanNPC_WaitForBubbleShield_StartAutoTitanBehavior( titan )
-}
-
-void function CleanupTitanFallDisablingEntity( entity titanFallDisablingEntity, entity titan )
-{
- titanFallDisablingEntity.EndSignal( "OnDestroy" ) //titanFallDisablingEntity can be destroyed multiple ways
- titan.EndSignal( "ClearDisableTitanfall" ) //This is awkward, CreateBubbleShield() and OnHotDropImpact() signals this to deestroy CleanupTitanFallDisablingEntity
- titan.EndSignal( "OnDestroy" )
-
- OnThreadEnd(
- function() : ( titanFallDisablingEntity )
- {
- if( IsValid( titanFallDisablingEntity ) )
- titanFallDisablingEntity.Destroy()
-
- }
- )
-
- WaitForever()
-}
-
-void function DrawReplacementTitanLocation( entity player, vector origin, float delay )
-{
- // have to keep resending this info because a dead player won't see it
- player.EndSignal( "OnDestroy" )
- float endTime = Time() + delay
-
- for ( ;; )
- {
- if ( !IsAlive( player ) )
- {
- player.WaitSignal( "OnRespawned" )
- continue
- }
-
- float remainingTime = endTime - Time()
- if ( remainingTime <= 0 )
- return
-
- player.SetHotDropImpactDelay( remainingTime )
- Remote_CallFunction_Replay( player, "ServerCallback_ReplacementTitanSpawnpoint", origin.x, origin.y, origin.z, Time() + remainingTime )
- player.WaitSignal( "OnDeath" )
- }
-}
-
-void function TryAnnounceTitanfallWarningToEnemyTeam( int team, vector origin )
-{
- float innerDistance = TITANFALL_OUTER_RADIUS * TITANFALL_OUTER_RADIUS
- float outerDistance = innerDistance * 4.0
-
- array<entity> enemies = GetPlayerArrayOfEnemies( team )
- foreach ( entity enemyPlayer in enemies )
- {
- float distSqr = DistanceSqr( origin, enemyPlayer.GetOrigin() )
- if ( distSqr > outerDistance )
- continue
-
- if ( distSqr < innerDistance )
- Remote_CallFunction_NonReplay( enemyPlayer, "ServerCallback_TitanFallWarning", true )
- else
- Remote_CallFunction_NonReplay( enemyPlayer, "ServerCallback_TitanFallWarning", false )
- }
-}
-
-TitanSettings function GetTitanForPlayer( entity player )
-{
- string ornull currentTitanSettings
- array<string> currentTitanMods
-
- if ( player.IsBot() )
- {
- string botTitanSettings = GetConVarString( "bot_titan_settings" )
- array<string> legalLoadouts = GetAllowedTitanSetFiles()
- if ( legalLoadouts.contains( botTitanSettings ) )
- currentTitanSettings = botTitanSettings
- else
- currentTitanSettings = legalLoadouts.getrandom()
- }
-
- if ( currentTitanSettings == null )
- {
- TitanLoadoutDef loadout = GetTitanLoadoutForPlayer( player )
- currentTitanSettings = loadout.setFile
- foreach ( mod in loadout.setFileMods )
- {
- currentTitanMods.append( mod )
- }
- }
-
- if ( DebugNewTitanModels() )
- {
- switch ( currentTitanSettings )
- {
- case "titan_atlas":
- currentTitanSettings = "titan_medium_ajax"
- break
- case "titan_stryder":
- currentTitanSettings = "titan_light_locust"
- break
- case "titan_ogre":
- currentTitanSettings = "titan_heavy_ogre"
- break
- }
- }
-
- TitanSettings titanSettings
- titanSettings.titanSetFile = expect string( currentTitanSettings )
- titanSettings.titanSetFileMods = currentTitanMods
- return titanSettings
-}
-
-Attachment function GetAttachmentAtTimeFromModel( asset model, string animation, string attachment, vector origin, vector angles, float time )
-{
- entity dummy = CreatePropDynamic( model, origin, angles )
- Attachment start = dummy.Anim_GetAttachmentAtTime( animation, attachment, time )
- dummy.Destroy()
- return start
-}
-
-#if R1_VGUI_MINIMAP
-function PingMinimapDuringHotdrop( player, titan, impactOrigin )
-{
- expect entity( player )
- expect entity( titan )
-
- player.EndSignal( "titan_impact" )
- player.EndSignal( "OnDestroy" )
- titan.EndSignal( "OnDeath" )
-
- titan.Minimap_Hide( TEAM_IMC, null )
- titan.Minimap_Hide( TEAM_MILITIA, null )
-
- OnThreadEnd(
- function() : ( player, titan )
- {
- if ( !IsAlive( titan ) )
- return
-
- titan.Minimap_DisplayDefault( TEAM_IMC, null )
- titan.Minimap_DisplayDefault( TEAM_MILITIA, null )
- }
- )
-
- while ( true )
- {
- Minimap_CreatePingForPlayer( player, impactOrigin, $"vgui/HUD/threathud_titan_friendlyself", 0.5 )
- wait 0.4
- }
-}
-#endif
-
-function EmptyTitanPlaysAnim( titan )
-{
- local idleAnimAlias = "at_atlas_getin_idle"
- if ( titan.HasKey( "idleAnim" ) )
- idleAnimAlias = titan.GetValueForKey( "idleAnim" )
-
- thread PlayAnim( titan, idleAnimAlias )
-}
-
-function FreeSpawnpointOnEnterTitan( spawnpoint, titan )
-{
- titan.EndSignal( "OnDestroy" )
- titan.EndSignal( "TitanEntered" )
-
- OnThreadEnd(
- function() : ( spawnpoint, titan )
- {
- Assert( IsValid( titan ) )
- spawnpoint.e.spawnPointInUse = false
- }
- )
-
- titan.WaitSignal( "TitanBeingEntered" )
-}
-
-
-function DebugText( origin, text, time )
-{
- local endTime = Time() + time
-
- while( Time() < endTime )
- {
- DebugDrawText( origin, text, true, 1.0 )
- wait 1
- }
-}
-
-
-
-bool function ReplacementTitanTimerFinished( player, timeBuffer = 0 )
-{
- local nextTitanTime = player.GetNextTitanRespawnAvailable()
- if ( nextTitanTime < 0 )
- return false
-
- return nextTitanTime - Time() <= timeBuffer
-}
-
-
-struct
-{
- float titanTimerPauseTime = 0
- table<entity, float> playerPauseStartTimes
-
-} protoFile
-
-
-void function PauseTitansThink()
-{
- bool titan
- while ( true )
- {
- array<entity> players = GetPlayerArray()
-
- bool foundTitan = false
- foreach ( player in players )
- {
- if ( player.IsTitan() || IsValid( player.GetPetTitan() ) )
- {
- foundTitan = true
- break
- }
- }
-
- if ( foundTitan && protoFile.titanTimerPauseTime == 0 )
- thread PauseTitanTimers()
- else if ( !foundTitan && protoFile.titanTimerPauseTime != 0 )
- thread PauseTitanTimers()
-
- WaitFrame()
- }
-}
-
-
-void function PauseTitanTimers()
-{
- RegisterSignal( "PauseTitanTimers" )
- svGlobal.levelEnt.Signal( "PauseTitanTimers" )
- svGlobal.levelEnt.EndSignal( "PauseTitanTimers" )
-
- if ( protoFile.titanTimerPauseTime != 0 )
- {
- protoFile.playerPauseStartTimes = {}
- protoFile.titanTimerPauseTime = 0
- return
- }
-
- protoFile.titanTimerPauseTime = Time()
- float lastTime = Time()
-
- while ( true )
- {
- array<entity> players = GetPlayerArray()
-
- float addTime = Time() - protoFile.titanTimerPauseTime
-
- foreach ( player in players )
- {
- if ( player.IsTitan() )
- {
- if ( player in protoFile.playerPauseStartTimes )
- delete protoFile.playerPauseStartTimes[player]
-
- continue
- }
-
- if ( IsValid( player.GetPetTitan() ) )
- {
- if ( player in protoFile.playerPauseStartTimes )
- delete protoFile.playerPauseStartTimes[player]
-
- continue
- }
-
- if ( Time() > player.GetNextTitanRespawnAvailable() )
- {
- if ( player in protoFile.playerPauseStartTimes )
- delete protoFile.playerPauseStartTimes[player]
-
- continue
- }
-
- if ( !(player in protoFile.playerPauseStartTimes) )
- {
- protoFile.playerPauseStartTimes[player] <- player.GetNextTitanRespawnAvailable()
- }
-
- protoFile.playerPauseStartTimes[player] += Time() - lastTime
-
- player.SetNextTitanRespawnAvailable( protoFile.playerPauseStartTimes[player] )
- }
-
- lastTime = Time()
- wait 0.1
- }
-}
-
-bool function ShouldDoTitanfall()
-{
- if ( svGlobal.forceDisableTitanfalls )
- return false
-
- return ( GetCurrentPlaylistVarInt( "enable_titanfalls", 1 ) == 1 )
-} \ No newline at end of file