aboutsummaryrefslogtreecommitdiff
path: root/Northstar.Coop/scripts/vscripts/sp/_gamestate_sp.gnut
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.Coop/scripts/vscripts/sp/_gamestate_sp.gnut')
-rw-r--r--Northstar.Coop/scripts/vscripts/sp/_gamestate_sp.gnut793
1 files changed, 793 insertions, 0 deletions
diff --git a/Northstar.Coop/scripts/vscripts/sp/_gamestate_sp.gnut b/Northstar.Coop/scripts/vscripts/sp/_gamestate_sp.gnut
new file mode 100644
index 000000000..ac741370f
--- /dev/null
+++ b/Northstar.Coop/scripts/vscripts/sp/_gamestate_sp.gnut
@@ -0,0 +1,793 @@
+const RESPAWN_TRIG_RECHECK_WAIT = 1
+const DEFAULT_SP_ARRIVAL_TOLERANCE = 200
+const DEFAULT_SP_ASSAULT_TIMEOUT = 0
+
+// move these to auto precache
+global const TEAM_MIL_GRUNT_MODEL = $"models/humans/grunts/mlt_grunt_rifle.mdl"
+global const TEAM_MIL_GRUNT_MODEL_LMG = $"models/humans/grunts/mlt_grunt_lmg.mdl"
+global const TEAM_MIL_GRUNT_MODEL_RIFLE = $"models/humans/grunts/mlt_grunt_rifle.mdl"
+global const TEAM_MIL_GRUNT_MODEL_ROCKET = $"models/humans/grunts/mlt_grunt_rifle.mdl"
+global const TEAM_MIL_GRUNT_MODEL_SHOTGUN = $"models/humans/grunts/mlt_grunt_shotgun.mdl"
+global const TEAM_MIL_GRUNT_MODEL_SMG = $"models/humans/grunts/mlt_grunt_smg.mdl"
+
+
+global function GamemodeSp_Init
+global function GiveBatteryChargeTool
+global function HasBatteryChargeTool
+global function FriendlyFire_MissionFailure
+global function DamageAlwaysLethal
+global function ServerRestartMission
+global function DisableFriendlyHighlight
+global function EnableFriendlyHighlight
+global function SP_PlayerLastSlideTime
+
+//global function CodeCallback_Ping
+
+global function SetGameState
+global function GetGameModeAnnouncement
+
+global function CodeCallback_GamerulesThink
+
+global struct SvGlobalsSP
+{
+ int gruntCombatState = eGruntCombatState.IDLE
+
+ array<void functionref( entity )> onLoadSaveGameCallbacks
+}
+
+global SvGlobalsSP svGlobalSP
+
+//////////////////////////////
+
+global function DEV_ToggleFriendlyHighlight
+
+//////////////////////////////
+
+struct
+{
+ LevelTransitionStruct ornull storedLevelTransitionStruct
+ entity spPetTitanStart
+ bool friendlyHighlightEnabled = true
+ float playerLastSlideTime
+} file
+
+void function GamemodeSp_Init()
+{
+ FlagInit( "FriendlyFireStrict" )
+ FlagInit( "TitanCanSavePlayer" )
+ FlagInit( "TitanDeathPenalityDisabled" )
+ FlagInit( "SaveGame_Enabled", true )
+ FlagInit( "MissionFailed" )
+ RegisterSignal( "TitanSavesPlayer" )
+
+ FlagSet( "PilotBot" )
+
+ AddSoulDeathCallback( SoulDeath_ReloadOnPetTitanDeath )
+ AddClientCommandCallback( "RestartMission", ClientCommand_RestartMission )
+
+ SetRoundBased( false )
+
+ AddCallback_OnClientConnecting( SpPlayerConnecting )
+ AddCallback_OnClientConnected( SpPlayerConnected )
+
+ AddSpawnCallback( "npc_soldier", SpNpcCommon )
+ AddSpawnCallback( "npc_spectre", SpNpcCommon )
+ AddSpawnCallback( "npc_titan", SpNpcCommon )
+
+ AddSpawnCallback( "npc_soldier", SpNpcCommonGrunt )
+
+ AddSpawnCallbackEditorClass( "info_target", "info_pet_titan_start", PetTitanStartSpawnInit )
+ AddCallback_OnPlayerRespawned( GameStateSP_OnPlayerRespawn )
+
+ AddDamageCallbackSourceID( eDamageSourceId.damagedef_titan_fall, PreventFriendlyTitanfallDamage )
+ AddDamageCallbackSourceID( eDamageSourceId.damagedef_reaper_fall, PreventFriendlyTitanfallDamage )
+
+ shGlobal.proto_soldierShieldRegenDelay = 3000.0
+ svGlobal.cloakBreaksOnMelee = true
+ svGlobal.defaultPilotLeechTime = 2.0
+
+ //AddDamageCallback( "player", DiminishPlayerComboDamage )
+
+ SPTitanLoadout_SetupForLevelStart()
+
+ SpSharedInit()
+
+ AddCallback_EntitiesDidLoad( EntitiesDidLoad_SpGameState )
+ AddDeathCallback( "npc_soldier", SoldierFriendlyFireCheck_OnKilled )
+
+ AddCallback_OnPilotBecomesTitan( PilotBecomesTitanStoreWeaponVar )
+
+ // SAVE THIS LEVEL IF IT'S IN THE LEVEL LIST
+ var dataTable = GetDataTable( $"datatable/sp_levels.rpak" )
+ string mapName = GetMapName()
+ string startPoint = GetStartPoint()
+ int numRows = GetDatatableRowCount( dataTable )
+ int lastLevelNum = 0
+
+ int bspCol = GetDataTableColumnByName( dataTable, "level" )
+ int levelCol = GetDataTableColumnByName( dataTable, "levelNum" )
+
+ for ( int i=0; i<numRows; i++ )
+ {
+ string levelBsp = GetDataTableString( dataTable, i, bspCol )
+ int levelNum = GetDataTableInt( dataTable, i, levelCol )
+
+ if ( levelBsp == mapName )
+ {
+ #if DEV
+ printt( "Setting this level as unlocked" )
+ printt( "BSP: " + levelBsp )
+ printt( "Level Num: " + levelNum )
+ #endif
+
+ SetConVarInt( "sp_lastMission", levelNum )
+ lastLevelNum = levelNum
+ break
+ }
+ }
+
+ int farthestLevelUnlocked = GetConVarInt( "sp_unlockedMission" )
+
+ if( Script_IsRunningTrialVersion() )
+ SetConVarInt( "sp_unlockedMission", 1 ) // Set to sp_crashsite so if they buy the game, it starts there.
+ else
+ SetConVarInt( "sp_unlockedMission", maxint(farthestLevelUnlocked, lastLevelNum) )
+
+ foreach( entity player in GetPlayerArray() )
+ UpdateHeroStatsForPlayer( player )
+
+ if ( IsTestMap() )
+ {
+ PilotLoadoutDef loadout = GetPilotLoadoutForCurrentMapSP()
+ foreach ( model in GetModelsFromSetFile( loadout.setFile ) )
+ {
+ PrecacheModel( model )
+ }
+
+ TitanLoadoutDef titanLoadout = GetTitanLoadoutForCurrentMap()
+ foreach ( model in GetModelsFromSetFile( titanLoadout.setFile ) )
+ {
+ PrecacheModel( model )
+ }
+ }
+}
+
+
+void function EntitiesDidLoad_SpGameState()
+{
+ SetGameState( eGameState.Playing )
+ FlagSet( "ReadyToStartMatch" )
+
+ file.storedLevelTransitionStruct = GetLevelTransitionStruct()
+
+ SetCustomIntroLength( 0 )
+
+// level.nv.replayDisabled = true //HACK - remove once the bug about replay hud is fixed
+ level.nv.minimapState = eMinimapState.Hidden
+
+ level.nv.replayDisabled = true
+ if ( !IsTestMap() )
+ level.nv.titanAvailability = eTitanAvailability.Never
+
+ ServerCommand( "sv_weapon_despawn_Time 180" )
+}
+
+/************************************************************************************************\
+
+ ###### ####### ## ## ## ## ######## ###### ########
+## ## ## ## ### ## ### ## ## ## ## ##
+## ## ## #### ## #### ## ## ## ##
+## ## ## ## ## ## ## ## ## ###### ## ##
+## ## ## ## #### ## #### ## ## ##
+## ## ## ## ## ### ## ### ## ## ## ##
+ ###### ####### ## ## ## ## ######## ###### ##
+
+\************************************************************************************************/
+void function SpPlayerConnecting( entity player )
+{
+ if ( GetPlayerArray().len() > 1 )
+ {
+ CodeWarning( "Can't play SP with more or less than 1 player" )
+ return
+ }
+
+ SetTeam( player, TEAM_MILITIA )
+ InitPassives( player )
+
+ player.SetInventoryChangedCallbackEnabled( true )
+
+ entity ornull spawningOn = GetPlayerToSpawnOn()
+ if ( spawningOn == null )
+ {
+ // vanilla spawning logic - spawn first player at the level's spawnpoint
+ entity start = GetEnt( "info_player_start" )
+ player.SetOrigin( start.GetOrigin() )
+ player.SetAngles( start.GetAngles() )
+ }
+ else
+ {
+ expect entity( spawningOn )
+ // use safe func otherwise we can get stuck in the ceiling and shit
+ thread TeleportToEntitySafe( player, spawningOn )
+ }
+
+ if ( IsValid( file.spPetTitanStart ) )
+ {
+ CreatePetTitan( player )
+ entity titan = player.GetPetTitan()
+ if ( titan != null )
+ titan.kv.alwaysAlert = false
+ }
+}
+
+void function GameStateSP_OnPlayerRespawn( entity player )
+{
+ UpdateSpDifficulty( player )
+ thread TrackPlayerLastSlideTime( player )
+
+ if ( !IsTestMap() )
+ {
+ CheckPoint_ForcedSilent()
+ }
+}
+
+void function SpPlayerConnected( entity player )
+{
+ thread SpPlayerConnected_Thread( player )
+}
+
+void function SpPlayerConnected_Thread( entity player )
+{
+ player.EndSignal( "OnDestroy" )
+
+ if ( IsTestMap() )
+ return
+
+ string levelName = GetMapName()
+ int startIndex = GetStartPointIndexFromName( levelName, GetCurrentStartPoint() )
+
+ string startPointEnum = GetStartPointNameFromIndex( levelName, startIndex )
+ if ( !StartPointHasDetente( levelName, startPointEnum ) )
+ return
+
+ var dataTable = GetDataTable( $"datatable/sp_introscreen.rpak" )
+ int row = GetDataTableRowMatchingStringValue( dataTable, GetDataTableColumnByName( dataTable, "level" ), levelName )
+ if ( row == -1 )
+ return
+
+ float delay = GetDataTableFloat( dataTable, row, GetDataTableColumnByName( dataTable, "bgFadeDelay" ) )
+ float fadeTime = GetDataTableFloat( dataTable, row, GetDataTableColumnByName( dataTable, "bgFadeTime" ) )
+
+ printt( "Detent fade in " + delay + " blend " + fadeTime )
+
+ WaitFrame()
+ WaitFrame() // wait two frames to fix ScreenFade bug
+
+ ScreenFade( player, 0, 0, 0, 255, fadeTime, delay, FFADE_IN | FFADE_PURGE )
+ //printt( "sv SCREENFADE: " + fadeTime + " " + delay )
+}
+
+float function SP_PlayerLastSlideTime()
+{
+ return file.playerLastSlideTime
+}
+
+void function PetTitanStartSpawnInit( entity spawn )
+{
+ file.spPetTitanStart = spawn
+}
+
+void function TrackPlayerLastSlideTime( entity player )
+{
+ player.EndSignal( "OnDeath" )
+
+ for ( ;; )
+ {
+ if ( player.IsSliding() )
+ file.playerLastSlideTime = Time()
+ wait 0.5
+ }
+}
+
+void function CreatePetTitan( entity player )
+{
+ Assert( IsValid( file.spPetTitanStart ) )
+ // Player is in his Titan, don't create a titan
+ if ( player.IsTitan() )
+ return
+
+ // Player already has a pet titan, don't create one
+ entity petTitan = player.GetPetTitan()
+ if ( IsValid( petTitan ) )
+ return
+
+ // Make a pet titan at the spawn point
+ TitanLoadoutDef loadout = GetTitanLoadoutForCurrentMap()
+ entity titanStart = file.spPetTitanStart
+ entity titan = CreateAutoTitanForPlayer_FromTitanLoadout( player, loadout, titanStart.GetOrigin(), titanStart.GetAngles() )
+ DispatchSpawn( titan )
+ player.SetPetTitan( titan )
+
+ titan.DisableHibernation()
+}
+
+/************************************************************************************************\
+
+######## ### ## ## ### ###### ########
+## ## ## ## ### ### ## ## ## ## ##
+## ## ## ## #### #### ## ## ## ##
+## ## ## ## ## #### ## ## ## ## ### ######
+## ## ######### ## ## ## ######### ## ## ##
+## ## ## ## ## ## ## ## ## ## ##
+######## ## ## ## ## ## ## ###### ########
+
+\************************************************************************************************/
+
+// putting this stuff here for now since it's only for SP at this point
+
+
+
+
+bool function TryTitanSavesPlayer( entity player )
+{
+ if ( !Flag( "TitanCanSavePlayer" ) )
+ return false
+
+ if ( !IsAlive( player.GetPetTitan() ) )
+ return false
+
+ entity titan = player.GetPetTitan()
+ if ( TitanIsCurrentlyEmbarkableForPlayer( player, titan ) )
+ {
+ thread TitanSavesPlayer( player, titan )
+ return true
+ }
+
+ return false
+}
+
+void function TitanSavesPlayer( entity player, entity titan )
+{
+ player.EndSignal( "OnDestroy" )
+ titan.EndSignal( "OnDeath" )
+
+ player.SetNoTarget( true )
+ player.SetInvulnerable()
+ titan.SetInvulnerable()
+
+ player.DisableWeapon()
+ player.FreezeControlsOnServer()
+ player.ForceCrouch()
+
+ OnThreadEnd(
+ function() : ( player, titan )
+ {
+ if ( IsValid( player ) )
+ {
+ if ( !IsPlayerEmbarking( player ) )
+ {
+ player.EnableWeapon()
+ }
+ player.UnforceCrouch()
+ player.UnfreezeControlsOnServer()
+ player.ClearInvulnerable()
+ player.SetNoTarget( false )
+ }
+
+ if ( IsValid( titan ) )
+ titan.ClearInvulnerable()
+ }
+ )
+
+ wait 0.25
+
+ float fadeTime = 2
+ float blackTime_pre = 4.0
+ float blackTime_post = 1.0
+
+ thread ScreenFadeToBlack( player, 2.0, blackTime_pre )
+
+ wait blackTime_pre * 0.5
+ string titanAlias = GenerateTitanOSAlias( player, "briefCriticalDamage" )
+ thread EmitSoundOnEntity( player, titanAlias )
+ wait blackTime_pre * 0.5
+
+ vector ornull clampedPos = NavMesh_ClampPointForAI( player.GetOrigin(), titan )
+ if ( clampedPos != null )
+ titan.SetOrigin( expect vector( clampedPos ) )
+
+ titan.SetAngles( Vector( 0, player.GetAngles().y, 0 ) )
+
+ entity soul = titan.GetTitanSoul()
+ SetStanceKneel( soul )
+
+ table criteria = {
+ embark = "front",
+ titanCanStandRequired = false
+ }
+
+ var embarkAction
+ embarkAction = FindEmbarkActionForCriteria( criteria )
+ if ( embarkAction == null )
+ embarkAction = GetRandomEmbarkAction()
+
+ table action = expect table( GenerateEmbarkActionTable( player, titan, embarkAction ) )
+ thread PlayerEmbarksTitan( player, titan, action )
+ thread ScreenFadeFromBlack( player, 12.0, blackTime_post )
+
+ player.Signal( "TitanSavesPlayer" )
+}
+
+bool function DamageAlwaysLethal( var damageInfo )
+{
+ const damageMask = DF_INSTANT | DF_IMPACT | DF_TITAN_STEP | DF_KILLSHOT | DF_MELEE // | DF_EXPLOSION
+ if ( DamageInfo_GetCustomDamageType( damageInfo ) & damageMask )
+ return true
+// not quite sure what this returns. It doesn't seem to be the flags listed in death_package.nut
+// if ( DamageInfo_GetDamageType( damageInfo ) & damageMask )
+// return false
+
+ // damage type doesn't seem to be correct for most things so I'm forced to check GetDamageSourceIdentifier -Roger
+ switch ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) )
+ {
+ case damagedef_crush:
+ case damagedef_nuclear_core:
+ case damagedef_suicide:
+ case damagedef_titan_fall:
+ case damagedef_titan_hotdrop:
+ case eDamageSourceId.bubble_shield:
+ case eDamageSourceId.burn:
+ case eDamageSourceId.droppod_impact:
+ case eDamageSourceId.evac_dropship_explosion:
+ case eDamageSourceId.fall:
+ case eDamageSourceId.flash_surge:
+ case eDamageSourceId.floor_is_lava:
+ case eDamageSourceId.human_execution:
+ case eDamageSourceId.human_melee:
+ case eDamageSourceId.indoor_inferno:
+ case eDamageSourceId.outOfBounds:
+ case eDamageSourceId.round_end:
+ case eDamageSourceId.splat:
+ case eDamageSourceId.stuck:
+ case eDamageSourceId.submerged:
+ case eDamageSourceId.switchback_trap:
+ case eDamageSourceId.team_switch:
+ case eDamageSourceId.titan_execution:
+ case eDamageSourceId.titan_explosion:
+ case eDamageSourceId.wall_smash:
+// case eDamageSourceId.grunt_melee:
+// case eDamageSourceId.prowler_melee:
+// case eDamageSourceId.spectre_melee:
+ return true
+
+ default:
+ break
+ }
+
+ return false
+}
+
+/************************************************************************************************\
+
+ ## ## ######## ######
+ ### ## ## ## ## ##
+ #### ## ## ## ##
+ ## ## ## ######## ##
+ ## #### ## ##
+ ## ### ## ## ##
+ ## ## ## ######
+
+\************************************************************************************************/
+void function SpNpcCommon( entity npc )
+{
+ if ( npc.GetTeam() == TEAM_MILITIA )
+ {
+ if ( !npc.IsTitan() )
+ HideName( npc )
+
+ // this is a temporary stop gap until we get skins
+ if ( file.friendlyHighlightEnabled )
+ Highlight_SetFriendlyHighlight( npc, "sp_friendly_pilot" )
+ }
+}
+
+void function SpNpcCommonGrunt( entity npc )
+{
+ // heros clear this setting so they should keep their names
+ if ( npc.GetTeam() == TEAM_MILITIA )
+ {
+
+ string title
+ if ( npc.Dev_GetAISettingByKeyField( "IsGenericGrunt" ) == 0 )
+ {
+ title = npc.GetSettingTitle()
+ }
+ else
+ {
+ title = GetMilitiaTitle()
+ }
+
+ npc.SetTitle( title )
+ ShowName( npc )
+ }
+}
+
+void function DiminishPlayerComboDamage( entity player, var damageInfo )
+{
+ if ( !IsPilot( player ) )
+ return
+
+// printt( "damage " + DamageInfo_GetDamage( damageInfo ) )
+// printt( "shield health " + player.GetShieldHealth() )
+ if ( player.GetShieldHealth() > 0 )
+ return
+
+ // blunt damage from combos
+ float damage = DamageInfo_GetDamage( damageInfo )
+
+ float recentDamage = TotalDamageOverTime_BlendedOut( player, 0.5, 1.5 )
+
+ // damage is ramped down based on how much damage was taken recently
+ float damageMod = GraphCapped( recentDamage, 70, 140, 1.0, 0.1 )
+ DamageInfo_ScaleDamage( damageInfo, damageMod )
+}
+
+void function SoulDeath_ReloadOnPetTitanDeath( entity soul, var damageInfo )
+{
+ if ( Flag( "TitanDeathPenalityDisabled" ) )
+ return
+
+ if ( IsTestMap() )
+ return
+
+ thread SoulDeath_ReloadOnPetTitanDeath_Thread( soul, damageInfo )
+}
+
+void function SoldierFriendlyFireCheck_OnKilled( entity npc, var damageInfo )
+{
+ if ( !Flag( "FriendlyFireStrict" ) )
+ return
+
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
+ if ( !attacker.IsPlayer() )
+ return
+
+ if ( npc.GetTeam() != attacker.GetTeam() )
+ return
+
+ thread SoldierFriendlyFireCheck_OnKilledDelayed()
+}
+
+void function SoldierFriendlyFireCheck_OnKilledDelayed()
+{
+ FlagClear( "SaveGame_Enabled" ) // no more saving, you have lost
+ wait 0.75
+ FriendlyFire_MissionFailure()
+}
+
+void function FriendlyFire_MissionFailure()
+{
+ if ( Flag( "MissionFailed" ) )
+ return
+
+ foreach ( player in GetPlayerArray() )
+ {
+ Remote_CallFunction_NonReplay( player, "ServerCallback_FriendlyFire_MissionFailure" )
+ }
+
+ ReloadForMissionFailure()
+}
+
+void function SoulDeath_ReloadOnPetTitanDeath_Thread( entity soul, var damageInfo )
+{
+ entity player = soul.GetBossPlayer()
+
+ if ( !IsValid( player ) )
+ return
+
+ if ( !level.nv.replayDisabled )
+ {
+ if ( player.p.watchingPetTitanKillReplay )
+ return
+
+ player.p.watchingPetTitanKillReplay = true
+ }
+
+ if ( damageInfo == null )
+ {
+ printt( "ServerCallback_TitanDied with null sourceid" )
+ ReloadForMissionFailure()
+ return
+ }
+
+ int source = DamageInfo_GetDamageSourceIdentifier( damageInfo )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_TitanDied", source )
+ #if DEV
+ printt( "ServerCallback_TitanDied with sourceid " + source + " and source string " + GetObitFromDamageSourceID( source ) )
+ #endif
+
+ if ( IsInstantDeath( damageInfo ) )
+ {
+ ReloadForMissionFailure()
+ return
+ }
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
+ if ( !IsValid( attacker ) )
+ {
+ ReloadForMissionFailure()
+ return
+ }
+
+ int index = attacker.GetIndexForEntity()
+ entity titan = soul.GetTitan()
+
+ FlagClear( "SaveGame_Enabled" ) // no more saving, you have lost
+
+ if ( !level.nv.replayDisabled )
+ {
+ /*
+ wait 3.8
+ float replayDelay = 6.5
+ player.SetKillReplayDelay( replayDelay )
+ player.SetViewIndex( index )
+
+ if ( IsValid( titan ) )
+ player.SetKillReplayVictim( titan )
+
+ ReloadForMissionFailure( replayDelay + 2.5 )
+ */
+ }
+ else
+ {
+ ReloadForMissionFailure() // replayDelay + 2.5
+ }
+}
+
+bool function HasBatteryChargeTool( entity player )
+{
+ switch ( CHARGE_TOOL )
+ {
+ case "sp_weapon_proto_battery_charger_offhand":
+ return HasOffhandWeapon( player, CHARGE_TOOL )
+
+ case "sp_weapon_arc_tool":
+ return HasWeapon( player, CHARGE_TOOL )
+ }
+
+ unreachable
+}
+
+void function GiveBatteryChargeTool( entity player )
+{
+ switch ( CHARGE_TOOL )
+ {
+ case "sp_weapon_proto_battery_charger_offhand":
+ player.GiveOffhandWeapon( CHARGE_TOOL, OFFHAND_SPECIAL )
+ break
+
+ case "sp_weapon_arc_tool":
+ player.GiveWeapon( CHARGE_TOOL )
+ break
+ }
+ UpdateArcConnectorHints()
+}
+
+/*
+void function CodeCallback_Ping( entity player )
+{
+
+}
+*/
+
+/* ----------------------------------------------------------------------------------------------
+
+STUFF FORM MP THAT WE WILL SLOWLY GET RID OF
+
+-------------------------------------------------------------------------------------------------*/
+
+string function GetGameModeAnnouncement()
+{
+ return ""
+}
+
+void function SetGameState( int newState )
+{
+ level.nv.gameStartTime = Time()
+ level.nv.gameStateChangeTime = Time()
+ level.nv.gameState = newState
+ svGlobal.levelEnt.Signal( "GameStateChanged" )
+
+ foreach ( callbackFunc in svGlobal.gameStateEnterCallbacks[ newState ] )
+ {
+ callbackFunc()
+ }
+}
+
+void function CodeCallback_GamerulesThink()
+{
+
+}
+
+void function DEV_ToggleFriendlyHighlight()
+{
+ file.friendlyHighlightEnabled = !file.friendlyHighlightEnabled
+ UpdateFriendlyHighlight()
+}
+
+void function DisableFriendlyHighlight()
+{
+ file.friendlyHighlightEnabled = false
+ UpdateFriendlyHighlight()
+}
+
+void function EnableFriendlyHighlight()
+{
+ file.friendlyHighlightEnabled = true
+ UpdateFriendlyHighlight()
+}
+
+void function UpdateFriendlyHighlight()
+{
+ if ( file.friendlyHighlightEnabled )
+ {
+ foreach ( npc in GetNPCArrayOfTeam( TEAM_MILITIA ) )
+ Highlight_SetFriendlyHighlight( npc, "sp_friendly_pilot" )
+ }
+ else
+ {
+ foreach ( npc in GetNPCArrayOfTeam( TEAM_MILITIA ) )
+ Highlight_ClearFriendlyHighlight( npc )
+ }
+}
+
+bool function ClientCommand_RestartMission( entity player, array<string> args )
+{
+ ServerRestartMission( player )
+ return true
+}
+
+void function ServerRestartMission( entity player )
+{
+ if ( IsTestMap() )
+ {
+ ServerCommand( "reload" )
+ return
+ }
+
+ string mapName = GetMapName()
+ LevelTransitionStruct ornull trans = file.storedLevelTransitionStruct
+ if ( trans == null )
+ {
+ int startIndex = 0
+ #if DEV
+ string startName = Dev_GetStartCommandLine( mapName )
+ if ( startName != "" )
+ startIndex = GetStartPointIndexFromName( mapName, startName )
+ #endif
+ // loaded a level manually in dev or are in sp_training
+ ExecuteLoadingClientCommands_SetStartPoint( mapName, startIndex )
+ ClientCommand( player, "map " + mapName )
+ return
+ }
+
+ expect LevelTransitionStruct( trans )
+ ExecuteLoadingClientCommands_SetStartPoint( mapName, trans.startPointIndex )
+ ChangeLevel( mapName, trans )
+}
+
+void function PilotBecomesTitanStoreWeaponVar( entity pilot, entity npc_titan )
+{
+ entity weapon = pilot.GetMainWeapons()[0]
+ int index = GetTitanLoadoutIndex( weapon.GetWeaponClassName() )
+ SetConVarInt( "sp_titanLoadoutCurrent", index )
+}
+
+void function PreventFriendlyTitanfallDamage( entity ent, var damageInfo )
+{
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
+
+ if ( attacker.GetTeam() == ent.GetTeam() )
+ {
+ DamageInfo_SetDamage( damageInfo, 0 )
+ }
+} \ No newline at end of file