global function AiGameModes_Init global function AiGameModes_SetNPCWeapons global function AiGameModes_SpawnDropShip global function AiGameModes_SpawnDropPod global function AiGameModes_SpawnReaper global function AiGameModes_SpawnTitan global function GetValidIntroDropShipSpawn const INTRO_DROPSHIP_CUTOFF = 2000 struct { table< string, array > npcWeaponsTable // npcs have their default weapon in aisettings file } file void function AiGameModes_Init() { } //------------------------------------------------------ void function AiGameModes_SetNPCWeapons( string npcClass, array weapons ) { if ( !( npcClass in file.npcWeaponsTable ) ) file.npcWeaponsTable[ npcClass ] <- [] file.npcWeaponsTable[ npcClass ] = weapons } //------------------------------------------------------ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int count, void functionref( array guys ) squadHandler = null ) { string squadName = MakeSquadName( team, UniqueString( "" ) ) CallinData drop drop.origin = pos drop.yaw = rot.y drop.dist = 768 drop.team = team drop.squadname = squadName SetDropTableSpawnFuncs( drop, CreateSoldier, count ) SetCallinStyle( drop, eDropStyle.ZIPLINE_NPC ) thread RunDropshipDropoff( drop ) WaitSignal( drop, "OnDropoff" ) array< entity > guys = GetNPCArrayBySquad( squadName ) foreach ( guy in guys ) { SetUpNPCWeapons( guy ) guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) } if ( squadHandler != null ) thread squadHandler( guys ) } void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null, int flags = 0 ) { entity pod = CreateDropPod( pos, <0,0,0> ) InitFireteamDropPod( pod, flags ) waitthread LaunchAnimDropPod( pod, "pod_testpath", pos, rot ) string squadName = MakeSquadName( team, UniqueString( "" ) ) array guys for ( int i = 0; i < 4 ;i++ ) { entity npc = CreateNPC( content, team, pos,<0,0,0> ) DispatchSpawn( npc ) SetSquad( npc, squadName ) SetUpNPCWeapons( npc ) npc.SetParent( pod, "ATTACH", true ) npc.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) guys.append( npc ) } ActivateFireteamDropPod( pod, guys ) // start searching for enemies if ( squadHandler != null ) thread squadHandler( guys ) } const float REAPER_WARPFALL_DELAY = 4.7 // same as fd does void function AiGameModes_SpawnReaper( vector pos, vector rot, int team, string aiSettings = "", void functionref( entity reaper ) reaperHandler = null ) { float reaperLandTime = REAPER_WARPFALL_DELAY + 1.2 // reaper takes ~1.2s to warpfall thread HotDrop_Spawnpoint( pos, team, reaperLandTime, false, damagedef_reaper_fall ) wait REAPER_WARPFALL_DELAY entity reaper = CreateSuperSpectre( team, pos, rot ) reaper.EndSignal( "OnDestroy" ) // reaper highlight Highlight_SetFriendlyHighlight( reaper, "sp_enemy_pilot" ) reaper.Highlight_SetParam( 1, 0, < 1,1,1 > ) SetDefaultMPEnemyHighlight( reaper ) Highlight_SetEnemyHighlight( reaper, "enemy_titan" ) SetSpawnOption_Titanfall( reaper ) SetSpawnOption_Warpfall( reaper ) if ( aiSettings != "" ) SetSpawnOption_AISettings( reaper, aiSettings ) HideName( reaper ) // prevent flash a name onto it DispatchSpawn( reaper ) reaper.WaitSignal( "WarpfallComplete" ) ShowName( reaper ) // show name again after drop if ( reaperHandler != null ) thread reaperHandler( reaper ) } // copied from cl_replacement_titan_hud.gnut void function HotDrop_Spawnpoint( vector origin, int team, float impactTime, bool hasFriendlyWarning = false, int damageDef = -1 ) { array targetEffects = [] vector surfaceNormal = < 0, 0, 1 > int index = GetParticleSystemIndex( $"P_ar_titan_droppoint" ) if( hasFriendlyWarning ) { entity effectFriendly = StartParticleEffectInWorld_ReturnEntity( index, origin, surfaceNormal ) SetTeam( effectFriendly, team ) EffectSetControlPointVector( effectFriendly, 1, FRIENDLY_COLOR_FX ) effectFriendly.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY effectFriendly.DisableHibernation() // prevent it from fading out targetEffects.append( effectFriendly ) } entity effectEnemy = StartParticleEffectInWorld_ReturnEntity( index, origin, surfaceNormal ) SetTeam( effectEnemy, team ) EffectSetControlPointVector( effectEnemy, 1, ENEMY_COLOR_FX ) effectEnemy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_ENEMY effectEnemy.DisableHibernation() // prevent it from fading out targetEffects.append( effectEnemy ) // so enemy npcs will mostly avoid them entity damageAreaInfo if ( damageDef > -1 ) { damageAreaInfo = CreateEntity( "info_target" ) DispatchSpawn( damageAreaInfo ) AI_CreateDangerousArea_DamageDef( damageDef, damageAreaInfo, team, true, true ) } wait impactTime // clean up foreach( entity targetEffect in targetEffects ) { if ( IsValid( targetEffect ) ) EffectStop( targetEffect ) } if ( IsValid( damageAreaInfo ) ) damageAreaInfo.Destroy() } // including aisettings stuff specifically for at bounty titans const float TITANFALL_WARNING_DURATION = 5.0 void function AiGameModes_SpawnTitan( vector pos, vector rot, int team, string setFile, string aiSettings = "", void functionref( entity titan ) titanHandler = null ) { entity titan = CreateNPCTitan( setFile, TEAM_BOTH, pos, rot ) SetSpawnOption_Titanfall( titan ) SetSpawnOption_Warpfall( titan ) // modified: do a hotdrop spawnpoint warning thread HotDrop_Spawnpoint( pos, team, TITANFALL_WARNING_DURATION, false, damagedef_titan_fall ) if ( aiSettings != "" ) SetSpawnOption_AISettings( titan, aiSettings ) DispatchSpawn( titan ) if ( titanHandler != null ) thread titanHandler( titan ) } void function SetUpNPCWeapons( entity guy ) { string className = guy.GetClassName() array mainWeapons if ( className in file.npcWeaponsTable ) mainWeapons = file.npcWeaponsTable[ className ] if ( mainWeapons.len() == 0 ) // no valid weapons return // take off existing main weapons, or sometimes they'll have a archer by default foreach ( entity weapon in guy.GetMainWeapons() ) guy.TakeWeapon( weapon.GetWeaponClassName() ) if ( mainWeapons.len() > 0 ) { string weaponName = mainWeapons[ RandomInt( mainWeapons.len() ) ] guy.GiveWeapon( weaponName ) guy.SetActiveWeaponByName( weaponName ) } } // Checks if we can spawn a dropship at a node, this should guarantee dropship ziplines array function GetValidIntroDropShipSpawn( array introNodes ) { array introShipSpawns if ( GetZiplineDropshipSpawns().len() == 0 ) return [] foreach ( node in introNodes ) { entity closestNode = GetClosest( GetZiplineDropshipSpawns(), node.GetOrigin() ) SetTeam( closestNode, node.GetTeam() ) if ( Distance( closestNode.GetOrigin(), node.GetOrigin() ) < INTRO_DROPSHIP_CUTOFF ) introShipSpawns.append( closestNode ) } return introShipSpawns }