aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/mp
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/mp')
-rw-r--r--Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut6
-rw-r--r--Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut33
-rw-r--r--Northstar.CustomServers/scripts/vscripts/mp/levels/mp_wargames.nut408
3 files changed, 21 insertions, 426 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut
index 8069b4a5..69fcfb50 100644
--- a/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut
+++ b/Northstar.CustomServers/scripts/vscripts/mp/_base_gametype_mp.gnut
@@ -231,12 +231,6 @@ void function CodeCallback_OnPlayerKilled( entity player, var damageInfo )
void function PostDeathThread_MP( entity player, var damageInfo ) // based on gametype_sp: postdeaththread_sp
{
- // honestly this feels jank af, it's messy and the sp code it's based off is a bit of a pain imo, needs a rewrite at some point
- // also this likely needs an onthreadend to set a couple values
-
- //if ( player.p.watchingPetTitanKillReplay )
- // return
-
if ( player.s.inPostDeath )
return
diff --git a/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut
index 21d529e4..97e06377 100644
--- a/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut
+++ b/Northstar.CustomServers/scripts/vscripts/mp/_gamestate_mp.nut
@@ -218,7 +218,7 @@ void function GameStateEnter_Playing_Threaded()
else
winningTeam = GameScore_GetWinningTeam()
- if ( file.switchSidesBased && !file.hasSwitchedSides )
+ if ( file.switchSidesBased && !file.hasSwitchedSides && !IsRoundBased() ) // in roundbased modes, we handle this in setwinner
SetGameState( eGameState.SwitchingSides )
else if ( file.suddenDeathBased && winningTeam == TEAM_UNASSIGNED ) // suddendeath if we draw and suddendeath is enabled and haven't switched sides
SetGameState( eGameState.SuddenDeath )
@@ -258,7 +258,10 @@ void function GameStateEnter_WinnerDetermined_Threaded()
float replayLength = 2.0 // extra delay if no replay
if ( doReplay )
{
- replayLength = min( ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY, Time() - replayAttacker.s.respawnTime ) // 7.5s unless player lifetime < that
+ replayLength = ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY
+ if ( "respawnTime" in replayAttacker.s && Time() - replayAttacker.s.respawnTime < replayLength )
+ replayLength += Time() - expect float ( replayAttacker.s.respawnTime )
+
SetServerVar( "roundWinningKillReplayEntHealthFrac", file.roundWinningKillReplayHealthFrac )
}
@@ -278,11 +281,15 @@ void function GameStateEnter_WinnerDetermined_Threaded()
if ( IsRoundBased() )
{
svGlobal.levelEnt.Signal( "RoundEnd" )
- SetServerVar( "roundsPlayed", GetServerVar( "roundsPlayed" ) + 1 )
+ int roundsPlayed = expect int ( GetServerVar( "roundsPlayed" ) )
+ SetServerVar( "roundsPlayed", roundsPlayed + 1 )
+
+ float highestScore = max( GameRules_GetTeamScore( TEAM_IMC ), GameRules_GetTeamScore( TEAM_MILITIA ) )
+ int roundScoreLimit = GameMode_GetRoundScoreLimit( GAMETYPE )
- if ( max( GameRules_GetTeamScore( TEAM_IMC ), GameRules_GetTeamScore( TEAM_MILITIA ) ) >= GameMode_GetRoundScoreLimit( GAMETYPE ) )
+ if ( highestScore >= roundScoreLimit )
SetGameState( eGameState.Postmatch )
- else if ( file.switchSidesBased && !file.hasSwitchedSides )
+ else if ( file.switchSidesBased && !file.hasSwitchedSides && highestScore >= ( roundScoreLimit.tofloat() / 2.0 ) ) // round up
SetGameState( eGameState.SwitchingSides ) // note: switchingsides will handle setting to pickloadout and prematch by itself
else if ( file.usePickLoadoutScreen )
SetGameState( eGameState.PickLoadout )
@@ -366,12 +373,15 @@ void function GameStateEnter_SwitchingSides_Threaded()
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
+ && Time() - file.roundWinningKillReplayTime <= SWITCHING_SIDES_DELAY
float replayLength = SWITCHING_SIDES_DELAY_REPLAY // extra delay if no replay
if ( doReplay )
- {
- replayLength = min( SWITCHING_SIDES_DELAY, Time() - replayAttacker.s.respawnTime ) // 6s unless player lifetime < that
+ {
+ replayLength = SWITCHING_SIDES_DELAY
+ if ( "respawnTime" in replayAttacker.s && Time() - replayAttacker.s.respawnTime < replayLength )
+ replayLength += Time() - expect float ( replayAttacker.s.respawnTime )
+
SetServerVar( "roundWinningKillReplayEntHealthFrac", file.roundWinningKillReplayHealthFrac )
}
@@ -509,7 +519,7 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo )
return
// set round winning killreplay info here if no custom replaydelay
- if ( file.roundWinningKillReplayTrackPilotKills )
+ if ( file.roundWinningKillReplayTrackPilotKills && victim != attacker )
{
file.roundWinningKillReplayTime = Time()
file.roundWinningKillReplayVictim = victim
@@ -554,10 +564,9 @@ void function OnTitanKilled( entity victim, var damageInfo )
return
// set round winning killreplay info here if no custom replaydelay
- if ( file.roundWinningKillReplayTrackTitanKills )
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
+ if ( file.roundWinningKillReplayTrackTitanKills && victim != attacker )
{
- entity attacker = DamageInfo_GetAttacker( damageInfo )
-
file.roundWinningKillReplayTime = Time()
file.roundWinningKillReplayVictim = victim
file.roundWinningKillReplayAttacker = attacker
diff --git a/Northstar.CustomServers/scripts/vscripts/mp/levels/mp_wargames.nut b/Northstar.CustomServers/scripts/vscripts/mp/levels/mp_wargames.nut
index 9252cced..b6c8cfc2 100644
--- a/Northstar.CustomServers/scripts/vscripts/mp/levels/mp_wargames.nut
+++ b/Northstar.CustomServers/scripts/vscripts/mp/levels/mp_wargames.nut
@@ -1,415 +1,7 @@
untyped
-
-const POD_ATTACHPOINT = "REF"
-
-const FX_LIGHT_ORANGE = "runway_light_orange"
-const FX_LIGHT_GREEN = "runway_light_green"
-const FX_POD_LASER = "P_pod_scan_laser_FP"
-const FX_POD_GLOWLIGHT = "P_pod_door_glow_FP"
-const FX_POD_SCREEN_IN = "P_pod_screen_lasers_IN"
-const FX_POD_SCREEN_OUT = "P_pod_screen_lasers_OUT"
-const FX_POD_DLIGHT_CONSOLE1 = $"P_pod_Dlight_console1"
-const FX_POD_DLIGHT_CONSOLE2 = $"P_pod_Dlight_console2"
-const FX_POD_DLIGHT_BACKLIGHT_SIDE = "P_pod_Dlight_backlight_side"
-const FX_POD_DLIGHT_BACKLIGHT_TOP = "P_pod_Dlight_backlight_top"
-const FX_TITAN_COCKPIT_LIGHT = "xo_cockpit_dlight"
-
-struct TrainingPod_dLightMapping
-{
- string scriptAlias
- asset fxName
- string attachName
- entity fxHandle
-}
-
-struct TrainingPod_LaserEmitter
-{
- entity ent
- string attachName
- vector ogAng
- bool sweepDone = false
- entity fxHandle
-}
-
-struct TrainingPod_GlowLightRow
-{
- array<string> fxSpotsL
- array<string> fxSpotsR
-}
-
global function CodeCallback_MapInit
-global function WargamesIntroStart
-
-struct {
- entity militiaTrainingPod
- entity imcTrainingPod
- array< TrainingPod_dLightMapping >[2] podDLightMappings
- array< TrainingPod_LaserEmitter >[2] podLaserEmitters
-
- array< entity > playersWatchingIntro
- string currentPodAnim
- float currentPodAnimStartTime
-} file
void function CodeCallback_MapInit()
{
- //FlagInit( "TrainingPodSetupDone" )
- //FlagInit( "IntroRunning" )
- //
- //FlagSet( "DogFights" )
- //FlagSet( "StratonFlybys" )
- //
- //ClassicMP_SetIntroLevelSetupFunc( Wargames_Intro_LevelSetupFunc )
- //ClassicMP_SetIntroPlayerSpawnFunc( Wargames_ClassicMPIntroSpawn )
- //ClassicMP_SetPrematchSpawnPlayersFunc( Wargames_PrematchSpawnPlayersFunc )
- //
- //AddCallback_GameStateEnter( eGameState.WaitingForPlayers, WargamesIntroStart ) // This starts the main intro control thread
- //AddCallback_GameStateEnter( eGameState.PickLoadout, Wargames_GameStateEnterFunc_PickLoadout )
- //AddCallback_GameStateEnter( eGameState.Prematch, Wargames_GameStateEnterFunc_PrematchCallback )
-}
-
-// setup
-
-bool function Wargames_Intro_LevelSetupFunc()
-{
- array< entity > militiaTrainingPods = GetEntArrayByName_Expensive( "training_pod" )
- Assert( militiaTrainingPods.len() == 1 )
- file.militiaTrainingPod = militiaTrainingPods[0]
- file.militiaTrainingPod.s.teamIdx <- TEAM_MILITIA
-
- array< entity > imcTrainingPods = GetEntArrayByName_Expensive( "training_pod_imc" )
- Assert( imcTrainingPods.len() == 1 )
- file.imcTrainingPod = imcTrainingPods[0]
- file.imcTrainingPod.s.teamIdx <- TEAM_IMC
-
- SetupTrainingPod( file.militiaTrainingPod )
- SetupTrainingPod( file.imcTrainingPod )
-
- FlagSet( "TrainingPodSetupDone" )
- return true
-}
-
-void function SetupTrainingPod( entity pod )
-{
- pod.DisableHibernation()
- pod.s.glowLightFXHandles <- []
- pod.s.dLights <- []
-
- // FUN hack because can't assign struct => var
- int podStructIndex = pod.s.teamIdx == TEAM_MILITIA ? 0 : 1
-
- array< TrainingPod_dLightMapping > tempLightMappings
-
- TrainingPod_dLightMapping m1
- m1.scriptAlias = "console1"
- m1.fxName = FX_POD_DLIGHT_CONSOLE1
- m1.attachName = "light_console1"
- tempLightMappings.append( m1 )
-
- TrainingPod_dLightMapping m2
- m2.scriptAlias = "console2"
- m2.fxName = FX_POD_DLIGHT_CONSOLE2
- m2.attachName = "light_console2"
- tempLightMappings.append( m2 )
-
- file.podDLightMappings[ podStructIndex ] = tempLightMappings
-
- array< string > laserAttachNames = [ "fx_laser_L", "fx_laser_R" ]
-
- foreach ( string attachName in laserAttachNames )
- {
- entity emitterEnt = CreateScriptMover( pod.GetOrigin(), pod.GetAngles() )
- int attachID = pod.LookupAttachment( attachName )
- vector attachOrg = pod.GetAttachmentOrigin( attachID )
- vector attachAng = pod.GetAttachmentAngles( attachID )
-
- TrainingPod_LaserEmitter emitter
- emitter.ent = emitterEnt
- emitter.attachName = attachName
- emitter.ogAng = attachAng
-
- file.podLaserEmitters[ podStructIndex ].append( emitter )
- }
-
- // HACK we do this later as well to reset the emitter positions, so it's a separate function
- TrainingPod_SnapLaserEmittersToAttachPoints( pod )
-}
-
-void function TrainingPod_SnapLaserEmittersToAttachPoints( entity pod )
-{
- foreach ( TrainingPod_LaserEmitter emitter in file.podLaserEmitters[ pod.s.teamIdx == TEAM_MILITIA ? 0 : 1 ] )
- {
- int attachID = pod.LookupAttachment( emitter.attachName )
- vector attachOrg = pod.GetAttachmentOrigin( attachID )
- vector attachAng = pod.GetAttachmentAngles( attachID )
-
- emitter.ent.ClearParent()
- emitter.ent.SetOrigin( attachOrg ) // HACK set this to ANYTHING (even 0, 0, 0) and the position is correct, otherwise it's offset from the attachpoint when parented
- emitter.ent.SetParent( pod, emitter.attachName )
- }
-}
-
-// spawning/intro sequence
-
-void function Wargames_ClassicMPIntroSpawn( entity player )
-{
- Assert( !IsAlive( player ) )
-
- thread PlayerWatchPodIntro( player )
- // return true
-}
-
-void function Wargames_PrematchSpawnPlayersFunc( array< entity > players )
-{
-
-}
-
-void function PlayerWatchPodIntro( entity player )
-{
- player.EndSignal( "Disconnected" )
- player.EndSignal( "OnDeath" )
-
- int team = player.GetTeam()
-
- entity pod
- if ( team == TEAM_MILITIA )
- pod = file.militiaTrainingPod
- else
- pod = file.imcTrainingPod
-
- AddCinematicFlag( player, CE_FLAG_INTRO )
- file.playersWatchingIntro.append( player )
-
- OnThreadEnd(
- function() : ( player )
- {
- if ( IsValid( player ) )
- {
- printt( "PlayerWatchPodIntro: clearing up player:", player )
-
- //ArrayRemove( file.playersWatchingIntro, player )
- file.playersWatchingIntro.remove( file.playersWatchingIntro.find( player ) )
-
- player.Anim_Stop()
- //player.ClearAnimViewEntity()
- //player.ClearParent()
- player.UnforceStand()
- player.EnableWeaponViewModel()
- player.kv.VisibilityFlags = 7 // All can see now that intro is over
-
- FadeOutSoundOnEntity( player, "Amb_Wargames_Pod_Ambience", 0.13 )
-
- // turns hud back on
- if ( HasCinematicFlag( player, CE_FLAG_INTRO ) )
- RemoveCinematicFlag( player, CE_FLAG_INTRO )
- }
- }
- )
-
- // FIRST SPAWN
- int attachID = pod.LookupAttachment( POD_ATTACHPOINT )
- vector podRefOrg = pod.GetAttachmentOrigin( attachID )
- vector podRefAng = pod.GetAttachmentAngles( attachID )
- player.SetOrigin( podRefOrg )
- player.SetAngles( podRefAng )
- player.RespawnPlayer( null )
-
- player.kv.VisibilityFlags = 1 // visible to player only, so others don't see his viewmodel during the anim
- player.DisableWeaponViewModel()
- player.ForceStand()
-
- EmitSoundOnEntityOnlyToPlayer( player, player, "Amb_Wargames_Pod_Ambience" )
- thread Intro_StartPlayerFirstPersonSequence( player )
-
- FlagWait( "IntroRunning" )
- player.UnfreezeControlsOnServer()
-
- // wait for intro to finish for OnThreadEnd cleanup
- FlagWaitClear( "IntroRunning" )
- printt( "PlayerWatchPodIntro: intro finished normally for player", player )
-}
-
-void function Intro_StartPlayerFirstPersonSequence( entity player )
-{
- player.EndSignal( "Disconnected" )
- player.EndSignal( "OnDeath" )
-
- entity pod
- if ( player.GetTeam() == TEAM_MILITIA )
- pod = file.militiaTrainingPod
- else
- pod = file.imcTrainingPod
-
- FirstPersonSequenceStruct playerSequence
- playerSequence.blendTime = 0.0
- playerSequence.attachment = POD_ATTACHPOINT
- playerSequence.renderWithViewModels = true
- playerSequence.firstPersonAnimIdle = "ptpov_trainingpod_idle"
-
- //FirstPersonSequenceStruct podSequence
- //podSequence.blendTime = 0.25
- //podSequence.thirdPersonAnim = "trainingpod_doors_close"
- //podSequence.thirdPersonAnimIdle = "trainingpod_doors_close_idle"
- //podSequence.renderWithViewModels = true
-
- void functionref( entity ) viewconeFunc = null
- viewconeFunc = TrainingPod_ViewConeLock_SemiStrict
-
- // i don't get this whole animevent system tbh, might just skip it lol
- entity viewmodel = player.GetFirstPersonProxy()
- //if ( !HasAnimEvent( viewmodel, "PlaySound_SimPod_DoorShut" ) )
- //{
- printt( "adding anim event... this probably won't work", player )
- AddAnimEvent( viewmodel, "PlaySound_SimPod_DoorShut", PlaySound_SimPod_DoorShut )
- AddAnimEvent( viewmodel, "PlaySound_SimPod_DoorShut", PlaySound_SimPod_DoorShut )
- AddAnimEvent( viewmodel, "PlaySound_SimPod_DoorShut", PlaySound_SimPod_DoorShut )
- AddAnimEvent( viewmodel, "PlaySound_SimPod_DoorShut", PlaySound_SimPod_DoorShut )
- AddAnimEvent( viewmodel, "PlaySound_SimPod_DoorShut", PlaySound_SimPod_DoorShut )
-
- print( "this SHOULD have caused errors in console due to registering it multiple times but doesn't????" )
- //}
-
- if ( file.currentPodAnim == "closing" )
- {
- playerSequence.firstPersonAnim = "ptpov_trainingpod_doors_close"
- }
-
- // TODO: correct viewcone funcs and catchup stuff
-
- //thread FirstPersonSequence( podSequence, pod )
- thread FirstPersonSequence( playerSequence, player, pod )
-
- if ( viewconeFunc != null )
- viewconeFunc( player )
-
- FlagClear( "IntroRunning" )
-}
-
-void function Intro_StartPlayerFirstPersonSequenceForAll()
-{
- foreach ( entity player in file.playersWatchingIntro )
- thread Intro_StartPlayerFirstPersonSequence( player )
-}
-
-void function TrainingPod_ViewConeLock_SemiStrict( entity player )
-{
- player.PlayerCone_FromAnim()
- player.PlayerCone_SetMinYaw( -10 )
- player.PlayerCone_SetMaxYaw( 10 )
- player.PlayerCone_SetMinPitch( -10 )
- player.PlayerCone_SetMaxPitch( 10 )
-}
-
-void function PlaySound_SimPod_DoorShut( entity playerFirstPersonProxy )
-{
- print( "playing anim event!" )
- // never called lol
-
- entity player = playerFirstPersonProxy.GetOwner()
- if ( !IsValid( player ) )
- return
-
- EmitSoundOnEntityOnlyToPlayer( player, player, "NPE_Scr_SimPod_DoorShut" )
-}
-
-void function WargamesIntroStart()
-{
- thread WargamesIntroStartThreaded()
-}
-
-void function WargamesIntroStartThreaded()
-{
- FlagWait( "TrainingPodSetupDone" )
-
- // early connecting players start idling
- file.currentPodAnim = "idle"
-
- file.militiaTrainingPod.s.ambienceLoud <- "Wargames_Emit_MCOR_Intro_HighPass"
- file.militiaTrainingPod.s.ambienceQuiet <- "Wargames_Emit_MCOR_Intro_LowPass"
-
- file.imcTrainingPod.s.ambienceLoud <- "Wargames_Emit_IMC_Intro_HighPass"
- file.imcTrainingPod.s.ambienceQuiet <- "Wargames_Emit_IMC_Intro_LowPass"
-
- OnThreadEnd(
- function() : ()
- {
-
- }
- )
-
- // wait for prematch, after waiting for players
- WaittillGameStateOrHigher( eGameState.Prematch )
-
- EmitSoundOnEntity( file.militiaTrainingPod, "Wargames_Emit_MCOR_Intro_HighPass" )
- EmitSoundOnEntity( file.militiaTrainingPod, "Wargames_Emit_MCOR_Intro_LowPass" )
-
- EmitSoundOnEntity( file.imcTrainingPod, "Wargames_Emit_IMC_Intro_HighPass")
- EmitSoundOnEntity( file.imcTrainingPod, "Wargames_Emit_IMC_Intro_LowPass" )
-
- // todo: intro skits
-
- FlagSet( "IntroRunning" )
- float startTime = Time()
-
- file.currentPodAnimStartTime = Time()
- FirstPersonSequenceStruct podSequence
- podSequence.blendTime = 0.0
- podSequence.thirdPersonAnimIdle = "trainingpod_doors_open_idle"
- podSequence.renderWithViewModels = true
-
- // turn on top lights
- TrainingPod_TurnOnInteriorDLight( "console1", file.militiaTrainingPod )
- TrainingPod_TurnOnInteriorDLight( "console2", file.militiaTrainingPod )
- thread FirstPersonSequence( podSequence, file.militiaTrainingPod )
-
- TrainingPod_TurnOnInteriorDLight( "console1", file.imcTrainingPod )
- TrainingPod_TurnOnInteriorDLight( "console2", file.imcTrainingPod )
- thread FirstPersonSequence( podSequence, file.imcTrainingPod )
-
- //thread Intro_PlayersHearPodVO()
-
- Intro_StartPlayerFirstPersonSequenceForAll()
- wait 8
-
- file.currentPodAnim = "closing"
- file.currentPodAnimStartTime = Time()
- podSequence.blendTime = 0.0
- podSequence.thirdPersonAnim = "trainingpod_doors_close"
- podSequence.thirdPersonAnimIdle = "trainingpod_doors_close_idle"
-
- Intro_StartPlayerFirstPersonSequenceForAll()
-
- thread FirstPersonSequence( podSequence, file.militiaTrainingPod )
- waitthread FirstPersonSequence( podSequence, file.imcTrainingPod )
-
- file.currentPodAnim = "done"
-
- wait 4.5
-
-
- FlagClear( "IntroRunning" )
-}
-
-void function TrainingPod_TurnOnInteriorDLight( string alias, entity pod )
-{
- int teamIdx = pod.s.teamIdx == TEAM_MILITIA ? 0 : 1
- foreach ( TrainingPod_dLightMapping mapping in file.podDLightMappings[ teamIdx ] )
- {
- if ( mapping.scriptAlias == alias )
- {
- PlayLoopFXOnEntity( mapping.fxName, pod, mapping.attachName )
- pod.s.dLights.append( mapping.fxName )
- break
- }
- }
-}
-
-void function Wargames_GameStateEnterFunc_PickLoadout()
-{
- level.nv.minPickLoadOutTime = Time() + 0.5
-}
-
-void function Wargames_GameStateEnterFunc_PrematchCallback()
-{
} \ No newline at end of file