aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut')
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut236
1 files changed, 222 insertions, 14 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
index bce8b4c7..760daef0 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
@@ -69,11 +69,21 @@ struct {
entity evacIcon
} file
+struct EvacShipSetting
+{
+ asset shipModel
+ string flyinSound
+ string hoverSound
+ string flyoutSound
+}
+
void function Evac_Init()
{
EvacShared_Init()
RegisterSignal( "EvacShipLeaves" )
RegisterSignal( "EvacOver" )
+
+ PrecacheParticleSystem( FX_EVAC_MARKER )
}
void function AddEvacNode( entity evacNode )
@@ -100,7 +110,7 @@ void function EvacEpilogueSetup()
void function EvacEpilogue()
{
- int winner = GetWinningTeam()
+ int winner = GetWinningTeam()
// make sure we don't run evac if it won't be supported for current map/gamestate
bool canRunEvac = GetCurrentPlaylistVarInt( "max_teams", 2 ) == 2 &&
@@ -110,6 +120,10 @@ void function EvacEpilogue()
if ( canRunEvac )
{
thread SetRespawnAndWait( false )
+
+ // no players can evac? end match
+ thread CheckIfAnyPlayerLeft( GetOtherTeam( winner ) )
+
thread Evac( GetOtherTeam( winner ), EVAC_INITIAL_WAIT, EVAC_ARRIVAL_TIME, EVAC_WAIT_TIME, EvacEpiloguePlayerCanBoard, EvacEpilogueShouldLeaveEarly, EvacEpilogueCompleted )
}
else
@@ -139,6 +153,10 @@ void function SetRespawnAndWait( bool mode )
{
wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY
SetRespawnsEnabled( mode )
+
+ // clear any respawn availablity, or players are able to save there respawn for whenever they want
+ foreach( entity player in GetPlayerArray() )
+ ClearRespawnAvailable( player )
}
bool function EvacEpiloguePlayerCanBoard( entity dropship, entity player )
@@ -174,12 +192,16 @@ void function EvacEpilogueCompleted( entity dropship )
ScreenFadeToBlackForever( player, 2.0 )
wait 2.0
- SetGameState( eGameState.Postmatch )
+ if( GetGameState() != eGameState.Postmatch )
+ SetGameState( eGameState.Postmatch )
}
// global evac func, anything can call this, it's not necessarily an epilogue thing
void function Evac( int evacTeam, float initialWait, float arrivalTime, float waitTime, bool functionref( entity, entity ) canBoardCallback, bool functionref( entity ) shouldLeaveEarlyCallback, void functionref( entity ) completionCallback, entity customEvacNode = null )
{
+ // get evac ship sound and model for specific team
+ EvacShipSetting evacShip = GetEvacShipSettingByTeam( evacTeam )
+
wait initialWait
// setup evac nodes if not manually registered
@@ -212,23 +234,39 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
DispatchSpawn( file.evacIcon )
file.evacIcon.DisableHibernation()
+ // start evac beam
+ int index = GetParticleSystemIndex( FX_EVAC_MARKER )
+
+ entity effectFriendly = StartParticleEffectInWorld_ReturnEntity( index, evacNode.GetOrigin(), < 0,0,0 > )
+ SetTeam( effectFriendly, evacTeam )
+ effectFriendly.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY
+
wait 0.5 // need to wait here, or the target won't appear on clients for some reason
// eta until arrive
SetTeamActiveObjective( evacTeam, "EG_DropshipExtract", Time() + arrivalTime, file.evacIcon )
SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract", Time() + arrivalTime, file.evacIcon )
+ foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) //Show the Evac Match Goal for players of the team that lost the match
+ Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 0 )
+
// would've liked to use cd_dropship_rescue_side_start length here, but can't since this is done before dropship spawn, can't
wait arrivalTime - 4.33333
entity dropship = CreateDropship( evacTeam, evacNode.GetOrigin(), evacNode.GetAngles() )
- dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
- dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
+
+ thread DropShipTempHide( dropship ) // prevent showing model and health bar on spawn
+ dropship.SetModel( evacShip.shipModel )
+ dropship.SetValueForModelKey( evacShip.shipModel )
+
dropship.SetMaxHealth( EVAC_SHIP_HEALTH )
dropship.SetHealth( EVAC_SHIP_HEALTH )
dropship.SetShieldHealth( EVAC_SHIP_SHIELDS )
SetTargetName( dropship, "#NPC_EVAC_DROPSHIP" )
DispatchSpawn( dropship )
- dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
+
+ // reduce nuclear core's damage
+ AddEntityCallback_OnDamaged( dropship, EvacDropshipDamaged )
+
AddEntityCallback_OnKilled( dropship, EvacDropshipKilled )
dropship.s.evacSlots <- [ null, null, null, null, null, null, null, null ]
@@ -241,9 +279,15 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
dropship.s.evacTrigger.Destroy()
// this should be for both teams
- SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" )
- SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" )
-
+ if( !IsValid( dropship ) )
+ {
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" )
+
+ foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) )
+ SetPlayerChallengeEvacState( player, 0 )
+ }
+
foreach ( entity player in dropship.s.evacSlots )
{
if ( !IsValid( player ) )
@@ -255,10 +299,14 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
// this is called whether dropship is destroyed or evac finishes, callback can handle this itself
thread completionCallback( dropship )
})
-
+
// flyin
Spectator_SetCustomSpectatorFunc( EvacSpectatorFunc )
thread PlayAnim( dropship, "cd_dropship_rescue_side_start", evacNode )
+
+ // fly in sound and effect
+ EmitSoundOnEntity( dropship, evacShip.flyinSound )
+ thread WarpInEffectEvacShip( dropship )
// calculate time until idle start
float sequenceDuration = dropship.GetSequenceDuration( "cd_dropship_rescue_side_start" )
@@ -266,11 +314,22 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
wait sequenceDuration * cycleFrac
thread PlayAnim( dropship, "cd_dropship_rescue_side_idle", evacNode )
+
+ // hover sound
+ EmitSoundOnEntity( dropship, evacShip.hoverSound )
// eta until leave
- SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + EVAC_WAIT_TIME, file.evacIcon )
- SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + EVAC_WAIT_TIME, file.evacIcon )
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + waitTime, file.evacIcon )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + waitTime, file.evacIcon )
+ // dialogue
+ PlayFactionDialogueToTeam( "mp_evacGo", evacTeam )
+ PlayFactionDialogueToTeam( "mp_evacStop", GetOtherTeam( evacTeam ) )
+
+ // stop evac beam
+ if( IsValid( effectFriendly ) )
+ EffectStop( effectFriendly )
+
// setup evac trigger
entity trigger = CreateEntity( "trigger_cylinder" )
trigger.SetRadius( 150 )
@@ -298,6 +357,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
WaitFrame()
}
+
+ // fly out sound
+ StopSoundOnEntity( dropship, evacShip.hoverSound )
+ EmitSoundOnEntity( dropship, evacShip.flyoutSound )
// holster all weapons
foreach ( entity player in dropship.s.evacSlots )
@@ -320,6 +383,12 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
Remote_CallFunction_NonReplay( player, "ServerCallback_PlayScreenFXWarpJump" )
wait WARPINFXTIME
+
+ dropship.kv.VisibilityFlags = 0 // prevent jetpack trails being like "dive" into ground
+ WaitFrame() // better wait because we are server
+ if( !IsValid( dropship ) )
+ return
+ thread __WarpOutEffectShared( dropship )
// go to space
@@ -339,24 +408,64 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
if ( !PlayerInDropship( player, dropship ) )
{
if ( player.GetTeam() == dropship.GetTeam() )
+ {
SetPlayerActiveObjective( player, "EG_DropshipExtractFailedEscape" )
+ SetPlayerChallengeEvacState( player, 2 )
+ }
continue
}
SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" )
+
+ // let evacing team able to see the ship again
+ dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY
// skybox
player.SetSkyCamera( GetEnt( SKYBOXSPACE ) )
Remote_CallFunction_NonReplay( player, "ServerCallback_DisableHudForEvac" )
Remote_CallFunction_NonReplay( player, "ServerCallback_SetClassicSkyScale", dropship.GetEncodedEHandle(), 0.7 )
Remote_CallFunction_NonReplay( player, "ServerCallback_SetMapSettings", 4.0, false, 0.4, 0.125 )
+ SetPlayerChallengeEvacState( player, 1 )
// display player [Evacuated] in killfeed
foreach ( entity otherPlayer in GetPlayerArray() )
Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_EvacObit", player.GetEncodedEHandle() )
}
-
+
+ // award player score to evacing team
+ int evacCount = 0
+ array<entity> evacingPlayers = GetPlayerArrayOfTeam( dropship.GetTeam() ) // all players that are supposed to evac in the dropship
+
+ // count how many players are in the dropship
+ foreach ( entity player in evacingPlayers )
+ {
+ if ( !PlayerInDropship( player, dropship ) )
+ continue
+
+ evacCount++
+ }
+
+ bool allEvac = evacCount == evacingPlayers.len()
+
+ foreach(entity player in evacingPlayers)
+ {
+ if ( !PlayerInDropship( player, dropship ) )
+ continue
+
+ AddPlayerScore( player, "HotZoneExtract" )
+ UpdatePlayerStat( player, "misc_stats", "evacsSurvived" )
+
+ if ( allEvac )
+ AddPlayerScore( player, "TeamBonusFullEvac" )
+ }
+
+ // sole survivor (but not the only one on the team)
+ if ( evacCount == 1 && !allEvac )
+ {
+ // we can assume there is one player in the array because otherwise evacCount wouldn't be 1
+ AddPlayerScore( evacingPlayers[0], "SoleSurvivor" )
+ }
}
void function AddPlayerToEvacDropship( entity dropship, entity player )
@@ -376,7 +485,12 @@ void function AddPlayerToEvacDropship( entity dropship, entity player )
// no slots available
if ( !PlayerInDropship( player, dropship ) )
return
-
+
+ UpdatePlayerStat( player, "misc_stats", "evacsAttempted" )
+
+ // need to cancel if the dropship dies
+ dropship.EndSignal( "OnDeath", "OnDestroy" )
+
player.SetInvulnerable()
player.UnforceCrouch()
player.ForceStand()
@@ -391,7 +505,7 @@ void function AddPlayerToEvacDropship( entity dropship, entity player )
EmitSoundOnEntityOnlyToPlayer( player, player, SHIFTER_START_SOUND_3P )
// should play SHIFTER_START_SOUND_1P when they actually arrive in the ship i think, unsure how this is supposed to be done
PlayPhaseShiftDisappearFX( player )
- waitthread FirstPersonSequence( fp, player, dropship )
+ FirstPersonSequence( fp, player, dropship )
FirstPersonSequenceStruct idleFp
idleFp.firstPersonAnimIdle = EVAC_IDLE_ANIMS_1P[ slot ]
@@ -426,3 +540,97 @@ void function EvacDropshipKilled( entity dropship, var damageInfo )
}
}
}
+
+// if there's no player left in evacing team, we end this match
+void function CheckIfAnyPlayerLeft( int evacTeam )
+{
+ wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY
+ float startTime = Time()
+
+ OnThreadEnd(
+ function() : ( evacTeam )
+ {
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtractEvacPlayersKilled" )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractEvacPlayersKilled" )
+ thread EvacEpilogueCompleted( null )
+
+ // score for killing the entire evacing team
+ foreach ( entity player in GetPlayerArray() )
+ {
+ if ( player.GetTeam() == evacTeam )
+ continue
+
+ AddPlayerScore( player, "TeamBonusKilledAll")
+ }
+ }
+ )
+ while( true )
+ {
+ if( GetPlayerArrayOfTeam_Alive( evacTeam ).len() == 0 )
+ break
+ if( GetGameState() == eGameState.Postmatch )
+ return
+ WaitFrame()
+ }
+}
+
+void function DropShipTempHide( entity dropship )
+{
+ dropship.kv.VisibilityFlags = 0 // or it will still shows the jetpack fxs
+ HideName( dropship )
+ wait 0.46
+ if( IsValid( dropship ) )
+ {
+ dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE
+ ShowName( dropship )
+ }
+}
+
+EvacShipSetting function GetEvacShipSettingByTeam( int team )
+{
+ EvacShipSetting tempSetting
+ tempSetting.shipModel = $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl"
+ tempSetting.flyinSound = "Goblin_IMC_Evac_Flyin"
+ tempSetting.hoverSound = "Goblin_IMC_Evac_Hover"
+ tempSetting.flyoutSound = "Goblin_IMC_Evac_FlyOut"
+
+ if( team == TEAM_MILITIA )
+ {
+ tempSetting.shipModel = $"models/vehicle/crow_dropship/crow_dropship_hero.mdl"
+ tempSetting.flyinSound = "Crow_MCOR_Evac_Flyin"
+ tempSetting.hoverSound = "Crow_MCOR_Evac_Hover"
+ tempSetting.flyoutSound = "Crow_MCOR_Evac_Flyout"
+ }
+ return tempSetting
+}
+
+void function EvacDropshipDamaged( entity evacShip, var damageInfo )
+{
+ int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo )
+ if( damageSourceID == damagedef_nuclear_core )
+ DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) * EVAC_SHIP_DAMAGE_MULTIPLIER_AGAINST_NUCLEAR_CORE )
+}
+
+void function WarpInEffectEvacShip( entity dropship )
+{
+ dropship.EndSignal( "OnDestroy" )
+ float sfxWait = 0.1
+ float totalTime = WARPINFXTIME
+ float preWaitTime = 0.16 // give it some time so it's actually playing anim, and we can get it's "origin" attatch for playing warp in effect
+ string sfx = "dropship_warpin"
+
+ wait preWaitTime
+
+ int attach = dropship.LookupAttachment( "origin" )
+ vector origin = dropship.GetAttachmentOrigin( attach )
+ vector angles = dropship.GetAttachmentAngles( attach )
+
+ entity fx = PlayFX( FX_GUNSHIP_CRASH_EXPLOSION_ENTRANCE, origin, angles )
+ fx.FXEnableRenderAlways()
+ fx.DisableHibernation()
+
+ wait sfxWait
+ EmitSoundAtPosition( TEAM_UNASSIGNED, origin, sfx )
+
+ wait totalTime - sfxWait
+} \ No newline at end of file