aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/mod/scripts/vscripts
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-12-19 17:32:09 +0000
committerBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-12-19 17:32:09 +0000
commitf8685213baf4eef93dae6cc98c8e4a8318565bd3 (patch)
treec5bfb10ee066e5f7fb031376ddb8b435577b2991 /Northstar.CustomServers/mod/scripts/vscripts
parent7cac56cb9bcaabed9562a7b46718f5c5de3400b8 (diff)
downloadNorthstarMods-f8685213baf4eef93dae6cc98c8e4a8318565bd3.tar.gz
NorthstarMods-f8685213baf4eef93dae6cc98c8e4a8318565bd3.zip
fixes and dropship refactor
Diffstat (limited to 'Northstar.CustomServers/mod/scripts/vscripts')
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut35
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut16
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut16
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut192
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut6
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_lf_deck.nut25
6 files changed, 160 insertions, 130 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
index 58d38ce7..2017b64b 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
@@ -19,7 +19,7 @@ void function SvLoadoutsMP_Init()
RegisterSignal( "EndUpdateCachedLoadouts" )
RegisterSignal( "GracePeriodDone" ) // temp to get weapons\_weapon_utility.nut:2271 to behave
- AddCallback_OnClientConnected( UpdateCallsignOnConnect )
+ AddCallback_OnClientConnected( LoadoutsMPInitPlayer )
AddClientCommandCallback( "RequestPilotLoadout", ClientCommandCallback_RequestPilotLoadout )
AddClientCommandCallback( "RequestTitanLoadout", ClientCommandCallback_RequestTitanLoadout )
@@ -38,7 +38,7 @@ void function SvLoadoutsMP_Init()
AddClientCommandCallback( "InGameMPMenuClosed", ClientCommandCallback_InGameMPMenuClosed )
AddClientCommandCallback( "LoadoutMenuClosed", ClientCommandCallback_LoadoutMenuClosed )
}
-
+
AddCallback_OnPlayerKilled( DestroyDroppedWeapon )
}
@@ -70,8 +70,10 @@ TitanLoadoutDef function GetTitanLoadoutForPlayer( entity player )
return def
}
-void function UpdateCallsignOnConnect( entity player )
+void function LoadoutsMPInitPlayer( entity player )
{
+ player.s.loadoutDirty <- false
+
// these netints are required for callsigns and such to display correctly on other clients
player.SetPlayerNetInt( "activeCallingCardIndex", player.GetPersistentVarAsInt( "activeCallingCardIndex" ) )
player.SetPlayerNetInt( "activeCallsignIconIndex", player.GetPersistentVarAsInt( "activeCallsignIconIndex" ) )
@@ -129,6 +131,7 @@ bool function ClientCommandCallback_SetPersistentLoadoutValue( entity player, ar
// VERY temp and insecure
SetPersistentLoadoutValue( player, args[0], args[1].tointeger(), args[2], val )
+ print( args[ 0 ] )
if ( args[0] == "pilot" )
SetPlayerLoadoutDirty( player )
@@ -227,7 +230,7 @@ bool function ClientCommandCallback_LoadoutMenuClosed( entity player, array<stri
bool function ClientCommandCallback_InGameMPMenuClosed( entity player, array<string> args )
{
- //TryGivePilotLoadoutForGracePeriod( player )
+ TryGivePilotLoadoutForGracePeriod( player )
return true
}
@@ -238,19 +241,31 @@ bool function IsRefValidAndOfType( string ref, int itemType )
void function SetPlayerLoadoutDirty( entity player )
{
- if ( file.loadoutGracePeriodEnabled || player.p.usingLoadoutCrate )
- file.dirtyLoadouts.append( player )
+ if ( !IsLobby() )
+ player.s.loadoutDirty = true
}
void function TryGivePilotLoadoutForGracePeriod( entity player )
{
- if ( !IsLobby() && file.dirtyLoadouts.contains( player ) )
+ if ( !IsLobby() && IsAlive( player ) && player.s.loadoutDirty )
{
- file.dirtyLoadouts.remove( file.dirtyLoadouts.find( player ) )
+ player.s.loadoutDirty = false
- if ( Time() - player.s.respawnTime <= CLASS_CHANGE_GRACE_PERIOD || player.p.usingLoadoutCrate )
+ // for intros
+ float respawnTimeReal
+ if ( GetGameState() == eGameState.Playing && Time() - expect float( GetServerVar( "gameStateChangeTime" ) ) <= CLASS_CHANGE_GRACE_PERIOD )
+ respawnTimeReal = expect float( GetServerVar( "gameStateChangeTime" ) )
+ else
+ respawnTimeReal = expect float( player.s.respawnTime )
+
+ if ( Time() - respawnTimeReal <= CLASS_CHANGE_GRACE_PERIOD || player.p.usingLoadoutCrate || GetGameState() < eGameState.Playing )
{
- Loadouts_TryGivePilotLoadout( player )
+ // because the game sucks and stuff Loadouts_TryGivePilotLoadout doesn't work in intro so have to do this manually
+ int loadoutIndex = GetPersistentSpawnLoadoutIndex( player, "pilot" )
+ GivePilotLoadout( player, GetPilotLoadoutFromPersistentData( player, loadoutIndex ) )
+ SetActivePilotLoadout( player )
+ SetActivePilotLoadoutIndex( player, loadoutIndex )
+
player.p.usingLoadoutCrate = false
}
else
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
index 96b84c23..d086d65b 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
@@ -136,19 +136,10 @@ void function EvacEpilogueCompleted( entity dropship )
{
wait 5.0
- if ( IsValid( dropship ) )
- {
- foreach ( entity player in dropship.s.evacSlots )
- {
- if ( !IsValid( player ) )
- continue
-
- ScreenFadeToBlackForever( player, 2.0 )
- }
- }
+ foreach ( entity player in GetPlayerArray() )
+ ScreenFadeToBlackForever( player, 2.0 )
wait 2.0
-
SetGameState( eGameState.Postmatch )
}
@@ -197,6 +188,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
DispatchSpawn( dropship )
+ dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
dropship.s.evacSlots <- [ null, null, null, null, null, null, null, null ]
@@ -305,7 +297,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
if ( player.GetTeam() == dropship.GetTeam() )
SetPlayerActiveObjective( player, "EG_DropshipExtractFailedEscape" )
- return
+ continue
}
SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut
index 88a95fe4..fb0270cc 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut
@@ -31,7 +31,6 @@ void function GamemodeColiseum_Init()
Riff_ForceBoostAvailability( eBoostAvailability.Disabled )
Riff_ForceSetEliminationMode( eEliminationMode.Pilots )
SetLoadoutGracePeriodEnabled( false ) // prevent modifying loadouts with grace period
- SetWeaponDropsEnabled( false )
ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() )
AddCallback_GameStateEnter( eGameState.Prematch, ShowColiseumIntroScreen )
@@ -139,6 +138,21 @@ void function SetupColiseumEpilogue()
void function RunColiseumOutro()
{
+ // also since this runs on game end, do winstreak stuff
+ foreach ( entity player in GetPlayerArray() )
+ {
+ if ( GetWinningTeam() == player.GetTeam() )
+ {
+ player.SetPersistentVar( "coliseumTotalWins", player.GetPersistentVarAsInt( "coliseumTotalWins" ) + 1 )
+ player.SetPersistentVar( "coliseumWinStreak", player.GetPersistentVarAsInt( "coliseumWinStreak" ) + 1 )
+ }
+ else
+ {
+ player.SetPersistentVar( "coliseumTotalWins", maxint( player.GetPersistentVarAsInt( "coliseumTotalWins" ) - 1, 0 ) )
+ player.SetPersistentVar( "coliseumWinStreak", 0 )
+ }
+ }
+
entity outroAnimPoint = GetEnt( "intermission" )
array<entity> winningPlayers = GetPlayerArrayOfTeam( GetWinningTeam() )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut
index b6b0aa10..69f67584 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut
@@ -20,8 +20,9 @@ const array<string> DROPSHIP_JUMP_ANIMS_POV = [ "Classic_MP_flyin_exit_povA_jump
"Classic_MP_flyin_exit_povB_jump",
"Classic_MP_flyin_exit_povC_jump",
"Classic_MP_flyin_exit_povD_jump" ]
+
+const int MAX_DROPSHIP_PLAYERS = 4
-const array<int> DROPSHIP_ANIMS_YAW = [ -18, 8, 8, -16 ]
global const float DROPSHIP_INTRO_LENGTH = 15.0 // TODO tweak this
@@ -30,66 +31,28 @@ struct IntroDropship
entity dropship
int playersInDropship
- entity[4] players
+ entity[MAX_DROPSHIP_PLAYERS] players
}
struct {
- IntroDropship[2] militiaDropships
- IntroDropship[2] imcDropships
+ // these used to be IntroDropship[2]s but i wanted to be able to use array.getrandom so they have to be actual arrays
+ array<IntroDropship> militiaDropships
+ array<IntroDropship> imcDropships
float introStartTime
- int numPlayersInIntro
} file
void function ClassicMP_DefaultDropshipIntro_Setup()
{
- AddCallback_OnClientConnected( DropshipIntro_OnClientConnected )
- AddCallback_OnClientDisconnected( DropshipIntro_OnClientDisconnected )
-
+ AddCallback_OnClientConnected( DropshipIntro_OnClientConnected )
AddCallback_GameStateEnter( eGameState.Prematch, OnPrematchStart )
}
void function DropshipIntro_OnClientConnected( entity player )
{
- // find the player's team's dropships
- IntroDropship[2] teamDropships = player.GetTeam() == TEAM_MILITIA ? file.militiaDropships : file.imcDropships
-
- // find a dropship with an empty slot
- foreach ( IntroDropship dropship in teamDropships )
- if ( dropship.playersInDropship < 4 )
- // we've found a valid dropship
- // find an empty player slot
- for ( int i = 0; i < dropship.players.len(); i++ )
- if ( dropship.players[ i ] == null ) // empty slot
- {
- dropship.players[ i ] = player
- dropship.playersInDropship++
-
- // spawn player into intro if we're already doing intro
- if ( GetGameState() == eGameState.Prematch )
- thread SpawnPlayerIntoDropship( player )
-
- return
- }
-}
-
-void function DropshipIntro_OnClientDisconnected( entity player )
-{
- // find the player's dropship
- IntroDropship[2] teamDropships = player.GetTeam() == TEAM_MILITIA ? file.militiaDropships : file.imcDropships
-
- // find the player
- foreach ( IntroDropship dropship in teamDropships )
- for ( int i = 0; i < dropship.players.len(); i++ )
- if ( dropship.players[ i ] == player )
- {
- // we've found the player, remove them
- dropship.players[ i ] = null
- dropship.playersInDropship--
-
- return
- }
+ if ( GetGameState() == eGameState.Prematch )
+ thread SpawnPlayerIntoDropship( player )
}
void function OnPrematchStart()
@@ -99,16 +62,20 @@ void function OnPrematchStart()
print( "starting dropship intro!" )
file.introStartTime = Time()
+ // make 2 empty dropship structs per team
+ IntroDropship emptyDropship
+ file.militiaDropships = [ clone emptyDropship, clone emptyDropship ]
+ file.imcDropships = [ clone emptyDropship, clone emptyDropship ]
+
// spawn dropships
- array<entity> dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" )
- foreach ( entity dropshipSpawn in dropshipSpawns )
+ foreach ( entity dropshipSpawn in GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" ) )
{
if ( GameModeRemove( dropshipSpawn ) || ( GetSpawnpointGamemodeOverride() != GAMETYPE && dropshipSpawn.HasKey( "gamemode_" + GetSpawnpointGamemodeOverride() ) && dropshipSpawn.kv[ "gamemode_" + GetSpawnpointGamemodeOverride() ] == "0" ) )
continue
// todo: possibly make this only spawn dropships if we've got enough players to need them
- int createTeam = GetServerVar( "switchedSides" ) != 1 ? dropshipSpawn.GetTeam() : GetOtherTeam( dropshipSpawn.GetTeam() )
- IntroDropship[2] teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships
+ int createTeam = HasSwitchedSides() ? dropshipSpawn.GetTeam() : GetOtherTeam( dropshipSpawn.GetTeam() )
+ array<IntroDropship> teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships
int dropshipIndex = !IsValid( teamDropships[ 0 ].dropship ) ? 0 : 1
// create entity
@@ -116,6 +83,8 @@ void function OnPrematchStart()
teamDropships[ dropshipIndex ].dropship = dropship
AddAnimEvent( dropship, "dropship_warpout", WarpoutEffect )
+ dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
+ dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
DispatchSpawn( dropship )
@@ -128,6 +97,14 @@ void function OnPrematchStart()
foreach ( entity player in GetPlayerArray() )
thread SpawnPlayerIntoDropship( player )
+
+ thread EndIntroWhenFinished()
+}
+
+void function EndIntroWhenFinished()
+{
+ wait 15.0
+ ClassicMP_OnIntroFinished()
}
void function SpawnPlayerIntoDropship( entity player )
@@ -135,18 +112,37 @@ void function SpawnPlayerIntoDropship( entity player )
if ( IsAlive( player ) )
player.Die() // kill them so we don't have any issues respawning them later
+ player.s.dropshipIntroIsJumping <- false
+ OnThreadEnd( function() : ( player )
+ {
+ if ( IsValid( player ) )
+ {
+ player.ClearParent()
+ ClearPlayerAnimViewEntity( player )
+
+ if ( !player.s.dropshipIntroIsJumping )
+ {
+ player.MovementEnable()
+ player.EnableWeaponViewModel()
+ RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING )
+ }
+ }
+ })
+
WaitFrame()
player.EndSignal( "OnDeath" )
player.EndSignal( "OnDestroy" )
- player.EndSignal( "Disconnected" )
-
- file.numPlayersInIntro++
// find the player's dropship and seat
- IntroDropship[2] teamDropships = player.GetTeam() == TEAM_MILITIA ? file.militiaDropships : file.imcDropships
+ array<IntroDropship> teamDropships
+ if ( player.GetTeam() == TEAM_MILITIA )
+ teamDropships = file.militiaDropships
+ else
+ teamDropships = file.imcDropships
+
IntroDropship playerDropship
- int playerDropshipIndex
+ int playerDropshipIndex = -1
foreach ( IntroDropship dropship in teamDropships )
for ( int i = 0; i < dropship.players.len(); i++ )
if ( dropship.players[ i ] == player )
@@ -156,29 +152,13 @@ void function SpawnPlayerIntoDropship( entity player )
break
}
-
- if ( playerDropship.dropship == null )
+
+ if ( true )//if ( playerDropship.dropship == null )
{
- // if we're at this point, we have more players than we do dropships, oh dear
- ScreenFadeFromBlack( player, 0.0 )
- RespawnAsPilot( player )
-
- file.numPlayersInIntro--
- return
+ // if we're at this point, we have more players than we do dropships, so just pick a random one
+ playerDropship = teamDropships.getrandom()
+ playerDropshipIndex = RandomInt( MAX_DROPSHIP_PLAYERS )
}
-
- // figure out what anims we're using for idle
- string idleAnim = DROPSHIP_IDLE_ANIMS[ playerDropshipIndex ]
- string idleAnimPov = DROPSHIP_IDLE_ANIMS_POV[ playerDropshipIndex ]
-
- FirstPersonSequenceStruct idleSequence
- idleSequence.firstPersonAnim = idleAnimPov
- idleSequence.thirdPersonAnim = idleAnim
- idleSequence.attachment = "ORIGIN"
- idleSequence.teleport = true
- idleSequence.viewConeFunction = ViewConeRampFree
- idleSequence.hideProxy = true
- idleSequence.setInitialTime = Time() - file.introStartTime
// respawn player and holster their weapons so they aren't out
player.RespawnPlayer( null )
@@ -189,36 +169,47 @@ void function SpawnPlayerIntoDropship( entity player )
ScreenFadeFromBlack( player, 0.5, 0.5 )
// faction leaders are done clientside, spawn them here
Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.dropship.GetEncodedEHandle(), file.introStartTime )
- thread FirstPersonSequence( idleSequence, player, playerDropship.dropship )
-
- // wait until the anim is done
- WaittillAnimDone( player ) // unsure if this is the best way to do this
- // todo: possibly rework this to actually get the time the idle anim takes and start the starttime of the jump sequence for very late joiners using that
-
- // honestly go rewrite alot of this too it's messy
- // figure out what anims we're using for jump
- string jumpAnim = DROPSHIP_JUMP_ANIMS[ playerDropshipIndex ]
- string jumpAnimPov = DROPSHIP_JUMP_ANIMS_POV[ playerDropshipIndex ]
+ // do firstperson sequence
+ FirstPersonSequenceStruct idleSequence
+ idleSequence.firstPersonAnim = DROPSHIP_IDLE_ANIMS_POV[ playerDropshipIndex ]
+ idleSequence.thirdPersonAnim = DROPSHIP_IDLE_ANIMS[ playerDropshipIndex ]
+ idleSequence.attachment = "ORIGIN"
+ idleSequence.teleport = true
+ idleSequence.viewConeFunction = ViewConeRampFree
+ idleSequence.hideProxy = true
+ idleSequence.setInitialTime = Time() - file.introStartTime
+ thread FirstPersonSequence( idleSequence, player, playerDropship.dropship )
+ WaittillAnimDone( player )
+ // todo: possibly rework this to actually get the time the idle anim takes and start the starttime of the jump sequence for very late joiners using that
+
+ // jump sequence
FirstPersonSequenceStruct jumpSequence
- jumpSequence.firstPersonAnim = jumpAnimPov
- jumpSequence.thirdPersonAnim = jumpAnim
+ jumpSequence.firstPersonAnim = DROPSHIP_JUMP_ANIMS_POV[ playerDropshipIndex ]
+ jumpSequence.thirdPersonAnim = DROPSHIP_JUMP_ANIMS[ playerDropshipIndex ]
jumpSequence.attachment = "ORIGIN"
- //jumpSequence.setInitialTime = Time() - ( file.introStartTime + player.GetSequenceDuration( idleAnim ) )
jumpSequence.setInitialTime = Time() - ( file.introStartTime + 10.9 ) // pretty sure you should do this with GetScriptedAnimEventCycleFrac?
// idk unsure how to use that, all i know is getsequenceduration > the length it actually should be
- thread FirstPersonSequence( jumpSequence, player, playerDropship.dropship )
- WaittillAnimDone( player )
+ FirstPersonSequence( jumpSequence, player, playerDropship.dropship )
+
+ player.s.dropshipIntroIsJumping <- true
+ thread PlayerJumpsFromDropship( player )
+}
- // unparent player and their camera from the dropship
- player.ClearParent()
- ClearPlayerAnimViewEntity( player )
-
- file.numPlayersInIntro--
- if ( file.numPlayersInIntro == 0 )
- ClassicMP_OnIntroFinished() // set intro as finished
+void function PlayerJumpsFromDropship( entity player )
+{
+ OnThreadEnd( function() : ( player )
+ {
+ if ( IsValid( player ) )
+ {
+ // show weapon viewmodel and hud and let them move again
+ player.MovementEnable()
+ player.EnableWeaponViewModel()
+ RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING )
+ }
+ })
// wait for intro timer to be fully done
wait ( file.introStartTime + DROPSHIP_INTRO_LENGTH ) - Time()
@@ -229,10 +220,5 @@ void function SpawnPlayerIntoDropship( entity player )
while ( !player.IsOnGround() && !player.IsWallRunning() && !player.IsWallHanging() ) // todo this needs tweaking
WaitFrame()
- // show weapon viewmodel and hud and let them move again
- player.MovementEnable()
- player.EnableWeaponViewModel()
- RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING )
-
TryGameModeAnnouncement( player )
} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
index bf21b492..b2ce4fca 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
@@ -648,9 +648,9 @@ void function CleanUpEntitiesForRoundEnd()
foreach ( entity npc in GetNPCArray() )
if ( IsValid( npc ) )
npc.Destroy() // need this because getnpcarray includes the pettitans we just killed at this point
-
- foreach ( entity weapon in GetEntArrayByClass_Expensive( "weaponx" ) )
- weapon.Destroy()
+
+ // destroy weapons
+ ClearDroppedWeapons()
foreach ( entity battery in GetEntArrayByClass_Expensive( "item_titan_battery" ) )
battery.Destroy()
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_lf_deck.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_lf_deck.nut
index dca30fe9..592422ee 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_lf_deck.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_lf_deck.nut
@@ -2,6 +2,29 @@ global function CodeCallback_MapInit
void function CodeCallback_MapInit()
{
- FlagClear( "Disable_Marvins" )
SetupLiveFireMaps()
+
+ // worker drone model
+ PrecacheModel( $"models/robots/aerial_unmanned_worker/aerial_unmanned_worker.mdl" )
+
+ // note: this map has no marvin spawns, have to spawn them using idle nodes
+ AddSpawnCallback_ScriptName( "worker_drone_spawn", DeckSpawnWorkerDrone )
+ AddSpawnCallback_ScriptName( "marvin_idle_node", DeckSpawnMarvinForIdleNode )
+}
+
+void function DeckSpawnWorkerDrone( entity spawnpoint )
+{
+
+ entity drone = CreateWorkerDrone( TEAM_UNASSIGNED, spawnpoint.GetOrigin(), spawnpoint.GetAngles() )
+ DispatchSpawn( drone )
+}
+
+void function DeckSpawnMarvinForIdleNode( entity node )
+{
+ entity marvin = CreateMarvin( TEAM_UNASSIGNED, node.GetOrigin(), node.GetAngles() )
+ DispatchSpawn( marvin )
+
+ // doing this because no ai rn
+ if ( GetAINScriptVersion() == -1 )
+ thread PlayAnim( marvin, node.kv.leveled_animation )
} \ No newline at end of file