diff options
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/mp')
-rw-r--r-- | Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut | 27 | ||||
-rw-r--r-- | Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut | 113 |
2 files changed, 88 insertions, 52 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut index 244d323e..8069b4a5 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -12,6 +12,7 @@ global function TryGameModeAnnouncement global function SetKillcamsEnabled global function KillcamsEnabled +global function SetPlayerDeathsHidden global function ShouldEntTakeDamage_SPMP global function GetTitanBuildTime @@ -19,6 +20,7 @@ global function TitanPlayerHotDropsIntoLevel struct { bool killcamsEnabled = true + bool playerDeathsHidden = false entity intermissionCamera array<entity> specCams @@ -148,6 +150,10 @@ void function CodeCallback_OnClientConnectionCompleted( entity player ) PlayCurrentTeamMusicEventsOnPlayer( player ) SetCurrentTeamObjectiveForPlayer( player ) + entity skycam = GetEnt( "skybox_cam_level" ) + if ( skycam != null ) + player.SetSkyCamera( skycam ) + FinishClientScriptInitialization( player ) // Added via AddCallback_OnClientConnected @@ -304,7 +310,8 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga player.SetObserverTarget( null ) } - Remote_CallFunction_NonReplay( player, "ServerCallback_YouDied", attacker.GetEncodedEHandle(), GetHealthFrac( attacker ), methodOfDeath ) + if ( !file.playerDeathsHidden ) + Remote_CallFunction_NonReplay( player, "ServerCallback_YouDied", attacker.GetEncodedEHandle(), GetHealthFrac( attacker ), methodOfDeath ) float deathcamLength = GetDeathCamLength( player ) wait deathcamLength @@ -385,15 +392,6 @@ void function EndReplayOnTime( entity player, float replayLength ) void function DecideRespawnPlayer( entity player ) { // this isn't even used atm, could likely be removed if some vanilla code didn't rely on it - - Assert( IsValid( player ), player + " is invalid!!" ) - Assert( !IsAlive( player ), player + " is already alive" ) - Assert( player.hasConnected, player + "isn't connected" ) - - if ( GetClassicMPMode() && GetGameState() < eGameState.Playing ) - return // let intro functions handle spawning if we're in classicmp and not spawned yet - - } void function RespawnAsPilot( entity player, bool manualPosition = false ) @@ -437,7 +435,7 @@ void function RespawnAsTitan( entity player, bool manualPosition = false ) vector xyOffset = RotateAroundOrigin2D( < 44, 0, 520 >, < 0, 0, 0 >, spawnpoint.GetAngles().y ) camera.SetLocalOrigin( xyOffset ) - camera.SetLocalAngles( < camera.GetAngles().x, spawnpoint.GetAngles().y, camera.GetAngles().z > ) + camera.SetLocalAngles( < camera.GetAngles().x, spawnpoint.GetAngles().y, camera.GetAngles().z > ) // this straight up just does not work lol camera.Fire( "Enable", "!activator", 0, player ) waitthread TitanHotDrop( titan, "at_hotdrop_01", spawnpoint.GetOrigin(), spawnpoint.GetAngles(), player, camera ) // do hotdrop anim @@ -474,7 +472,6 @@ void function PlayerBecomesSpectator( entity player ) foreach( entity cam in file.specCams ) targets.append( cam ) - array<entity> targetPlayers if ( IsFFAGame() ) targetPlayers = GetPlayerArray_Alive() @@ -566,9 +563,13 @@ bool function KillcamsEnabled() return file.killcamsEnabled } -// stuff to change later +void function SetPlayerDeathsHidden( bool hidden ) +{ + file.playerDeathsHidden = hidden +} +// stuff to change later bool function ShouldEntTakeDamage_SPMP( entity ent, var damageInfo ) { diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut index 2fa24e9d..21d529e4 100644 --- a/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut @@ -39,11 +39,14 @@ struct { bool roundWinningKillReplayTrackPilotKills = true bool roundWinningKillReplayTrackTitanKills = false + float roundWinningKillReplayTime entity roundWinningKillReplayVictim entity roundWinningKillReplayAttacker int roundWinningKillReplayMethodOfDeath float roundWinningKillReplayTimeOfDeath float roundWinningKillReplayHealthFrac + + array<void functionref()> roundEndCleanupCallbacks } file void function PIN_GameStart() @@ -69,9 +72,10 @@ void function PIN_GameStart() AddCallback_GameStateEnter( eGameState.SuddenDeath, GameStateEnter_SuddenDeath ) AddCallback_GameStateEnter( eGameState.Postmatch, GameStateEnter_Postmatch ) - AddCallback_OnClientConnected( SetSkyCam ) // had no idea where to put this lol AddCallback_OnPlayerKilled( OnPlayerKilled ) AddDeathCallback( "npc_titan", OnTitanKilled ) + + RegisterSignal( "CleanUpEntitiesForRoundEnd" ) } void function SetGameState( int newState ) @@ -241,11 +245,16 @@ void function GameStateEnter_WinnerDetermined() void function GameStateEnter_WinnerDetermined_Threaded() { + bool killcamsWereEnabled = KillcamsEnabled() + if ( killcamsWereEnabled ) // dont want killcams to interrupt stuff + SetKillcamsEnabled( false ) + WaitFrame() // wait a frame so other scripts can setup killreplay stuff entity replayAttacker = file.roundWinningKillReplayAttacker - bool doReplay = Replay_IsEnabled() && Evac_IsEnabled() && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker ) - + bool doReplay = Replay_IsEnabled() && !( !IsRoundBased() && Evac_IsEnabled() ) && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker ) + && Time() - file.roundWinningKillReplayTime <= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY + float replayLength = 2.0 // extra delay if no replay if ( doReplay ) { @@ -256,7 +265,15 @@ void function GameStateEnter_WinnerDetermined_Threaded() foreach ( entity player in GetPlayerArray() ) thread PlayerWatchesRoundWinningKillReplay( player, doReplay, replayLength ) - wait replayLength + ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME + wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME + CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see + wait replayLength + + WaitFrame() // prevent a race condition with PlayerWatchesRoundWinningKillReplay + file.roundWinningKillReplayAttacker = null // clear this + + if ( killcamsWereEnabled ) + SetKillcamsEnabled( true ) if ( IsRoundBased() ) { @@ -266,7 +283,7 @@ void function GameStateEnter_WinnerDetermined_Threaded() if ( max( GameRules_GetTeamScore( TEAM_IMC ), GameRules_GetTeamScore( TEAM_MILITIA ) ) >= GameMode_GetRoundScoreLimit( GAMETYPE ) ) SetGameState( eGameState.Postmatch ) else if ( file.switchSidesBased && !file.hasSwitchedSides ) - SetGameState( eGameState.SwitchingSides ) + SetGameState( eGameState.SwitchingSides ) // note: switchingsides will handle setting to pickloadout and prematch by itself else if ( file.usePickLoadoutScreen ) SetGameState( eGameState.PickLoadout ) else @@ -300,12 +317,6 @@ void function PlayerWatchesRoundWinningKillReplay( entity player, bool doReplay, ScreenFadeToBlackForever( player, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME - // do this after screen goes black so people can't see the titan dying - // don't use .die since that makes explosions and that - // todo: need a function specifically for cleaning up npcs and stuff on round end, this is imperfect - if ( IsAlive( player.GetPetTitan() ) ) - player.GetPetTitan().Destroy() - if ( doReplay ) { player.SetPredictionEnabled( false ) // prediction fucks with replays @@ -347,8 +358,15 @@ void function GameStateEnter_SwitchingSides() void function GameStateEnter_SwitchingSides_Threaded() { + bool killcamsWereEnabled = KillcamsEnabled() + if ( killcamsWereEnabled ) // dont want killcams to interrupt stuff + SetKillcamsEnabled( false ) + + WaitFrame() // wait a frame so callbacks can set killreplay info + entity replayAttacker = file.roundWinningKillReplayAttacker bool doReplay = Replay_IsEnabled() && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker ) && !IsRoundBased() // for roundbased modes, we've already done the replay + && Time() - file.roundWinningKillReplayTime <= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY float replayLength = SWITCHING_SIDES_DELAY_REPLAY // extra delay if no replay if ( doReplay ) @@ -360,9 +378,15 @@ void function GameStateEnter_SwitchingSides_Threaded() foreach ( entity player in GetPlayerArray() ) thread PlayerWatchesSwitchingSidesKillReplay( player, doReplay, replayLength ) - wait SWITCHING_SIDES_DELAY_REPLAY + replayLength + wait SWITCHING_SIDES_DELAY_REPLAY + CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see + wait replayLength + + if ( killcamsWereEnabled ) + SetKillcamsEnabled( true ) file.hasSwitchedSides = true + svGlobal.levelEnt.Signal( "RoundEnd" ) // might be good to get a new signal for this? not 100% necessary tho i think SetServerVar( "switchedSides", 1 ) file.roundWinningKillReplayAttacker = null // reset this after replay @@ -379,11 +403,6 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla ScreenFadeToBlackForever( player, SWITCHING_SIDES_DELAY_REPLAY ) // automatically cleared wait SWITCHING_SIDES_DELAY_REPLAY - // do this after screen goes black so people can't see the titan dying - // don't use .die since that makes explosions and that - if ( IsAlive( player.GetPetTitan() ) ) - player.GetPetTitan().Destroy() - if ( doReplay ) { player.SetPredictionEnabled( false ) // prediction fucks with replays @@ -483,13 +502,6 @@ void function ForceFadeToBlack( entity player ) // shared across multiple gamestates -void function SetSkyCam( entity player ) -{ - entity skycam = GetEnt( "skybox_cam_level" ) - - if ( skycam != null ) - player.SetSkyCamera( skycam ) -} void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { @@ -499,6 +511,7 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) // set round winning killreplay info here if no custom replaydelay if ( file.roundWinningKillReplayTrackPilotKills ) { + file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim file.roundWinningKillReplayAttacker = attacker file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) @@ -532,7 +545,7 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) } if ( ( Riff_EliminationMode() == eEliminationMode.Titans || Riff_EliminationMode() == eEliminationMode.PilotsTitans ) && victim.IsTitan() ) // need an extra check for this - OnTitanKilled( victim, damageInfo ) + OnTitanKilled( victim, damageInfo ) } void function OnTitanKilled( entity victim, var damageInfo ) @@ -545,6 +558,7 @@ void function OnTitanKilled( entity victim, var damageInfo ) { entity attacker = DamageInfo_GetAttacker( damageInfo ) + file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim file.roundWinningKillReplayAttacker = attacker file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) @@ -582,6 +596,36 @@ void function OnTitanKilled( entity victim, var damageInfo ) } } +void function AddCallback_OnRoundEndCleanup( void functionref() callback ) +{ + file.roundEndCleanupCallbacks.append( callback ) +} + +void function CleanUpEntitiesForRoundEnd() +{ + // this function should clean up any and all entities that need to be removed between rounds, ideally at a point where it isn't noticable to players + SetPlayerDeathsHidden( true ) // hide death sounds and such so people won't notice they're dying + + foreach ( entity player in GetPlayerArray() ) + { + if ( IsAlive( player ) ) + player.Die() + + if ( IsAlive( player.GetPetTitan() ) ) + player.GetPetTitan().Destroy() + } + + foreach ( entity npc in GetNPCArray() ) + npc.Die() + + // allow other scripts to clean stuff up too + svGlobal.levelEnt.Signal( "CleanUpEntitiesForRoundEnd" ) + foreach ( void functionref() callback in file.roundEndCleanupCallbacks ) + callback() + + SetPlayerDeathsHidden( false ) +} + // stuff for gamemodes to call @@ -606,16 +650,17 @@ void function SetShouldUseRoundWinningKillReplay( bool shouldUse ) SetServerVar( "roundWinningKillReplayEnabled", shouldUse ) } -// is this necessary? idk really void function SetRoundWinningKillReplayKillClasses( bool pilot, bool titan ) { file.roundWinningKillReplayTrackPilotKills = pilot file.roundWinningKillReplayTrackTitanKills = titan // player kills in titans should get tracked anyway, might be worth renaming this } -void function SetRoundWinningKillReplayAttacker( entity target ) +void function SetRoundWinningKillReplayAttacker( entity attacker ) { - file.roundWinningKillReplayAttacker = target + file.roundWinningKillReplayTime = Time() + file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) + file.roundWinningKillReplayAttacker = attacker } void function SetWinner( int team, string winningReason = "", string losingReason = "" ) @@ -664,16 +709,6 @@ void function AddTeamScore( int team, int amount ) SetGameState( eGameState.SwitchingSides ) } -void function SetRoundWinningKillReplayInfo( entity victim, entity attacker, int methodOfDeath, float timeOfDeath ) // can't just pass in a damageinfo because they seem to die over time somehow -{ - file.roundWinningKillReplayVictim = victim - file.roundWinningKillReplayAttacker = attacker - file.roundWinningKillReplayMethodOfDeath = methodOfDeath - file.roundWinningKillReplayTimeOfDeath = timeOfDeath - if ( attacker != null ) - file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) -} - void function SetTimeoutWinnerDecisionFunc( int functionref() callback ) { file.timeoutWinnerDecisionFunc = callback @@ -696,7 +731,7 @@ bool function ShouldRunEvac() return true } -void function GiveTitanToPlayer(entity player) +void function GiveTitanToPlayer( entity player ) { } |