diff options
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/titan')
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 567ad6e7..00000000 --- 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 c9d986bc..00000000 --- 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 5970f7ea..00000000 --- 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 06232c08..00000000 --- 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 d600cb03..00000000 --- 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 0e8b4b5b..00000000 --- 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 e3410de8..00000000 --- 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 7515b868..00000000 --- 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 5f72385e..00000000 --- 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 -} |