aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/mod/scripts/vscripts/gamemodes
diff options
context:
space:
mode:
authorRoyalBlue1 <malte.hoermeyer@web.de>2022-05-30 05:01:33 +0200
committerRoyalBlue1 <malte.hoermeyer@web.de>2022-05-30 05:01:33 +0200
commitc4a807ce87c9be6f6a453d1e8deb4876630531bf (patch)
tree4e9d6a864f5cd90b2f41f4d8b989c218f16c59b6 /Northstar.CustomServers/mod/scripts/vscripts/gamemodes
parent217f476f7aeeb0bb4a18a534075a979d8e95115b (diff)
downloadNorthstarMods-c4a807ce87c9be6f6a453d1e8deb4876630531bf.tar.gz
NorthstarMods-c4a807ce87c9be6f6a453d1e8deb4876630531bf.zip
Split FD into multiple files
-added dummy wave creation function for all "vanilla" FD maps -reworked event handling to support multiple event threads -tracking more variables for end medals -added debugging function to stationary firing positions
Diffstat (limited to 'Northstar.CustomServers/mod/scripts/vscripts/gamemodes')
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut845
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_events.nut736
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_nav.nut97
3 files changed, 939 insertions, 739 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut
index 7ace0591..f26cdf6e 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut
@@ -1,79 +1,34 @@
global function GamemodeFD_Init
global function RateSpawnpoints_FD
global function startHarvester
-global function createSmokeEvent
-global function createArcTitanEvent
-global function createWaitForTimeEvent
-global function createSuperSpectreEvent
-global function createDroppodGruntEvent
-global function createNukeTitanEvent
-global function createMortarTitanEvent
-global function createGenericSpawnEvent
-global function createGenericTitanSpawnWithAiSettingsEvent
-global function createDroppodStalkerEvent
-global function createDroppodSpectreMortarEvent
-global function createWaitUntilAliveEvent
-global function createCloakDroneEvent
-global function CreateTickEvent
-global function CreateToneSniperTitanEvent
-global function CreateNorthstarSniperTitanEvent
-
-global struct SmokeEvent{
- vector position
- float lifetime
-}
-
-global struct SpawnEvent{
- vector origin
- vector angles
- string route //defines route taken by the ai
- int skippedRouteNodes //defines how many route nodes will be skipped
- int spawnType //Just used for Wave Info but can be used for spawn too should contain aid of spawned enemys
- int spawnAmount //Just used for Wave Info but can be used for spawn too should contain amound of spawned enemys
- string npcClassName
- string aiSettings
-}
-
-global struct WaitEvent{
- float amount
-}
+global function GetTargetNameForID
-global struct SoundEvent{
- string soundEventName
-}
-global struct WaveEvent{
- void functionref(SmokeEvent,SpawnEvent,WaitEvent,SoundEvent) eventFunction
- bool shouldThread
- SmokeEvent smokeEvent
- SpawnEvent spawnEvent
- WaitEvent waitEvent
- SoundEvent soundEvent
-}
struct player_struct_fd{
bool diedThisRound
- float scoreThisRound
+ int scoreThisRound
int totalMVPs
- int mortarUnitsKilled //not implemented yet
+ int mortarUnitsKilled
int moneySpend
int coresUsed
float longestTitanLife //not implemented yet
int turretsRepaired //not implemented yet
int moneyShared
float timeNearHarvester //dont know how to track
- float longestLife //not implemented yet
+ float longestLife
int heals //dont know what to track
- int titanKills //not implemented yet
+ int titanKills
float damageDealt
int harvesterHeals
+ float lastRespawn
}
global HarvesterStruct& fd_harvester
global vector shopPosition
-global array<array<WaveEvent> > waveEvents
global table<string,array<vector> > routes
-
+global array<entity> routeNodes
+global array<entity> spawnedNPCs
@@ -81,12 +36,10 @@ global table<string,array<vector> > routes
struct {
array<entity> aiSpawnpoints
array<entity> smokePoints
- array<entity> routeNodes
array<float> harvesterDamageSource
bool havesterWasDamaged
bool harvesterShieldDown
float harvesterDamageTaken
- array<entity> spawnedNPCs
table<entity,player_struct_fd> players
entity harvester_info
}file
@@ -105,26 +58,28 @@ void function GamemodeFD_Init()
PlayerEarnMeter_SetEnabled(false)
SetShouldUsePickLoadoutScreen( true )
-
+ //general Callbacks
AddCallback_EntitiesDidLoad(LoadEntities)
AddCallback_GameStateEnter(eGameState.Prematch,FD_createHarvester)
AddCallback_GameStateEnter( eGameState.Playing,startMainGameLoop)
- AddCallback_OnClientConnected(GamemodeFD_InitPlayer)
- AddCallback_OnPlayerKilled(GamemodeFD_OnPlayerKilled)
AddCallback_OnRoundEndCleanup(FD_NPCCleanup)
- AddDamageByCallback("player",FD_DamageByPlayerCallback)
+ AddCallback_OnClientConnected(GamemodeFD_InitPlayer)
+ //Damage Callbacks
+ AddDamageByCallback("player",FD_DamageByPlayerCallback)
AddDamageCallback( "player", DamageScaleByDifficulty )
AddDamageCallback( "npc_titan", DamageScaleByDifficulty )
AddDamageCallback( "npc_turret_sentry", DamageScaleByDifficulty )
+ //Spawn Callbacks
AddSpawnCallback( "npc_titan", HealthScaleByDifficulty )
AddSpawnCallback( "npc_super_spectre", HealthScaleByDifficulty )
-
-
- AddCallback_OnNPCKilled(OnNpcDeath)
+ AddSpawnCallback( "player", FD_PlayerRespawnCallback )
AddSpawnCallback("npc_turret_sentry", AddTurretSentry )
- SetUsedCoreCallback(FD_UsedCoreCallback)
-
+ //death Callbacks
+ AddCallback_OnNPCKilled(OnNpcDeath)
+ AddCallback_OnPlayerKilled(GamemodeFD_OnPlayerKilled)
+
+ //Command Callbacks
AddClientCommandCallback("FD_ToggleReady",ClientCommandCallbackToggleReady)
AddClientCommandCallback("FD_UseHarvesterShieldBoost",useShieldBoost)
@@ -138,6 +93,11 @@ void function FD_BoostPurchaseCallback(entity player,BoostStoreData data)
file.players[player].moneySpend += data.cost
}
+void function FD_PlayerRespawnCallback(entity player)
+{
+ if(player in file.players)
+ file.players[player].lastRespawn = Time()
+}
void function FD_TeamReserveDepositOrWithdrawCallback(entity player, string action,int amount)
{
@@ -153,6 +113,7 @@ void function FD_TeamReserveDepositOrWithdrawCallback(entity player, string acti
}
void function GamemodeFD_OnPlayerKilled(entity victim, entity attacker, var damageInfo)
{
+ file.players[victim].longestLife = Time() - file.players[victim].lastRespawn
file.players[victim].diedThisRound = true
array<entity> militiaplayers = GetPlayerArrayOfTeam( TEAM_MILITIA )
int deaths = 0
@@ -193,12 +154,18 @@ void function GamemodeFD_InitPlayer(entity player)
}
void function OnNpcDeath( entity victim, entity attacker, var damageInfo )
-{
- int findIndex = file.spawnedNPCs.find( victim )
+{
+ if(victim.IsTitan()&&attacker in file.players)
+ file.players[attacker].titanKills++
+ int victimTypeID = FD_GetAITypeID_ByString(victim.GetTargetName())
+ if(victimTypeID == eFD_AITypeIDs.TITAN_MORTAR||victimTypeID == eFD_AITypeIDs.SPECTRE_MORTAR)
+ if(attacker in file.players)
+ file.players[attacker].mortarUnitsKilled++
+ int findIndex = spawnedNPCs.find( victim )
if ( findIndex != -1 )
{
- file.spawnedNPCs.remove( findIndex )
- switch(FD_GetAITypeID_ByString(victim.GetTargetName())) //FD_GetAINetIndex_byAITypeID does not support all titan ids
+ spawnedNPCs.remove( findIndex )
+ switch(victimTypeID) //FD_GetAINetIndex_byAITypeID does not support all titan ids
{
case(eFD_AITypeIDs.TITAN):
case(eFD_AITypeIDs.RONIN):
@@ -212,7 +179,7 @@ void function OnNpcDeath( entity victim, entity attacker, var damageInfo )
SetGlobalNetInt("FD_AICount_Titan",GetGlobalNetInt("FD_AICount_Titan")-1)
break
default:
- string netIndex = FD_GetAINetIndex_byAITypeID(FD_GetAITypeID_ByString(victim.GetTargetName()))
+ string netIndex = GetAiNetIdFromTargetName(victim.GetTargetName())
if(netIndex != "")
SetGlobalNetInt(netIndex,GetGlobalNetInt(netIndex)-1)
}
@@ -252,7 +219,7 @@ void function OnNpcDeath( entity victim, entity attacker, var damageInfo )
AddMoneyToPlayer( attacker , money )
attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, playerScore ) // seems to be how combat score is counted
-
+ file.players[attacker].scoreThisRound += playerScore
table<int, bool> alreadyAssisted
foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory )
{
@@ -315,33 +282,7 @@ void function mainGameLoop()
}
-array<entity> function getRoute(string routeName)
-{
- array<entity> ret
- array<entity> currentNode = []
- foreach(entity node in file.routeNodes)
- {
- if(!node.HasKey("route_name"))
- continue
- if(node.kv.route_name==routeName)
- {
- currentNode = [node]
- break
- }
- }
- if(currentNode.len()==0)
- {
- printt("Route not found")
- return []
- }
- while(currentNode.len()!=0)
- {
- ret.append(currentNode[0])
- currentNode = currentNode[0].GetLinkEntArray()
- }
- return ret
-}
array<int> function getHighestEnemyAmountsForWave(int waveIndex)
{
@@ -537,18 +478,7 @@ bool function runWave(int waveIndex,bool shouldDoBuyTime)
//main wave loop
thread SetWaveStateReady()
- foreach(WaveEvent event in waveEvents[waveIndex])
- {
-
- if(event.shouldThread)
- thread event.eventFunction(event.smokeEvent,event.spawnEvent,event.waitEvent,event.soundEvent)
- else
- event.eventFunction(event.smokeEvent,event.spawnEvent,event.waitEvent,event.soundEvent)
- if(!IsAlive(fd_harvester.harvester))
- break
-
- }
- waitUntilLessThanAmountAlive_expensive(0)
+ executeWave()
SetGlobalNetInt("FD_waveState",WAVE_STATE_COMPLETE)
if(!IsAlive(fd_harvester.harvester))
{
@@ -591,7 +521,7 @@ bool function runWave(int waveIndex,bool shouldDoBuyTime)
else
SetRoundBased(false)
SetWinner(TEAM_IMC)//restart round
- file.spawnedNPCs = [] // reset npcs count
+ spawnedNPCs = [] // reset npcs count
return false
}
@@ -611,7 +541,7 @@ bool function runWave(int waveIndex,bool shouldDoBuyTime)
AddPlayerScore(player,"FDTeamWave")
}
wait 1
- float highestScore = 0;
+ int highestScore = 0;
entity highestScore_player = GetPlayerArray()[0]
foreach(entity player in GetPlayerArray())
{
@@ -631,6 +561,10 @@ bool function runWave(int waveIndex,bool shouldDoBuyTime)
foreach(entity player in GetPlayerArray())
if(!file.havesterWasDamaged)
AddPlayerScore(player,"FDTeamFlawlessWave")
+
+
+
+
SetRoundBased(false)
SetWinner(TEAM_MILITIA)
PlayFactionDialogueToTeam( "fd_matchVictory", TEAM_MILITIA )
@@ -675,7 +609,7 @@ bool function runWave(int waveIndex,bool shouldDoBuyTime)
EmitSoundOnEntityOnlyToPlayer(player,player,"HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P")
}
wait 1
- float highestScore = 0;
+ int highestScore = 0;
entity highestScore_player = GetPlayerArray()[0]
foreach(entity player in GetPlayerArray())
{
@@ -730,6 +664,11 @@ void function SetWaveStateReady(){
SetGlobalNetInt("FD_waveState",WAVE_STATE_IN_PROGRESS)
}
+void function gameWonMedals(){
+ table<string,entity> medals
+ //most mvps
+}
+
void function OnHarvesterDamaged(entity harvester, var damageInfo)
{
@@ -971,7 +910,7 @@ void function FD_DamageByPlayerCallback(entity victim,var damageInfo)
return
float damage = DamageInfo_GetDamage(damageInfo)
file.players[player].damageDealt += damage
- file.players[player].scoreThisRound += damage //TODO NOT HOW SCORE WORKS
+ file.players[player].scoreThisRound += damage.tointeger() //TODO NOT HOW SCORE WORKS
if(victim.IsTitan())
{
//TODO Money and score for titan damage
@@ -1133,7 +1072,7 @@ void function LoadEntities()
AddStationaryAIPosition(info_target.GetOrigin(),int(info_target.kv.aiType))
break
case"info_fd_route_node":
- file.routeNodes.append(info_target)
+ routeNodes.append(info_target)
break
case"info_fd_smoke_screen":
file.smokePoints.append(info_target)
@@ -1146,67 +1085,7 @@ void function LoadEntities()
initNetVars()
}
-void function singleNav_thread(entity npc, string routeName,int nodesToScip= 0,float nextDistance = 500.0)
-{
- npc.EndSignal( "OnDeath" )
- npc.EndSignal( "OnDestroy" )
-
-
-
- if(!npc.IsNPC())
- return
-
-
- array<entity> routeArray = getRoute(routeName)
- WaitFrame()//so other code setting up what happens on signals is run before this
- if(routeArray.len()==0)
- {
-
- npc.Signal("OnFailedToPath")
- return
- }
- int scippedNodes = 0
- foreach(entity node in routeArray)
- {
- if(!IsAlive(fd_harvester.harvester))
- return
- if(scippedNodes < nodesToScip)
- {
- scippedNodes++
- continue
- }
- npc.AssaultPoint(node.GetOrigin())
- npc.AssaultSetGoalRadius( 100 )
- int i = 0
- table result = npc.WaitSignal("OnFinishedAssault","OnFailedToPath")
- if(result.signal == "OnFailedToPath")
- break
- }
- npc.Signal("FD_ReachedHarvester")
-}
-
-void function SquadNav_Thread( array<entity> npcs ,string routeName,int nodesToScip = 0,float nextDistance = 200.0)
-{
- //TODO this function wont stop when noone alive anymore also it only works half of the time
-
- array<entity> routeArray = getRoute(routeName)
- WaitFrame()//so other code setting up what happens on signals is run before this
- if(routeArray.len()==0)
- return
-
- int nodeIndex = 0
- foreach(entity node in routeArray)
- {
- if(!IsAlive(fd_harvester.harvester))
- return
- if(nodeIndex++ < nodesToScip)
- continue
-
- SquadAssaultOrigin(npcs,node.GetOrigin(),nextDistance)
-
- }
-}
bool function allPlayersReady()
{
@@ -1326,576 +1205,64 @@ string function GetTargetNameForID(int typeId)
unreachable
}
-/****************************************************************************************************************\
-####### # # ####### # # ####### ##### ####### # # ####### ###### # ####### ####### ######
-# # # # ## # # # # # ## # # # # # # # # # # #
-# # # # # # # # # # # # # # # # # # # # # # #
-##### # # ##### # # # # # #### ##### # # # ##### ###### # # # # # ######
-# # # # # # # # # # # # # # # # # ####### # # # # #
-# # # # # ## # # # # # ## # # # # # # # # # #
-####### # ####### # # # ##### ####### # # ####### # # # # # ####### # #
-\*****************************************************************************************************************/
-
-WaveEvent function createSmokeEvent(vector position,float lifetime)
-{
- WaveEvent event
- event.eventFunction = spawnSmoke
- event.shouldThread = true
- event.smokeEvent.position = position
- event.smokeEvent.lifetime = lifetime
- return event
-}
-
-WaveEvent function createArcTitanEvent(vector origin,vector angles,string route)
-{
- WaveEvent event
- event.eventFunction = spawnArcTitan
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_ARC
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- event.spawnEvent.route = route
- return event
-}
-
-WaveEvent function createSuperSpectreEvent(vector origin,vector angles,string route)
-{
- WaveEvent event
- event.eventFunction = spawnSuperSpectre
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.REAPER
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- event.spawnEvent.route = route
- return event
-}
-
-WaveEvent function createDroppodGruntEvent(vector origin,string route)
-{
- WaveEvent event
- event.eventFunction = spawnDroppodGrunts
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.GRUNT
- event.spawnEvent.spawnAmount = 4
- event.spawnEvent.origin = origin
- event.spawnEvent.route = route
- return event
-}
-
-WaveEvent function createDroppodStalkerEvent(vector origin,string route)
-{
- WaveEvent event
- event.eventFunction = spawnDroppodStalker
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.STALKER
- event.spawnEvent.spawnAmount = 4
- event.spawnEvent.origin = origin
- event.spawnEvent.route = route
- return event
-}
-
-WaveEvent function createDroppodSpectreMortarEvent(vector origin,string route)
-{
- WaveEvent event
- event.eventFunction = spawnDroppodSpectreMortar
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.SPECTRE_MORTAR
- event.spawnEvent.spawnAmount = 4
- event.spawnEvent.origin = origin
- event.spawnEvent.route = route
- return event
-}
-
-WaveEvent function createWaitForTimeEvent(float amount)
-{
- WaveEvent event
- event.shouldThread = false
- event.eventFunction = waitForTime
- event.waitEvent.amount = amount
- return event
-}
-
-WaveEvent function createWaitUntilAliveEvent(int amount)
-{
- WaveEvent event
- event.eventFunction = waitUntilLessThanAmountAliveEvent
- event.shouldThread = false
- event.waitEvent.amount = amount.tofloat()
- return event
-}
-
-WaveEvent function createGenericSpawnEvent(string npcClassName,vector origin,vector angles,string route,int spawnType,int spawnAmount)
-{
- WaveEvent event
- event.eventFunction = spawnGenericNPC
- event.shouldThread = true
- event.spawnEvent.npcClassName = npcClassName
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- event.spawnEvent.route = route
- event.spawnEvent.spawnType = spawnType
- event.spawnEvent.spawnAmount = spawnAmount
- return event
-}
-
-WaveEvent function createGenericTitanSpawnWithAiSettingsEvent(string npcClassName,string aiSettings,vector origin,vector angles,string route,int spawnType,int spawnAmount)
-{
- WaveEvent event
- event.eventFunction = spawnGenericNPCTitanwithSettings
- event.shouldThread = true
- event.spawnEvent.npcClassName = npcClassName
- event.spawnEvent.aiSettings = aiSettings
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- event.spawnEvent.route = route
- event.spawnEvent.spawnType = spawnType
- event.spawnEvent.spawnAmount = spawnAmount
- return event
-}
-
-WaveEvent function createNukeTitanEvent(vector origin,vector angles,string route)
-{
- WaveEvent event
- event.eventFunction = spawnNukeTitan
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_NUKE
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- event.spawnEvent.route = route
- return event
-}
-
-WaveEvent function createMortarTitanEvent(vector origin,vector angles)
-{
- WaveEvent event
- event.eventFunction = spawnMortarTitan
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_MORTAR
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- return event
-}
-
-WaveEvent function createCloakDroneEvent(vector origin,vector angles){
- WaveEvent event
- event.eventFunction = fd_spawnCloakDrone
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.DRONE_CLOAK
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- return event
-}
-
-WaveEvent function CreateTickEvent( vector origin, vector angles, int amount = 4, string route = "" )
-{
- WaveEvent event
- event.eventFunction = SpawnTick
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.TICK
- event.spawnEvent.spawnAmount = amount
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- return event
-}
-
-WaveEvent function CreateNorthstarSniperTitanEvent(vector origin,vector angles)
-{
- WaveEvent event
- event.eventFunction = spawnSniperTitan
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_SNIPER
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- return event
-}
-
-WaveEvent function CreateToneSniperTitanEvent(vector origin,vector angles)
-{
- WaveEvent event
- event.eventFunction = SpawnToneSniperTitan
- event.shouldThread = true
- event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_SNIPER
- event.spawnEvent.spawnAmount = 1
- event.spawnEvent.origin = origin
- event.spawnEvent.angles = angles
- return event
-}
-
-/************************************************************************************************************\
-####### # # ####### # # ####### ####### # # # # ##### ####### ### ####### # # #####
-# # # # ## # # # # # ## # # # # # # # ## # # #
-# # # # # # # # # # # # # # # # # # # # # # #
-##### # # ##### # # # # ##### # # # # # # # # # # # # # #####
-# # # # # # # # # # # # # # # # # # # # # # #
-# # # # # ## # # # # # ## # # # # # # # ## # #
-####### # ####### # # # # ##### # # ##### # ### ####### # # #####
-\************************************************************************************************************/
-
-void function spawnSmoke(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- printt("smoke")
- SmokescreenStruct smokescreen
- smokescreen.smokescreenFX = $"P_smokescreen_FD"
- smokescreen.isElectric = false
- smokescreen.origin = smokeEvent.position + < 0 , 0, 150>
- smokescreen.angles = <0,0,0>
- smokescreen.lifetime = smokeEvent.lifetime
- smokescreen.fxXYRadius = 150
- smokescreen.fxZRadius = 120
- smokescreen.fxOffsets = [ <120.0, 0.0, 0.0>,<0.0, 120.0, 0.0>, <0.0, 0.0, 0.0>,<0.0, -120.0, 0.0>,< -120.0, 0.0, 0.0>, <0.0, 100.0, 0.0>]
- Smokescreen(smokescreen)
-
-}
-
-void function spawnArcTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateArcTitan(TEAM_IMC,spawnEvent.origin,spawnEvent.angles)
- npc.DisableNPCFlag(NPC_ALLOW_INVESTIGATE | NPC_USE_SHOOTING_COVER|NPC_ALLOW_PATROL)
- SetSpawnOption_Titanfall(npc)
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
- SetSpawnOption_AISettings(npc,"npc_titan_stryder_leadwall_arc")
- file.spawnedNPCs.append(npc)
- DispatchSpawn(npc)
- AddMinimapForTitans(npc)
- npc.WaitSignal( "TitanHotDropComplete" )
- npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
- thread singleNav_thread(npc,spawnEvent.route)
- thread EMPTitanThinkConstant(npc)
-}
-
-void function waitForTime(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- float waitUntil = Time() + waitEvent.amount
- while(Time()<waitUntil)
- {
- if(!IsAlive(fd_harvester.harvester))
- break
- WaitFrame()
+string function GetAiNetIdFromTargetName(string targetName)
+{
+ switch ( targetName )
+ {
+ case "titan":
+ case "sniperTitan":
+ case "npc_titan_ogre_meteor_boss_fd":
+ case "npc_titan_ogre_meteor":
+ case "npc_titan_ogre_minigun_boss_fd":
+ case "npc_titan_ogre_minigun":
+ case "npc_titan_atlas_stickybomb_boss_fd":
+ case "npc_titan_atlas_stickybomb":
+ case "npc_titan_atlas_tracker_boss_fd":
+ case "npc_titan_atlas_tracker":
+ case "npc_titan_stryder_leadwall_boss_fd":
+ case "npc_titan_stryder_leadwall":
+ case "npc_titan_stryder_sniper_boss_fd":
+ case "npc_titan_stryder_sniper":
+ case "npc_titan_sniper":
+ case "npc_titan_sniper_tone":
+ case "npc_titan_atlas_vanguard_boss_fd":
+ case "npc_titan_atlas_vanguard":
+ return "FD_AICount_Titan"
+ case "empTitan":
+ case "npc_titan_arc":
+ return "FD_AICount_Titan_Arc"
+ case "mortarTitan":
+ case "npc_titan_mortar":
+ return "FD_AICount_Titan_Mortar"
+ case "nukeTitan":
+ case "npc_titan_nuke":
+ return "FD_AICount_Titan_Nuke"
+ case "npc_soldier":
+ case "grunt":
+ return "FD_AICount_Grunt"
+ case "spectre":
+ return "FD_AICount_Spectre"
+ case "mortar_spectre":
+ return "FD_AICount_Spectre_Mortar"
+ case "npc_stalker":
+ case "stalker":
+ return "FD_AICount_Stalker"
+ case "npc_super_spectre":
+ case "reaper":
+ return "FD_AICount_Reaper"
+ case "npc_drone":
+ case "drone":
+ return "FD_AICount_Drone"
+ case "cloakedDrone":
+ return "FD_AICount_Drone_Cloak"
+ case "tick":
+ return "FD_AICount_Ticks"
}
+ printt("unknown target name ",targetName)
+ return ""
}
-void function waitUntilLessThanAmountAliveEvent(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- waitUntilLessThanAmountAlive(int(waitEvent.amount))
-}
-
-void function spawnSuperSpectre(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
-
- entity npc = CreateSuperSpectre(TEAM_IMC,spawnEvent.origin,spawnEvent.angles)
- SetSpawnOption_AISettings(npc,"npc_super_spectre_fd")
- file.spawnedNPCs.append(npc)
- wait 4.7
- DispatchSpawn(npc)
- AddMinimapForHumans(npc)
- thread SuperSpectre_WarpFall(npc)
- thread ReaperMinionLauncherThink(npc)
-
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType))
-
-}
-
-void function spawnDroppodGrunts(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
- SetTeam( pod, TEAM_IMC )
- InitFireteamDropPod( pod )
- waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
-
- string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
- array<entity> guys
- bool adychecked = false
-
- for ( int i = 0; i < spawnEvent.spawnAmount; i++ )
- {
- entity guy = CreateSoldier( TEAM_IMC, spawnEvent.origin,<0,0,0> )
-
- SetTeam( guy, TEAM_IMC )
- guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE )
- guy.DisableNPCFlag( NPC_ALLOW_PATROL)
- DispatchSpawn( guy )
-
- guy.SetParent( pod, "ATTACH", true )
- SetSquad( guy, squadName )
-
- SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.GRUNT))
- AddMinimapForHumans(guy)
- file.spawnedNPCs.append(guy)
- guys.append( guy )
- }
-
- ActivateFireteamDropPod( pod, guys )
- SquadNav_Thread(guys,spawnEvent.route)
-}
-
-void function spawnDroppodStalker(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
- SetTeam( pod, TEAM_IMC )
- InitFireteamDropPod( pod )
- waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
-
- string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
- array<entity> guys
-
- for ( int i = 0; i < spawnEvent.spawnAmount; i++ )
- {
- entity guy = CreateStalker( TEAM_IMC, spawnEvent.origin,<0,0,0> )
-
- SetTeam( guy, TEAM_IMC )
- guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE )
- guy.DisableNPCFlag( NPC_ALLOW_PATROL)
- DispatchSpawn( guy )
-
- SetSquad( guy, squadName )
- AddMinimapForHumans(guy)
- SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.STALKER))
- guys.append( guy )
- }
-
- ActivateFireteamDropPod( pod, guys )
- SquadNav_Thread(guys,spawnEvent.route)
-
-}
-
-void function spawnDroppodSpectreMortar(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
- SetTeam( pod, TEAM_IMC )
- InitFireteamDropPod( pod )
- waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
-
- string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
- array<entity> guys
-
- for ( int i = 0; i < 4; i++ )
- {
- entity guy = CreateSpectre( TEAM_IMC, spawnEvent.origin,<0,0,0> )
-
- SetTeam( guy, TEAM_IMC )
- DispatchSpawn( guy )
-
- SetSquad( guy, squadName )
- SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.SPECTRE_MORTAR))
- AddMinimapForHumans(guy)
- guys.append( guy )
- }
-
- ActivateFireteamDropPod( pod, guys )
-}
-
-void function spawnGenericNPC(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateNPC( spawnEvent.npcClassName, TEAM_IMC, spawnEvent.origin, spawnEvent.angles )
- DispatchSpawn(npc)
-}
-
-void function spawnGenericNPCTitanwithSettings(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateNPCTitan( spawnEvent.npcClassName, TEAM_IMC, spawnEvent.origin, spawnEvent.angles )
- if( spawnEvent.aiSettings == "npc_titan_atlas_tracker_fd_sniper" )
- SetTargetName( npc, "npc_titan_atlas_tracker" ) // required for client to create icons
- SetSpawnOption_AISettings( npc, spawnEvent.aiSettings)
- SetSpawnOption_Titanfall(npc)
- DispatchSpawn(npc)
- file.spawnedNPCs.append(npc)
- AddMinimapForTitans(npc)
- npc.WaitSignal( "TitanHotDropComplete" )
- npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
-}
-
-void function spawnNukeTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateNPCTitan("titan_ogre",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
- SetSpawnOption_AISettings(npc,"npc_titan_ogre_minigun_nuke")
- SetSpawnOption_Titanfall(npc)
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
- npc.EnableNPCMoveFlag(NPCMF_WALK_ALWAYS)
- DispatchSpawn(npc)
- file.spawnedNPCs.append(npc)
- AddMinimapForTitans(npc)
- npc.WaitSignal( "TitanHotDropComplete" )
- npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
- thread singleNav_thread(npc,spawnEvent.route)
- thread NukeTitanThink(npc,fd_harvester.harvester)
-
-}
-
-void function spawnMortarTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
-
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateNPCTitan("titan_atlas",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
- SetSpawnOption_AISettings(npc,"npc_titan_atlas_tracker_mortar")
- SetSpawnOption_Titanfall(npc)
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
- DispatchSpawn(npc)
- file.spawnedNPCs.append(npc)
- AddMinimapForTitans(npc)
- npc.WaitSignal( "TitanHotDropComplete" )
- npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
- thread MortarTitanThink(npc,fd_harvester.harvester)
-}
-
-void function spawnSniperTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateNPCTitan("titan_stryder",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
- SetSpawnOption_AISettings(npc,"npc_titan_stryder_sniper_fd")
- SetSpawnOption_Titanfall(npc)
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
- DispatchSpawn(npc)
- file.spawnedNPCs.append(npc)
- AddMinimapForTitans(npc)
- npc.WaitSignal( "TitanHotDropComplete" )
- npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
- thread SniperTitanThink(npc,fd_harvester.harvester)
-
-}
-
-void function SpawnToneSniperTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity npc = CreateNPCTitan("titan_atlas",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
- SetSpawnOption_AISettings(npc,"npc_titan_atlas_tracker_fd_sniper")
- SetSpawnOption_Titanfall(npc)
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
- DispatchSpawn( npc )
- file.spawnedNPCs.append(npc)
- AddMinimapForTitans(npc)
- npc.WaitSignal( "TitanHotDropComplete" )
- npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
- thread SniperTitanThink(npc,fd_harvester.harvester)
-
-}
-
-void function fd_spawnCloakDrone(SmokeEvent smokeEffect,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- entity npc = SpawnCloakDrone( TEAM_IMC, spawnEvent.origin, spawnEvent.angles, file.harvester_info.GetOrigin() )
- file.spawnedNPCs.append(npc)
- SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType))
- AddMinimapForHumans(npc)
-}
-
-void function SpawnTick(SmokeEvent smokeEffect,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
-{
- PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
- entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
- SetTeam( pod, TEAM_IMC )
- InitFireteamDropPod( pod )
- waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
-
- string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
- array<entity> guys
-
- for ( int i = 0; i < spawnEvent.spawnAmount; i++ )
- {
- entity guy = CreateFragDrone( TEAM_IMC, spawnEvent.origin, <0,0,0> )
-
- SetSpawnOption_AISettings(guy, "npc_frag_drone_fd")
- SetTeam( guy, TEAM_IMC )
- guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE )
- guy.EnableNPCMoveFlag(NPCMF_WALK_ALWAYS | NPCMF_PREFER_SPRINT)
- DispatchSpawn( guy )
- AddMinimapForHumans(guy)
- SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.TICK))
- SetSquad( guy, squadName )
-
- guys.append( guy )
- }
-
- ActivateFireteamDropPod( pod, guys )
- SquadNav_Thread(guys,spawnEvent.route)
-}
-
-/****************************************************************************************\
-####### # # ####### # # ####### # # ####### # ###### ####### ######
-# # # # ## # # # # # # # # # # #
-# # # # # # # # # # # # # # # # #
-##### # # ##### # # # # ####### ##### # ###### ##### ######
-# # # # # # # # # # # # # # # #
-# # # # # ## # # # # # # # # #
-####### # ####### # # # # # ####### ####### # ####### # #
-\****************************************************************************************/
-
-
-void function PingMinimap(float x, float y, float duration, float spreadRadius, float ringRadius, int colorIndex)
-{
- foreach(entity player in GetPlayerArray())
- {
- Remote_CallFunction_NonReplay(player, "ServerCallback_FD_PingMinimap", x, y, duration, spreadRadius, ringRadius, colorIndex)
- }
-}
-
-void function waitUntilLessThanAmountAlive(int amount)
-{
-
- int aliveTitans = file.spawnedNPCs.len()
- while(aliveTitans>amount)
- {
- WaitFrame()
- aliveTitans = file.spawnedNPCs.len()
- if(!IsAlive(fd_harvester.harvester))
- break
- }
-}
-
-void function waitUntilLessThanAmountAlive_expensive(int amount)
-{
-
- array<entity> npcs = GetNPCArray()
- int deduct = 0
- foreach (entity npc in npcs)
- if (IsValid(GetPetTitanOwner( npc )))
- deduct++
- int aliveTitans = npcs.len() - deduct
- while(aliveTitans>amount)
- {
- WaitFrame()
- npcs = GetNPCArray()
- deduct = 0
- foreach(entity npc in npcs)
- if (IsValid(GetPetTitanOwner( npc )))
- deduct++
- aliveTitans = GetNPCArray().len() - deduct
- if(!IsAlive(fd_harvester.harvester))
- break
- }
-}
-
-void function AddMinimapForTitans(entity titan)
-{
- titan.Minimap_SetAlignUpright( true )
- titan.Minimap_AlwaysShow( TEAM_IMC, null )
- titan.Minimap_AlwaysShow( TEAM_MILITIA, null )
- titan.Minimap_SetHeightTracking( true )
- titan.Minimap_SetCustomState( eMinimapObject_npc_titan.AT_BOUNTY_BOSS )
-}
-
-// including drones
-void function AddMinimapForHumans(entity human)
-{
- human.Minimap_SetAlignUpright( true )
- human.Minimap_AlwaysShow( TEAM_IMC, null )
- human.Minimap_AlwaysShow( TEAM_MILITIA, null )
- human.Minimap_SetHeightTracking( true )
- human.Minimap_SetCustomState( eMinimapObject_npc.AI_TDM_AI )
-}
void function AddTurretSentry(entity turret)
{
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_events.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_events.nut
new file mode 100644
index 00000000..5a8996ec
--- /dev/null
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_events.nut
@@ -0,0 +1,736 @@
+global function createSmokeEvent
+global function createArcTitanEvent
+global function createWaitForTimeEvent
+global function createSuperSpectreEvent
+global function createDroppodGruntEvent
+global function createNukeTitanEvent
+global function createMortarTitanEvent
+global function createGenericSpawnEvent
+global function createGenericTitanSpawnWithAiSettingsEvent
+global function createDroppodStalkerEvent
+global function createDroppodSpectreMortarEvent
+global function createWaitUntilAliveEvent
+global function createCloakDroneEvent
+global function CreateTickEvent
+global function CreateToneSniperTitanEvent
+global function CreateNorthstarSniperTitanEvent
+global function executeWave
+
+
+global struct SmokeEvent{
+ vector position
+ float lifetime
+}
+
+global struct SpawnEvent{
+ vector origin
+ vector angles
+ string route //defines route taken by the ai
+ int skippedRouteNodes //defines how many route nodes will be skipped
+ int spawnType //Just used for Wave Info but can be used for spawn too should contain aid of spawned enemys
+ int spawnAmount //Just used for Wave Info but can be used for spawn too should contain amound of spawned enemys
+ string npcClassName
+ string aiSettings
+}
+
+global struct WaitEvent{
+ float amount
+}
+
+global struct SoundEvent{
+ string soundEventName
+}
+
+global struct WaveEvent{
+ void functionref(SmokeEvent,SpawnEvent,WaitEvent,SoundEvent) eventFunction
+ bool shouldThread
+ int executeOnThisCall //will actually be executed when called this many times
+ int timesExecuted
+ int nextEventIndex
+ SmokeEvent smokeEvent
+ SpawnEvent spawnEvent
+ WaitEvent waitEvent
+ SoundEvent soundEvent
+}
+
+
+
+
+global array<array<WaveEvent> > waveEvents
+
+
+
+void function executeWave()
+{
+ print("executeWave Start")
+ thread runEvents(0)
+ while(IsAlive(fd_harvester.harvester)&&(!allEventsExecuted(GetGlobalNetInt("FD_currentWave"))))
+ WaitFrame()
+ waitUntilLessThanAmountAlive(0)
+ waitUntilLessThanAmountAlive_expensive(0)
+}
+
+bool function allEventsExecuted(int waveIndex)
+{
+ foreach(WaveEvent e in waveEvents[waveIndex])
+ {
+ if(e.executeOnThisCall>e.timesExecuted)
+ return false
+ }
+ return true
+}
+
+void function runEvents(int firstExecuteIndex)
+{
+ print("runEvents Start")
+ WaveEvent currentEvent = waveEvents[GetGlobalNetInt("FD_currentWave")][firstExecuteIndex]
+
+ while(true)
+ {
+ currentEvent.timesExecuted++
+ if(currentEvent.timesExecuted!=currentEvent.executeOnThisCall)
+ {
+ print("not on this call")
+ return
+ }
+ if(!IsAlive(fd_harvester.harvester))
+ {
+ print("harvesterDead")
+ return
+ }
+ if(currentEvent.shouldThread)
+ {
+ print("execute with thread")
+ thread currentEvent.eventFunction(currentEvent.smokeEvent,currentEvent.spawnEvent,currentEvent.waitEvent,currentEvent.soundEvent)
+ }
+ else
+ {
+ print("execute without thread")
+ currentEvent.eventFunction(currentEvent.smokeEvent,currentEvent.spawnEvent,currentEvent.waitEvent,currentEvent.soundEvent)
+ }
+ if(currentEvent.nextEventIndex==0)
+ {
+ print("zero index")
+ return
+ }
+ currentEvent = waveEvents[GetGlobalNetInt("FD_currentWave")][currentEvent.nextEventIndex]
+ }
+ print("runEvents End")
+}
+
+
+
+
+
+
+
+
+
+
+/****************************************************************************************************************\
+####### # # ####### # # ####### ##### ####### # # ####### ###### # ####### ####### ######
+# # # # ## # # # # # ## # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # #
+##### # # ##### # # # # # #### ##### # # # ##### ###### # # # # # ######
+# # # # # # # # # # # # # # # # # ####### # # # # #
+# # # # # ## # # # # # ## # # # # # # # # # #
+####### # ####### # # # ##### ####### # # ####### # # # # # ####### # #
+\*****************************************************************************************************************/
+
+WaveEvent function createSmokeEvent(vector position,float lifetime,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnSmoke
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.smokeEvent.position = position
+ event.smokeEvent.lifetime = lifetime
+ return event
+}
+
+WaveEvent function createArcTitanEvent(vector origin,vector angles,string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnArcTitan
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_ARC
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ event.spawnEvent.route = route
+ return event
+}
+
+WaveEvent function createSuperSpectreEvent(vector origin,vector angles,string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnSuperSpectre
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.REAPER
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ event.spawnEvent.route = route
+ return event
+}
+
+WaveEvent function createDroppodGruntEvent(vector origin,string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnDroppodGrunts
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.GRUNT
+ event.spawnEvent.spawnAmount = 4
+ event.spawnEvent.origin = origin
+ event.spawnEvent.route = route
+ return event
+}
+
+WaveEvent function createDroppodStalkerEvent(vector origin,string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnDroppodStalker
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.STALKER
+ event.spawnEvent.spawnAmount = 4
+ event.spawnEvent.origin = origin
+ event.spawnEvent.route = route
+ return event
+}
+
+WaveEvent function createDroppodSpectreMortarEvent(vector origin,string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnDroppodSpectreMortar
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.SPECTRE_MORTAR
+ event.spawnEvent.spawnAmount = 4
+ event.spawnEvent.origin = origin
+ event.spawnEvent.route = route
+ return event
+}
+
+WaveEvent function createWaitForTimeEvent(float amount,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.shouldThread = false
+ event.eventFunction = waitForTime
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.waitEvent.amount = amount
+ return event
+}
+
+WaveEvent function createWaitUntilAliveEvent(int amount,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = waitUntilLessThanAmountAliveEvent
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = false
+ event.waitEvent.amount = amount.tofloat()
+ return event
+}
+
+WaveEvent function createGenericSpawnEvent(string npcClassName,vector origin,vector angles,string route,int spawnType,int spawnAmount,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnGenericNPC
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.npcClassName = npcClassName
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ event.spawnEvent.route = route
+ event.spawnEvent.spawnType = spawnType
+ event.spawnEvent.spawnAmount = spawnAmount
+ return event
+}
+
+WaveEvent function createGenericTitanSpawnWithAiSettingsEvent(string npcClassName,string aiSettings,vector origin,vector angles,string route,int spawnType,int spawnAmount,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnGenericNPCTitanwithSettings
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.npcClassName = npcClassName
+ event.spawnEvent.aiSettings = aiSettings
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ event.spawnEvent.route = route
+ event.spawnEvent.spawnType = spawnType
+ event.spawnEvent.spawnAmount = spawnAmount
+ return event
+}
+
+WaveEvent function createNukeTitanEvent(vector origin,vector angles,string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnNukeTitan
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_NUKE
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ event.spawnEvent.route = route
+ return event
+}
+
+WaveEvent function createMortarTitanEvent(vector origin,vector angles,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnMortarTitan
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_MORTAR
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ return event
+}
+
+WaveEvent function createCloakDroneEvent(vector origin,vector angles,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = fd_spawnCloakDrone
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.DRONE_CLOAK
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ return event
+}
+
+WaveEvent function CreateTickEvent( vector origin, vector angles, int amount, string route,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = SpawnTick
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.TICK
+ event.spawnEvent.spawnAmount = amount
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ return event
+}
+
+WaveEvent function CreateNorthstarSniperTitanEvent(vector origin,vector angles,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = spawnSniperTitan
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_SNIPER
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ return event
+}
+
+WaveEvent function CreateToneSniperTitanEvent(vector origin,vector angles,int nextEventIndex,int executeOnThisCall = 1)
+{
+ WaveEvent event
+ event.eventFunction = SpawnToneSniperTitan
+ event.executeOnThisCall = executeOnThisCall
+ event.nextEventIndex = nextEventIndex
+ event.shouldThread = true
+ event.spawnEvent.spawnType= eFD_AITypeIDs.TITAN_SNIPER
+ event.spawnEvent.spawnAmount = 1
+ event.spawnEvent.origin = origin
+ event.spawnEvent.angles = angles
+ return event
+}
+
+/************************************************************************************************************\
+####### # # ####### # # ####### ####### # # # # ##### ####### ### ####### # # #####
+# # # # ## # # # # # ## # # # # # # # ## # # #
+# # # # # # # # # # # # # # # # # # # # # # #
+##### # # ##### # # # # ##### # # # # # # # # # # # # # #####
+# # # # # # # # # # # # # # # # # # # # # # #
+# # # # # ## # # # # # ## # # # # # # # ## # #
+####### # ####### # # # # ##### # # ##### # ### ####### # # #####
+\************************************************************************************************************/
+
+void function spawnSmoke(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ printt("smoke")
+ SmokescreenStruct smokescreen
+ smokescreen.smokescreenFX = $"P_smokescreen_FD"
+ smokescreen.isElectric = false
+ smokescreen.origin = smokeEvent.position + < 0 , 0, 150>
+ smokescreen.angles = <0,0,0>
+ smokescreen.lifetime = smokeEvent.lifetime
+ smokescreen.fxXYRadius = 150
+ smokescreen.fxZRadius = 120
+ smokescreen.fxOffsets = [ <120.0, 0.0, 0.0>,<0.0, 120.0, 0.0>, <0.0, 0.0, 0.0>,<0.0, -120.0, 0.0>,< -120.0, 0.0, 0.0>, <0.0, 100.0, 0.0>]
+
+
+}
+
+void function spawnArcTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateArcTitan(TEAM_IMC,spawnEvent.origin,spawnEvent.angles)
+ npc.DisableNPCFlag(NPC_ALLOW_INVESTIGATE | NPC_USE_SHOOTING_COVER|NPC_ALLOW_PATROL)
+ SetSpawnOption_Titanfall(npc)
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
+ SetSpawnOption_AISettings(npc,"npc_titan_stryder_leadwall_arc")
+ spawnedNPCs.append(npc)
+ DispatchSpawn(npc)
+ AddMinimapForTitans(npc)
+ npc.WaitSignal( "TitanHotDropComplete" )
+ npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
+ npc.AssaultSetFightRadius(0)
+ thread singleNav_thread(npc,spawnEvent.route)
+ thread EMPTitanThinkConstant(npc)
+
+}
+
+void function waitForTime(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ float waitUntil = Time() + waitEvent.amount
+ while(Time()<waitUntil)
+ {
+ if(!IsAlive(fd_harvester.harvester))
+ return
+ WaitFrame()
+ }
+}
+
+void function waitUntilLessThanAmountAliveEvent(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ waitUntilLessThanAmountAlive(int(waitEvent.amount))
+}
+
+void function spawnSuperSpectre(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+
+ entity npc = CreateSuperSpectre(TEAM_IMC,spawnEvent.origin,spawnEvent.angles)
+ SetSpawnOption_AISettings(npc,"npc_super_spectre_fd")
+ spawnedNPCs.append(npc)
+
+ wait 4.7
+ DispatchSpawn(npc)
+ AddMinimapForHumans(npc)
+ thread SuperSpectre_WarpFall(npc)
+ thread ReaperMinionLauncherThink(npc)
+
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType))
+}
+
+void function spawnDroppodGrunts(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
+ SetTeam( pod, TEAM_IMC )
+ InitFireteamDropPod( pod )
+ waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
+
+ string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
+ array<entity> guys
+ bool adychecked = false
+
+ for ( int i = 0; i < spawnEvent.spawnAmount; i++ )
+ {
+ entity guy = CreateSoldier( TEAM_IMC, spawnEvent.origin,<0,0,0> )
+
+ SetTeam( guy, TEAM_IMC )
+ guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE )
+ guy.DisableNPCFlag( NPC_ALLOW_PATROL)
+ DispatchSpawn( guy )
+
+ guy.SetParent( pod, "ATTACH", true )
+ SetSquad( guy, squadName )
+
+ SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.GRUNT))
+ AddMinimapForHumans(guy)
+ spawnedNPCs.append(guy)
+ guys.append( guy )
+ }
+
+ ActivateFireteamDropPod( pod, guys )
+ thread SquadNav_Thread(guys,spawnEvent.route)
+}
+
+void function spawnDroppodStalker(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
+ SetTeam( pod, TEAM_IMC )
+ InitFireteamDropPod( pod )
+ waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
+
+ string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
+ array<entity> guys
+
+ for ( int i = 0; i < spawnEvent.spawnAmount; i++ )
+ {
+ entity guy = CreateStalker( TEAM_IMC, spawnEvent.origin,<0,0,0> )
+
+ SetTeam( guy, TEAM_IMC )
+ guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE )
+ guy.DisableNPCFlag( NPC_ALLOW_PATROL)
+ DispatchSpawn( guy )
+
+ SetSquad( guy, squadName )
+ AddMinimapForHumans(guy)
+ SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.STALKER))
+ guys.append( guy )
+ }
+
+ ActivateFireteamDropPod( pod, guys )
+ thread SquadNav_Thread(guys,spawnEvent.route)
+
+}
+
+void function spawnDroppodSpectreMortar(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
+ SetTeam( pod, TEAM_IMC )
+ InitFireteamDropPod( pod )
+ waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
+
+ string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
+ array<entity> guys
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ entity guy = CreateSpectre( TEAM_IMC, spawnEvent.origin,<0,0,0> )
+
+ SetTeam( guy, TEAM_IMC )
+ DispatchSpawn( guy )
+
+ SetSquad( guy, squadName )
+ SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.SPECTRE_MORTAR))
+ AddMinimapForHumans(guy)
+ guys.append( guy )
+ }
+
+ ActivateFireteamDropPod( pod, guys )
+}
+
+void function spawnGenericNPC(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateNPC( spawnEvent.npcClassName, TEAM_IMC, spawnEvent.origin, spawnEvent.angles )
+ DispatchSpawn(npc)
+}
+
+void function spawnGenericNPCTitanwithSettings(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateNPCTitan( spawnEvent.npcClassName, TEAM_IMC, spawnEvent.origin, spawnEvent.angles )
+ if( spawnEvent.aiSettings == "npc_titan_atlas_tracker_fd_sniper" )
+ SetTargetName( npc, "npc_titan_atlas_tracker" ) // required for client to create icons
+ SetSpawnOption_AISettings( npc, spawnEvent.aiSettings)
+ SetSpawnOption_Titanfall(npc)
+ DispatchSpawn(npc)
+ spawnedNPCs.append(npc)
+ AddMinimapForTitans(npc)
+ npc.WaitSignal( "TitanHotDropComplete" )
+ npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
+}
+
+void function spawnNukeTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateNPCTitan("titan_ogre",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
+ SetSpawnOption_AISettings(npc,"npc_titan_ogre_minigun_nuke")
+ SetSpawnOption_Titanfall(npc)
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
+ npc.EnableNPCMoveFlag(NPCMF_WALK_ALWAYS)
+ npc.AssaultSetFightRadius(0)
+ DispatchSpawn(npc)
+ spawnedNPCs.append(npc)
+ AddMinimapForTitans(npc)
+ npc.WaitSignal( "TitanHotDropComplete" )
+ npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
+ thread singleNav_thread(npc,spawnEvent.route)
+ thread NukeTitanThink(npc,fd_harvester.harvester)
+
+}
+
+void function spawnMortarTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateNPCTitan("titan_atlas",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
+ SetSpawnOption_AISettings(npc,"npc_titan_atlas_tracker_mortar")
+ SetSpawnOption_Titanfall(npc)
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
+ DispatchSpawn(npc)
+ spawnedNPCs.append(npc)
+ AddMinimapForTitans(npc)
+ npc.WaitSignal( "TitanHotDropComplete" )
+ npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
+ thread MortarTitanThink(npc,fd_harvester.harvester)
+}
+
+void function spawnSniperTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateNPCTitan("titan_stryder",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
+ SetSpawnOption_AISettings(npc,"npc_titan_stryder_sniper_fd")
+ SetSpawnOption_Titanfall(npc)
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
+ DispatchSpawn(npc)
+ spawnedNPCs.append(npc)
+ AddMinimapForTitans(npc)
+ npc.WaitSignal( "TitanHotDropComplete" )
+ npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
+ thread SniperTitanThink(npc,fd_harvester.harvester)
+
+}
+
+void function SpawnToneSniperTitan(SmokeEvent smokeEvent,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity npc = CreateNPCTitan("titan_atlas",TEAM_IMC, spawnEvent.origin, spawnEvent.angles)
+ SetSpawnOption_AISettings(npc,"npc_titan_atlas_tracker_fd_sniper")
+ SetSpawnOption_Titanfall(npc)
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType)) // required for client to create icons
+ DispatchSpawn( npc )
+ npc.AssaultSetFightRadius(0)
+ spawnedNPCs.append(npc)
+ AddMinimapForTitans(npc)
+ npc.WaitSignal( "TitanHotDropComplete" )
+ npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true )
+ thread SniperTitanThink(npc,fd_harvester.harvester)
+}
+
+void function fd_spawnCloakDrone(SmokeEvent smokeEffect,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ entity npc = SpawnCloakDrone( TEAM_IMC, spawnEvent.origin, spawnEvent.angles, fd_harvester.harvester.GetOrigin() )
+ spawnedNPCs.append(npc)
+ SetTargetName( npc, GetTargetNameForID(spawnEvent.spawnType))
+ AddMinimapForHumans(npc)
+}
+
+void function SpawnTick(SmokeEvent smokeEffect,SpawnEvent spawnEvent,WaitEvent waitEvent,SoundEvent soundEvent)
+{
+ PingMinimap(spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0)
+ entity pod = CreateDropPod( spawnEvent.origin, <0,0,0> )
+ SetTeam( pod, TEAM_IMC )
+ InitFireteamDropPod( pod )
+ waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, <0,0,0> )
+
+ string squadName = MakeSquadName( TEAM_IMC, UniqueString( "ZiplineTable" ) )
+ array<entity> guys
+
+ for ( int i = 0; i < spawnEvent.spawnAmount; i++ )
+ {
+ entity guy = CreateFragDrone( TEAM_IMC, spawnEvent.origin, <0,0,0> )
+
+ SetSpawnOption_AISettings(guy, "npc_frag_drone_fd")
+ SetTeam( guy, TEAM_IMC )
+ guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE )
+ guy.EnableNPCMoveFlag(NPCMF_WALK_ALWAYS | NPCMF_PREFER_SPRINT)
+ DispatchSpawn( guy )
+ AddMinimapForHumans(guy)
+ SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.TICK))
+ SetSquad( guy, squadName )
+
+ guys.append( guy )
+ }
+
+ ActivateFireteamDropPod( pod, guys )
+ thread SquadNav_Thread(guys,spawnEvent.route)
+}
+
+
+
+/****************************************************************************************\
+####### # # ####### # # ####### # # ####### # ###### ####### ######
+# # # # ## # # # # # # # # # # #
+# # # # # # # # # # # # # # # # #
+##### # # ##### # # # # ####### ##### # ###### ##### ######
+# # # # # # # # # # # # # # # #
+# # # # # ## # # # # # # # # #
+####### # ####### # # # # # ####### ####### # ####### # #
+\****************************************************************************************/
+
+
+void function PingMinimap(float x, float y, float duration, float spreadRadius, float ringRadius, int colorIndex)
+{
+ foreach(entity player in GetPlayerArray())
+ {
+ Remote_CallFunction_NonReplay(player, "ServerCallback_FD_PingMinimap", x, y, duration, spreadRadius, ringRadius, colorIndex)
+ }
+}
+
+void function waitUntilLessThanAmountAlive(int amount)
+{
+
+ int aliveTitans = spawnedNPCs.len()
+ while(aliveTitans>amount)
+ {
+ WaitFrame()
+ aliveTitans = spawnedNPCs.len()
+ if(!IsAlive(fd_harvester.harvester))
+ return
+ }
+}
+
+void function waitUntilLessThanAmountAlive_expensive(int amount)
+{
+
+ array<entity> npcs = GetNPCArray()
+ int deduct = 0
+ foreach (entity npc in npcs)
+ if (IsValid(GetPetTitanOwner( npc )))
+ deduct++
+ int aliveTitans = npcs.len() - deduct
+ while(aliveTitans>amount)
+ {
+ WaitFrame()
+ npcs = GetNPCArray()
+ deduct = 0
+ foreach(entity npc in npcs)
+ if (IsValid(GetPetTitanOwner( npc )))
+ deduct++
+ aliveTitans = GetNPCArray().len() - deduct
+ if(!IsAlive(fd_harvester.harvester))
+ return
+ }
+}
+
+void function AddMinimapForTitans(entity titan)
+{
+ titan.Minimap_SetAlignUpright( true )
+ titan.Minimap_AlwaysShow( TEAM_IMC, null )
+ titan.Minimap_AlwaysShow( TEAM_MILITIA, null )
+ titan.Minimap_SetHeightTracking( true )
+ titan.Minimap_SetCustomState( eMinimapObject_npc_titan.AT_BOUNTY_BOSS )
+}
+
+// including drones
+void function AddMinimapForHumans(entity human)
+{
+ human.Minimap_SetAlignUpright( true )
+ human.Minimap_AlwaysShow( TEAM_IMC, null )
+ human.Minimap_AlwaysShow( TEAM_MILITIA, null )
+ human.Minimap_SetHeightTracking( true )
+ human.Minimap_SetCustomState( eMinimapObject_npc.AI_TDM_AI )
+} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_nav.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_nav.nut
new file mode 100644
index 00000000..1ca2bc16
--- /dev/null
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd_nav.nut
@@ -0,0 +1,97 @@
+global function singleNav_thread
+global function SquadNav_Thread
+global function getRoute
+
+
+
+void function singleNav_thread(entity npc, string routeName,int nodesToScip= 0,float nextDistance = 500.0)
+{
+ npc.EndSignal( "OnDeath" )
+ npc.EndSignal( "OnDestroy" )
+
+
+
+ if(!npc.IsNPC()){
+ return
+ }
+
+
+
+ array<entity> routeArray = getRoute(routeName)
+ WaitFrame()//so other code setting up what happens on signals is run before this
+ if(routeArray.len()==0)
+ {
+
+ npc.Signal("OnFailedToPath")
+ return
+ }
+ int scippedNodes = 0
+ foreach(entity node in routeArray)
+ {
+ if(!IsAlive(fd_harvester.harvester))
+ return
+ if(scippedNodes < nodesToScip)
+ {
+ scippedNodes++
+ continue
+ }
+ npc.AssaultPoint(node.GetOrigin())
+ npc.AssaultSetGoalRadius( 50 )
+ int i = 0
+ table result = npc.WaitSignal("OnFinishedAssault","OnFailedToPath")
+ if(result.signal == "OnFailedToPath")
+ break
+ }
+ npc.Signal("FD_ReachedHarvester")
+}
+
+void function SquadNav_Thread( array<entity> npcs ,string routeName,int nodesToScip = 0,float nextDistance = 200.0)
+{
+ //TODO this function wont stop when noone alive anymore also it only works half of the time
+
+ array<entity> routeArray = getRoute(routeName)
+ WaitFrame()//so other code setting up what happens on signals is run before this
+ if(routeArray.len()==0)
+ return
+
+ int nodeIndex = 0
+ foreach(entity node in routeArray)
+ {
+ if(!IsAlive(fd_harvester.harvester))
+ return
+ if(nodeIndex++ < nodesToScip)
+ continue
+
+ SquadAssaultOrigin(npcs,node.GetOrigin(),nextDistance)
+
+ }
+
+}
+
+array<entity> function getRoute(string routeName)
+{
+ array<entity> ret
+ array<entity> currentNode = []
+ foreach(entity node in routeNodes)
+ {
+ if(!node.HasKey("route_name"))
+ continue
+ if(node.kv.route_name==routeName)
+ {
+ currentNode = [node]
+ break
+ }
+
+ }
+ if(currentNode.len()==0)
+ {
+ printt("Route not found")
+ return []
+ }
+ while(currentNode.len()!=0)
+ {
+ ret.append(currentNode[0])
+ currentNode = currentNode[0].GetLinkEntArray()
+ }
+ return ret
+} \ No newline at end of file