aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/titan
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/titan')
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_battery_generator.gnut128
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans.gnut1183
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans_drop.gnut443
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_titan_commands.gnut49
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_titan_health.gnut1072
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_titan_hints.gnut267
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_titan_hotdrop.gnut778
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/_titan_triple_health.gnut524
-rw-r--r--Northstar.CustomServers/scripts/vscripts/titan/class_titan.gnut77
9 files changed, 0 insertions, 4521 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_battery_generator.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_battery_generator.gnut
deleted file mode 100644
index 567ad6e74..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_battery_generator.gnut
+++ /dev/null
@@ -1,128 +0,0 @@
-global function InitDestroyableGenerator
-global function ClearGenerators
-
-const GENERATOR_HEALTH = 200
-
-const MODEL_DESTROYED_GENERATOR = $"models/beacon/charge_generator_01_destroyed.mdl"
-const FX_GENERATOR_EXP = $"P_generator_exp"
-
-struct
-{
- array<entity> generators
-} file
-
-void function InitDestroyableGenerator()
-{
- AddSpawnCallbackEditorClass( "script_ref", "script_battery_generator", SpawnPropGenerator )
- AddSpawnCallback_ScriptName( "prop_battery_generator", PropBatteryGeneratorThink )
-
- PrecacheModel( MODEL_GENERATOR )
- PrecacheModel( MODEL_DESTROYED_GENERATOR )
- PrecacheParticleSystem( FX_GENERATOR_EXP )
-}
-
-void function SpawnPropGenerator( entity generatorRef )
-{
- entity generator = CreatePropScript( MODEL_GENERATOR, generatorRef.GetOrigin(), generatorRef.GetAngles(), 6 )
- thread PropBatteryGeneratorThink( generator )
- generatorRef.Destroy()
-}
-
-void function PropBatteryGeneratorThink( entity generator )
-{
- SetObjectCanBeMeleed( generator, true )
- SetVisibleEntitiesInConeQueriableEnabled( generator, true )
- generator.SetTakeDamageType( DAMAGE_EVENTS_ONLY )
- generator.SetDamageNotifications( true )
- generator.SetMaxHealth( GENERATOR_HEALTH )
- generator.SetHealth( GENERATOR_HEALTH )
- generator.DisableHibernation()
- AddEntityCallback_OnDamaged( generator, GeneratorOnDamage )
-
- entity trigger = CreateEntity( "trigger_cylinder" )
- trigger.SetRadius( 150 )
- trigger.SetAboveHeight( 150 )
- trigger.SetBelowHeight( 150 ) //i.e. make the trigger a sphere as opposed to a cylinder
- trigger.SetOrigin( generator.GetOrigin() )
- trigger.SetParent( generator )
- DispatchSpawn( trigger )
- trigger.SetEnterCallback( GeneratorTriggerThink )
-
-
- file.generators.append( generator )
-}
-
-void function GeneratorTriggerThink( entity trigger, entity ent )
-{
- if ( ent.IsTitan() || IsSuperSpectre( ent ) )
- {
- entity generator = trigger.GetParent()
-
- if ( generator != null )
- {
- GeneratorDestroy( generator )
- }
- }
-}
-
-void function GeneratorOnDamage( entity generator, var damageInfo )
-{
- if ( !IsValid( generator ) )
- {
- // sometimes OnDamage gets called twice in the same frame, ( scorch's fire )
- // and first call destroys generator in GeneratorDestroy()
- return
- }
-
- float damage = DamageInfo_GetDamage( damageInfo )
-
- int health = generator.GetHealth()
- health -= int( damage )
-
- if ( health <= 0 )
- GeneratorDestroy( generator )
- else
- generator.SetHealth( health )
-}
-
-void function GeneratorDestroy( entity generator )
-{
- int solidType = 6 //phys collision
- entity destroyedProp = CreatePropDynamic( MODEL_DESTROYED_GENERATOR, generator.GetOrigin(), generator.GetAngles(), solidType )
- if ( generator.GetParent() )
- destroyedProp.SetToSameParentAs( generator )
-
- destroyedProp.AllowMantle()
- destroyedProp.DisableHibernation()
- int fxID = GetParticleSystemIndex( FX_GENERATOR_EXP )
- vector origin = generator.GetOrigin()
- vector up = generator.GetUpVector()
-
- EmitSoundOnEntity( destroyedProp, "BatteryCrate_Explosion" )
- StartParticleEffectOnEntity( destroyedProp, fxID, FX_PATTACH_ABSORIGIN_FOLLOW, -1 )
-
- entity battery = CreateTitanBattery( origin + ( up * 40 ) )
- battery.DisableHibernation()
-
- //throw out the battery
- vector right = generator.GetRightVector() * RandomFloatRange( -0.5, 0.5 )
- vector forward = generator.GetForwardVector() * RandomFloatRange( -0.5, 0.5 )
- vector velocity = Normalize( up + right + forward ) * 10
-
- //for moving geo
- vector parentVelocity = generator.GetVelocity()
-
- battery.SetVelocity( velocity + parentVelocity )
-
- file.generators.fastremovebyvalue( generator )
- generator.Destroy()
-}
-
-void function ClearGenerators()
-{
- foreach ( g in file.generators )
- {
- g.Destroy()
- }
- file.generators = []
-} \ No newline at end of file
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
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans_drop.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans_drop.gnut
deleted file mode 100644
index 5970f7eab..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_replacement_titans_drop.gnut
+++ /dev/null
@@ -1,443 +0,0 @@
-global function ReplacementTitansDrop_Init
-global function GetTitanReplacementPoint
-global function HullTraceDropPoint
-global function DebugTitanSpawn
-global function TitanFindDropNodes
-global function TitanHulldropSpawnpoint
-
-global const TITANDROP_LOS_DIST = 2000 // 2D distance at which we do the line of sight check to see where the player wants to call in the titan
-global const TITANDROP_MIN_FOV = 10
-global const TITANDROP_MAX_FOV = 80
-global const TITANDROP_FOV_PENALTY = 8
-global const TITANDROP_PATHNODESEARCH_EXACTDIST = 500 // within this distance, we use the position the player is looking for the pathnode search
-global const TITANDROP_PATHNODESEARCH_DISTFRAC = 0.8 // beyond that distance, we use this fraction of how far the player is looking.
-global const TITANDROP_GROUNDSEARCH_ZDIR = -1.0 // if the player's not looking at anything, we search downward for ground at this slope
-global const TITANDROP_GROUNDSEARCH_FORWARDDIST = 350 // if the player's not looking at anything, we search for ground starting this many units in front of the player
-global const TITANDROP_GROUNDSEARCH_DIST = 1000 // if the player's not looking at anything, we search for ground this many units forward (max)
-global const TITANDROP_FALLBACK_DIST = 150 // if the ground search hits, we go this many units forward from it
-
-struct
-{
- int replacementSpawnpointsID
-} file
-
-void function ReplacementTitansDrop_Init()
-{
- AddSpawnCallback( "info_spawnpoint_titan", AddDroppoint )
- AddSpawnCallback( "info_spawnpoint_titan_start", AddDroppoint )
- AddSpawnCallback( "info_replacement_titan_spawn", AddDroppoint )
-
- AddCallback_EntitiesDidLoad( EntitiesDidLoad )
- file.replacementSpawnpointsID = CreateScriptManagedEntArray()
-}
-
-void function EntitiesDidLoad()
-{
-}
-
-
-void function AddDroppoint( entity ent )
-{
- AddToScriptManagedEntArray( file.replacementSpawnpointsID, ent )
-}
-
-void function DebugTitanSpawn()
-{
- thread DebugTitanSpawnThread()
-}
-
-void function DebugTitanSpawnThread()
-{
- entity player = GetPlayerArray()[0]
-
- float interval = 0.1
-
- FlightPath flightPath = GetAnalysisForModel( GetFlightPathModel( "fp_titan_model" ), HOTDROP_TURBO_ANIM )
- int dataIndex = GetAnalysisDataIndex( flightPath )
-
- for ( ;; )
- {
- if ( !IsValid( player ) )
- {
- wait interval
- continue
- }
-
- vector playerOrg = player.GetOrigin()
- vector playerEyeForward = player.GetViewVector()
- vector playerEyePos = player.EyePosition()
- vector playerEyeAngles = player.EyeAngles()
- float yaw = playerEyeAngles.y
- vector ornull desiredPos = GetReplacementTrace( playerEyePos, playerEyeForward )
- vector pathNodeSearchPos
- if ( desiredPos == null )
- {
- pathNodeSearchPos = GetPathNodeSearchPos( playerOrg, playerEyePos, playerEyeForward, true )
- }
- else
- {
- expect vector( desiredPos )
- DebugDrawCircle( desiredPos, Vector(0,0,0), 10, 128, 255, 128, true, interval )
- DebugDrawText( desiredPos + Vector(0,0,60), "Looking here", false, interval )
- pathNodeSearchPos = GetPathNodeSearchPosWithLookPos( playerOrg, playerEyePos, playerEyeForward, desiredPos, true )
- }
-
- DebugDrawCircle( pathNodeSearchPos, Vector(0,0,0), 10, 128, 128, 255, true, interval )
- DebugDrawText( pathNodeSearchPos + Vector(0,0,40), "Searching from here", false, interval )
-
- DebugDrawLine( playerOrg, playerOrg + AnglesToForward( Vector( 0, yaw - TITANDROP_MIN_FOV, 0 ) ) * 500, 200, 200, 200, true, interval )
- DebugDrawLine( playerOrg, playerOrg + AnglesToForward( Vector( 0, yaw + TITANDROP_MIN_FOV, 0 ) ) * 500, 200, 200, 200, true, interval )
- DebugDrawLine( playerOrg, playerOrg + AnglesToForward( Vector( 0, yaw - TITANDROP_MAX_FOV, 0 ) ) * 500, 128, 128, 128, true, interval )
- DebugDrawLine( playerOrg, playerOrg + AnglesToForward( Vector( 0, yaw + TITANDROP_MAX_FOV, 0 ) ) * 500, 128, 128, 128, true, interval )
-
- int node = GetBestNodeForPosInWedge( pathNodeSearchPos, playerEyePos, yaw, TITANDROP_MIN_FOV, TITANDROP_MAX_FOV, TITANDROP_FOV_PENALTY, dataIndex, /*ANALYSIS_STEPS*/ 8 )
-
- if ( node >= 0 )
- {
- Assert( NodeHasFlightPath( dataIndex, node ) )
-
- vector pos = GetNodePos( node )
- DebugDrawCircle( pos, Vector(0,0,0), 25, 255, 255, 128, true, interval )
- DebugDrawText( pos + Vector(0,0,20), "Best node", false, interval )
- }
-
- Point actualResult = GetTitanReplacementPoint( player, true )
- vector actualPos = actualResult.origin
- DebugDrawCircle( actualPos, Vector(0,0,0), 32, 255, 255, 255, true, interval )
- DebugDrawLine( actualPos, actualPos + AnglesToForward( actualResult.angles ) * 40, 255, 255, 255, true, interval )
- DebugDrawText( actualPos, "Final location", false, interval )
-
- wait interval
- }
-}
-
-Point function GetTitanReplacementPoint( entity player, bool forDebugging = false )
-{
- vector playerEyePos = player.EyePosition()
- vector playerEyeAngles = player.EyeAngles()
- vector playerOrg = player.GetOrigin()
-
- return CalculateTitanReplacementPoint( playerOrg, playerEyePos, playerEyeAngles, forDebugging )
-}
-
-Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEyePos, vector playerEyeAngles, bool forDebugging = false )
-{
- //local playerEyePos = Vector(-281.036224, 34.857925, 860.031250)
- //local playerEyeAngles = Vector(60.055622, 80.775780, 0.000000)
- //local playerOrg = Vector(-281.036224, 34.857925, 800.031250)
-
- if ( !forDebugging )
- printt( "Requested replacement Titan from eye pos " + playerEyePos + " view angles " + playerEyeAngles + " player origin " + playerOrg + " map " + GetMapName() )
-
- vector playerEyeForward = AnglesToForward( playerEyeAngles )
-
- // use the flightPath to find a position
- FlightPath flightPath = GetAnalysisForModel( GetFlightPathModel( "fp_titan_model" ), HOTDROP_TURBO_ANIM )
- int dataIndex = GetAnalysisDataIndex( flightPath )
-
- var dropPoint
- vector ornull traceOrigin = GetReplacementTrace( playerEyePos, playerEyeForward )
- bool traceOriginIsNull = traceOrigin == null
-
- if ( !traceOriginIsNull )
- {
- expect vector( traceOrigin )
-
- dropPoint = TitanHulldropSpawnpoint( flightPath, traceOrigin, 0 )
- if ( dropPoint != null && !NearTitanfallBlocker( dropPoint ) )
- {
- expect vector( dropPoint )
- if ( EdgeTraceDropPoint( dropPoint ) )
- {
- if ( SafeForTitanFall( dropPoint ) && TitanTestDropPoint( dropPoint, flightPath ) )
- {
- vector yawVec = playerEyePos - dropPoint
- vector yawAngles = VectorToAngles( yawVec )
- yawAngles.x = 0
- yawAngles.z = 0
- // add some randomness
- yawAngles.y += RandomFloatRange( -60, 60 )
- if ( yawAngles.y < 0 )
- yawAngles.y += 360
- else if ( yawAngles.y > 360 )
- yawAngles.y -= 360
-
- Point point
- point.origin = dropPoint
- point.angles = yawAngles
- return point
- }
- }
- }
- }
-
- vector pathNodeSearchPos
- if ( !traceOriginIsNull )
- {
- expect vector( traceOrigin )
- pathNodeSearchPos = GetPathNodeSearchPosWithLookPos( playerOrg, playerEyePos, playerEyeForward, traceOrigin, false )
- }
- else
- {
- pathNodeSearchPos = GetPathNodeSearchPos( playerOrg, playerEyePos, playerEyeForward, false )
- }
-
- int node = GetBestNodeForPosInWedge( pathNodeSearchPos, playerEyePos, playerEyeAngles.y, TITANDROP_MIN_FOV, TITANDROP_MAX_FOV, TITANDROP_FOV_PENALTY, dataIndex, /*ANALYSIS_STEPS*/ 8 )
-
- if ( node < 0 )
- {
- // This won't ever happen on a map with any reasonably placed path nodes.
- entity spawner = FindSpawnpoint_ForReplacementTitan( playerOrg )
- Assert( spawner )
- Point point
- point.origin = spawner.GetOrigin()
- return point
- }
-
- Assert( NodeHasFlightPath( dataIndex, node ) )
-
- vector nodeOrigin = GetNodePos( node )
- vector dir = nodeOrigin - playerEyePos
- vector angles = VectorToAngles( dir )
- float yaw = angles.y + 180
-
- if ( yaw < 0 )
- yaw += 360
- else if ( yaw > 360 )
- yaw -= 360
-
- var yawResult = GetSpawnPoint_ClosestYaw( node, dataIndex, yaw, 360.0 )
- Assert( yawResult != null )
- yaw = expect float( yawResult )
- Assert( yaw >= 0 )
- Assert( yaw <= 360 )
-
- Point point
- point.origin = nodeOrigin
- point.angles = Vector( 0, yaw, 0 )
- return point
-}
-
-vector function GetPathNodeSearchPosWithLookPos( vector playerOrg, vector playerEyePos, vector playerEyeForward, vector playerLookPos, bool debug )
-{
- float dist2DSqr = Distance2DSqr( playerOrg, playerLookPos )
- if ( dist2DSqr > (TITANDROP_PATHNODESEARCH_EXACTDIST / TITANDROP_PATHNODESEARCH_DISTFRAC) * (TITANDROP_PATHNODESEARCH_EXACTDIST / TITANDROP_PATHNODESEARCH_DISTFRAC) )
- {
- return playerOrg + (playerLookPos - playerOrg) * TITANDROP_PATHNODESEARCH_DISTFRAC
- }
- else if ( dist2DSqr > TITANDROP_PATHNODESEARCH_EXACTDIST * TITANDROP_PATHNODESEARCH_EXACTDIST )
- {
- vector dir = Normalize( playerLookPos - playerOrg )
- return playerOrg + dir * TITANDROP_PATHNODESEARCH_EXACTDIST
- }
- else
- {
- return playerLookPos
- }
-
- unreachable
-}
-
-vector function GetPathNodeSearchPos( vector playerOrg, vector playerEyePos, vector playerEyeForward, bool debug )
-{
- vector diagonallyDown = Normalize( <playerEyeForward.x, playerEyeForward.y, 0> )
- diagonallyDown.z = TITANDROP_GROUNDSEARCH_ZDIR
-
- vector startPos = playerEyePos + playerEyeForward * TITANDROP_GROUNDSEARCH_FORWARDDIST
- vector endPos = startPos + diagonallyDown * TITANDROP_GROUNDSEARCH_DIST
-
- TraceResults result = TraceLine( startPos, endPos, null, TRACE_MASK_SOLID_BRUSHONLY, TRACE_COLLISION_GROUP_NONE )
-
- if ( debug )
- {
- DebugDrawLine( playerEyePos, startPos, 128,128,200, true, 0.1 )
- DebugDrawLine( startPos, result.endPos, 128,128,200, true, 0.1 )
- if ( result.fraction < 1 )
- DebugDrawLine( result.endPos, result.endPos + playerEyeForward * TITANDROP_FALLBACK_DIST, 128,128,200, true, 0.1 )
- }
-
- if ( result.fraction < 1 )
- return result.endPos + playerEyeForward * TITANDROP_FALLBACK_DIST
-
- return playerEyePos + playerEyeForward * TITANDROP_FALLBACK_DIST
-}
-
-// Returns a position vector or null
-vector ornull function GetReplacementTrace( vector startPos, vector viewVector )
-{
- float viewDirLen2D = Length2D( viewVector )
- if ( viewDirLen2D < 0.1 )
- viewDirLen2D = 0.1
-
- vector endPos = startPos + ( viewVector * ( TITANDROP_LOS_DIST / viewDirLen2D ) )
- int mask = TRACE_MASK_SOLID & (~CONTENTS_WINDOW)
- TraceResults result = TraceLine( startPos, endPos, null, mask, TRACE_COLLISION_GROUP_NONE )
- //DebugDrawLine( result.endPos, endPos, 255, 0, 0, true, 20.0 )
- //DebugDrawLine( startPos, result.endPos, 0, 255, 0, true, 20.0 )
-
- if ( result.fraction == 1 )
- return null
-
- entity hitEnt = result.hitEnt
- if ( IsValid( hitEnt ) && ( hitEnt.IsTitan() || hitEnt.IsPlayer() || hitEnt.IsNPC() ) )
- {
- endPos = OriginToGround( hitEnt.GetOrigin() )
- }
- else
- {
- endPos = result.endPos
-
- if ( result.surfaceNormal.Dot( <0.0, 0.0, 1.0> ) < 0.7 )
- {
- //DebugDrawLine( endPos, Vector(0,0,0), 0, 200, 0, true, 5.0 )
- // pull it back towards player
- float titanRadius = GetBoundsMax( HULL_TITAN ).x * 1.2
- endPos -= viewVector * titanRadius
- endPos += result.surfaceNormal * titanRadius
-
- endPos = OriginToGround( endPos )
- }
- }
-
- vector ornull clampedEndPos = NavMesh_ClampPointForHullWithExtents( endPos, HULL_TITAN, <160.0, 160.0, 80.0> )
-
- if ( !clampedEndPos )
- return null
-
- expect vector( clampedEndPos )
-
- vector dir = clampedEndPos - startPos
- if ( DotProduct2D( dir, viewVector ) < 0 )
- return null
-
- return clampedEndPos
-}
-
-var function HullTraceDropPoint( FlightPath flightPath, vector baseOrigin, float heightCapMax = 190 )
-{
- float heightCapMin = -512
- vector startOrigin = baseOrigin + Vector( 0,0,1000 )
- vector endOrigin = baseOrigin + Vector( 0,0, heightCapMin )
-
- int mask = flightPath.traceMask
-
- TraceResults result = TraceHull( startOrigin, endOrigin, flightPath.mins, flightPath.maxs, null, mask, TRACE_COLLISION_GROUP_NONE )
- //DebugDrawLine( startOrigin, result.endPos, 0, 255, 0, true, 5.0 )
- //DebugDrawLine( result.endPos, endOrigin, 255, 0, 0, true, 5.0 )
-
-// DebugDrawLine( startOrigin, baseOrigin, 0, 255, 0, true, 5.0 )
-// DebugDrawLine( baseOrigin, endOrigin, 255, 0, 0, true, 5.0 )
-// local offset = Vector(0.15, 0.15, 0.0 )
-// DebugDrawLine( startOrigin + offset, result.endPos + offset, 0, 255, 0, true, 5.0 )
-// DebugDrawLine( result.endPos + offset, endOrigin + offset, 255, 0, 0, true, 5.0 )
-// DrawArrow( baseOrigin, Vector(0,0,0), 5.0, 50 )
-// DebugDrawLine( result.endPos, baseOrigin, 255, 255, 255, true, 4.5 )
-
-/*
- printt( " " )
- printt( "Hull drop " )
- printt( "start " + startOrigin )
- printt( "end " + endOrigin )
- printt( "hit " + result.endPos )
- printt( "mins " + flightPath.mins + " maxs " + flightPath.maxs )
- printt( "mask " + mask )
-*/
- if ( result.allSolid || result.startSolid || result.hitSky )
- return null
-
- if ( result.fraction == 0 || result.fraction == 1 )
- return null
-
- if ( fabs( result.endPos.z - baseOrigin.z ) > heightCapMax )
- return null
-
- return result.endPos
-}
-
-
-entity function FindSpawnpoint_ForReplacementTitan( vector origin )
-{
- Assert( GetScriptManagedEntArrayLen( file.replacementSpawnpointsID ) > 0 )
-
- array<entity> spawnpoints = GetScriptManagedEntArray( file.replacementSpawnpointsID )
- entity selectedSpawnpoint = spawnpoints[0]
-
- float closestDist = -1
- foreach ( spawnpoint in spawnpoints )
- {
- if ( spawnpoint.e.spawnPointInUse )
- continue
- if ( spawnpoint.IsOccupied() )
- continue
-
- float dist = DistanceSqr( spawnpoint.GetOrigin(), origin )
- if ( closestDist == -1 || dist < closestDist )
- {
- closestDist = dist
- selectedSpawnpoint = spawnpoint
- }
-
- }
-
- Assert( selectedSpawnpoint )
- return selectedSpawnpoint
-}
-
-bool function TitanFindDropNodes( FlightPath flightPath, vector baseOrigin, float yaw )
-{
-// return TitanFindDropNodesReloadable( flightPath, baseOrigin, yaw )
-//}
-//function TitanFindDropNodesReloadable( flightPath, baseOrigin, yaw )
-//{
- if ( NearTitanfallBlocker( baseOrigin ) )
- return false
-
- asset model = flightPath.model
- string animation = flightPath.anim
- //local flightPath = GetAnalysisForModel( model, animation )
-
- vector origin = baseOrigin
- vector angles = Vector(0,yaw,0)
- //entity titan = CreatePropDynamic( model, origin, Vector(0,0,0) )
- //entity titan = CreateNPCTitanFromSettings( "titan_atlas", TEAM_IMC, origin, angles )
-
- entity titan = expect entity( level.ainTestTitan )
-
- titan.SetModel( model )
- titan.SetAngles( angles )
- titan.SetOrigin( origin )
-
- float impactTime = GetHotDropImpactTime( titan, animation )
- Attachment result = titan.Anim_GetAttachmentAtTime( animation, "OFFSET", impactTime )
- vector maxs = titan.GetBoundingMaxs()
- vector mins = titan.GetBoundingMins()
- int mask = titan.GetPhysicsSolidMask()
- origin = ModifyOriginForDrop( origin, mins, maxs, result.position, mask )
- titan.SetOrigin( origin )
-
- // Don't use nodes on top of the roof in kodai
- if ( GetMapName() == "mp_forwardbase_kodai" && origin.z > 1200 )
- return false
-
- if ( !TitanTestDropPoint( origin, flightPath ) )
- return false
-
- if ( !TitanCanStand( titan ) )
- return false
-
- if ( TitanHulldropSpawnpoint( flightPath, origin, 0 ) == null )
- return false
-
- if ( !EdgeTraceDropPoint( origin ) )
- return false
-
- return true
-}
-
-
-var function TitanHulldropSpawnpoint( FlightPath flightPath, vector origin, float _ )
-{
- return HullTraceDropPoint( flightPath, origin, 20 )
-}
-
-
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_titan_commands.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_titan_commands.gnut
deleted file mode 100644
index 06232c08b..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_titan_commands.gnut
+++ /dev/null
@@ -1,49 +0,0 @@
-untyped
-
-global function TitanCommands_Init
-
-
-function TitanCommands_Init()
-{
- if ( GetCurrentPlaylistVarInt( "titan_move_command_enabled", 0 ) == 0 )
- return
-
- AddClientCommandCallback( "PrototypeOrderTitanMove", Prototype_OrderTitanMove )
- RegisterSignal( "Prototype_TitanMove" )
-}
-
-bool function Prototype_OrderTitanMove( entity player, array<string> args )
-{
- Assert( args.len() == 3 )
- vector pos = Vector( args[0].tofloat(), args[1].tofloat(), args[2].tofloat() )
-
- DebugDrawLine( pos, pos + Vector(0,0,500), 255, 0, 0, true, 5.0 )
- entity titan = player.GetPetTitan()
- if ( !IsAlive( titan ) )
- return true
-
- thread Prototype_TitanMove( player, titan, pos )
-
- return true
-}
-
-void function Prototype_TitanMove( entity player, entity titan, vector origin )
-{
- titan.Signal( "Prototype_TitanMove" )
- titan.EndSignal( "Prototype_TitanMove" )
- titan.EndSignal( "ChangedTitanMode" )
- titan.EndSignal( "OnDeath" )
- local mode = player.GetPetTitanMode()
- if ( mode != eNPCTitanMode.STAY ) // assuming there are only 2 modes
- {
- player.SetPetTitanMode( eNPCTitanMode.STAY )
- titan.DisableBehavior( "Follow" )
- #if R1_VGUI_MINIMAP
- titan.Minimap_SetBossPlayerMaterial( $"vgui/HUD/threathud_titan_friendlyself_guard" )
- #endif
-
- titan.AssaultSetOrigin( origin )
- }
-
- AssaultOrigin( titan, origin, 100 )
-} \ No newline at end of file
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_titan_health.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_titan_health.gnut
deleted file mode 100644
index d600cb03b..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_titan_health.gnut
+++ /dev/null
@@ -1,1072 +0,0 @@
-global function TitanHealth_Init
-
-global function Titan_PlayerTookDamage
-global function Titan_NPCTookDamage
-
-global function GetShieldRegenTime
-global function GetShieldRegenDelay
-global function PlayerHasAutoEject
-global function SetTitanCoreTimer
-global function GetTitanCoreTimer
-
-global function AddCreditToTitanCoreBuilderForTitanDamageInflicted
-global function AddCreditToTitanCoreBuilderForTitanDamageReceived
-global function AddCreditToTitanCoreBuilderForDoomInflicted
-global function AddCreditToTitanCoreBuilderForDoomEntered
-global function AddCreditToTitanCoreBuilder
-
-global function TitanShieldRegenThink
-
-global function IsRodeoDamageFromBatteryPack
-global function IsKillshot
-
-global function DoomedHealthThink
-global function UndoomTitan
-global function RestoreTitan
-
-global const SIGNAL_TITAN_HEALTH_REGEN = "BeginTitanHealthRegen"
-global const SIGNAL_TITAN_SHIELD_REGEN = "BeginTitanShieldRegen"
-
-global const TITAN_HEALTH_REGEN_DELAY_MAX = 0.7 // 2.2
-
-#if MP
-// PROTO : Was 99, 49 is for test
-global const TITAN_REGEN_MIN_DAMAGE = 49
-global const TITAN_REGEN_MIN_DAMAGE_DELAY = 0.5
-#elseif SP
-global const TITAN_REGEN_MIN_DAMAGE = 70
-global const TITAN_REGEN_MIN_DAMAGE_DELAY = 0.5
-#endif
-
-// titan health system
-const TITAN_HEALTH_HISTORY_FALLOFF_START = 0 // how many seconds until shield begins to regen
-
-const float TITAN_HEALTH_HISTORY_FALLOFF_END = 4.0
-
-struct
-{
- float earn_meter_titan_multiplier
-} file
-
-void function TitanHealth_Init()
-{
- RegisterSignal( SIGNAL_TITAN_HEALTH_REGEN )
- RegisterSignal( SIGNAL_TITAN_SHIELD_REGEN )
- RegisterSignal( "Doomed" )
- RegisterSignal( "TitanUnDoomed" )
- RegisterSignal( "StopShieldRegen" )
- RegisterSignal( "WeakTitanHealthInitialized" )
-
- file.earn_meter_titan_multiplier = GetCurrentPlaylistVarFloat( "earn_meter_titan_multiplier", 1.0 )
-
- if ( IsMenuLevel() )
- return
-
- HealthRegenInit()
- AddSoulInitFunc( TitanShieldRegenThink ) //This runs even if playlist var titan_shield_regen is set to 0 because it also does stuff like give friendly Pilots protection with shield, etc
- AddSoulDeathCallback( Titan_MonarchCleanup )
-}
-
-void function UndoomTitan( entity titan, int numSegments )
-{
- entity soul = titan.GetTitanSoul()
- string settings = GetSoulPlayerSettings( soul )
-
- soul.DisableDoomed()
- int maxHealth
- int segmentHealth = GetSegmentHealthForTitan( titan )
- if ( titan.IsNPC() )
- {
- maxHealth = int( GetPlayerSettingsFieldForClassName_Health( settings ) )
- if ( titan.ai.titanSpawnLoadout.setFileMods.contains( "fd_health_upgrade" ) )
- maxHealth += segmentHealth
- if ( soul.soul.titanLoadout.setFileMods.contains( "core_health_upgrade" ) )
- maxHealth += segmentHealth
- }
- else
- {
- maxHealth = int( titan.GetPlayerModHealth() )
- }
- titan.SetMaxHealth( maxHealth )
- titan.SetHealth( segmentHealth * numSegments )
- SetSoulBatteryCount( soul, numSegments )
-
- titan.Signal( "TitanUnDoomed" )
- UndoomTitan_Body( titan )
- thread TitanShieldRegenThink( soul )
-}
-
-void function RestoreTitan( entity titan, float percent = 0.625 )
-{
- entity soul = titan.GetTitanSoul()
- if ( soul.IsDoomed() )
- UndoomTitan( titan, 1 )
-
- soul.nextRegenTime = 0.0
- soul.SetShieldHealth( soul.GetShieldHealthMax() )
- int minHealth = int( titan.GetMaxHealth() * percent )
- if ( titan.GetHealth() < minHealth )
- {
- titan.SetHealth( minHealth )
- int segmentHealth = GetSegmentHealthForTitan( titan )
- int segments = int( minHealth / float( segmentHealth ) )
- SetSoulBatteryCount( soul, segments )
- }
-}
-
-bool function IsRodeoDamage( entity soul, var damageInfo )
-{
- entity titan = soul.GetTitan()
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- if ( !attacker.IsPlayer() )
- {
- entity rider = GetRodeoPilot( titan )
- if ( rider == attacker )
- return true
- else
- return false
- }
-
- if ( attacker.GetTitanSoulBeingRodeoed() != soul )
- return false
-
- return true
-}
-
-bool function IsCoopRodeoDamage( entity soul, var damageInfo )
-{
- entity titan = soul.GetTitan()
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- entity rider = GetRodeoPilot( titan )
- if ( rider == attacker )
- return true
- else
- return false
-
- unreachable
-}
-
-
-void function CheckRodeoRiderHitsTitan( entity soul, var damageInfo )
-{
- if ( IsRodeoDamage( soul, damageInfo ) )
- {
- //Set Last Attack Time so warning is triggered
- soul.SetLastRodeoHitTime( Time() )
-
- DamageInfo_AddCustomDamageType( damageInfo, DF_RODEO )
- }
-}
-
-bool function ShouldMultiplyRodeoDamage( var damageInfo )
-{
- switch ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) )
- {
- case eDamageSourceId.mp_weapon_smr:
- case eDamageSourceId.mp_titanability_smoke:
- return false
-
- case eDamageSourceId.mp_weapon_defender :
- return true
- }
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_EXPLOSION )
- return false
-
- return true
-}
-
-bool function IsRodeoDamageFromBatteryPack( entity soul, var damageInfo )
-{
- if ( !IsRodeoDamage( soul, damageInfo ) )
- return false
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) != damageTypes.rodeoBatteryRemoval )
- return false
-
- return true
-}
-
-
-int function ShieldHealthUpdate( entity titan, var damageInfo, bool critHit )
-{
- entity soul = titan.GetTitanSoul()
- if ( DamageInfo_GetForceKill( damageInfo ) )
- {
- soul.SetShieldHealth( 0 )
- return 0
- }
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_BYPASS_SHIELD )
- return 0
-
- float damage = DamageInfo_GetDamage( damageInfo )
- int damageType = DamageInfo_GetCustomDamageType( damageInfo )
-
- Assert( soul == titan.GetTitanSoul() )
- int shieldHealth = soul.GetShieldHealth()
-
- if ( soul.e.forcedRegenTime <= Time() )
- soul.nextRegenTime = CalculateNextRegenTime( damage, damageType, critHit, expect float( soul.nextRegenTime ), GetShieldRegenDelay( soul ) )
-
- int result = 0
- if ( shieldHealth )
- {
- DamageInfo_AddCustomDamageType( damageInfo, DF_SHIELD_DAMAGE )
- result = int( ShieldModifyDamage( titan, damageInfo ) )
- }
- else
- {
- TakeAwayFriendlyRodeoPlayerProtection( titan )
- }
-
- return result
-}
-
-
-void function PlayerOrNPCTitanTookDamage( entity titan, var damageInfo, bool critHit, TitanDamage titanDamage )
-{
- entity soul = titan.GetTitanSoul()
-
- if ( !IsValid( soul ) ) //Defensive fix for transient times in frame where Titan can have no soul but be damaged, e.g. immediately after embark
- return
-
- // zero out small forces
- if ( LengthSqr( DamageInfo_GetDamageForce( damageInfo ) ) < 30000 * 30000 )
- DamageInfo_SetDamageForce( damageInfo, < 0, 0, 0 > )
-
- titanDamage.shieldDamage = CheckSpecialCaseShieldDamage( soul, titan, damageInfo )
- if ( titanDamage.shieldDamage < 0 )
- {
- CheckRodeoRiderHitsTitan( soul, damageInfo )
- titanDamage.shieldDamage = ShieldHealthUpdate( titan, damageInfo, critHit )
- }
-
- HandleKillshot( titan, damageInfo, titanDamage )
-
- // health regen based on how much damage dealt to titan
- float damage = DamageInfo_GetDamage( damageInfo )
- int damageType = DamageInfo_GetCustomDamageType( damageInfo )
- bool rodeoDamage = ( ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_RODEO ) > 0 )
-
- if ( soul.e.forcedRegenTime <= Time() )
- soul.nextHealthRegenTime = CalculateNextRegenTime( damage, damageType, critHit || rodeoDamage, expect float( soul.nextHealthRegenTime ), GetHealthRegenDelay( soul ) )
-}
-
-int function CheckSpecialCaseShieldDamage( entity soul, entity titan, var damageInfo )
-{
- if ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) == damagedef_suicide )
- return 0
-
- // no protection from doomed health loss
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_DOOMED_HEALTH_LOSS )
- return 0
-
- if ( IsTitanWithinBubbleShield( titan ) || TitanHasBubbleShieldWeapon( titan ) )
- {
- DamageInfo_SetDamage( damageInfo, 0 )
- return 0
- }
-
- return -1
-}
-
-void function Titan_NPCTookDamage( entity titan, var damageInfo, TitanDamage titanDamage )
-{
- Assert( titan.IsTitan() )
- Assert( DamageInfo_GetDamage( damageInfo ) > 0 )
-
- // dead entities can take damage
- if ( !IsAlive( titan ) )
- return
-
- entity soul = titan.GetTitanSoul()
-
- if ( !IsValid( soul ) ) //Defensive fix for transient times in frame where Titan can have no soul but be damaged, e.g. immediately after embark
- return
-
- bool critHit = false
- if ( CritWeaponInDamageInfo( damageInfo ) )
- critHit = IsCriticalHit( DamageInfo_GetAttacker( damageInfo ), titan, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageType( damageInfo ) )
-
- if ( critHit )
- DamageInfo_AddCustomDamageType( damageInfo, DF_CRITICAL )
-
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- if ( HeavyArmorCriticalHitRequired( damageInfo ) && CritWeaponInDamageInfo( damageInfo ) && !critHit && IsValid( attacker ) && !attacker.IsTitan())
- {
- float shieldHealth = float( titan.GetTitanSoul().GetShieldHealth() )
- float damage = DamageInfo_GetDamage( damageInfo )
- if ( shieldHealth - damage <= 0 )
- {
- if ( shieldHealth > 0 )
- DamageInfo_SetDamage( damageInfo, shieldHealth )
- else
- DamageInfo_SetDamage( damageInfo, 0 )
- }
- }
-
- PlayerOrNPCTitanTookDamage( titan, damageInfo, critHit, titanDamage )
-
- RecordDamageToNPCTitanSoul( soul, damageInfo )
-
- entity owner = GetPetTitanOwner( titan )
- if ( IsValid( owner ) )
- AutoTitan_TryMultipleTitanCallout( titan, damageInfo )
-
- if ( GetDoomedState( titan ) )
- titanDamage.shieldDamage = 0
-}
-
-void function Titan_PlayerTookDamage( entity player, var damageInfo, entity attacker, bool critHit, TitanDamage titanDamage )
-{
- Assert( player.IsTitan() )
-
- float damage = DamageInfo_GetDamage( damageInfo )
-
- if ( !IsAlive( player ) )
- return
-
- entity soul = player.GetTitanSoul()
- if ( !IsValid( soul ) ) //Defensive fix for transient times in frame where Titan can have no soul but be damaged, e.g. immediately after embark
- return
-
- if ( damage > 0 )
- AdjustVelocityFromHit( player, damageInfo, attacker, damage, critHit )
-
- if ( IsDemigod( player ) )
- EntityDemigod_TryAdjustDamageInfo( player, damageInfo )
-
- bool critHit = false
- if ( CritWeaponInDamageInfo( damageInfo ) )
- critHit = IsCriticalHit( attacker, player, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageType( damageInfo ) )
-
- if ( critHit )
- DamageInfo_AddCustomDamageType( damageInfo, DF_CRITICAL )
-
- #if MP
- if ( HeavyArmorCriticalHitRequired( damageInfo ) && CritWeaponInDamageInfo( damageInfo ) && !critHit && IsValid( attacker ) && !attacker.IsTitan())
- {
- float shieldHealth = float( player.GetTitanSoul().GetShieldHealth() )
- if ( shieldHealth - damage <= 0 )
- {
- if ( shieldHealth > 0 )
- DamageInfo_SetDamage( damageInfo, shieldHealth )
- else
- DamageInfo_SetDamage( damageInfo, 0 )
- }
- }
- #endif
-
- PlayerOrNPCTitanTookDamage( player, damageInfo, critHit, titanDamage )
-}
-
-bool function IsKillshot( entity ent, var damageInfo, entity titanSoul )
-{
- float damage = DamageInfo_GetDamage( damageInfo )
- int health = ent.GetHealth()
-
- if ( health - damage > DOOMED_MIN_HEALTH )
- return false
-
- return true
-}
-
-bool function ShouldDoomTitan( entity ent, var damageInfo )
-{
- if ( DoomStateDisabled() )
- return false
-
- if ( GetDoomedState( ent ) )
- return false
-
- if ( DamageInfo_GetForceKill( damageInfo ) )
- return false
-
- float doomedHealth = GetTitanSoulDoomedHealth( ent.GetTitanSoul() )
- if ( doomedHealth <= 0 )
- return false
-
- entity soul = ent.GetTitanSoul()
- if ( soul.soul.skipDoomState )
- return false
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_SKIP_DAMAGE_PROT )
- return doomedHealth > ( DamageInfo_GetDamage( damageInfo ) - ent.GetHealth() )
-
- bool skipDoom = ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_SKIPS_DOOMED_STATE ) > 0
- return !skipDoom
-}
-
-bool function HandleKillshot( entity ent, var damageInfo, TitanDamage titanDamage )
-{
- #if NPC_TITAN_PILOT_PROTOTYPE
- if ( TitanHasNpcPilot( ent ) ) //an npc titan that was dropped by an npc human
- {
- float damage = DamageInfo_GetDamage( damageInfo )
- int health = ent.GetHealth()
-
- if ( health - damage <= 0 )
- {
- DamageInfo_SetDamage( damageInfo, 0 )
- thread TitanEjectPlayer( ent )
- }
-
- return
- }
- #endif
-
- if ( ent.IsPlayer() && ent.IsBuddhaMode() )
- return false
-
- entity titanSoul = ent.GetTitanSoul()
-
- if ( IsKillshot( ent, damageInfo, titanSoul ) )
- {
- entity boss = titanSoul.GetBossPlayer()
- Soul_SetLastAttackInfo( titanSoul, damageInfo )
-
- if ( ShouldDoomTitan( ent, damageInfo ) )
- {
- // Added via AddCallback_OnTitanDoomed
- foreach ( callbackFunc in svGlobal.onTitanDoomedCallbacks )
- {
- callbackFunc( ent, damageInfo )
- }
-
- if ( IsMultiplayer() )
- {
- entity attacker = expect entity( expect table( titanSoul.lastAttackInfo ).attacker )
- if ( IsValid( attacker ) )
- {
- entity bossPlayer = attacker.GetBossPlayer()
- if ( attacker.IsNPC() && IsValid( bossPlayer ) )
- attacker = bossPlayer
-
- if ( attacker.IsPlayer() )
- ScoreEvent_TitanDoomed( ent, attacker, damageInfo )
- }
- }
-
- thread DoomedHealthThink( titanSoul, damageInfo )
-
- titanDamage.doomedNow = true
- titanDamage.doomedDamage = int( DamageInfo_GetDamage( damageInfo ) )
-
- int health = ent.GetHealth()
- DamageInfo_SetDamage( damageInfo, health - 1 )
- return true
- }
- else
- {
- // handle auto eject here
- if ( ent.IsPlayer() && PlayerHasAutoEject( ent ) )
- {
- int health = ent.GetHealth()
- DamageInfo_SetDamage( damageInfo, health - 1 )
- thread HandleAutoEject( ent, titanSoul )
- return false
- }
- }
- }
-
- // Handle doom state damage
- if ( GetDoomedState( ent ) )
- {
- // as long as we're dying but not yet ejecting, the last player to damage us gets credit
- if ( titanSoul.IsEjecting() )
- {
- Soul_SetLastAttackInfo( titanSoul, damageInfo )
- }
- else if ( ent.IsPlayer() && PlayerHasAutoEject( ent ) ) //Handle auto eject for when the frame in which Titan became doomed was not valid for ejecting, e.g. melee
- {
- int health = ent.GetHealth()
- DamageInfo_SetDamage( damageInfo, health - 1 )
- thread HandleAutoEject( ent, titanSoul )
- return false
- }
-
- // protect players who eject early
- // if ( ent.IsPlayer() && IsEjectProtected( ent, damageInfo ) )
- // DamageInfo_SetDamage( damageInfo, 0 )
-
- // slight protection to prevent multiple rapid damage events from eating through doomed state health
- if ( Time() - titanSoul.soul.doomedStartTime < TITAN_DOOMED_INVUL_TIME && !DamageInfo_GetForceKill( damageInfo ) )
- DamageInfo_SetDamage( damageInfo, 0 )
- }
- else
- {
- Soul_SetLastAttackInfo( titanSoul, damageInfo )
- }
-
- return false
-}
-
-bool function PlayerHasAutoEject( entity player )
-{
- if ( player.IsBot() )
- return false
-
- if ( !PlayerHasPassive( player, ePassives.PAS_AUTO_EJECT ) )
- return false
-
- return true
-}
-
-
-void function AdjustVelocityFromHit( entity player, var damageInfo, entity attacker, float damage, bool critHit )
-{
-/*
- if ( DamageInfo_GetDamageCriticalHitScale( damageInfo ) > 1.0 )
- {
- // if you can crit, you have to crit!
- if ( !critHit )
- return
- }
-*/
-
- //printt( " " )
- //printt( "damage: " + damage )
-
- vector damageForward = DamageInfo_GetDamageForce( damageInfo )
- damageForward.z = 0
- //printt( "damageForward " + damageForward )
-
- damageForward.Norm()
-
- //vector org = DamageInfo_GetDamagePosition( damageInfo )
- //DebugDrawLine( org, org + damageForward * 250, 255, 0, 0, true, 5.0 )
-
- vector velocity = player.GetVelocity()
- vector velForward = player.GetVelocity()
- velForward.z = 0
- velForward.Norm()
-
- //DebugDrawLine( org, org + velForward * 250, 0, 255, 0, true, 5.0 )
-
- float dot = DotProduct( velForward, damageForward )
-
- // only stop from the ~front cone
- if ( dot >= -0.5 )
- return
-
- float speedPercent
-
- switch ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) )
- {
- //case eDamageSourceId.mp_titanweapon_40mm:
- // speedPercent = GraphCapped( damage, 0, 750, 1, 0 )
- // break
-
- case eDamageSourceId.mp_titanweapon_xo16:
- speedPercent = 0.075
- break
-
- default:
- speedPercent = GraphCapped( damage, 0, 2500, 0, 1.0 )
- }
-
- //float dif = GraphCapped( dot, -1, -0.5, 1, 0 )
- //speedPercent = speedPercent * dif + ( 1.0 - dif )
-
- speedPercent *= GraphCapped( dot, -1.0, -0.5, 1, 0 )
-
- //printt( " " )
- //printt( "Damage: " + damage )
- //printt( "dot: " + dot )
- //printt( "speedPercent: " + speedPercent )
- speedPercent = 1.0 - speedPercent
- // make the dot into a tighter range
- //dot += 0.5
- //dot *= -2.0
-
- //printt( "modifier: " + ( speedPercent ) )
- velocity *= ( speedPercent )
- player.SetVelocity( velocity )
-}
-
-
-
-void function DoomedHealthThink( entity titanSoul, var damageInfo )
-{
- Assert( expect table( titanSoul.lastAttackInfo ).attacker, "Player entered reserve health with no attacker" )
-
- entity soulOwner = titanSoul.GetTitan()
- Assert( IsValid( soulOwner ), "Invalid owner " + soulOwner )
-
- titanSoul.soul.doomedStartTime = Time()
-
- // kill any existing health regen thread
- titanSoul.Signal( SIGNAL_TITAN_HEALTH_REGEN )
- titanSoul.Signal( SIGNAL_TITAN_SHIELD_REGEN )
-
- titanSoul.EndSignal( "OnDestroy" )
- titanSoul.EndSignal( "OnTitanDeath" )
-
- float tickRate = 0.15
- float maxDoomedHealth = GetTitanSoulDoomedHealth( titanSoul )
- float doomedHealth = maxDoomedHealth
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_SKIP_DAMAGE_PROT )
- doomedHealth = min( doomedHealth + soulOwner.GetHealth() - DamageInfo_GetDamage( damageInfo ), doomedHealth )
-
- float DPS = (doomedHealth / TITAN_DOOMED_MAX_DURATION )
-
- titanSoul.EnableDoomed()
- titanSoul.doomedTime = Time()
- soulOwner.SetDoomed()
- DoomTitan( soulOwner )
- soulOwner.Signal( "Doomed" )
- titanSoul.Signal( "Doomed" )
-
- // allow the damage to go through before resetting the health, so that we get proper damage indicators, etc...
- // this process should also be in code
- WaitEndFrame()
-
- // grab the soul owner again since there was a wait
- soulOwner = titanSoul.GetTitan()
- if ( !IsValid( soulOwner ) )
- return
-
- if ( PROTO_AlternateDoomedState() )
- {
- //printt( soulOwner.GetHealth() )
- soulOwner.SetHealth( doomedHealth )
- soulOwner.SetMaxHealth( maxDoomedHealth )
- //soulOwner.SetHealthPerSegment( 0 )
-
- soulOwner.ClearDoomed()
-
- if ( soulOwner.IsPlayer() && PlayerHasAutoEject( soulOwner ) )
- {
- HandleAutoEject( soulOwner, titanSoul )
- }
- else
- {
- //If it's an auto-titan with auto-eject, this just instantly kills it.
- var attacker = ( "attacker" in titanSoul.lastAttackInfo ) ? expect table( titanSoul.lastAttackInfo ).attacker : null
- expect entity( attacker )
- var inflictor = ( "inflictor" in titanSoul.lastAttackInfo ) ? expect table( titanSoul.lastAttackInfo ).inflictor : null
- expect entity( inflictor )
- var damageSource = ( "damageSourceId" in titanSoul.lastAttackInfo ) ? expect table( titanSoul.lastAttackInfo ).damageSourceId : -1
- int damageFlags = expect int( expect table( titanSoul.lastAttackInfo ).scriptType )
- if ( SoulHasPassive( titanSoul, ePassives.PAS_AUTO_EJECT ) )
- {
- int scriptDamageType = damageTypes.titanEjectExplosion | damageFlags
- soulOwner.Die( attacker, inflictor, { scriptType = scriptDamageType, damageSourceId = damageSource } )
- }
- }
- return
- }
- soulOwner.SetHealth( doomedHealth )
- soulOwner.SetMaxHealth( maxDoomedHealth )
- //soulOwner.SetHealthPerSegment( 0 )
-
- string settings = GetSoulPlayerSettings( titanSoul )
- float damageMod = 1.0
- while ( true )
- {
- table lastAttackInfo = expect table( titanSoul.lastAttackInfo )
-
- table extraDeathInfo = {}
- extraDeathInfo.scriptType <- (DF_NO_INDICATOR | DF_DOOMED_HEALTH_LOSS)
- if ( expect int( lastAttackInfo.scriptType ) & DF_BURN_CARD_WEAPON )
- extraDeathInfo.scriptType = expect int( extraDeathInfo.scriptType ) | DF_BURN_CARD_WEAPON
- if ( expect int( lastAttackInfo.scriptType ) & DF_VORTEX_REFIRE )
- extraDeathInfo.scriptType = expect int( extraDeathInfo.scriptType ) | DF_VORTEX_REFIRE
-
- extraDeathInfo.damageSourceId <- lastAttackInfo.damageSourceId
-
- entity soulOwner = titanSoul.GetTitan()
- if ( !IsValid( soulOwner ) )
- return
- if ( soulOwner.IsPlayer() )
- {
- //if ( PlayerHasPassive( soulOwner, ePassives.PAS_DOOMED_TIME ) )
- // damageMod = 0.4
- //else
- // damageMod = 1.0
-
- if ( PlayerHasAutoEject( soulOwner ) )
- {
- //printt( "About to Auto Eject" )
- // do it in the loop cause player could somehow get in a titan in doomed state
- HandleAutoEject( soulOwner, titanSoul )
- }
- }
-
- float dmgAmount = DPS * tickRate * damageMod
-
- soulOwner.TakeDamage( dmgAmount, expect entity( lastAttackInfo.attacker ), expect entity( lastAttackInfo.inflictor ), extraDeathInfo )
-
- wait tickRate
- }
-}
-
-void function HandleAutoEject( entity rider, entity soul )
-{
- soul.EndSignal( "OnDestroy" )
- soul.EndSignal( "OnTitanDeath" )
-
- thread TitanEjectPlayer( rider )
- if ( soul.IsEjecting() )
- {
- // so we don't cloak the titan during the ejection animation
- if ( GetNuclearPayload( rider ) > 0 )
- wait 2.0
- else
- wait 1.0
-
- EnableCloak( rider, 7.0 )
- return
- }
-}
-
-void function TitanShieldRegenThink( entity soul )
-{
- thread TitanShieldRegenThink_Internal( soul )
-}
-
-// HACK: this technically doesn't work properly because server framerate and all that jazz. Should really be in code.
-void function TitanShieldRegenThink_Internal( entity soul )
-{
- soul.EndSignal( "OnDestroy" )
- soul.EndSignal( "Doomed" )
- soul.EndSignal( "StopShieldRegen" )
-
- //Shield starts at 0 health for now
- string settings = GetSoulPlayerSettings( soul )
- bool hasShield = Dev_GetPlayerSettingByKeyField_Global( settings, "start_with_shields" ) == 1
-
- if ( !hasShield )
- soul.SetShieldHealth( 0 )
-
- int lastShieldHealth = soul.GetShieldHealth()
- bool shieldHealthSound = false
- int maxShield = soul.GetShieldHealthMax()
- float lastTime = Time()
-
- while ( true )
- {
- entity titan = soul.GetTitan()
- if ( !IsValid( titan ) )
- return
-
- int shieldHealth = soul.GetShieldHealth()
- Assert( titan )
-
- if ( lastShieldHealth <= 0 && shieldHealth && titan.IsPlayer() )
- {
- EmitSoundOnEntityOnlyToPlayer( titan, titan, "titan_energyshield_up_1P" )
- shieldHealthSound = true
- if ( titan.IsTitan() )
- {
- GiveFriendlyRodeoPlayerProtection( titan )
- }
- else
- {
- if ( titan.IsPlayer() )
- {
- printt( "Player was " + titan.GetPlayerSettings() )
- }
-
- printt( "ERROR! Expected Titan, but got " + titan )
- }
- }
- else if ( shieldHealthSound && shieldHealth == soul.GetShieldHealthMax() )
- {
- shieldHealthSound = false
- }
- else if ( lastShieldHealth > shieldHealth && shieldHealthSound )
- {
- StopSoundOnEntity( titan, "titan_energyshield_up_1P" )
- shieldHealthSound = false
- }
-
- if ( Time() >= soul.nextRegenTime && TitanHasRegenningShield( soul ) )
- {
- float shieldRegenRate = maxShield / ( GetShieldRegenTime( soul ) / SHIELD_REGEN_TICK_TIME )
-
- if ( SoulHasPassive( soul, ePassives.PAS_SHIELD_BOOST ) )
- shieldRegenRate = SHIELD_BEACON_REGEN_RATE
-
- float frameTime = max( 0.0, Time() - lastTime )
- shieldRegenRate = shieldRegenRate * frameTime / SHIELD_REGEN_TICK_TIME
- // Faster shield recharge if we have Fusion Core active ability ( Stryder Signature )
- //if ( titan.IsPlayer() && PlayerHasPassive( titan, ePassives.PAS_FUSION_CORE ) )
- // shieldRegenRate *= 1.25
-
- soul.SetShieldHealth( minint( soul.GetShieldHealthMax(), int( shieldHealth + shieldRegenRate ) ) )
- }
-
- lastShieldHealth = shieldHealth
- lastTime = Time()
- WaitFrame()
- }
-}
-
-float function GetShieldRegenTime( entity soul )
-{
- float time
- if ( SoulHasPassive( soul, ePassives.PAS_SHIELD_REGEN ) )
- time = TITAN_SHIELD_REGEN_TIME * 0.5
- else
- time = TITAN_SHIELD_REGEN_TIME
-
- return time
-}
-
-float function GetHealthRegenDelay( entity soul )
-{
- if ( GetDoomedState( soul.GetTitan() ) )
- return TITAN_DOOMED_REGEN_DELAY
-
- return GetShieldRegenDelay( soul )
-}
-
-float function GetShieldRegenDelay( entity soul )
-{
- float regenDelay = TITAN_SHIELD_REGEN_DELAY
-
- string settings = GetSoulPlayerSettings( soul )
- regenDelay = expect float( Dev_GetPlayerSettingByKeyField_Global( settings, "titan_regen_delay" ) )
-
- float delay
- if ( SoulHasPassive( soul, ePassives.PAS_SHIELD_REGEN ) )
- delay = regenDelay - 1.0
- else
- delay = regenDelay
-
- if ( SoulHasPassive( soul, ePassives.PAS_SHIELD_BOOST ) )
- delay = 2.0
-
- return delay
-}
-
-void function RecordDamageToNPCTitanSoul( entity soul, var damageInfo )
-{
- float damage = DamageInfo_GetDamage( damageInfo )
-
- vector inflictOrigin = <0.0,0.0,0.0>
- entity inflictor = DamageInfo_GetInflictor( damageInfo )
- if ( IsValid( inflictor ) )
- inflictOrigin = inflictor.GetOrigin()
-
- entity attacker = DamageInfo_GetAttacker( damageInfo )
-
- entity weapon = DamageInfo_GetWeapon( damageInfo )
- array<string> weaponMods
- if ( IsValid( weapon ) )
- weaponMods = weapon.GetMods()
-
- StoreDamageHistoryAndUpdate( soul, TITAN_HEALTH_HISTORY_FALLOFF_END, damage, inflictOrigin, DamageInfo_GetCustomDamageType( damageInfo ), DamageInfo_GetDamageSourceIdentifier( damageInfo ), attacker, weaponMods )
-}
-
-void function AutoTitan_TryMultipleTitanCallout( entity titan, var damageInfo )
-{
- array<entity> titans = GetTitansHitMeInTime( titan.GetTitanSoul(), 5 )
- entity enemy = titan.GetEnemy()
- if ( IsAlive( enemy ) && enemy.IsTitan() && !titans.contains( enemy ) )
- titans.append( enemy )
-
- int totalEngagedTitans = titans.len()
-
- if ( totalEngagedTitans == 1 )
- PlayAutoTitanConversation( titan, "autoEngageTitan" )
- else if ( totalEngagedTitans > 1 )
- PlayAutoTitanConversation( titan, "autoEngageTitans" )
-}
-
-float function CalculateNextRegenTime( float damage, int damageType, bool critHit, float oldNextRegenTime, float maxRegenDelay )
-{
- if ( damage >= TITAN_REGEN_MIN_DAMAGE || critHit || damageType & DF_STOPS_TITAN_REGEN )
- {
- if ( PROTO_VariableRegenDelay() )
- {
- // regen delay based on damage dealt
- float minRegenDelay = 1.0
- float regenDelay = GraphCapped( damage, 100, 1000, minRegenDelay, maxRegenDelay )
-
- float nextRegenTime = oldNextRegenTime
- float delayBasedOnCurrentTime = Time() + regenDelay
- float delayBasedOnPreviousDelay = nextRegenTime + regenDelay
- maxRegenDelay = Time() + maxRegenDelay
-
- delayBasedOnCurrentTime = min( delayBasedOnCurrentTime, maxRegenDelay )
- delayBasedOnPreviousDelay = min( delayBasedOnPreviousDelay, maxRegenDelay )
- nextRegenTime = max( delayBasedOnCurrentTime, delayBasedOnPreviousDelay )
-
- return nextRegenTime
- }
- else
- {
- // old style
- return Time() + maxRegenDelay
- }
- }
- else
- {
- float addTime = TITAN_REGEN_MIN_DAMAGE_DELAY
-
- if ( oldNextRegenTime <= Time() + addTime )
- return Time() + addTime
- }
-
- return oldNextRegenTime
-}
-
-void function AddCreditToTitanCoreBuilderForTitanDamageInflicted( entity titanAttacker, float damage )
-{
- Assert( TitanDamageRewardsTitanCoreTime() )
-
- float rateRaw = CORE_BUILD_PERCENT_FROM_TITAN_DAMAGE_INFLICTED
- float rate = (rateRaw * 0.01)
- float credit = (rate * damage)
- if ( credit > 0.0 )
- AddCreditToTitanCoreBuilder( titanAttacker, credit )
-}
-
-void function AddCreditToTitanCoreBuilderForTitanDamageReceived( entity titanVictim, float damage )
-{
- Assert( TitanDamageRewardsTitanCoreTime() )
-
- float rateRaw = CORE_BUILD_PERCENT_FROM_TITAN_DAMAGE_RECEIVED
- float rate = (rateRaw * 0.01)
- float credit = (rate * damage)
- if ( credit > 0.0 )
- AddCreditToTitanCoreBuilder( titanVictim, credit )
-}
-
-void function AddCreditToTitanCoreBuilderForDoomInflicted( entity titanAttacker )
-{
- Assert( TitanDamageRewardsTitanCoreTime() )
-
- float valueRaw = CORE_BUILD_PERCENT_FROM_DOOM_INFLICTED
- float credit = (valueRaw * 0.01)
- if ( credit > 0.0 )
- AddCreditToTitanCoreBuilder( titanAttacker, credit )
-}
-
-void function AddCreditToTitanCoreBuilderForDoomEntered( entity titanVictim )
-{
- Assert( TitanDamageRewardsTitanCoreTime() )
-
- float valueRaw = CORE_BUILD_PERCENT_FROM_DOOM_ENTERED
- float credit = (valueRaw * 0.01)
- if ( credit > 0.0 )
- AddCreditToTitanCoreBuilder( titanVictim, credit )
-}
-
-void function AddCreditToTitanCoreBuilder( entity titan, float credit )
-{
- Assert( TitanDamageRewardsTitanCoreTime() )
-
- entity soul = titan.GetTitanSoul()
- if ( !IsValid( soul ) )
- return
-
- entity bossPlayer = soul.GetBossPlayer()
-
- if ( titan.IsPlayer() )
- {
- if ( !IsValid( bossPlayer ) )
- return
-
- if ( bossPlayer.IsTitan() && TitanCoreInUse( bossPlayer ) )
- return
- }
- else
- {
- Assert( titan.IsNPC() )
- if ( TitanCoreInUse( titan ) )
- return
- }
-
- if ( !IsAlive( titan ) )
- return
-
- if ( SoulHasPassive( soul, ePassives.PAS_VANGUARD_COREMETER ) )
- credit *= 1.10
-
- credit *= file.earn_meter_titan_multiplier
- #if MP
- if ( titan.IsPlayer() )
- {
- float coreModifier = titan.GetPlayerNetFloat( "coreMeterModifier" )
- if ( coreModifier >= 0.5 )
- credit *= FD_HOT_STREAK_MULTIPLIER
- }
- #endif
-
- bool coreWasAvailable = false
-
- if ( IsValid( bossPlayer ) )
- coreWasAvailable = IsCoreChargeAvailable( bossPlayer, soul )
-
- float oldTotalCredit = SoulTitanCore_GetNextAvailableTime( soul )
- float newTotalCredit = (credit + oldTotalCredit)
- if ( newTotalCredit >= 0.998 ) //JFS - the rui has a +0.001 for showing the meter as full. This fixes the case where the core meter displays 100 but can't be fired.
- newTotalCredit = 1.0
- SoulTitanCore_SetNextAvailableTime( soul, newTotalCredit )
-
- if ( IsValid( bossPlayer ) && !coreWasAvailable && IsCoreChargeAvailable( bossPlayer, soul ) )
- {
- AddPlayerScore( bossPlayer, "TitanCoreEarned" )
- #if MP
- UpdateTitanCoreEarnedStat( bossPlayer, titan )
- PIN_PlayerAbilityReady( bossPlayer, "core" )
- #endif
- }
-
- #if MP
- if ( IsValid( bossPlayer ) )
- JFS_PlayerEarnMeter_CoreRewardUpdate( titan, oldTotalCredit, newTotalCredit )
- #endif
-
- #if HAS_TITAN_TELEMETRY
- if ( titan.IsPlayer() )
- {
- if ( IsCoreChargeAvailable( titan, soul ) )
- {
- TitanHints_TryShowHint( titan, [OFFHAND_EQUIPMENT] )
- }
- }
- #endif
-}
-
-float function GetTitanCoreTimer( entity titan )
-{
- Assert( titan.IsTitan() )
- entity soul = titan.GetTitanSoul()
- Assert( soul )
-
- return SoulTitanCore_GetNextAvailableTime( soul ) - Time()
-}
-
-
-
-void function SetTitanCoreTimer( entity titan, float timeDiff )
-{
- Assert( !TitanDamageRewardsTitanCoreTime() )
-
- Assert( titan.IsTitan() )
- entity soul = titan.GetTitanSoul()
- Assert( soul )
-
- float newTime = Time() + timeDiff
- SoulTitanCore_SetNextAvailableTime( soul, max( Time() - 1, newTime ) )
-}
-
-
-void function Titan_MonarchCleanup( entity soul, var damageInfo )
-{
- entity titan = soul.GetTitan()
-
- if ( !IsValid( titan ) )
- return
-
- int statesIndex = titan.FindBodyGroup( "states" )
- if ( statesIndex <= -1 )
- return
-
- titan.SetBodygroup( statesIndex, 2 )
-} \ No newline at end of file
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_titan_hints.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_titan_hints.gnut
deleted file mode 100644
index 0e8b4b5b4..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_titan_hints.gnut
+++ /dev/null
@@ -1,267 +0,0 @@
-global function TitanHints_Init
-global function TitanHints_NotifyUsedOffhand
-global function TitanHints_ResetThresholds
-global function TitanHints_TryShowHint
-global function TitanHints_ShowHint
-
-const float FIGHT_START_THRESHOLD = 10.0
-const float FIGHT_HINT_THRESHOLD = 8.0
-const float TITAN_HINT_COOLDOWN = 15.0
-
-struct
-{
- float titanFightStartTime = -99
- float lastDidDamageTime = -99
- float lastTookDamageTime = -99
- float lastShowHintTime = -99
- float lastDodgeTime = -99
- table<int,float> titanHintThresholds
- table<int,float> titanHintThresholdAdd
- table<int,float> lastShowHintTimes
-} file
-
-void function TitanHints_Init()
-{
- AddDamageCallback( "player", TitanHint_Player_OnDamaged )
- AddDamageCallback( "npc_titan", TitanHint_NPC_OnDamaged )
- AddDamageCallback( "npc_super_spectre", TitanHint_NPC_OnDamaged )
-
- file.titanHintThresholds[ TITAN_HINT_DASH ] <- 5.0
- file.titanHintThresholds[ OFFHAND_ORDNANCE ] <- 5.0
- file.titanHintThresholds[ OFFHAND_SPECIAL ] <- 5.0
- file.titanHintThresholds[ OFFHAND_ANTIRODEO ] <- 10.0
- file.titanHintThresholds[ OFFHAND_EQUIPMENT ] <- 1.0
-
- file.lastShowHintTimes[ TITAN_HINT_DASH ] <- -99.0
- file.lastShowHintTimes[ OFFHAND_ORDNANCE ] <- -99.0
- file.lastShowHintTimes[ OFFHAND_SPECIAL ] <- -99.0
- file.lastShowHintTimes[ OFFHAND_ANTIRODEO ] <- -99.0
- file.lastShowHintTimes[ OFFHAND_EQUIPMENT ] <- -99.0
-
- file.titanHintThresholdAdd[ TITAN_HINT_DASH ] <- 0
- file.titanHintThresholdAdd[ OFFHAND_ORDNANCE ] <- 0
- file.titanHintThresholdAdd[ OFFHAND_SPECIAL ] <- 0
- file.titanHintThresholdAdd[ OFFHAND_ANTIRODEO ] <- 0
- file.titanHintThresholdAdd[ OFFHAND_EQUIPMENT ] <- 0
-
- AddCallback_OnPlayerInventoryChanged( TitanHints_ResetThresholds )
- AddSpawnCallback( "player", PlayerDidLoad )
-}
-
-void function PlayerDidLoad( entity player )
-{
- AddPlayerMovementEventCallback( player, ePlayerMovementEvents.DODGE, OnPlayerDodge )
-}
-
-void function TitanHint_Player_OnDamaged( entity player, var damageInfo )
-{
- if ( !player.IsTitan() )
- return
-
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- if ( !attacker.IsTitan() && !IsSuperSpectre(attacker) )
- return
-
- if ( attacker.GetTeam() == player.GetTeam() )
- return
-
- TrySetFightTime()
-
- file.lastTookDamageTime = Time()
-
- array<int> hintsToShow = [ TITAN_HINT_DASH, OFFHAND_EQUIPMENT, OFFHAND_SPECIAL, OFFHAND_ORDNANCE, OFFHAND_ANTIRODEO ]
-
- if ( GetDoomedState( player ) || GetTitanCurrentRegenTab( player ) < 2 )
- hintsToShow = [ TITAN_HINT_DASH, OFFHAND_SPECIAL ]
-
- TitanHints_TryShowHint( player, hintsToShow, attacker )
-}
-
-void function TitanHint_NPC_OnDamaged( entity victim, var damageInfo )
-{
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- if ( !attacker.IsPlayer() )
- return
-
- if ( !attacker.IsTitan() )
- return
-
- TrySetFightTime()
-
- file.lastDidDamageTime = Time()
-
- TitanHints_TryShowHint( attacker, [ OFFHAND_EQUIPMENT, OFFHAND_ORDNANCE, OFFHAND_ANTIRODEO ], victim )
-}
-
-// reset thresholds
-void function TitanHints_ResetThresholds( entity player )
-{
- if ( !player.IsTitan() )
- return
-
- foreach ( index, value in file.titanHintThresholdAdd )
- {
- if ( index != TITAN_HINT_DASH ) // don't reset dash
- file.titanHintThresholdAdd[ index ] = 0.0
- }
-}
-
-// increase threshold for hints every time the player uses it
-void function TitanHints_NotifyUsedOffhand( int index )
-{
- // never increment for core
- if ( index == OFFHAND_EQUIPMENT )
- return
-
- if ( index in file.titanHintThresholds )
- {
- file.titanHintThresholdAdd[ index ] += TITAN_HINT_COOLDOWN
- }
-}
-
-bool function TrySetFightTime()
-{
- if (
- Time() - file.lastTookDamageTime > FIGHT_START_THRESHOLD &&
- Time() - file.lastDidDamageTime > FIGHT_START_THRESHOLD
- )
- {
- file.titanFightStartTime = Time()
- return true
- }
-
- return false
-}
-
-void function TitanHints_TryShowHint( entity player, array<int> indexes, entity enemy = null )
-{
- if ( GetConVarInt( "hud_setting_showTips" ) == 0 )
- return
-
- float fightDuration = Time() - file.titanFightStartTime
- if ( fightDuration < FIGHT_HINT_THRESHOLD )
- return
-
- if ( TitanCoreInUse( player ) )
- return
-
- foreach ( idx in indexes )
- {
- float threshold = file.titanHintThresholds[idx] + file.titanHintThresholdAdd[idx]
-
- // have we been fighting for a while?
- if ( fightDuration < max( threshold, TITAN_HINT_COOLDOWN ) )
- continue
-
- // have we already shown this hint?
- if ( Time() - file.lastShowHintTimes[idx] < max( threshold, TITAN_HINT_COOLDOWN ) )
- continue
-
- // have we already shown a hint?
- if ( Time() - file.lastShowHintTime < TITAN_HINT_COOLDOWN )
- continue
-
- if ( idx != TITAN_HINT_DASH )
- {
- // when did you last use this ability?
- if ( Time() - player.p.lastTitanOffhandUseTime[idx] < threshold )
- continue
-
- entity weapon = player.GetOffhandWeapon( idx )
-
- if ( weapon == null )
- continue
-
- // has this ability been available for a while?
- if ( weapon.GetNextAttackAllowedTime() + threshold > Time() )
- continue
-
- var requiresLocks = weapon.GetWeaponInfoFileKeyField( "requires_lock" )
-
- if ( requiresLocks != null )
- {
- expect int( requiresLocks )
- if ( requiresLocks == 1 )
- {
- if ( weapon.SmartAmmo_IsEnabled() && !SmartAmmo_CanWeaponBeFired( weapon ) )
- continue
- }
- }
-
-
- int curEnergyCost = weapon.GetWeaponCurrentEnergyCost()
- if ( !player.CanUseSharedEnergy( curEnergyCost ) )
- continue
-
- if ( weapon.IsChargeWeapon() )
- {
- if ( weapon.GetWeaponChargeFraction() > 0.0 )
- continue
- }
-
- if ( weapon.GetWeaponPrimaryClipCount() < weapon.GetWeaponSettingInt( eWeaponVar.ammo_min_to_fire ) )
- continue
-
- // special core check
- if ( idx == OFFHAND_EQUIPMENT )
- {
- if( !CheckCoreAvailable( weapon ) )
- continue
- if ( IsConversationPlaying() )
- continue
- }
-
- var hintType = weapon.GetWeaponInfoFileKeyField( "hint_type" )
- if ( hintType != null )
- {
- if ( hintType == "range_toggle" )
- {
- if ( enemy != null )
- {
- float dist = Distance2D( enemy.GetOrigin(), player.GetOrigin() )
-
- if ( weapon.HasMod( "ammo_swap_ranged_mode" ) )
- { // has long range mode, will tell to swap to short range
- if ( dist > 2500 )
- {
- continue
- }
- }
- else
- { // has short range mode, will tell to swap to long range
- if ( dist < 1500 )
- {
- continue
- }
- }
- }
- }
- }
-
- }
- else
- {
- if ( Time() - file.lastDodgeTime < threshold )
- continue
-
- // should check if dodge is available here, but we can't seem to do that
- }
-
- // show hint
- TitanHints_ShowHint( player, idx )
- break
- }
-}
-
-void function TitanHints_ShowHint( entity player, int idx )
-{
- Remote_CallFunction_Replay( player, "ServerCallback_ShowOffhandWeaponHint", idx )
- file.lastShowHintTimes[idx] = Time()
- file.lastShowHintTime = Time()
-}
-
-void function OnPlayerDodge( entity player )
-{
- file.lastDodgeTime = Time()
- file.titanHintThresholdAdd[ TITAN_HINT_DASH ] += TITAN_HINT_COOLDOWN
-} \ No newline at end of file
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_titan_hotdrop.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_titan_hotdrop.gnut
deleted file mode 100644
index e3410de8a..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_titan_hotdrop.gnut
+++ /dev/null
@@ -1,778 +0,0 @@
-untyped
-
-global function TitanHotdrop_Init
-
-global function TitanHotDrop
-global function PlayersTitanHotdrops
-global function NPCTitanHotdrops
-global function NPCPrespawnWarpfallSequence
-global function WaitTillHotDropComplete
-global function OnTitanHotdropImpact
-global function PlayHotdropImpactFX
-global function TitanTestDropPoint
-global function EdgeTraceDropPoint
-
-
-global function GetHotDropImpactTime
-
-global function ModifyOriginForDrop
-
-global function NearTitanfallBlocker
-
-global function DevCheckInTitanfallBlocker
-
-global function DrawTitanfallBlockers
-
-global function DropPodFindDropNodes
-
-global function PlayDeathFromTitanFallSounds
-
-global const HOTDROP_FP_WARP = $"P_warpjump_FP"
-global const HOTDROP_TRAIL_FX = $"hotdrop_hld_warp"
-global int BUBBLE_SHIELD_FX_PARTICLE_SYSTEM_INDEX
-
-function TitanHotdrop_Init()
-{
-
- RegisterSignal( "titan_impact" )
- RegisterSignal( "TitanHotDropComplete" )
- RegisterSignal( "BubbleShieldStatusUpdate" )
-
- PrecacheEffect( HOTDROP_TRAIL_FX )
- PrecacheEffect( HOTDROP_FP_WARP )
-
- AddDamageCallbackSourceID( damagedef_titan_fall, TitanFall_DamagedPlayerOrNPC )
-
- PrecacheImpactEffectTable( HOTDROP_IMPACT_FX_TABLE )
-
- PrecacheModel( $"models/fx/xo_shield.mdl" )
- PrecacheModel( $"models/fx/xo_shield_wall.mdl" )
- BUBBLE_SHIELD_FX_PARTICLE_SYSTEM_INDEX = PrecacheParticleSystem( $"P_shield_hld_01_CP" )
-
- BubbleShield_Init()
-}
-
-void function TitanHotDrop( entity titan, string animation, vector origin, vector angles, entity player, entity camera )
-{
- Assert( titan.IsTitan(), titan + " is not a titan" )
-
- titan.EndSignal( "OnDeath" )
-
- HideName( titan )
-
- array<entity> cleanup = [] // ents that will be deleted upon completion
-
- OnThreadEnd(
- function() : ( cleanup, titan, player, camera )
- {
- printt( "Post impact,anim is done" )
- if ( IsValid( titan ) )
- {
- delete titan.s.hotDropPlayer
- titan.e.isHotDropping = false
- titan.Signal( "TitanHotDropComplete" )
- if ( !IsFFAGame() )
- titan.Minimap_DisplayDefault( titan.GetTeam(), null )
- }
-
- if ( IsValid( camera ) )
- camera.ClearParent()
-
- foreach ( entity ent in cleanup )
- {
- if ( IsValid_ThisFrame( ent ) )
- {
- // Delay enough seconds to allow titan hot drop smokeTrail FX to play fully
- ent.Kill_Deprecated_UseDestroyInstead()
- }
- }
-
- if ( IsValid( player ) )
- ScreenFadeFromBlack( player, 0.2, 0.2 )
- }
- )
-
- titan.s.hotDropPlayer <- player
- titan.e.isHotDropping = true
-
- origin += Vector(0,0,8 ) // work around for currently busted animation
-
- entity ref = CreateScriptRef()
- ref.SetOrigin( origin )
- ref.SetAngles( angles )
- ref.Show()
- cleanup.append( ref )
-
- // add smoke fx
-
- TitanHotDrop_Smoke( cleanup, titan, titan.GetBossPlayer() )
-
-// "Titan_1P_Warpfall_Hotdrop" - for first person drops while inside the titan dropping into the level
-// "Titan_1P_Warpfall_Start" - for first person warp calls, starting right on the button press
-// "Titan_1P_Warpfall_WarpToLanding" - for first person from the visual of the titan appearing and falling
-// "Titan_3P_Warpfall_Start" - for any 3P other player or NPC when they call in a warp, starting right on their button press
-// "Titan_3P_Warpfall_WarpToLanding" - for any 3P other player or NPC from the visual of the titan appearing and falling
- int teamNum = TEAM_UNASSIGNED
- if ( IsValid( player ) )
- teamNum = player.GetTeam();
-
- EmitSoundAtPositionOnlyToPlayer( teamNum, origin, player, "Titan_1P_Warpfall_Hotdrop" )
- EmitSoundAtPositionOnlyToPlayer( teamNum, origin, player, "Titan_1P_Warpfall_Start" )
- EmitSoundAtPositionExceptToPlayer( teamNum, origin, player, "Titan_3P_Warpfall_Start" )
- EmitSoundAtPositionExceptToPlayer( teamNum, origin, player, "Titan_3P_Warpfall_WarpToLanding" )
-
- float duration = titan.GetSequenceDuration( animation )
-
- Minimap_PingForTeam( titan.GetTeam(), origin, 64.0, duration, TEAM_COLOR_FRIENDLY / 255.0, 4, false )
- if ( !IsFFAGame() )
- titan.Minimap_Hide( titan.GetTeam(), null )
-
- titan.NotSolid();
- thread PlayAnimTeleport( titan, animation, ref )
- titan.EndSignal( "OnAnimationDone" )
-
- if ( player )
- {
- player.PlayerCone_SetMinYaw( -70 )
- player.PlayerCone_SetMaxYaw( 70 )
- player.PlayerCone_SetMinPitch( -90 )
- player.PlayerCone_SetMaxPitch( 90 )
- }
-
- titan.WaitSignal( "titan_impact" )
- player.ClearHotDropImpactTime()
-// wait duration - 1.25
-
- titan.Solid();
-
- ShowName( titan )
-
- vector sourcePosition = origin
- sourcePosition.z = sourcePosition.z + 5.0
-
- Explosion_DamageDefSimple(
- damagedef_titan_hotdrop,
- origin,
- titan, // attacker
- titan, // inflictor
- origin )
-
- float zoomTime = 2.0
- float rotateTime = 0.5
-
- //printt( "Post impact, before anim is done" )
-
- if ( IsValid( camera ) )
- {
- camera.ClearParent()
-
- entity mover = CreateExpensiveScriptMover()
- mover.SetOrigin( camera.GetOrigin() )
- mover.SetAngles( camera.GetAngles() )
- camera.SetParent( mover )
-
- mover.NonPhysicsMoveTo( titan.GetWorldSpaceCenter(), zoomTime, zoomTime * 0.4, zoomTime * 0.4 )
- cleanup.append( mover )
-
- wait 0.5
-
- ScreenFadeToBlackForever( player, 0.8 )
-
- wait 0.6
-
- mover.RotateTo( angles, rotateTime, rotateTime*0.2, rotateTime*0.2 )
- }
-
- WaittillAnimDone( titan )
-}
-
-entity function TitanHotDrop_Smoke( array<entity> cleanup, entity titan, entity player )
-{
- entity smokeTrail = CreateEntity( "info_particle_system" )
- if ( IsValid( player ) )
- {
- smokeTrail.SetOwner( player )
- smokeTrail.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER
- }
-
- smokeTrail.SetValueForEffectNameKey( HOTDROP_TRAIL_FX ) // HOTDROP_FP_WARP
- smokeTrail.kv.start_active = 1
- DispatchSpawn( smokeTrail )
- smokeTrail.SetParent( titan, "HATCH_HEAD" )
- cleanup.append( smokeTrail )
-
-
- smokeTrail = CreateEntity( "info_particle_system" )
- if ( IsValid( player ) )
- {
- smokeTrail.SetOwner( player )
- smokeTrail.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) //owner cant see
- }
-
- smokeTrail.SetValueForEffectNameKey( HOTDROP_TRAIL_FX ) // HOTDROP_FP_WARP
- smokeTrail.kv.start_active = 1
- DispatchSpawn( smokeTrail )
- smokeTrail.SetParent( titan, "HATCH_HEAD" )
- cleanup.append( smokeTrail )
-
- return smokeTrail
-}
-
-void function PlayersTitanHotdrops( entity titan, vector origin, vector angles, entity player, string animation )
-{
- titan.EndSignal( "OnDeath" )
- titan.s.disableAutoTitanConversation <- true // refactor: Should be created on spawn, and always exist -mackey
-
- OnThreadEnd(
- function() : ( titan, player )
- {
- if ( !IsValid( titan ) )
- return
-
- // removed so that model highlight always works for you autotitan
-// titan.DisableRenderAlways()
-
- delete titan.s.hotDropPlayer
- titan.e.isHotDropping = false
- titan.Signal( "TitanHotDropComplete" )
- DeleteAnimEvent( titan, "titan_impact" )
- DeleteAnimEvent( titan, "second_stage" )
- DeleteAnimEvent( titan, "set_usable" )
- }
- )
-
- HideName( titan )
- titan.s.hotDropPlayer <- player
- titan.e.isHotDropping = true
- titan.UnsetUsable() //Stop titan embark before it lands
- AddAnimEvent( titan, "titan_impact", OnTitanHotdropImpact )
- AddAnimEvent( titan, "second_stage", OnReplacementTitanSecondStage, origin )
- AddAnimEvent( titan, "set_usable", SetTitanUsableByOwner )
-
- string sfxFirstPerson
- string sfxThirdPerson
-
- switch ( animation )
- {
- case "at_hotdrop_drop_2knee_turbo_upgraded":
- sfxFirstPerson = "Titan_1P_Warpfall_WarpToLanding_fast"
- sfxThirdPerson = "Titan_3P_Warpfall_WarpToLanding_fast"
- break
-
- case "bt_hotdrop_skyway":
- sfxFirstPerson = "titan_hot_drop_turbo_begin"
- sfxThirdPerson = "titan_hot_drop_turbo_begin_3P"
- break
-
- case "at_hotdrop_drop_2knee_turbo":
- sfxFirstPerson = "titan_hot_drop_turbo_begin"
- sfxThirdPerson = "titan_hot_drop_turbo_begin_3P"
- break
-
- default:
- Assert( 0, "Unknown anim " + animation )
- }
-
- float impactTime = GetHotDropImpactTime( titan, animation )
- Attachment result = titan.Anim_GetAttachmentAtTime( animation, "OFFSET", impactTime )
- vector maxs = titan.GetBoundingMaxs()
- vector mins = titan.GetBoundingMins()
- int mask = titan.GetPhysicsSolidMask()
- origin = ModifyOriginForDrop( origin, mins, maxs, result.position, mask )
-
- titan.SetInvulnerable() //Make Titan invulnerable until bubble shield is up. Cleared in OnTitanHotdropImpact
-
- if ( SoulHasPassive( titan.GetTitanSoul(), ePassives.PAS_BUBBLESHIELD ) )
- {
- delaythread( impactTime ) CreateBubbleShield( titan, origin, angles )
- }
- else if ( SoulHasPassive( titan.GetTitanSoul(), ePassives.PAS_WARPFALL ) )
- {
- angles = AnglesCompose( angles, Vector( 0.0, 180.0, 0.0) )
- }
-
- //DrawArrow( origin, angles, 10, 150 )
- // HACK: not really a hack, but this could be optimized to only render always for a given client
- titan.EnableRenderAlways()
-
- int teamNum = TEAM_UNASSIGNED
- if ( IsValid( player ) )
- teamNum = player.GetTeam()
-
- EmitDifferentSoundsAtPositionForPlayerAndWorld( sfxFirstPerson, sfxThirdPerson, origin, player, teamNum )
-
- SetStanceKneel( titan.GetTitanSoul() )
-
- waitthread PlayAnimTeleport( titan, animation, origin, angles )
-
- TitanCanStand( titan )
- if ( !titan.GetCanStand() )
- {
- titan.SetOrigin( origin )
- titan.SetAngles( angles )
- }
-
- titan.ClearInvulnerable() //Make Titan vulnerable again once he's landed
-
- if ( !Flag( "DisableTitanKneelingEmbark" ) )
- {
- if ( IsValid( GetEmbarkPlayer( titan ) ) )
- {
- titan.SetTouchTriggers( true ) //Hack, potential fix for triggers bug. See bug 212751
- //A player is trying to get in before the hotdrop animation has finished
- //Wait until the embark animation has finished
- WaittillAnimDone( titan )
- return
- }
-
- titan.s.standQueued = false // SetStanceKneel should set this
- SetStanceKneel( titan.GetTitanSoul() )
- thread PlayAnim( titan, "at_MP_embark_idle_blended" )
- }
-}
-
-float function GetHotDropImpactTime( entity titan, string animation )
-{
- float impactTime = titan.GetScriptedAnimEventCycleFrac( animation, "titan_impact" )
- if ( impactTime < 0.0 )
- impactTime = titan.GetScriptedAnimEventCycleFrac( animation, "signal:titan_impact" )
-
- Assert( impactTime > -1.0, "No event titan_impact in " + animation )
-
- float duration = titan.GetSequenceDuration( animation )
-
- impactTime *= duration
-
- return impactTime
-}
-
-function NPCTitanHotdrops( entity titan, bool standImmediately, string titanfallAnim = "at_hotdrop_drop_2knee_turbo" )
-{
- titan.EndSignal( "OnDeath" )
- titan.EndSignal( "OnDestroy" )
-
- titan.e.isHotDropping = true
- titan.s.bubbleShieldStatus <- 0
-
- titan.SetEfficientMode( true )
- titan.SetTouchTriggers( false )
- titan.SetAimAssistAllowed( false )
-
- float impactTime = GetHotDropImpactTime( titan, titanfallAnim )
- vector origin = titan.GetOrigin()
- vector angles = titan.GetAngles()
-
- #if GRUNTCHATTER_ENABLED
- GruntChatter_TryIncomingSpawn( titan, origin )
- #endif
-
- #if MP
- TryAnnounceTitanfallWarningToEnemyTeam( titan.GetTeam(), origin )
- #endif
-
- if ( NPCShouldDoBubbleShieldAfterHotdrop( titan ) )
- {
- titan.SetNoTarget( true )
- thread CreateGenericBubbleShield_Delayed( titan, origin, angles, impactTime - 0.1 )
- }
-
- waitthread PlayersTitanHotdrops( titan, origin, angles, null, titanfallAnim )
-
- if ( standImmediately )
- {
- SetStanceStand( titan.GetTitanSoul() )
- waitthread PlayAnimGravity( titan, "at_hotdrop_quickstand" )
- }
-
- titan.SetEfficientMode( false )
- titan.SetTouchTriggers( true )
- titan.SetAimAssistAllowed( true )
-
- titan.e.isHotDropping = false
- titan.Signal( "TitanHotDropComplete" )
-
- titan.SetNoTarget( false )
-
- while( titan.s.bubbleShieldStatus == 1 )
- titan.WaitSignal( "BubbleShieldStatusUpdate" )
-}
-
-void function NPCPrespawnWarpfallSequence( string aiSettings, vector spawnOrigin, vector spawnAngle )
-{
- string animation = "at_hotdrop_drop_2knee_turbo_upgraded"
-// string settings = GetTitanForPlayer( player ).titanSetFile
- string playerSettings = expect string( Dev_GetAISettingByKeyField_Global( aiSettings, "npc_titan_player_settings" ) )
- asset model = GetPlayerSettingsAssetForClassName( playerSettings, "bodymodel" )
- Attachment warpAttach = GetAttachmentAtTimeFromModel( model, animation, "offset", spawnOrigin, spawnAngle, 0 )
-
- entity fakeTitan = CreatePropDynamic( model )
- float impactTime = GetHotDropImpactTime( fakeTitan, animation )
-
- #if SP //MP AI already call DisableTitanfallForLifetimeOfEntityNearOrigin() in SpawnNeutralAI()/SpawnTeamAI() functions. Pretty sure can just remove this for SP too
- thread TemporarilyDisableTitanfallAroundRadius( spawnOrigin, 72, WARPFALL_SOUND_DELAY + WARPFALL_FX_DELAY ) //TODO: Look into getting rid of this. Doesn't play well with DisableTitanfallForLifetimeOfEntityNearOrigin. Only used in Beacon
- #endif
-
- fakeTitan.Kill_Deprecated_UseDestroyInstead()
-
- EmitSoundAtPosition( TEAM_UNASSIGNED, spawnOrigin, "Titan_3P_Warpfall_CallIn" )
-
- 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
- EmitSoundAtPosition( TEAM_UNASSIGNED, spawnOrigin, "Titan_3P_Warpfall_Start" )
-
- PlayFX( TURBO_WARP_FX, warpAttach.position + Vector(0,0,-104), warpAttach.angle )
-
- wait WARPFALL_FX_DELAY
-}
-
-void function WaitTillHotDropComplete( entity titan )
-{
- titan.EndSignal( "OnDeath" )
- titan.EndSignal( "OnDestroy" )
-
- // waits for him to drop in from the sky AND stand up
- if ( titan.e.isHotDropping )
- WaitSignal( titan, "TitanHotDropComplete" )
-}
-
-function CreateGenericBubbleShield_Delayed( entity titan, vector origin, vector angles, float delay = 0.0 )
-{
- titan.EndSignal( "OnDestroy" )
-
- if ( delay > 0 )
- wait delay
-
- titan.s.bubbleShieldStatus = 1
- CreateGenericBubbleShield( titan, origin, angles )
- titan.s.bubbleShieldStatus = 0
- titan.Signal( "BubbleShieldStatusUpdate" )
-}
-
-
-vector function ModifyOriginForDrop( vector origin, vector mins, vector maxs, vector resultPos, int mask )
-{
- TraceResults trace = TraceHull( resultPos + Vector(0,0,20), resultPos + Vector(0,0,-20), mins, maxs, null, mask, TRACE_COLLISION_GROUP_NONE )
- float zDif = trace.endPos.z - resultPos.z
- origin.z += zDif
- origin.z += 3.0
-
- return origin
-}
-
-void function OnReplacementTitanSecondStage( entity titan )
-{
- vector origin = expect vector( GetOptionalAnimEventVar( titan, "second_stage" ) )
-
- string sfxFirstPerson = "titan_drop_pod_turbo_landing"
- string sfxThirdPerson = "titan_drop_pod_turbo_landing_3P"
- entity player = titan.GetBossPlayer()
- EmitDifferentSoundsAtPositionForPlayerAndWorld( sfxFirstPerson, sfxThirdPerson, origin, player, titan.GetTeam() )
-}
-
-void function OnTitanHotdropImpact( entity titan )
-{
- ShowName( titan )
- PlayHotdropImpactFX( titan )
- titan.Signal( "ClearDisableTitanfall" )
-}
-
-function SetTitanUsable( titan )
-{
- titan.SetUsableByGroup( "friendlies pilot" )
-}
-
-void function SetTitanUsableByOwner( entity titan )
-{
- titan.SetUsableByGroup( "owner pilot" )
-}
-
-function PlayHotdropImpactFX( titan )
-{
- expect entity( titan )
- if ( !IsAlive( titan ) || !titan.IsTitan() )
- return
-
- local origin = titan.GetOrigin()
-
- Explosion_DamageDefSimple(
- damagedef_titan_fall,
- origin,
- titan, // attacker
- titan, // inflictor
- origin )
-
-
- CreateShake( titan.GetOrigin(), 16, 150, 2, 1500 )
- // No Damage - Only Force
- // Push players
- // Push radially - not as a sphere
- // Test LOS before pushing
- int flags = 15
- vector impactOrigin = titan.GetOrigin() + Vector( 0,0,10 )
- float impactRadius = 512
- CreatePhysExplosion( impactOrigin, impactRadius, PHYS_EXPLOSION_LARGE, flags )
-}
-
-function NearTitanfallBlocker( baseOrigin )
-{
- foreach ( hardpoint in level.testHardPoints )
- {
- local hpOrigin = hardpoint.GetOrigin()
- hpOrigin.z -= 100 // why are hardpoints not really at the origin?
- if ( Distance( hpOrigin, baseOrigin ) < SAFE_TITANFALL_DISTANCE )
- return true
- }
-
- foreach ( flagSpawnPoint in level.testFlagSpawnPoints )
- {
- local fspOrigin = flagSpawnPoint.GetOrigin()
- if ( Distance( fspOrigin, baseOrigin ) < SAFE_TITANFALL_DISTANCE_CTF )
- return true
- }
-
- foreach ( blocker in level.titanfallBlockers )
- {
- if ( Distance2D( baseOrigin, blocker.origin ) > blocker.radius )
- continue
-
- if ( baseOrigin.z < blocker.origin.z )
- continue
-
- if ( baseOrigin.z > blocker.maxHeight )
- continue
-
- return true
- }
-
- return false
-}
-
-function DevCheckInTitanfallBlocker()
-{
- if ( "toggleBlocker" in svGlobal.levelEnt.s )
- {
- svGlobal.levelEnt.s.toggleBlocker.Kill_Deprecated_UseDestroyInstead()
- delete svGlobal.levelEnt.s.toggleBlocker
- return
- }
-
- svGlobal.levelEnt.s.toggleBlocker <- CreateScriptRef()
- svGlobal.levelEnt.s.toggleBlocker.EndSignal( "OnDestroy" )
-
- entity player = GetPlayerArray()[0]
- for ( ;; )
- {
- printt( "Inside Titanfall blocker: " + NearTitanfallBlocker( player.GetOrigin() ) )
- DrawTitanfallBlockers()
- wait 0.5
- }
-}
-
-function DrawTitanfallBlockers()
-{
- foreach ( hardpoint in level.testHardPoints )
- {
- vector hpOrigin = expect entity( hardpoint ).GetOrigin()
- DebugDrawCircle( hpOrigin, Vector(0,0,0), SAFE_TITANFALL_DISTANCE, 255, 255, 0, true, 1.0 )
- }
-
- foreach ( flagSpawnPoint in level.testFlagSpawnPoints )
- {
- vector fspOrigin = expect entity( flagSpawnPoint ).GetOrigin()
- DebugDrawCircle( fspOrigin, Vector(0,0,0), SAFE_TITANFALL_DISTANCE_CTF, 255, 255, 0, true, 1.0 )
- }
-
- foreach ( blocker in level.titanfallBlockers )
- {
- DebugDrawCircle( expect vector( blocker.origin ), Vector(0,0,0), expect float( blocker.radius ), 255, 255, 0, true, 1.0 )
- vector org = Vector( blocker.origin.x, blocker.origin.y, blocker.maxHeight )
- DebugDrawCircle( org, Vector(0,0,0), expect float( blocker.radius ), 255, 255, 0, true, 1.0 )
- }
-}
-
-
-
-bool function EdgeTraceDropPoint( vector dropPoint )
-{
- local offsetArray = [
- Vector( 64,64,0 ),
- Vector( -64,64,0 ),
- Vector( 64,-64,0 ),
- Vector( -64,-64,0 ),
- ]
- local maxDif = 48
- local mask = TRACE_MASK_TITANSOLID | TRACE_MASK_PLAYERSOLID | TRACE_MASK_SOLID | TRACE_MASK_NPCSOLID
- local totalDif = 0
-
- foreach ( offset in offsetArray )
- {
- local startPos = dropPoint + Vector( 0, 0, 64 ) + offset
- local endPos = dropPoint + Vector( 0, 0, -64 ) + offset
- TraceResults result = TraceLine( startPos, endPos, null, mask, TRACE_COLLISION_GROUP_NONE )
- local dif = fabs( result.endPos.z - dropPoint.z )
- totalDif += dif
-
- if ( dif > maxDif )
- {
- //DebugDrawLine( startPos, result.endPos, 200, 50, 50, true, 3 )
- return false
- }
- //DebugDrawLine( startPos, result.endPos, 50, 50, 200, true, 3 )
- }
-
- if ( totalDif > ( maxDif * 2 ) )
- {
- // this should catch cases where a small item like a box or barrel stops the hull collision trace above the ground.
- return false
- }
-
- return true
-}
-
-
-bool function DropPodFindDropNodes( FlightPath flightPath, vector origin, float yaw )
-{
- if ( NearTitanfallBlocker( origin ) )
- return false
-
- //level.drawAnalysisPreview = true
- if ( !TitanTestDropPoint( origin, flightPath ) )
- return false
-
- return EdgeTraceDropPoint( origin )
-}
-
-bool function TitanTestDropPoint( vector start, FlightPath flightPath )
-{
- local draw = level.drawAnalysisPreview
- local end = start + Vector(0,0,8000)
-
- TraceResults result = TraceHull( start, end, flightPath.mins, flightPath.maxs, null, flightPath.traceMask, TRACE_COLLISION_GROUP_NONE )
- if ( result.startSolid )
- {
- if ( draw )
- {
- DrawArrow( start, Vector(0,0,0), 5.0, 80 )
- DebugDrawLine( start, result.endPos, 0, 255, 0, true, 5.0 )
- DebugDrawLine( result.endPos, end, 255, 0, 0, true, 5.0 )
- //local newstart = start + Vector(0,0,150)
- //local reresult = TraceHull( newstart, start, flightPath.mins, flightPath.maxs, null, flightPath.traceMask, TRACE_COLLISION_GROUP_NONE )
- //printt( "surface " + reresult.surfaceName )
- //DebugDrawLine( newstart, reresult.endPos, 155, 0, 0, true, ANALYSIS_PREVIEW_TIME )
- //DrawArrow( reresult.endPos, Vector(0,0,0), ANALYSIS_PREVIEW_TIME, 15 )
- //
-// //DrawArrow( start, Vector(0,0,0), ANALYSIS_PREVIEW_TIME, 15 )
- //DebugDrawLine( start, result.endPos, 255, 0, 0, true, ANALYSIS_PREVIEW_TIME )
- //printt( "length " + Length( start - result.endPos ) )
- }
- return false
- }
-
- if ( result.fraction < 1 )
- {
- if ( result.hitSky )
- {
- if ( draw )
- {
- DebugDrawLine( start, end, 0, 0, 255, true, ANALYSIS_PREVIEW_TIME )
- //DrawArrow( start, Vector(0,0,0), 1.0, 100 )
- }
- return true
- }
-
-// if ( draw )
-// DebugDrawLine( orgs[i-1] + Vector(10,10,10), orgs[i]+ Vector(10,10,10), 255, 255, 0, true, ANALYSIS_PREVIEW_TIME )
-
- // some fudge factor
- if ( Distance( result.endPos, end ) > 16 )
- {
- if ( draw )
- {
- local offset = Vector(-0.1, -0.1, 0 )
- DebugDrawLine( start + offset, result.endPos + offset, 0, 255, 0, true, ANALYSIS_PREVIEW_TIME )
- DebugDrawLine( result.endPos + offset, end + offset, 255, 0, 0, true, ANALYSIS_PREVIEW_TIME )
- //DebugDrawLine( start, end, 255, 0, 0, true, ANALYSIS_PREVIEW_TIME )
- }
- return false
- }
- }
-
-// DebugDrawLine( orgs[i-1], orgs[i], 0, 255, 0, true, ANALYSIS_PREVIEW_TIME )
-
- if ( draw )
- DebugDrawLine( start, end, 0, 255, 0, true, 0.2 )
- return true
-}
-
-
-
-
-
-void function TitanFall_DamagedPlayerOrNPC( entity ent, var damageInfo )
-{
- if ( !ent.IsPlayer() )
- return
-
- if ( !ent.IsTitan() )
- return
-
- vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo )
- vector entityOrigin = ent.GetOrigin()
- local distance = Distance( entityOrigin, damageOrigin )
-
- // on top of them, let the titans fall where they may
- if ( distance < TITANFALL_INNER_RADIUS )
- return
-
- if ( IsTitanWithinBubbleShield( ent ) )
- {
- DamageInfo_SetDamage( damageInfo, 0 )
- return
- }
-
- vector pushVector = Normalize( entityOrigin - damageOrigin )
-
- vector traceEndOrigin = damageOrigin + (pushVector * TITANFALL_OUTER_RADIUS)
- TraceResults traceResult = TraceHull( damageOrigin, traceEndOrigin, ent.GetBoundingMins(), ent.GetBoundingMins(), ent, TRACE_MASK_NPCSOLID_BRUSHONLY, TRACE_COLLISION_GROUP_NONE )
-
- // no room to push them
- if ( traceResult.fraction < 0.85 )
- return
-
- DamageInfo_ScaleDamage( damageInfo, 0.15 )
-
- ent.SetVelocity( pushVector * 400 )
- ent.SetStaggering()
-}
-
-function PlayDeathFromTitanFallSounds( player )
-{
- if ( player.IsTitan() )
- {
- //printt( "Playing titanfall_on_titan at: "+ player.GetOrigin() )
- EmitSoundAtPosition( TEAM_UNASSIGNED, player.GetOrigin(), "titanfall_on_titan" )
- }
- else
- {
- //printt( "Playing titanfall_on_human at " + player.GetOrigin() )
- EmitSoundAtPosition( TEAM_UNASSIGNED, player.GetOrigin(), "titanfall_on_human" )
- }
-}
-
-bool function NPCShouldDoBubbleShieldAfterHotdrop( entity titan )
-{
- if ( titan.HasKey( "script_hotdrop" ) )
- {
- switch ( titan.kv.script_hotdrop )
- {
- case "4":
- case "3":
- printt( "DROP WITH NO BUBBLE" )
- return false
- }
- }
-
- return true
-} \ No newline at end of file
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/_titan_triple_health.gnut b/Northstar.CustomServers/scripts/vscripts/titan/_titan_triple_health.gnut
deleted file mode 100644
index 7515b868f..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/_titan_triple_health.gnut
+++ /dev/null
@@ -1,524 +0,0 @@
-untyped
-
-global function HealthRegenInit
-
-global function TitanLoseSegementFX //JFS: Only being used for Rodeo now, rename later if needed
-global function GibBodyPart
-
-const SEGMENT_DOWN_SOUNDS_3P = [
- "titan_healthbar_tier3_down_3P_vs_3P", // 0 left (doom)
- "titan_healthbar_tier2_down_3P_vs_3P", // 1 left
- "titan_healthbar_tier1_down_3P_vs_3P", // 2 left
- "titan_healthbar_tier1_down_3P_vs_3P" // shield gone
-]
-
-const SEGMENT_DOWN_SOUNDS_3P_ATTACKER = [
- "titan_healthbar_tier3_down_1P_vs_3P", // 0 left (doom)
- "titan_healthbar_tier2_down_1P_vs_3P", // 1 left
- "titan_healthbar_tier1_down_1P_vs_3P", // 2 left
- "titan_healthbar_tier1_down_1P_vs_3P" // shield gone
-]
-
-const SEGMENT_DOWN_SOUNDS_1P = [
- "titan_healthbar_tier3_down_1P", // 0 left (doom)
- "titan_healthbar_tier2_down_1P", // 1 left
- "titan_healthbar_tier1_down_1P", // 2 left
- "titan_healthbar_tier1_down_1P" // shield gone
-]
-
-const DAMAGE_FORGIVENESS_CEILING = 1200.0
-const DAMAGE_FORGIVENESS_FLOOR = 500.0
-const LOW_HEALTH_WARNING_SOUND = "Weapon_Vortex_Gun.ExplosiveWarningBeep"
-
-const TITAN_DAMAGE_MITIGATION_DAMAGESCALE = 0.5
-
-struct {
- int shieldDecayRate = 2
-
- table< entity, table< entity, float > > soulToSoulDamageMemory
-} file;
-
-function HealthRegenInit()
-{
- if ( GetCurrentPlaylistVarInt( "titan_health_decay_amount", 0 ) > 0 )
- {
- AddSoulInitFunc( TitanHealthDecayThink )
- }
-
- AddSoulInitFunc( TitanHealthRegenThink )
-
- if ( TitanShieldDecayEnabled() )
- {
- AddSoulInitFunc( TitanShieldDecayThink )
- }
-
- AddDamageCallback( "player", TitanSegmentedHealth_OnDamage )
- AddDamageCallback( "npc_titan", TitanSegmentedHealth_OnDamage )
- AddCallback_OnTitanDoomed( OnTitanDoomed )
-
- RegisterSignal( "HealthSegmentLost" )
-}
-
-
-void function TitanHealthDecayThink( entity soul )
-{
- thread TitanHealthDecayThinkInternal( soul )
-}
-
-void function TitanHealthDecayThinkInternal( entity soul )
-{
- soul.EndSignal( "OnDestroy" )
- soul.EndSignal( "OnTitanDeath" )
-
- soul.SetShieldHealth( 0 )
-
- while ( 1 )
- {
- entity titan = soul.GetTitan()
- int damageAmout = GetCurrentPlaylistVarInt( "titan_health_decay_amount", 0 )
- titan.TakeDamage( damageAmout, null, null, { scriptType = DF_DOOMED_HEALTH_LOSS, damageSourceId = damagedef_suicide } )
- WaitFrame()
- }
-}
-
-void function TitanHealthRegenThink( entity soul )
-{
- thread TitanHealthRegenThink_Internal( soul )
-}
-
-void function TitanHealthRegenThink_Internal( entity soul )
-{
- soul.EndSignal( SIGNAL_TITAN_HEALTH_REGEN )
- soul.EndSignal( "OnTitanDeath" )
- soul.EndSignal( "OnDestroy" )
-
- if ( !soul.soul.regensHealth )
- return
-
- entity titan = soul.GetTitan()
-
- if ( !IsValid( titan ) )
- return
-
- int healthPerTab = GetSegmentHealthForTitan( titan )
-
- // set this if AI titans need to be aware of segment health. Not used currently
- //titan.SetHealthPerSegment( healthPerTab )
-
- int lastTitanHealth = titan.GetHealth()
- bool regenSound = false
- int maxHealth = titan.GetMaxHealth()
- float lastTime = Time()
-
- while ( 1 )
- {
- titan = soul.GetTitan()
- if ( !IsAlive( titan ) )
- return
- int titanHealth = titan.GetHealth()
- Assert( titan )
-
- if ( !titan.IsTitan() )
- return
-
- if ( !soul.soul.regensHealth )
- return
-
- int currentRegenTab = GetTitanCurrentRegenTab( titan )
-
- if ( currentRegenTab != GetSoulBatteryCount( soul ) )
- SetSoulBatteryCount( soul, GetTitanCurrentRegenTab( titan ) )
-
- int maxHealthForCurrentTab = currentRegenTab * healthPerTab
-
- if ( titanHealth == maxHealthForCurrentTab )
- {
- if ( regenSound )
- {
- StopSoundOnEntity( titan, "titan_energyshield_up" )
- regenSound = false
- }
- }
-
- lastTitanHealth = titanHealth
- lastTime = Time()
- WaitFrame()
- }
-}
-
-void function TitanSegmentedHealth_OnDamage( entity titan, var damageInfo )
-{
- if ( !titan.IsTitan() )
- return
-
- entity soul = titan.GetTitanSoul()
-
- if ( !IsValid( soul ) )
- return
-
- if ( ShouldReduceDamageForSegmentedHealth( soul, damageInfo ) )
- DamageInfo_ScaleDamage( damageInfo, 0.3 )
-
- thread TitanSegmentedHealth_OnDamage_Thread( soul, damageInfo )
-}
-
-bool function ShouldReduceDamageForSegmentedHealth( entity soul, damageInfo )
-{
- if ( !soul.soul.rebooting )
- return false
-
- if ( IsRodeoDamageFromBatteryPack( soul, damageInfo ) )
- return false
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_DOOMED_HEALTH_LOSS )
- return false
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_DOOM_FATALITY )
- return false
-
- return true
-}
-
-function TitanSegmentedHealth_OnDamage_Thread( entity soul, damageInfo )
-{
- soul.EndSignal( "OnTitanDeath" )
- soul.EndSignal( "OnDestroy" )
- soul.EndSignal( "Doomed" )
-
- entity titan = soul.GetTitan()
-
- vector damageOrigin = GetDamageOrigin( damageInfo, titan )
- float damageAmount = DamageInfo_GetDamage( damageInfo )
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- int hitBox = DamageInfo_GetHitBox( damageInfo )
-
- int healthFloor = CalculateHealthFloorForDamage( soul, titan, damageInfo )
-
- bool skipDoom = ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_SKIPS_DOOMED_STATE ) > 0
-
-
- WaitEndFrame()
-
- titan = soul.GetTitan()
- Assert( IsValid( titan ) )
-
- if ( soul.soul.lastSegmentLossTime >= Time() )
- return
-
- if ( GetDoomedState( titan ) )
- return
-
- if ( titan.GetHealth() > healthFloor )
- return
-
- if ( !IsAlive( titan ) )
- return
-
- string settings = GetSoulPlayerSettings( soul )
- if ( Dev_GetPlayerSettingByKeyField_Global( settings, "use_damage_states" ) == 1 )
- UpdateDamageStateForTab( titan, GetTitanCurrentRegenTab( titan ), hitBox )
-
- thread TitanLoseSegement( soul, titan, damageOrigin, damageAmount, attacker )
-}
-
-int function CalculateHealthFloorForDamage( entity soul, entity titan, damageInfo )
-{
- //Lets you bypass the health segment limitation and remove an entire health segment.
- /*if ( IsRodeoDamageFromBatteryPack( soul, damageInfo ) )
- return minint( 0, int ( titan.GetHealth() - DamageInfo_GetDamage( damageInfo ) ) )
- */
- int oldTab = GetTitanCurrentRegenTab( titan )
- return ( oldTab - 1 ) * GetSegmentHealthForTitan( titan )
-}
-
-void function TitanLoseSegement( entity soul, entity titan, vector damageOrigin, float damageAmount, entity attacker )
-{
- if ( !IsValid( soul ) )
- return
-
- if ( !IsValid( titan ) )
- return
-
- if ( soul.soul.lastSegmentLossTime >= Time() )
- return
-
- soul.soul.lastSegmentLossTime = Time()
-
- entity player
- if ( titan.IsPlayer() )
- player = titan
-
- foreach ( callbackFunc in svGlobal.onTitanHealthSegmentLostCallbacks )
- {
- callbackFunc( titan, attacker )
- }
-
- // Added via AddTitanCallback_OnHealthSegmentLost
- foreach ( callbackFunc in titan.e.entSegmentLostCallbacks )
- {
- callbackFunc( titan, attacker )
- }
-
- GiveDefenderAmmo( titan )
-
- titan.Signal( "HealthSegmentLost" )
-
- soul.EndSignal( "OnTitanDeath" )
- soul.EndSignal( "OnDestroy" )
-
- if ( GetCurrentPlaylistVarInt( "titan_health_chicklet_fx", 0 ) == 1 )
- TitanLoseSegementFX( titan, attacker, damageOrigin )
-
- SetSoulBatteryCount( soul, GetTitanCurrentRegenTab( titan ) )
-}
-
-void function TitanLoseSegementFX( entity titan, entity attacker, vector damageOrigin )
-{
- int handle = titan.GetEncodedEHandle()
- int handleAttacker = -1
-
- if ( IsValid( attacker ) )
- handleAttacker = attacker.GetEncodedEHandle()
-
- array<entity> players = GetPlayerArray()
- foreach ( player in players )
- {
- Remote_CallFunction_Replay( player, "ServerCallback_TitanLostHealthSegment", handle, handleAttacker, damageOrigin.x, damageOrigin.y, damageOrigin.z )
- }
-
- if ( !IsAlive( titan ) )
- return
-
- int currentRegenTab = minint( GetTitanCurrentRegenTab( titan ), SEGMENT_DOWN_SOUNDS_3P_ATTACKER.len()-1 )
- if ( currentRegenTab < SEGMENT_DOWN_SOUNDS_3P_ATTACKER.len() )
- {
- if ( titan.IsPlayer() && IsAlive( attacker ) && attacker.IsPlayer() )
- {
- EmitSoundOnEntityOnlyToPlayer( titan, attacker, SEGMENT_DOWN_SOUNDS_3P_ATTACKER[ currentRegenTab ] )
- EmitSoundOnEntityOnlyToPlayer( titan, titan, SEGMENT_DOWN_SOUNDS_1P[ currentRegenTab ] )
-
- // need a command here to play for not victim and not attacker
- EmitSoundOnEntityExceptToPlayer( titan, titan, SEGMENT_DOWN_SOUNDS_3P[ currentRegenTab ] )
- }
- else if ( IsAlive( attacker ) && attacker.IsPlayer() )
- {
- EmitSoundOnEntityOnlyToPlayer( titan, attacker, SEGMENT_DOWN_SOUNDS_3P_ATTACKER[ currentRegenTab ] )
- EmitSoundOnEntityExceptToPlayer( titan, attacker, SEGMENT_DOWN_SOUNDS_3P[ currentRegenTab ] )
- }
- else if ( titan.IsPlayer() )
- {
- EmitSoundOnEntityOnlyToPlayer( titan, titan, SEGMENT_DOWN_SOUNDS_1P[ currentRegenTab ] )
- EmitSoundOnEntityExceptToPlayer( titan, titan, SEGMENT_DOWN_SOUNDS_3P[ currentRegenTab ] )
- }
- else
- {
- EmitSoundOnEntity( titan, SEGMENT_DOWN_SOUNDS_3P[ currentRegenTab ] )
- }
- }
-}
-
-
-void function UpdateDamageStateForTab( entity titan, int tab, int hitBox )
-{
- if ( hitBox == -1 ) // not every hitbox has data defined
- return
-
- var bodyGroup = titan.GetBodyGroupNameFromHitboxId( hitBox ) // can be null
-
- if ( bodyGroup == null )
- {
- printt( "bodyGroup was null" )
- return
- }
-
-#if MP
- // these are flipped on purpose to prevent both legs or arms from being blown up
- switch ( bodyGroup )
- {
- case "left_leg":
- if ( IsBroken( titan, "right_leg" ) )
- return
- break
-
- case "right_leg":
- if ( IsBroken( titan, "left_leg" ) )
- return
- break
-
- case "left_arm":
- if ( IsBroken( titan, "right_arm" ) )
- return
- break
-
- case "right_arm":
- if ( IsBroken( titan, "left_arm" ) )
- return
- break
-
- default:
- return
- }
-
- GibBodyPart( titan, bodyGroup )
-#else
- int maxTab = 3
- int count = maxTab - tab
-
- RecursiveGibBodyPart( titan, bodyGroup, count )
-#endif
-}
-
-void function RecursiveGibBodyPart( entity titan, var bodyGroup, int count )
-{
- GibBodyPart( titan, bodyGroup )
-
- count -= 1
- if ( count <= 0 )
- return
-
- foreach ( siblingName in titan.s.skeletonData[bodyGroup].siblings )
- {
- // printt( count + " recurse: " + siblingName )
- RecursiveGibBodyPart( titan, siblingName, count )
- }
-}
-
-bool function IsBroken( entity titan, var bodyGroup )
-{
- local bodyGroupIndex = titan.FindBodyGroup( bodyGroup )
- local stateCount = GetStateCountForBodyGroup( titan, bodyGroup )
- local bodyGroupState = titan.GetBodyGroupState( bodyGroupIndex )
-
- //return ( bodyGroupState >= (stateCount - 1) )
- return ( bodyGroupState > 0 )
-}
-
-void function GibBodyPart( entity titan, var bodyGroup )
-{
- // if ( IsBodyGroupBroken( titan, bodyGroup ) )
- // return
-
- // titan.s.damageStateInfo[bodyGroup] = 1
-
- local bodyGroupIndex = titan.FindBodyGroup( bodyGroup )
- local stateCount = GetStateCountForBodyGroup( titan, bodyGroup )
- local bodyGroupState = titan.GetBodyGroupState( bodyGroupIndex )
-
- if ( bodyGroupState >= (stateCount - 1) )
- return
-
- titan.SetBodygroup( bodyGroupIndex, bodyGroupState + 1 )
- // printt( "break: " + bodyGroup )
-}
-
-function GiveAttackerAmmo( entity titan )
-{
-}
-
-void function TemporaryInvul( entity titan )
-{
- titan.EndSignal( "OnDestroy" )
- titan.EndSignal( "OnDeath" )
- if ( titan.IsPlayer() )
- {
- titan.EndSignal( "DisembarkingTitan" )
- titan.EndSignal( "TitanEjectionStarted" )
- }
-
- OnThreadEnd(
- function() : ( titan )
- {
- if ( IsValid( titan ) )
- titan.ClearInvulnerable()
- }
- )
-
- titan.SetInvulnerable()
- wait 0.25
-}
-
-void function GiveDefenderAmmo( entity titan )
-{
- entity soul = titan.GetTitanSoul()
-
- if ( IsSingleplayer() )
- {
- if ( titan.IsNPC() )
- {
- soul.SetNextCoreChargeAvailable( soul.GetNextCoreChargeAvailable() + 0.5 ) // shave time off core timer
- }
- }
-}
-
-void function OnTitanDoomed( entity titan, var damageInfo )
-{
-
- if ( !IsAlive( titan ) )
- return
-
- entity soul = titan.GetTitanSoul()
-
- if ( titan.IsPlayer() )
- {
- if ( SoulHasPassive( soul, ePassives.PAS_RONIN_AUTOSHIFT ) )
- PhaseShift( titan, 0, 3.0 )
-
- if ( SoulHasPassive( soul, ePassives.PAS_AUTO_EJECT ) )
- return
- }
-
- soul.nextHealthRegenTime = Time()
-
- vector damageOrigin = GetDamageOrigin( damageInfo, titan )
- float damageAmount = DamageInfo_GetDamage( damageInfo )
- entity attacker = DamageInfo_GetAttacker( damageInfo )
-
- if ( TitanDamageRewardsTitanCoreTime() && (titan != attacker) )
- {
- AddCreditToTitanCoreBuilderForDoomEntered( titan )
- if ( attacker.IsTitan() )
- AddCreditToTitanCoreBuilderForDoomInflicted( attacker )
- }
-
- thread TitanLoseSegement( soul, titan, damageOrigin, damageAmount, attacker )
-
- if ( SoulHasPassive( soul, ePassives.PAS_DOOMED_TIME ) )
- return
-
- if ( NoWeaponDoomState() )
- TakeAllWeapons( titan )
-}
-
-void function OnTitanDeath( entity titan, var damageInfo )
-{
- if ( !titan.IsTitan() )
- return
-
- if ( !PROTO_AlternateDoomedState() )
- return
-
- entity soul = titan.GetTitanSoul()
- vector damageOrigin = GetDamageOrigin( damageInfo, titan )
- float damageAmount = DamageInfo_GetDamage( damageInfo )
- entity attacker = DamageInfo_GetAttacker( damageInfo )
-
- thread TitanLoseSegement( soul, titan, damageOrigin, damageAmount, attacker )
-}
-
-void function TitanShieldDecayThink( entity soul )
-{
- thread TitanShieldDecayThinkInternal( soul )
-}
-
-void function TitanShieldDecayThinkInternal( entity soul )
-{
- soul.EndSignal( "OnDestroy" ) //This needs to be OnDestroy instead of OnDeath because souls don't have a death animation
- soul.EndSignal( "OnTitanDeath" )
-
- while ( 1 )
- {
- if ( Time() >= soul.e.nextShieldDecayTime && !TitanHasRegenningShield( soul ) )
- soul.SetShieldHealth( maxint( soul.GetShieldHealth() - file.shieldDecayRate, 0 ) )
- WaitFrame()
- }
-} \ No newline at end of file
diff --git a/Northstar.CustomServers/scripts/vscripts/titan/class_titan.gnut b/Northstar.CustomServers/scripts/vscripts/titan/class_titan.gnut
deleted file mode 100644
index 5f72385ea..000000000
--- a/Northstar.CustomServers/scripts/vscripts/titan/class_titan.gnut
+++ /dev/null
@@ -1,77 +0,0 @@
-untyped
-
-global function ClassTitan_Init
-
-global function Titan_AddPlayer
-global function Titan_OnPlayerDeath
-global function ClientCommand_TitanEject
-global function ApplyTitanLoadoutModifiers
-
-
-const TITAN_HATCHCOMMANDANIMTIME = 1.5 // cooldown time between toggling the cockpit state. Will be needed when we have animations to play
-
-const COCKPIT_JOLT_DAMAGE_MIN = 1
-const COCKPIT_JOLT_DAMAGE_MAX = 200
-const TITAN_STUMBLE_HEALTH_PERCENTAGE = 0.5
-
-string thisClassName = "titan"
-
-function ClassTitan_Init()
-{
-
- AddClientCommandCallback( "TitanEject", ClientCommand_TitanEject ) //
-}
-
-function Titan_AddPlayer( player )
-{
- player.playerClassData[thisClassName] <- {}
- player.s.lastStaggerTime <- 0
-}
-
-
-// TODO: There should be an equivalent function for pilots
-TitanLoadoutDef function ApplyTitanLoadoutModifiers( entity player, TitanLoadoutDef loadout )
-{
- return loadout
-}
-
-void function Titan_OnPlayerDeath( entity player, var damageInfo )
-{
- player.p.storedWeapons.clear()
-}
-
-bool function PlayerCanEject( entity player )
-{
- if ( !IsAlive( player ) )
- return false
-
- if ( !player.IsTitan() )
- return false
-
- if ( Riff_TitanExitEnabled() == eTitanExitEnabled.Never )
- return false
-
- //if ( !CanDisembark( player ) )
- // return false
-
- if ( IsPlayerDisembarking( player ) )
- return false
-
- if ( TitanEjectIsDisabled() )
- return false
-
- return true
-}
-
-bool function ClientCommand_TitanEject( entity player, array<string> args )
-{
- if ( !PlayerCanEject( player ) )
- return true
-
- int ejectPressCount = args[ 0 ].tointeger()
- if ( ejectPressCount < 3 )
- return true
-
- thread TitanEjectPlayer( player )
- return true
-}