From 31c8a052e8f3cdccedb7f6f8d2bd11678189001a Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 27 Jun 2021 20:55:35 +0100 Subject: added ttdm, more scoreevents and ctf comp --- Northstar.Custom/mod.json | 7 ++ Northstar.Custom/playlists_v2.txt | 87 ++++++++++++++++ .../vscripts/gamemodes/sh_gamemode_ctf_comp.gnut | 109 +++++++++++++++++++++ .../scripts/vscripts/_loadouts_mp.gnut | 2 +- .../scripts/vscripts/gamemodes/_gamemode_lts.nut | 71 ++------------ .../vscripts/gamemodes/_gamemode_speedball.nut | 2 +- .../scripts/vscripts/gamemodes/_gamemode_ttdm.nut | 67 +++++++++++++ .../scripts/vscripts/gamemodes/sh_gamemode_mfd.nut | 66 ------------- .../scripts/vscripts/mp/_base_gametype_mp.gnut | 61 ++++++++---- .../scripts/vscripts/mp/_classic_mp.nut | 2 +- .../vscripts/mp/_classic_mp_dropship_intro.gnut | 2 +- .../scripts/vscripts/mp/_classic_mp_no_intro.gnut | 56 ++++++++--- .../scripts/vscripts/mp/_gamestate_mp.nut | 46 +++------ .../scripts/vscripts/mp/_score.nut | 103 +++++++++++++++++-- .../vscripts/mp/levels/_lf_maps_shared.gnut | 2 +- .../scripts/vscripts/mp/spawn.nut | 11 +++ 16 files changed, 493 insertions(+), 201 deletions(-) create mode 100644 Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut delete mode 100644 Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemode_mfd.nut diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 2c82cb0b7..75a142915 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -161,6 +161,13 @@ "RunOn": "CLIENT && MP" }, + { + "Path": "gamemodes/sh_gamemode_ctf_comp.gnut", + "RunOn": "( CLIENT || SERVER ) && MP", + "ClientPreCallback": "ShGamemodeCTFComp_Init", + "ServerPreCallback": "ShGamemodeCTFComp_Init" + }, + { "Path": "titan/sh_first_person_embark.gnut", "RunOn": "( CLIENT || SERVER ) && MP", diff --git a/Northstar.Custom/playlists_v2.txt b/Northstar.Custom/playlists_v2.txt index be938cc36..56b566032 100644 --- a/Northstar.Custom/playlists_v2.txt +++ b/Northstar.Custom/playlists_v2.txt @@ -996,6 +996,34 @@ playlists gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM } } + ctf_comp + { + inherit defaults + vars + { + name #GAMEMODE_ctf_comp + lobbytitle #PL_capture_the_flag_lobby + description #PL_capture_the_flag_desc + hint #PL_capture_the_flag_hint + abbreviation #PL_capture_the_flag_abbr + image ctf + respawn_delay 8 + scorelimit 5 + suddendeath_timelimit 2 + timelimit 12 + max_players 10 + phase_shift_drop_flag 1 + ctf_flag_return_time 1 + color "0 119 245 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_CTF + gamemode_bullet_001 #GAMEMODE_BULLET_CTF_001 + gamemode_bullet_002 #GAMEMODE_BULLET_CTF_002 + gamemode_bullet_003 #GAMEMODE_BULLET_CTF_003 + gamemode_bullet_004 #GAMEMODE_BULLET_CTF_004 + gamemode_bullet_005 #GAMEMODE_BULLET_CTF_005 + } + } // END OF MP GAMEMODES LINE ---------------------------------------------------- @@ -2684,6 +2712,63 @@ playlists } } } + ctf_comp + { + inherit defaults + vars + { + name #GAMEMODE_ctf_comp + lobbytitle #PL_capture_the_flag_lobby + description #PL_capture_the_flag_desc + abbreviation #PL_capture_the_flag_abbr + image ctf + mixtape_slot 4 + mixtape_timeout 120 + visible 1 + + // comp-exclusive settings + // note: these don't display right on the private match menu yet + pilot_health_multiplier 1.25 + respawn_delay 7.0 + + boosts_enabled 1 // this is actually disabled lol + earn_meter_pilot_overdrive 0 + earn_meter_pilot_multiplier 0.5 + earn_meter_titan_multiplier 0.5 + + scorelimit 6 + timelimit 14 + } + gamemodes + { + ctf + { + maps + { + mp_complex3 1 + mp_drydock 2 + mp_glitch 1 + mp_homestead 2 + mp_eden 2 + mp_forwardbase_kodai 1 + mp_black_water_canal 2 + mp_glitch 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 + mp_grave 2 + mp_homestead 2 + mp_drydock 2 + mp_glitch 1 + mp_thaw 1 + mp_eden 2 + mp_black_water_canal 2 + mp_glitch 1 + mp_relic02 1 + } + } + } + } // END OF MP PLAYLISTS LINE ---------------------------------------------------- @@ -4877,6 +4962,8 @@ playlists "FASTBALL_PANEL_CAPTURED" "%s1 captured panel %s2" "SCOREBOARD_FASTBALL_HACKS" "Panels Captured" + "GAMEMODE_ctf_comp" "Competitive CTF" + // FAQ - Community // diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut new file mode 100644 index 000000000..aff693c7d --- /dev/null +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut @@ -0,0 +1,109 @@ +global function ShGamemodeCTFComp_Init + +global const string GAMEMODE_CTF_COMP = "ctf_comp" + +void function ShGamemodeCTFComp_Init() +{ + // create custom gamemode + AddCallback_OnCustomGamemodesInit( CreateGamemodeCTFComp ) + AddCallback_OnRegisteringCustomNetworkVars( CTFCompRegisterNetworkVars ) +} + +void function CreateGamemodeCTFComp() +{ + GameMode_Create( GAMEMODE_CTF_COMP ) + GameMode_SetName( GAMEMODE_CTF_COMP, "#GAMEMODE_ctf_comp" ) + GameMode_SetGameModeAnnouncement( GAMEMODE_CTF_COMP, "ctf_modeDesc" ) + GameMode_SetDesc( GAMEMODE_CTF_COMP, "#PL_capture_the_flag_hint" ) + GameMode_SetIcon( GAMEMODE_CTF_COMP, $"ui/menu/playlist/ctf" ) + GameMode_SetSuddenDeath( GAMEMODE_CTF_COMP, true ) + GameMode_SetDefaultScoreLimits( GAMEMODE_CTF_COMP, 0, 5 ) + GameMode_SetDefaultTimeLimits( GAMEMODE_CTF_COMP, 0, 3.0 ) + GameMode_AddScoreboardColumnData( GAMEMODE_CTF_COMP, "#SCOREBOARD_CAPTURES", PGS_ASSAULT_SCORE, 2 ) + GameMode_AddScoreboardColumnData( GAMEMODE_CTF_COMP, "#SCOREBOARD_RETURNS", PGS_DEFENSE_SCORE, 2 ) + GameMode_AddScoreboardColumnData( GAMEMODE_CTF_COMP, "#SCOREBOARD_KILLS", PGS_KILLS, 2 ) + GameMode_AddScoreboardColumnData( GAMEMODE_CTF_COMP, "#SCOREBOARD_TITAN_DAMAGE", PGS_DISTANCE_SCORE, 6 ) // gotta use a weird pgs here since we're running out of them lol + GameMode_SetColor( GAMEMODE_CTF_COMP, [61, 117, 193, 255] ) + + // this gamemode is literally just normal ctf + a few extra settings + // as such we do all the inits in this file, not enough logic to be worth splitting it up + + #if SERVER + GameMode_AddServerInit( GAMEMODE_CTF_COMP, InitCTFCompSpecificSettings ) + GameMode_AddServerInit( GAMEMODE_CTF_COMP, CaptureTheFlag_Init ) + GameMode_SetPilotSpawnpointsRatingFunc( GAMEMODE_CTF_COMP, RateSpawnpoints_CTF ) + GameMode_SetTitanSpawnpointsRatingFunc( GAMEMODE_CTF_COMP, RateSpawnpoints_CTF ) + #elseif CLIENT + GameMode_AddClientInit( GAMEMODE_CTF_COMP, InitCTFCompSpecificSettings ) + GameMode_AddClientInit( GAMEMODE_CTF_COMP, ClCaptureTheFlag_Init ) + #endif + #if !UI + GameMode_SetScoreCompareFunc( GAMEMODE_CTF_COMP, CompareCTF ) + GameMode_AddSharedInit( GAMEMODE_CTF_COMP, GamemodeCtfDialogue_Init ) + GameMode_AddSharedInit( GAMEMODE_CTF_COMP, CaptureTheFlagShared_Init ) + #endif +} + +void function CTFCompRegisterNetworkVars() +{ + // copied from the vanilla ctf remote functions + RegisterNetworkedVariable( "imcFlag", SNDC_GLOBAL, SNVT_ENTITY ) + RegisterNetworkedVariable( "milFlag", SNDC_GLOBAL, SNVT_ENTITY ) + + RegisterNetworkedVariable( "imcFlagHome", SNDC_GLOBAL, SNVT_ENTITY ) + RegisterNetworkedVariable( "milFlagHome", SNDC_GLOBAL, SNVT_ENTITY ) + + RegisterNetworkedVariable( "imcFlagState", SNDC_GLOBAL, SNVT_INT, 0 ) + RegisterNetworkedVariable( "milFlagState", SNDC_GLOBAL, SNVT_INT, 0 ) + + RegisterNetworkedVariable( "flagReturnProgress", SNDC_GLOBAL, SNVT_FLOAT_RANGE_OVER_TIME, 0.0, 0.0, 1.0 ) + RegisterNetworkedVariable( "returningFlag", SNDC_PLAYER_EXCLUSIVE, SNVT_BOOL, false ) + + Remote_RegisterFunction( "ServerCallback_CTF_PlayMatchNearEndMusic" ) + Remote_RegisterFunction( "ServerCallback_CTF_StartReturnFlagProgressBar" ) + Remote_RegisterFunction( "ServerCallback_CTF_StopReturnFlagProgressBar" ) + + #if CLIENT + CLCaptureTheFlag_RegisterNetworkFunctions() + #endif +} + +void function InitCTFCompSpecificSettings() +{ + #if SERVER + SetShouldUsePickLoadoutScreen( true ) + TrackTitanDamageInPlayerGameStat( PGS_DISTANCE_SCORE ) + SetSpawnpointGamemodeOverride( CAPTURE_THE_FLAG ) + TeamTitanSelectMenu_Init() + #elseif CLIENT + ClTeamTitanSelectMenu_Init() + + // gotta register the music here because this is done hardcoded to ctf in cl_music + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_INTRO, "music_mp_ctf_intro_flyin", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_INTRO, "music_mp_ctf_intro_flyin", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_WIN, "music_mp_ctf_epilogue_win", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_WIN, "music_mp_ctf_epilogue_win", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_DRAW, "music_mp_ctf_halftime_losing", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_DRAW, "music_mp_ctf_halftime_losing", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_SUDDEN_DEATH, "music_mp_ctf_draw", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_SUDDEN_DEATH, "music_mp_ctf_draw", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_LOSS, "music_mp_ctf_epilogue_lose", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_LOSS, "music_mp_ctf_epilogue_lose", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.ROUND_BASED_GAME_WON, "music_mp_ctf_halftime_winning", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.ROUND_BASED_GAME_WON, "music_mp_ctf_halftime_winning", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.ROUND_BASED_GAME_LOST, "music_mp_ctf_halftime_losing", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.ROUND_BASED_GAME_LOST, "music_mp_ctf_halftime_losing", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.GAMEMODE_1, "music_mp_ctf_flag_4", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.GAMEMODE_1, "music_mp_ctf_flag_4", TEAM_MILITIA ) + + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_LAST_MINUTE, "music_mp_ctf_lastminute", TEAM_IMC ) + RegisterLevelMusicForTeam( eMusicPieceID.LEVEL_LAST_MINUTE, "music_mp_ctf_lastminute", TEAM_MILITIA ) + #endif +} \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/scripts/vscripts/_loadouts_mp.gnut index fdba12da9..74f5e0476 100644 --- a/Northstar.CustomServers/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/scripts/vscripts/_loadouts_mp.gnut @@ -167,7 +167,7 @@ bool function ClientCommandCallback_SwapSecondaryAndWeapon3PersistentLoadoutData bool function ClientCommandCallback_SetBurnCardPersistenceSlot( entity player, array args ) { - if ( args.len() != 1 ) + if ( args.len() != 1 || GetGameState() >= eGameState.Playing ) return true print( player + " SetBurnCardPersistenceSlot " + args[0] ) diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_lts.nut b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_lts.nut index 82c304b69..b9d5aa49d 100644 --- a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_lts.nut +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_lts.nut @@ -18,57 +18,26 @@ void function GamemodeLts_Init() SetRoundBased( true ) SetRespawnsEnabled( false ) Riff_ForceSetEliminationMode( eEliminationMode.PilotsTitans ) + Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) SetShouldUseRoundWinningKillReplay( true ) SetRoundWinningKillReplayKillClasses( true, true ) // both titan and pilot kills are tracked - - AddDamageCallback( "player", OnPlayerDamaged ) - AddDamageCallback( "npc_titan", OnTitanDamaged ) - + AddCallback_OnPilotBecomesTitan( RefreshThirtySecondWallhackHighlight ) AddCallback_OnTitanBecomesPilot( RefreshThirtySecondWallhackHighlight ) SetTimeoutWinnerDecisionFunc( CheckTitanHealthForDraw ) + TrackTitanDamageInPlayerGameStat( PGS_ASSAULT_SCORE ) - ClassicMP_SetCustomIntro( GamemodeLTS_Intro, 0.0 ) // dont any sorta timer + ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) + AddCallback_GameStateEnter( eGameState.Playing, WaitForThirtySecondsLeft ) } -// this should also probably be moved into a generic intro rather than being lts-specific -void function GamemodeLTS_Intro() +void function WaitForThirtySecondsLeft() { - AddCallback_GameStateEnter( eGameState.Prematch, LTSIntroOnPrematchStart ) + thread WaitForThirtySecondsLeftThreaded() } -void function LTSIntroOnPrematchStart() -{ - ClassicMP_OnIntroStarted() - - foreach ( entity player in GetPlayerArray() ) - thread LTSIntroSpawnPlayer( player ) - - wait 2.0 // literally a guess number for how long the drop might take - - ClassicMP_OnIntroFinished() - - thread GamemodeLTS_PlayingThink() -} - -void function LTSIntroSpawnPlayer( entity player ) -{ - if ( IsAlive( player ) ) - { - player.Die() - WaitFrame() // this doesn't work for some reason but the player will die in roundend anyway so not really an issue - } - - thread RespawnAsTitan( player, false ) - - while ( !player.IsTitan() ) - WaitFrame() - - TryGameModeAnnouncement( player ) -} - -void function GamemodeLTS_PlayingThink() +void function WaitForThirtySecondsLeftThreaded() { svGlobal.levelEnt.EndSignal( "RoundEnd" ) // end this on round end @@ -121,7 +90,7 @@ int function CheckTitanHealthForDraw() } } - // note: due to how stuff is set up rn, there's actually no way to do win/loss reasons in timeout decision funcs + // note: due to how stuff is set up rn, there's actually no way to do win/loss reasons outside of a SetWinner call, i.e. not in timeout winner decision // as soon as there is, strings in question are "#GAMEMODE_TITAN_TITAN_ADVANTAGE" and "#GAMEMODE_TITAN_TITAN_DISADVANTAGE" if ( militiaTitans != imcTitans ) @@ -130,26 +99,4 @@ int function CheckTitanHealthForDraw() return militiaHealth > imcHealth ? TEAM_MILITIA : TEAM_IMC return TEAM_UNASSIGNED -} - -// this should be generic, not restricted to a specific gamemode -void function AddToTitanDamageStat( entity victim, var damageInfo ) -{ - // todo: this needs to not count selfdamage - entity attacker = DamageInfo_GetAttacker( damageInfo ) - float amount = DamageInfo_GetDamage( damageInfo ) - - if ( attacker.IsPlayer() && attacker != victim ) - attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, amount ) // titan damage on -} - -void function OnPlayerDamaged( entity player, var damageInfo ) -{ - if ( player.IsTitan() ) - AddToTitanDamageStat( player, damageInfo ) -} - -void function OnTitanDamaged( entity titan, var damageInfo ) -{ - AddToTitanDamageStat( titan, damageInfo ) } \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_speedball.nut b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_speedball.nut index 91ebf8c69..4532fb972 100644 --- a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_speedball.nut +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_speedball.nut @@ -25,7 +25,7 @@ void function GamemodeSpeedball_Init() AddCallback_OnPlayerKilled( OnPlayerKilled ) SetTimeoutWinnerDecisionFunc( TimeoutCheckFlagHolder ) - ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, NOINTRO_INTRO_LENGTH ) + ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) } void function CreateFlag( entity flagSpawn ) diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_ttdm.nut b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_ttdm.nut index 92119c1cc..faf3e5cad 100644 --- a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_ttdm.nut +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_ttdm.nut @@ -1,6 +1,73 @@ global function GamemodeTTDM_Init +const float TTDMIntroLength = 15.0 + void function GamemodeTTDM_Init() { + Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) + Riff_ForceTitanExitEnabled( eTitanExitEnabled.Never ) + TrackTitanDamageInPlayerGameStat( PGS_ASSAULT_SCORE ) + + ClassicMP_SetCustomIntro( TTDMIntroSetup, TTDMIntroLength ) + + AddCallback_OnPlayerKilled( AddTeamScoreForPlayerKilled ) // dont have to track autotitan kills since you cant leave your titan in this mode + + // probably needs scoreevent earnmeter values +} + +void function TTDMIntroSetup() +{ + // this should show intermission cam for 15 sec in prematch, before spawning players as titans + AddCallback_GameStateEnter( eGameState.Prematch, TTDMIntroStart ) + AddCallback_OnClientConnected( TTDMIntroShowIntermissionCam ) +} + +void function TTDMIntroStart() +{ + thread TTDMIntroStartThreaded() +} + +void function TTDMIntroStartThreaded() +{ + ClassicMP_OnIntroStarted() + + foreach ( entity player in GetPlayerArray() ) + TTDMIntroShowIntermissionCam( player ) + + wait TTDMIntroLength + + ClassicMP_OnIntroFinished() +} +void function TTDMIntroShowIntermissionCam( entity player ) +{ + if ( GetGameState() != eGameState.Prematch ) + return + + thread PlayerWatchesTTDMIntroIntermissionCam( player ) +} + +void function PlayerWatchesTTDMIntroIntermissionCam( entity player ) +{ + ScreenFadeFromBlack( player ) + + entity intermissionCam = GetEntArrayByClass_Expensive( "info_intermission" )[ 0 ] + + // the angle set here seems sorta inconsistent as to whether it actually works or just stays at 0 for some reason + player.SetObserverModeStaticPosition( intermissionCam.GetOrigin() ) + player.SetObserverModeStaticAngles( intermissionCam.GetAngles() ) + player.StartObserverMode( OBS_MODE_STATIC_LOCKED ) + + wait TTDMIntroLength + + RespawnAsTitan( player, false ) + TryGameModeAnnouncement( player ) +} + +void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !victim.IsPlayer() || !attacker.IsPlayer() ) + return + + AddTeamScore( GetOtherTeam( victim.GetTeam() ), 1 ) } \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemode_mfd.nut b/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemode_mfd.nut deleted file mode 100644 index 4410a5136..000000000 --- a/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemode_mfd.nut +++ /dev/null @@ -1,66 +0,0 @@ -untyped - -global function GamemodeMfdShared_Init -global function GetMarked -global function GetPendingMarked -global function FillMFDMarkers -global function TargetsMarkedImmediately -global function IsTitanMarkedForDeathMode - -void function GamemodeMfdShared_Init() -{ - // mfd mfdActiveMarkedPlayerEnt are server side entities with a boss player that marks the marked - level.mfdActiveMarkedPlayerEnt <- {} - level.mfdActiveMarkedPlayerEnt[ TEAM_IMC ] <- null - level.mfdActiveMarkedPlayerEnt[ TEAM_MILITIA ] <- null - - level.mfdPendingMarkedPlayerEnt <- {} - level.mfdPendingMarkedPlayerEnt[ TEAM_IMC ] <- null - level.mfdPendingMarkedPlayerEnt[ TEAM_MILITIA ] <- null - - SetWaveSpawnInterval( 8.0 ) -} - -entity function GetMarked( int team ) -{ - if ( IsValid( level.mfdActiveMarkedPlayerEnt[ team ] ) ) - return expect entity( level.mfdActiveMarkedPlayerEnt[ team ] ).GetOwner() - - return null -} - -entity function GetPendingMarked( int team ) -{ - if ( IsValid( level.mfdPendingMarkedPlayerEnt[ team ] ) ) - return expect entity( level.mfdPendingMarkedPlayerEnt[ team ] ).GetOwner() - - return null -} - -function FillMFDMarkers( entity ent ) //Ent used for kill replay related issues... -{ - print( "FillMFDMarkers " + ent ) - - if ( ent.GetTargetName() == MARKET_ENT_MARKED_NAME ) - { - Assert( ent.GetTeam() != TEAM_UNASSIGNED ) - level.mfdActiveMarkedPlayerEnt[ ent.GetTeam() ] = ent - } - else if ( ent.GetTargetName() == MARKET_ENT_PENDING_MARKED_NAME ) - { - Assert( ent.GetTeam() != TEAM_UNASSIGNED ) - level.mfdPendingMarkedPlayerEnt[ ent.GetTeam() ] = ent - } - - return -} - -function TargetsMarkedImmediately() -{ - return IsRoundBased() && IsPilotEliminationBased() -} - -bool function IsTitanMarkedForDeathMode() -{ - return GetCurrentPlaylistVarInt( "titan_marked_for_death", 0 ) == 1 -} \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut index 69fcfb501..5a684f20f 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -13,6 +13,7 @@ global function TryGameModeAnnouncement global function SetKillcamsEnabled global function KillcamsEnabled global function SetPlayerDeathsHidden +global function TrackTitanDamageInPlayerGameStat global function ShouldEntTakeDamage_SPMP global function GetTitanBuildTime @@ -21,6 +22,7 @@ global function TitanPlayerHotDropsIntoLevel struct { bool killcamsEnabled = true bool playerDeathsHidden = false + int titanDamageGameStat = -1 entity intermissionCamera array specCams @@ -35,6 +37,9 @@ void function BaseGametype_Init_MPSP() AddClientCommandCallback( "spec_next", ClientCommandCallback_spec_next ) AddClientCommandCallback( "spec_prev", ClientCommandCallback_spec_prev ) AddClientCommandCallback( "spec_mode", ClientCommandCallback_spec_mode ) + + AddDamageCallback( "player", AddToTitanDamageStat ) + AddDamageCallback( "npc_titan", AddToTitanDamageStat ) } void function SetIntermissionCamera( entity camera ) @@ -222,10 +227,6 @@ void function CodeCallback_OnPlayerRespawned( entity player ) void function CodeCallback_OnPlayerKilled( entity player, var damageInfo ) { PlayerOrNPCKilled( player, damageInfo ) - - if ( player.IsTitan() ) - SoulDies( player.GetTitanSoul(), damageInfo ) // cleanup some titan stuff, no idea where else to put this - thread PostDeathThread_MP( player, damageInfo ) } @@ -253,6 +254,11 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga player.SetNoTargetSmartAmmo( false ) player.ClearExtraWeaponMods() + player.AddToPlayerGameStat( PGS_DEATHS, 1 ) + + if ( player.IsTitan() ) + SoulDies( player.GetTitanSoul(), damageInfo ) // cleanup some titan stuff, no idea where else to put this + ClearRespawnAvailable( player ) OnThreadEnd( function() : ( player ) @@ -285,24 +291,24 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga thread TrackDestroyTimeForReplay( attacker, replayTracker ) int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) - if ( damageSource == eDamageSourceId.fall ) - { - // this is straight up just incorrect lol, based off tf1 stuff - - player.SetObserverModeStaticPosition( player.GetOrigin() ) - player.SetObserverModeStaticAngles( player.GetVelocity() * -1 ) - - player.StartObserverMode( OBS_MODE_STATIC_LOCKED ) - player.SetObserverTarget( null ) - } - else - { + //if ( damageSource == eDamageSourceId.fall ) + //{ + // // this is straight up just incorrect lol, based off tf1 stuff + // + // player.SetObserverModeStaticPosition( player.GetOrigin() ) + // player.SetObserverModeStaticAngles( player.GetVelocity() * -1 ) + // + // player.StartObserverMode( OBS_MODE_STATIC_LOCKED ) + // player.SetObserverTarget( null ) + //} + //else + //{ player.StartObserverMode( OBS_MODE_DEATHCAM ) if ( ShouldSetObserverTarget( attacker ) ) player.SetObserverTarget( attacker ) else player.SetObserverTarget( null ) - } + //} if ( !file.playerDeathsHidden ) Remote_CallFunction_NonReplay( player, "ServerCallback_YouDied", attacker.GetEncodedEHandle(), GetHealthFrac( attacker ), methodOfDeath ) @@ -356,7 +362,7 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga player.WaitSignal( "RespawnMe" ) // set in base_gametype: ClientCommand_RespawnPlayer ClearRespawnAvailable( player ) // need so the respawn icon doesn't show for like a frame on next death - if ( ( expect bool( player.GetPersistentVar( "spawnAsTitan" ) ) && IsTitanAvailable( player ) ) || Riff_SpawnAsTitan() == 1 ) // spawn as titan + if ( ( expect bool( player.GetPersistentVar( "spawnAsTitan" ) ) && IsTitanAvailable( player ) ) || ( Riff_SpawnAsTitan() > 0 && Riff_ShouldSpawnAsTitan( player ) ) ) // spawn as titan thread RespawnAsTitan( player ) else // spawn as pilot RespawnAsPilot( player ) @@ -562,6 +568,25 @@ void function SetPlayerDeathsHidden( bool hidden ) file.playerDeathsHidden = hidden } +void function TrackTitanDamageInPlayerGameStat( int playerGameStat ) +{ + file.titanDamageGameStat = playerGameStat +} + +// this should be generic, not restricted to a specific gamemode +void function AddToTitanDamageStat( entity victim, var damageInfo ) +{ + if ( !victim.IsTitan() || file.titanDamageGameStat == -1 ) + return + + // todo: this needs to not count selfdamage + entity attacker = DamageInfo_GetAttacker( damageInfo ) + float amount = DamageInfo_GetDamage( damageInfo ) + + if ( attacker.IsPlayer() && attacker != victim ) + attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, amount ) // titan damage on +} + // stuff to change later diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp.nut b/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp.nut index d6ac8f55a..ac8a397f7 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp.nut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp.nut @@ -22,7 +22,7 @@ void function ClassicMP_TryDefaultIntroSetup() if ( file.introSetupFunc == null ) { if ( IsFFAGame() ) - ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, NOINTRO_INTRO_LENGTH ) + ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) else ClassicMP_SetCustomIntro( ClassicMP_DefaultDropshipIntro_Setup, DROPSHIP_INTRO_LENGTH ) } diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 20455c696..d4712cf1b 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -104,7 +104,7 @@ void function OnPrematchStart() array dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" ) foreach ( entity dropshipSpawn in dropshipSpawns ) { - if ( GameModeRemove( dropshipSpawn ) ) + if ( GameModeRemove( dropshipSpawn ) || ( GetSpawnpointGamemodeOverride() != GAMETYPE && dropshipSpawn.kv[ "gamemode_" + GetSpawnpointGamemodeOverride() ] == "0" ) ) continue // todo: possibly make this only spawn dropships if we've got enough players to need them diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_no_intro.gnut b/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_no_intro.gnut index 50e9e9a07..106f867b1 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_no_intro.gnut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_classic_mp_no_intro.gnut @@ -1,7 +1,11 @@ untyped global function ClassicMP_DefaultNoIntro_Setup -global const float NOINTRO_INTRO_LENGTH = 10.0 +global function ClassicMP_DefaultNoIntro_GetLength + +global const float NOINTRO_INTRO_PILOT_LENGTH = 10.0 +global const float TITAN_DROP_SPAWN_INTRO_LENGTH = 0.0 // this intro shouldn't have a countdown visually, so we have to set the length of this intro to 0 +global const float TITAN_DROP_SPAWN_INTRO_REAL_LENGTH = 2.0 // we wait roughly this long during the intro, even when it's technically over void function ClassicMP_DefaultNoIntro_Setup() { @@ -9,20 +13,35 @@ void function ClassicMP_DefaultNoIntro_Setup() AddCallback_GameStateEnter( eGameState.Prematch, ClassicMP_DefaultNoIntro_Start ) } +float function ClassicMP_DefaultNoIntro_GetLength() +{ + if ( ShouldIntroSpawnAsTitan() ) + return TITAN_DROP_SPAWN_INTRO_LENGTH + else + return NOINTRO_INTRO_PILOT_LENGTH + + unreachable +} + void function ClassicMP_DefaultNoIntro_Start() { ClassicMP_OnIntroStarted() foreach ( entity player in GetPlayerArray() ) - thread ClassicMP_DefaultNoIntro_SpawnPlayer( player ) + ClassicMP_DefaultNoIntro_SpawnPlayer( player ) - wait NOINTRO_INTRO_LENGTH - - foreach ( entity player in GetPlayerArray() ) + if ( ShouldIntroSpawnAsTitan() ) + wait TITAN_DROP_SPAWN_INTRO_REAL_LENGTH + else { - player.UnfreezeControlsOnServer() - RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) - TryGameModeAnnouncement( player ) + wait NOINTRO_INTRO_PILOT_LENGTH + + foreach ( entity player in GetPlayerArray() ) + { + player.UnfreezeControlsOnServer() + RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) + TryGameModeAnnouncement( player ) + } } ClassicMP_OnIntroFinished() @@ -34,13 +53,28 @@ void function ClassicMP_DefaultNoIntro_SpawnPlayer( entity player ) return if ( IsAlive( player ) ) - { player.Die() - WaitFrame() - } + if ( ShouldIntroSpawnAsTitan() ) + thread ClassicMP_DefaultNoIntro_TitanSpawnPlayer( player ) + else + thread ClassicMP_DefaultNoIntro_PilotSpawnPlayer( player ) +} + + +// spawn as pilot for intro +void function ClassicMP_DefaultNoIntro_PilotSpawnPlayer( entity player ) +{ RespawnAsPilot( player ) player.FreezeControlsOnServer() AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) ScreenFadeFromBlack( player, 0.5, 0.5 ) +} + +// spawn as titan for intro +void function ClassicMP_DefaultNoIntro_TitanSpawnPlayer( entity player ) +{ + // blocking call + RespawnAsTitan( player, false ) + TryGameModeAnnouncement( player ) } \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut index 97e06377b..bbeb72fbb 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut @@ -417,6 +417,8 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla { player.SetPredictionEnabled( false ) // prediction fucks with replays + // delay seems weird for switchingsides? ends literally the frame the flag is collected + entity attacker = file.roundWinningKillReplayAttacker player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() ) @@ -452,34 +454,6 @@ void function GameStateEnter_SuddenDeath() SetRespawnsEnabled( false ) } -void function GameStateEnter_SuddenDeath_Threaded() -{ - while ( GetGameState() == eGameState.SuddenDeath ) - { - // todo this really ought to work for ffa in the future - int imcPlayers - int militiaPlayers - - foreach ( entity player in GetPlayerArray() ) - { - if ( IsAlive( player ) ) - { - if ( player.GetTeam() == TEAM_IMC ) - imcPlayers++ - else - militiaPlayers++ - } - } - - if ( imcPlayers == 0 ) - SetWinner( TEAM_MILITIA ) - else if ( militiaPlayers == 0 ) - SetWinner( TEAM_IMC ) - - WaitFrame() - } -} - // eGameState.Postmatch void function GameStateEnter_Postmatch() @@ -502,6 +476,9 @@ void function GameStateEnter_Postmatch_Threaded() void function ForceFadeToBlack( entity player ) { + // todo: check if this is still necessary + player.EndSignal( "OnDestroy" ) + // hack until i figure out what deathcam stuff is causing fadetoblacks to be cleared while ( true ) { @@ -518,8 +495,9 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) if ( !GamePlayingOrSuddenDeath() ) return - // set round winning killreplay info here if no custom replaydelay - if ( file.roundWinningKillReplayTrackPilotKills && victim != attacker ) + // set round winning killreplay info here if we're tracking pilot kills + // todo: make this not count environmental deaths like falls, unsure how to prevent this + if ( file.roundWinningKillReplayTrackPilotKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) ) { file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim @@ -563,9 +541,10 @@ void function OnTitanKilled( entity victim, var damageInfo ) if ( !GamePlayingOrSuddenDeath() ) return - // set round winning killreplay info here if no custom replaydelay + // set round winning killreplay info here if we're tracking titan kills + // todo: make this not count environmental deaths like falls, unsure how to prevent this entity attacker = DamageInfo_GetAttacker( damageInfo ) - if ( file.roundWinningKillReplayTrackTitanKills && victim != attacker ) + if ( file.roundWinningKillReplayTrackTitanKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) ) { file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim @@ -625,7 +604,8 @@ void function CleanUpEntitiesForRoundEnd() } foreach ( entity npc in GetNPCArray() ) - npc.Die() + if ( IsAlive( npc ) ) + npc.Die() // need this because getnpcarray includes the pettitans we just killed at this point // allow other scripts to clean stuff up too svGlobal.levelEnt.Signal( "CleanUpEntitiesForRoundEnd" ) diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/scripts/vscripts/mp/_score.nut index b8ea6074b..9f1e59789 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_score.nut @@ -17,7 +17,14 @@ struct { void function Score_Init() { + AddCallback_OnClientConnected( InitPlayerForScoreEvents ) +} +void function InitPlayerForScoreEvents( entity player ) +{ + player.s.currentKillstreak <- 0 + player.s.lastKillTime <- 0.0 + player.s.currentTimedKillstreak <- 0 } void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity associatedEnt = null, string noideawhatthisis = "", int pointValueOverride = -1 ) @@ -33,13 +40,29 @@ void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity if ( pointValueOverride != -1 ) event.pointValue = pointValueOverride - - float scale = targetPlayer.IsTitan() ? event.coreMeterScalar : 1.0 + + float scale = targetPlayer.IsTitan() ? event.coreMeterScalar : 1.0 + float earnValue = event.earnMeterEarnValue * scale float ownValue = event.earnMeterOwnValue * scale PlayerEarnMeter_AddEarnedAndOwned( targetPlayer, earnValue * scale, ownValue * scale ) + // PlayerEarnMeter_AddEarnedAndOwned handles this scaling by itself, we just need to do this for the visual stuff + float pilotScaleVar = ( expect string ( GetCurrentPlaylistVarOrUseValue( "earn_meter_pilot_multiplier", "1" ) ) ).tofloat() + float titanScaleVar = ( expect string ( GetCurrentPlaylistVarOrUseValue( "earn_meter_titan_multiplier", "1" ) ) ).tofloat() + + if ( targetPlayer.IsTitan() ) + { + earnValue *= titanScaleVar + ownValue *= titanScaleVar + } + else + { + earnValue *= pilotScaleVar + ownValue *= pilotScaleVar + } + Remote_CallFunction_NonReplay( targetPlayer, "ServerCallback_ScoreEvent", event.eventId, event.pointValue, event.displayType, associatedHandle, ownValue, earnValue ) if ( event.displayType & eEventDisplayType.CALLINGCARD ) // callingcardevents are shown to all players @@ -54,24 +77,90 @@ void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity } if ( ScoreEvent_HasConversation( event ) ) - thread Delayed_PlayConversationToPlayer( event.conversation, targetPlayer, event.conversationDelay ) + PlayFactionDialogueToPlayer( event.conversation, targetPlayer ) } void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damageInfo ) { + // reset killstreaks and stuff + victim.s.currentKillstreak = 0 + victim.s.lastKillTime = 0.0 + victim.s.currentTimedKillstreak = 0 + + victim.p.numberOfDeathsSinceLastKill++ // this is reset on kill + + // have to do this early before we reset victim's player killstreaks + // nemesis when you kill a player that is dominating you + if ( attacker.IsPlayer() && attacker in victim.p.playerKillStreaks && victim.p.playerKillStreaks[ attacker ] == NEMESIS_KILL_REQUIREMENT ) + AddPlayerScore( attacker, "Nemesis" ) + + // reset killstreaks on specific players + foreach ( entity killstreakPlayer, int numKills in victim.p.playerKillStreaks ) + delete victim.p.playerKillStreaks[ killstreakPlayer ] + + if ( victim.IsTitan() ) + ScoreEvent_TitanKilled( victim, attacker, damageInfo ) + + if ( !attacker.IsPlayer() ) + return + + + // pilot kill AddPlayerScore( attacker, "KillPilot", victim ) + // headshot if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT ) AddPlayerScore( attacker, "Headshot", victim ) - + + // first strike if ( !file.firstStrikeDone ) { file.firstStrikeDone = true AddPlayerScore( attacker, "FirstStrike", attacker ) } - if ( victim.IsTitan() ) - ScoreEvent_TitanKilled( victim, attacker, damageInfo ) + // comeback + if ( attacker.p.numberOfDeathsSinceLastKill >= COMEBACK_DEATHS_REQUIREMENT ) + { + AddPlayerScore( attacker, "Comeback" ) + attacker.p.numberOfDeathsSinceLastKill = 0 + } + + + // untimed killstreaks + attacker.s.currentKillstreak++ + if ( attacker.s.currentKillstreak == 3 ) + AddPlayerScore( attacker, "KillingSpree" ) + else if ( attacker.s.currentKillstreak == 5 ) + AddPlayerScore( attacker, "Rampage" ) + + // increment untimed killstreaks against specific players + if ( !( victim in attacker.p.playerKillStreaks ) ) + attacker.p.playerKillStreaks[ victim ] <- 1 + else + attacker.p.playerKillStreaks[ victim ]++ + + // dominating + if ( attacker.p.playerKillStreaks[ victim ] == DOMINATING_KILL_REQUIREMENT ) + AddPlayerScore( attacker, "Dominating" ) + + + // timed killstreaks + if ( Time() - attacker.s.lastKillTime <= CASCADINGKILL_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak++ + + if ( attacker.s.currentTimedKillstreak == DOUBLEKILL_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "DoubleKill" ) + else if ( attacker.s.currentTimedKillstreak == TRIPLEKILL_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "TripleKill" ) + else if ( attacker.s.currentTimedKillstreak == MEGAKILL_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "MegaKill" ) + } + else + attacker.s.currentTimedKillstreak = 0 // reset if a kill took too long + + attacker.s.lastKillTime = Time() } void function ScoreEvent_TitanDoomed( entity titan, entity attacker, var damageInfo ) @@ -87,6 +176,8 @@ void function ScoreEvent_TitanDoomed( entity titan, entity attacker, var damageI void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damageInfo ) { // will this handle npc titans with no owners well? i have literally no idea + if ( !attacker.IsPlayer() ) + return if ( attacker.IsTitan() ) AddPlayerScore( attacker, "TitanKillTitan", victim.GetTitanSoul().GetOwner() ) diff --git a/Northstar.CustomServers/scripts/vscripts/mp/levels/_lf_maps_shared.gnut b/Northstar.CustomServers/scripts/vscripts/mp/levels/_lf_maps_shared.gnut index 69ec56fb5..d61d6baa6 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/levels/_lf_maps_shared.gnut +++ b/Northstar.CustomServers/scripts/vscripts/mp/levels/_lf_maps_shared.gnut @@ -4,5 +4,5 @@ global function SetupLiveFireMaps void function SetupLiveFireMaps() { Riff_ForceTitanAvailability( eTitanAvailability.Never ) - ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, NOINTRO_INTRO_LENGTH ) + ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) } \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/scripts/vscripts/mp/spawn.nut index b7a50453e..26e4c7135 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/scripts/vscripts/mp/spawn.nut @@ -7,6 +7,7 @@ global function SetSpawnsUseFrontline global function SetRespawnsEnabled global function RespawnsEnabled global function SetSpawnpointGamemodeOverride +global function GetSpawnpointGamemodeOverride global function CreateNoSpawnArea global function DeleteNoSpawnArea @@ -121,6 +122,16 @@ void function SetSpawnpointGamemodeOverride( string gamemode ) file.spawnpointGamemodeOverride = gamemode } +string function GetSpawnpointGamemodeOverride() +{ + if ( file.spawnpointGamemodeOverride != "" ) + return file.spawnpointGamemodeOverride + else + return GAMETYPE + + unreachable +} + void function SetSpawnsUseFrontline( bool useFrontline ) { file.frontlineBased = useFrontline -- cgit v1.2.3