diff --git a/Northstar.Client/kb_act.lst b/Northstar.Client/kb_act.lst index c9c9c6845..721266c87 100644 --- a/Northstar.Client/kb_act.lst +++ b/Northstar.Client/kb_act.lst @@ -2,7 +2,8 @@ "blank" "NORTHSTAR" "blank" "==========================" "toggleconsole" "Toggle Developer Console" -"pingspot" "Ping Spotted Enemy/Location" +"dropbattery" "Drop Battery" +"pingspot" "Ping Spotted Enemy/Location" "vote 1" "Vote 1" "vote 2" "Vote 2" "vote 3" "Vote 3" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index d5e2f1d24..02d04378f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -50,13 +50,14 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "MODE_SETTING_CATEGORY_RIFF" "Riffs" "MODE_SETTING_CATEGORY_MATCH" "Match" - "classic_mp" "Classic MP" + "run_intro" "Run Intro" "run_epilogue" "Run Epilogue" "scorelimit" "Score Limit" "roundscorelimit" "Score Limit (round-based)" "timelimit" "Time Limit" "roundtimelimit" "Time Limit (round-based)" "respawnprotection" "Respawn Protection Time" + "pick_loadout_every_round" "Pick Loadout Every Round" "pilot_health_multiplier" "Health multiplier" "respawn_delay" "Respawn Delay" @@ -79,6 +80,9 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "featured_mode_rocket_arena" "Rocket Arena" "featured_mode_shotguns_snipers" "Armed and Dangerous" "iron_rules" "Iron Titan Rules" + "riff_titan_queue" "Max Active Titans per Team" + "classic_executions" "Classic Executions" + "drop_battery_command" "Drop Battery Command" "cp_amped_capture_points" "Amped Hardpoints" "coliseum_loadouts_enabled" "Coliseum Loadouts" @@ -224,7 +228,6 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "custom_air_accel_pilot" "Air Acceleration" "no_pilot_collision" "Inter-Pilot Collision" "promode_enable" "Promode Weapons" - "fp_embark_enabled" "Firstperson embarks/executions" "classic_rodeo" "Classic Rodeo" "oob_timer_enabled" "Out of Bounds Timer" "riff_instagib" "Instagib Mode" @@ -412,5 +415,26 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "MOD_CORRUPTED" "Downloaded archive checksum does not match verified signature." "NO_DISK_SPACE_AVAILABLE" "There is not enough space on your disk." "MOD_FETCHING_FAILED_GENERAL" "Mod extraction failed. Check logs for more details." + + // Frontier defense playlistvars + "fd_harvester_health" "Harvester HP" + "fd_harvester_shield" "Harvester Shield" + "fd_wave_buy_time" "Wave Break Time" + "fd_titan_health_adjust" "Enemy Titans HP Adjust" + "fd_reaper_health_adjust" "Enemy Reapers HP Adjust" + "fd_mortar_spectre_setup_time" "Mortar Spectre Build Siege Time" + "fd_grunt_at_weapon_users" "Amount of Grunts with AT Weapons" + "fd_player_damage_scalar" "Player Damage Multiplier" + "fd_at_unlimited_ammo" "Unlimited Anti-Titan Ammo" + "fd_pro_titan_shields" "Enemies Spawns with Shields" + "fd_respawn_dropship" "Respawn In Dropship" + "fd_money_per_round" "Money Per Round" + "fd_money_flyouts" "Money Flyouts" + "riff_minimap_state" "Hide Minimap" + "fd_killcredit_grunt" "Grunt Kill Credit" + "fd_killcredit_drone" "Drone Kill Credit" + "fd_killcredit_spectre" "Spectre Kill Credit" + "fd_killcredit_stalker" "Stalker Kill Credit" + "fd_killcredit_reaper" "Reaper Kill Credit" } -} +} \ No newline at end of file diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 4ff0b2308..fbf33e338 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -49,7 +49,6 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "MODE_SETTING_CATEGORY_RIFF" "Riffs" "MODE_SETTING_CATEGORY_MATCH" "Match" - "classic_mp" "Multijoueurs classique" "run_epilogue" "Epilogue" "scorelimit" "Limite de score" "roundscorelimit" "Limite de score (manche)" @@ -223,7 +222,6 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "custom_air_accel_pilot" "Accélération aérienne" "no_pilot_collision" "Collisions entre pilotes" "promode_enable" "Armes du mode pro" - "fp_embark_enabled" "Animations 1e personne" "classic_rodeo" "Rodéo classique" "oob_timer_enabled" "Timer hors-limites" "riff_instagib" "Mode Instagib" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 516ea7012..d5ebacddf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -49,7 +49,6 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "MODE_SETTING_CATEGORY_RIFF" "Extras" "MODE_SETTING_CATEGORY_MATCH" "Match" - "classic_mp" "Klassischer Multiplayer" "run_epilogue" "Epilog" "scorelimit" "Höchstpunktzahl" "roundscorelimit" "Höchstpunktzahl (rundenbasiert)" @@ -214,7 +213,6 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "custom_air_accel_pilot" "Luftbeschleunigung" "no_pilot_collision" "Inter-Pilot Kollision" "promode_enable" "Pro-mode Waffen" - "fp_embark_enabled" "Firstperson Einstiege/Exekutionen" "classic_rodeo" "Klassisches Rodeo" "oob_timer_enabled" "Out of Bounds Timer" "riff_instagib" "Instagib Mode" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index eebdcb714..e67e1162d 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -47,7 +47,6 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "MODE_SETTING_CATEGORY_RIFF" "Extra" "MODE_SETTING_CATEGORY_MATCH" "Partita" - "classic_mp" "Multiplayer classico" "run_epilogue" "Epilogo fine partita" "scorelimit" "Limite Punteggio" "roundscorelimit" "Limite Punteggio (per round)" @@ -222,7 +221,6 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "custom_air_accel_pilot" "Accelerazione Aerea" "no_pilot_collision" "Collisione tra Piloti" "promode_enable" "Armi Modalità Competitiva" - "fp_embark_enabled" "Imbarchi/esecuzioni in 1º persona" "classic_rodeo" "Rodeo classico" "oob_timer_enabled" "Timer Fuori dai Limiti" "riff_instagib" "Modalità Instagib" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index 47507c001..4600f5d72 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -63,7 +63,6 @@ //要議論: "コンソールの表示/非表示"のままか、"コンソール表示のトグル"、それ以外への差し替え "TOGGLE_CONSOLE" "コンソールの表示/非表示" - "classic_mp" "クラシックマルチ" "run_epilogue" "エピローグの有効化" "scorelimit" "スコア上限" "roundscorelimit" "スコア上限 (ラウンドベース)" @@ -249,7 +248,6 @@ "custom_air_accel_pilot" "空中加速度" "no_pilot_collision" "パイロット同士の当たり判定" "promode_enable" "Proモードの武器" - "fp_embark_enabled" "搭乗と処刑の一人称視点" "classic_rodeo" "クラシックロデオ" "oob_timer_enabled" "アウトオブバウンドタイマー" "riff_instagib" "インスタギブモード" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index 50d1ef17f..ebea96183 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -49,7 +49,6 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "MODE_SETTING_CATEGORY_RIFF" "Riffs" "MODE_SETTING_CATEGORY_MATCH" "Partida" - "classic_mp" "Multijugador Clásico" "run_epilogue" "Habilitar Epílogo" "scorelimit" "Limite de puntos" "roundscorelimit" "Limite de puntos (basado en rondas)" @@ -223,7 +222,6 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "custom_air_accel_pilot" "Aceleración aerea" "no_pilot_collision" "Colisión de piloto" "promode_enable" "Armas de modo pro" - "fp_embark_enabled" "Embarques/Ejecucciones en primera persona" "classic_rodeo" "Rodeo Clásico" "oob_timer_enabled" "Temporizador de limite de mapa" "riff_instagib" "Modo Instagib" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt index 9b570cebe..6097b2fc7 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt @@ -49,7 +49,6 @@ Naciśnij Tak jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Mo "MODE_SETTING_CATEGORY_RIFF" "Modyfikatory rozgrywki" "MODE_SETTING_CATEGORY_MATCH" "Mecz" - "classic_mp" "Klasyczny tryb wieloosobowy" "run_epilogue" "Epilog" "scorelimit" "Limit wyniku" "roundscorelimit" "Limit wyniku (na rundę)" @@ -223,7 +222,6 @@ Naciśnij Tak jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Mo "custom_air_accel_pilot" "Air Acceleration" "no_pilot_collision" "Kolidowanie Pilotów" "promode_enable" "Bronie trybu pro" - "fp_embark_enabled" "Pierwszoosobowe wsiadanie/egzekucje" "classic_rodeo" "Klasyczne Rodeo" "oob_timer_enabled" "Licznik czasu poza granicami mapy" "riff_instagib" "Instagib Mode" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index ef053fb62..671332985 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -49,7 +49,6 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "MODE_SETTING_CATEGORY_RIFF" "Riffs" "MODE_SETTING_CATEGORY_MATCH" "Partida" - "classic_mp" "MP Clássico" "run_epilogue" "Executar epílogo" "scorelimit" "Limite de pontos" "roundscorelimit" "Limite de pontos (por rodada)" @@ -221,7 +220,6 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "custom_air_accel_pilot" "Aceleração aérea" "no_pilot_collision" "Colisão entre pilotos" "promode_enable" "Armas de Modo PRO" - "fp_embark_enabled" "Execuções/embarque em 1a pessoa" "classic_rodeo" "Rodeio clássico" "oob_timer_enabled" "Temporizador fora do mapa" "riff_instagib" "Modo Instagib" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index ae5b823b2..698f3c813 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -40,7 +40,6 @@ "MODE_SETTING_CATEGORY_RIFF" "Рифф" "MODE_SETTING_CATEGORY_MATCH" "Матч" - "classic_mp" "Классический мультиплеер" "run_epilogue" "Запустить эпилог" "scorelimit" "Лимит очков" "roundscorelimit" "Лимит очков (по раундам)" @@ -166,7 +165,6 @@ "custom_air_accel_pilot" "Ускорение в воздухе" "promode_enable" "Оружие из режима про" - "fp_embark_enabled" "Казни/посадки в титана от первого лица" "classic_rodeo" "Классическое родео" "oob_timer_enabled" "Таймер уничтожения за пределами карты" "riff_instagib" "Моментальная смерть при попадании" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index d4172232e..4fe8cccc3 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -49,7 +49,6 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "MODE_SETTING_CATEGORY_RIFF" "Fragmento" "MODE_SETTING_CATEGORY_MATCH" "Partida" - "classic_mp" "Multijugador Clasico" "run_epilogue" "Habilitar Epílogo" "scorelimit" "Limite de puntuación" "roundscorelimit" "Límite de punataje (rondas)" @@ -223,7 +222,6 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "custom_air_accel_pilot" "Aceleración aerea" "no_pilot_collision" "Colisión de piloto" "promode_enable" "Armas del Modo Pro" - "fp_embark_enabled" "Embarques/Ejecucciones en Primera Persona" "classic_rodeo" "Abordaje Clasico" "oob_timer_enabled" "Temporizador del limite de mapa" "riff_instagib" "Modo Instagib" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index fd649cdb6..0ac70defe 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -49,7 +49,6 @@ "MODE_SETTING_CATEGORY_RIFF" "規則" "MODE_SETTING_CATEGORY_MATCH" "比賽" - "classic_mp" "經典多人" "run_epilogue" "最終作戰" "scorelimit" "分數限制" "roundscorelimit" "分數限制(回合制)" @@ -223,7 +222,6 @@ "custom_air_accel_pilot" "空中加速" "no_pilot_collision" "取消鐵馭間碰撞" "promode_enable" "進階平衡武器" - "fp_embark_enabled" "第一人稱登機/處決" "classic_rodeo" "經典馴牛術" "oob_timer_enabled" "超出戰場計時" "riff_instagib" "瞬殺模式" diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut b/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut index 4237a0beb..97e2e1a28 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut @@ -449,8 +449,15 @@ void function Minimap_Ping( vector origin, float radius, float duration, vector RuiSetGameTime( rui, "endTime", Time() + duration ) RuiSetBool( rui, "reverse", reverse ) + + thread Minimap_DestroyPing_Threaded( duration, rui ) } +void function Minimap_DestroyPing_Threaded( float duration, var rui ) +{ + wait duration + RuiDestroy( rui ) +} var function Minimap_AddLayer( asset layerImage, bool isFriendly ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 7d52d4790..09fd1e6bc 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -1677,4 +1677,4 @@ void function Lobby_SetFDModeBasedOnSearching( string playlistToSearch ) } Lobby_SetFDMode( isFDMode ) -} \ No newline at end of file +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut index 3c3e89a55..fc2a53f70 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut @@ -17,18 +17,7 @@ global enum eModeMenuModeCategory } // List of blocked modes due to them being unfinished -#if VANILLA const array blockedModes = [] -#else -const array blockedModes = -[ - "fd_easy", - "fd_normal", - "fd_hard", - "fd_master", - "fd_insane" -] -#endif struct ListEntry_t { string mode diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 6d26187e0..222405032 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -7,6 +7,8 @@ global function OnServerSelected_Threaded global function AddConnectToServerCallback global function RemoveConnectToServerCallback +global function IsCoreMod + // Stop peeking const int BUTTONS_PER_PAGE = 15 // Number of servers we show diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut index be97a036e..b830f7488 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut @@ -585,7 +585,11 @@ function UpdatePrivateMatchButtons() #endif string modeName = PrivateMatch_GetSelectedMode() - bool settingsLocked = IsFDMode( modeName ) + bool settingsLocked = false + + #if VANILLA + settingsLocked = IsFDMode( modeName ) + #endif if ( settingsLocked && uiGlobal.activeMenu == GetMenu( "MatchSettingsMenu" ) ) CloseActiveMenu() diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index d60a24e5c..30ff2ffe9 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -2,6 +2,14 @@ playlists { Gamemodes { + defaults + { + vars + { + player_force_respawn 5 + pingspot_enabled 0 + } + } sbox { inherit defaults @@ -174,6 +182,7 @@ playlists max_players 10 phase_shift_drop_flag 1 ctf_flag_return_time 1 + pick_loadout_every_round 0 color "0 119 245 255" gamemode_score_hint #GAMEMODE_SCORE_HINT_CTF @@ -289,10 +298,9 @@ playlists lobbytitle #PL_gg_lobby description #PL_gg_desc abbreviation #PL_gg_abbr - image varietypack - //mixtape_slot 7 - mixtape_timeout 120 - visible 0 + image tdm + mixtape_promo_slot 6 + visible 1 } gamemodes { @@ -336,7 +344,8 @@ playlists hint #PL_tt_hint image lts abbreviation #PL_tt_abbr - visible 0 + mixtape_promo_slot 4 + visible 1 } gamemodes { @@ -372,9 +381,10 @@ playlists lobbytitle #PL_inf_lobby description #PL_inf_desc hint #PL_inf_hint - image ps + image fnf abbreviation #PL_inf_abbr - visible 0 + mixtape_promo_slot 7 + visible 1 } gamemodes { @@ -476,6 +486,8 @@ playlists classic_mp 1 timelimit 7.5 scorelimit 99999 // arbitrarily high number + mixtape_slot 5 + visible 1 } gamemodes { @@ -525,6 +537,8 @@ playlists scorelimit 5 roundtimelimit 2 roundscorelimit 5 + mixtape_promo_slot 1 + visible 1 gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM } @@ -603,19 +617,6 @@ playlists mixtape_slot 4 mixtape_timeout 120 visible 1 - - // comp-exclusive settings - // note: these don't display right on the private match menu yet - pilot_health_multiplier 1.25 - respawn_delay 7.0 - - boosts_enabled 1 // this is actually disabled lol - earn_meter_pilot_overdrive 0 - earn_meter_pilot_multiplier 0.5 - earn_meter_titan_multiplier 0.5 - - scorelimit 6 - timelimit 14 } gamemodes { @@ -623,27 +624,84 @@ playlists { maps { + mp_complex3 1 + mp_drydock 1 + mp_glitch 1 + mp_homestead 2 + mp_eden 1 mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_glitch 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 mp_grave 1 mp_homestead 1 + mp_drydock 1 + mp_glitch 1 mp_thaw 1 + mp_eden 2 mp_black_water_canal 1 - mp_eden 1 - mp_drydock 1 - mp_crashsite3 1 - mp_complex3 1 - mp_angel_city 1 - mp_colony02 1 mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + mp_crashsite3 1 mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 mp_lf_township 1 mp_lf_uma 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 + } + } + } + } + ctf + { + inherit defaults + vars + { + name #PL_capture_the_flag + lobbytitle #PL_capture_the_flag_lobby + description #PL_capture_the_flag_desc + abbreviation #PL_capture_the_flag_abbr + image ctf + mixtape_slot 4 + mixtape_timeout 120 + visible 1 + } + gamemodes + { + ctf + { + vars + { + scorelimit 6 + } + + maps + { + mp_complex3 1 + mp_drydock 2 + mp_glitch 1 + mp_homestead 2 + mp_eden 2 + mp_forwardbase_kodai 1 + mp_black_water_canal 2 + mp_glitch 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 + mp_grave 2 + mp_homestead 2 + mp_drydock 2 + mp_glitch 1 + mp_thaw 1 + mp_eden 2 + mp_black_water_canal 2 + mp_glitch 1 + mp_relic02 1 } } } @@ -658,9 +716,11 @@ playlists description #PL_hs_desc hint #PL_hs_hint abbreviation #PL_hs_abbr - image tdm + image fnf timelimit 10 max_players 16 + mixtape_slot 8 + visible 1 gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM } @@ -670,27 +730,35 @@ playlists { maps { + mp_complex3 1 + mp_drydock 1 + mp_glitch 1 + mp_homestead 2 + mp_eden 1 mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_glitch 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 mp_grave 1 mp_homestead 1 + mp_drydock 1 + mp_glitch 1 mp_thaw 1 + mp_eden 2 mp_black_water_canal 1 - mp_eden 1 - mp_drydock 1 - mp_crashsite3 1 - mp_complex3 1 - mp_angel_city 1 - mp_colony02 1 mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + mp_crashsite3 1 mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 mp_lf_township 1 mp_lf_uma 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 } } } @@ -704,10 +772,10 @@ playlists lobbytitle #PL_chamber_lobby description #PL_chamber_desc abbreviation #PL_chamber_abbr - image ps - //mixtape_slot 7 + image cp + mixtape_slot 10 mixtape_timeout 120 - visible 0 + visible 1 } gamemodes { @@ -728,6 +796,7 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 + mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -751,10 +820,10 @@ playlists lobbytitle #PL_hidden_lobby description #PL_hidden_desc abbreviation #PL_hidden_abbr - image ps - //mixtape_slot 7 + image fw + mixtape_slot 9 mixtape_timeout 120 - visible 0 + visible 1 } gamemodes { @@ -775,6 +844,7 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 + mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -837,8 +907,9 @@ playlists description #PL_sns_desc hint #PL_sns_desc abbreviation #PL_sns_abbr - image ps - visible 0 + image ffa + mixtape_slot 11 + visible 1 gamemode_score_hint #GAMEMODE_SCORE_HINT_FFA } @@ -875,5 +946,157 @@ playlists } } } + rocket_lf + { + inherit defaults + vars + { + name #PL_rocket_arena + lobbytitle #PL_rocket_arena_lobby + description #PL_rocket_arena_desc + abbreviation #PL_rocket_arena_abbr + image lf + visible 0 + scorelimit 50 + roundtimelimit 2.0 + featured_mode_rocket_arena 1 + boosts_enabled 1 + } + gamemodes + { + speedball + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + } + } + phase_aitdm + { + inherit defaults + vars + { + name "#PL_all_phase" + lobbytitle #PL_all_phase_lobby + description #PL_all_phase_desc + abbreviation #PL_all_phase_abbr + image aitdm + visible 0 + featured_mode_all_phase 1 + } + gamemodes + { + aitdm + { + } + } + } + spicy_aitdm + { + inherit defaults + vars + { + name "#PL_all_spicy" + lobbytitle #PL_all_spicy_lobby + description #PL_all_spicy_desc + abbreviation #PL_all_spicy_abbr + image aitdm + visible 0 + featured_mode_all_ticks 1 + } + gamemodes + { + aitdm + { + } + } + } + turbo_ttdm + { + inherit defaults + vars + { + name #PL_titan_brawl_turbo + lobbytitle #PL_titan_brawl_turbo_lobby + description #PL_titan_brawl_turbo_desc + abbreviation #PL_titan_brawl_turbo_abbr + image ttdm + visible 0 + max_players 10 + scorelimit 30 + //mixtape_slot 8 + boosts_enabled 1 + respawn_delay 10 + + featured_mode_turbo_titans 1 + earn_meter_titan_multiplier 2.0 + } + gamemodes + { + ttdm + { + maps + { + mp_glitch 1 + mp_colony02 1 + mp_wargames 1 + mp_eden 1 + mp_drydock 1 + mp_black_water_canal 1 + mp_thaw 1 + mp_homestead 1 + mp_forwardbase_kodai 1 + mp_angel_city 1 + mp_grave 1 + mp_rise 1 + } + } + } + } + coliseum + { + inherit defaults + vars + { + name #PL_coliseum + lobbytitle #PL_coliseum_lobby + description #PL_coliseum_desc + image coliseum + //mixtape_promo_slot 4 + visible 0 + } + gamemodes + { + coliseum {} + } + } + turbo_lts + { + inherit defaults + vars + { + name #PL_turbo_last_titan_standing + lobbytitle #PL_turbo_last_titan_standing_lobby + description #PL_turbo_last_titan_standing_desc + abbreviation #PL_turbo_last_titan_standing_abbr + image lts + visible 0 + featured_mode_turbo_titans 1 + earn_meter_titan_multiplier 2.0 + } + gamemodes + { + lts + { + } + } + } } -} +} \ No newline at end of file diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 95535cf86..d0a917e95 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -29,6 +29,16 @@ "Name": "ns_show_event_models", "DefaultValue": "1", "Flags": "ARCHIVE_PLAYERPROFILE" + }, + { + "Name": "ns_embark_style", + "DefaultValue": "0", + "Flags": "ARCHIVE_PLAYERPROFILE|USERINFO" + }, + { + "Name": "ns_execution_style", + "DefaultValue": "0", + "Flags": "ARCHIVE_PLAYERPROFILE|USERINFO" } ], "Scripts": [ @@ -318,16 +328,8 @@ "RunOn": "CLIENT && MP" }, { - "Path": "sh_3psequence_to_1p_hacks.gnut", - "RunOn": "( CLIENT || SERVER ) && MP", - "ClientCallback": { - "Before": "FirstPersonSequenceForce1P_Init", - "After": "FirstPersonSequenceForce1P_InitPlaylistVars" - }, - "ServerCallback": { - "Before": "FirstPersonSequenceForce1P_Init", - "After": "FirstPersonSequenceForce1P_InitPlaylistVars" - } + "Path": "_3psequence_to_1p_hacks.gnut", + "RunOn": "SERVER && MP" }, { "Path": "gamemodes/sh_riff_instagib.gnut", diff --git a/Northstar.Custom/mod/resource/northstar_custom_english.txt b/Northstar.Custom/mod/resource/northstar_custom_english.txt index d348aa207..ddfa3ce8d 100644 --- a/Northstar.Custom/mod/resource/northstar_custom_english.txt +++ b/Northstar.Custom/mod/resource/northstar_custom_english.txt @@ -1,4 +1,4 @@ -"lang" +"lang" { "Language" "english" "Tokens" @@ -93,5 +93,8 @@ "WPN_SHOTGUN_DBLBARREL_SHORT" "TWIN-B" "WPN_SHOTGUN_DBLBARREL_DESC" "Short-barreled Shotgun" "WPN_SHOTGUN_DBLBARREL_LONGDESC" "Short Double Barreled Shotgun" + + "rodeo_titan_lobotomy" "Titan Rodeo Lobotomy" + "pilot_battery_inventory_size" "Pilot Battery Inventory Size" } } diff --git a/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt b/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt index d6336f321..cbea34761 100644 --- a/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt +++ b/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt @@ -76,4 +76,4 @@ "WPN_SHOTGUN_DBLBARREL_DESC" "Escopeta de cano curto" "WPN_SHOTGUN_DBLBARREL_LONGDESC" "Escopeta dupla de cano curto" } -} +} \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/_3psequence_to_1p_hacks.gnut b/Northstar.Custom/mod/scripts/vscripts/_3psequence_to_1p_hacks.gnut new file mode 100644 index 000000000..90bd5d6ae --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/_3psequence_to_1p_hacks.gnut @@ -0,0 +1,387 @@ +global function FirstPersonSequenceForce1P +global function ShouldRunFirstPersonSequence + +global const string FORCE1P_PILOT_1P_ATTACHMENT = "HEADFOCUS" +global const string FORCE1P_TITAN_1P_ATTACHMENT = "HATCH_HEAD" + +global const string FORCE1P_PILOT_1P_HIDDEN_BODYGROUP = "head" +global const string FORCE1P_TITAN_1P_HIDDEN_BODYGROUP = "torso" + +global const string FORCE1P_PILOT_ENTITYCLASS = "npc_pilot_elite" +global const string FORCE1P_TITAN_ENTITYCLASS = "npc_titan" + +global struct Forced1PSequenceData +{ + entity player + entity ownerProxy + entity thirdPersonProxy +} + +Forced1PSequenceData function FirstPersonSequenceForce1P( FirstPersonSequenceStruct sequence, entity player, entity other = null ) +{ + string attachment = FORCE1P_PILOT_1P_ATTACHMENT + string hiddenBodygroup = FORCE1P_PILOT_1P_HIDDEN_BODYGROUP + string entityclass = FORCE1P_PILOT_ENTITYCLASS + + if ( player.IsTitan() ) + { + attachment = FORCE1P_TITAN_1P_ATTACHMENT + hiddenBodygroup = FORCE1P_TITAN_1P_HIDDEN_BODYGROUP + entityclass = FORCE1P_TITAN_ENTITYCLASS + } + + player.Hide() + + Forced1PSequenceData cleanupData + cleanupData.player = player + + vector angles = player.GetAngles() + + angles.y = player.EyeAngles().y + + entity ownerProxy + + if ( entityclass == FORCE1P_TITAN_ENTITYCLASS ) + ownerProxy = CreateNPCTitan( player.GetPlayerSettings(), player.GetTeam(), <0, 0, 0>, <0, 0, 0> ) + else + ownerProxy = CreateEntity( entityclass ) + + ownerProxy.SetOrigin( player.GetOrigin() ) + + if ( Distance( angles, angles ) < 359 ) + ownerProxy.SetAngles( angles ) + + ownerProxy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER + ownerProxy.kv.solid = 0 + ownerProxy.SetOwner( player ) + + DispatchSpawn( ownerProxy ) + + if ( ownerProxy.GetModelName() != player.GetModelName() ) + { + ownerProxy.SetModel( player.GetModelName() ) + ownerProxy.SetValueForModelKey( player.GetModelName() ) + } + + ownerProxy.EnableNPCFlag( NPC_IGNORE_ALL ) + ownerProxy.SetBossPlayer( player ) + + NPC_NoTarget( ownerProxy ) + SetTeam( ownerProxy, player.GetTeam() ) + TakeWeaponsForArray( ownerProxy, ownerProxy.GetMainWeapons() ) + + ownerProxy.SetSkin( player.GetSkin() ) + ownerProxy.SetCamo( player.GetCamo() ) + ownerProxy.SetDecal( player.GetDecal() ) + ownerProxy.SetInvulnerable() + + HideName( ownerProxy ) + + cleanupData.ownerProxy = ownerProxy + + if ( ownerProxy.IsTitan() && HasSoul( ownerProxy ) ) + { + entity ownerProxysoul = ownerProxy.GetTitanSoul() + + if ( IsValid( ownerProxysoul ) ) + { + ownerProxysoul.SetShieldHealth( ownerProxysoul.GetShieldHealthMax() ) + + if ( IsValid( ownerProxysoul.soul.batteryContainer ) ) + ownerProxysoul.soul.batteryContainer.Anim_Play( GetAnimFromAlias( GetSoulTitanSubClass( ownerProxysoul ), "hatch_rodeo_down_idle" ) ) + } + } + else + { + AddAnimEvent( ownerProxy, "phase_shift_start", ModdedPhaseEmbarkPhaseStart ) + AddAnimEvent( ownerProxy, "phase_shift_stop", ModdedPhaseEmbarkPhaseStop ) + + if ( !IsPlayerEmbarking( player ) ) + { + AddAnimEvent( ownerProxy, "phase_shift_explode", ModdedPhaseShiftExplodeSound ) + AddAnimEvent( ownerProxy, "cloak_on", ModdedAnimEvent_Cloak_On ) + AddAnimEvent( ownerProxy, "cloak_off", ModdedAnimEvent_Cloak_Off ) + } + } + + int bodygroupValue = 1 + + if ( hiddenBodygroup == "torso" ) + bodygroupValue = 2 + + if ( ownerProxy.FindBodyGroup( hiddenBodygroup ) != -1 ) + ownerProxy.SetBodygroup( ownerProxy.FindBodyGroup( hiddenBodygroup ), bodygroupValue ) + + entity thirdPersonProxy + + if ( entityclass == FORCE1P_TITAN_ENTITYCLASS ) + thirdPersonProxy = CreateNPCTitan( player.GetPlayerSettings(), player.GetTeam(), <0, 0, 0>, <0, 0, 0> ) + else + thirdPersonProxy = CreateEntity( entityclass ) + + thirdPersonProxy.SetOrigin( player.GetOrigin() ) + + if ( Distance( angles, angles ) < 359 ) + thirdPersonProxy.SetAngles( angles ) + + thirdPersonProxy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE & ~ENTITY_VISIBLE_TO_OWNER + thirdPersonProxy.kv.solid = 0 + thirdPersonProxy.SetOwner( player ) + + DispatchSpawn( thirdPersonProxy ) + + if ( thirdPersonProxy.GetModelName() != player.GetModelName() ) + { + thirdPersonProxy.SetModel( player.GetModelName() ) + thirdPersonProxy.SetValueForModelKey( player.GetModelName() ) + } + + thirdPersonProxy.EnableNPCFlag( NPC_IGNORE_ALL ) + thirdPersonProxy.SetBossPlayer( player ) + + NPC_NoTarget( thirdPersonProxy ) + SetTeam( thirdPersonProxy, player.GetTeam() ) + TakeWeaponsForArray( thirdPersonProxy, thirdPersonProxy.GetMainWeapons() ) + + thirdPersonProxy.SetSkin( player.GetSkin() ) + thirdPersonProxy.SetCamo( player.GetCamo() ) + thirdPersonProxy.SetDecal( player.GetDecal() ) + thirdPersonProxy.SetInvulnerable() + + HideName( thirdPersonProxy ) + + cleanupData.thirdPersonProxy = thirdPersonProxy + + if ( thirdPersonProxy.IsTitan() ) + { + Highlight_SetEnemyHighlight( thirdPersonProxy, "enemy_titan" ) + + if ( HasSoul( thirdPersonProxy ) ) + { + entity thirdPersonProxySoul = thirdPersonProxy.GetTitanSoul() + + if ( IsValid( thirdPersonProxySoul ) ) + { + thirdPersonProxySoul.SetShieldHealth( thirdPersonProxySoul.GetShieldHealthMax() ) + + if ( IsValid( thirdPersonProxySoul.soul.batteryContainer ) ) + thirdPersonProxySoul.soul.batteryContainer.Anim_Play( GetAnimFromAlias( GetSoulTitanSubClass( thirdPersonProxySoul ), "hatch_rodeo_down_idle" ) ) + } + } + } + else + { + Highlight_SetEnemyHighlight( thirdPersonProxy, "enemy_player" ) + AddAnimEvent( thirdPersonProxy, "phase_shift_start", ModdedPhaseEmbarkPhaseStart ) + AddAnimEvent( thirdPersonProxy, "phase_shift_stop", ModdedPhaseEmbarkPhaseStop ) + + if ( !IsPlayerEmbarking( player ) ) + { + AddAnimEvent( thirdPersonProxy, "phase_shift_explode", ModdedPhaseShiftExplodeSound ) + AddAnimEvent( thirdPersonProxy, "cloak_on", ModdedAnimEvent_Cloak_On ) + AddAnimEvent( thirdPersonProxy, "cloak_off", ModdedAnimEvent_Cloak_Off ) + } + } + + thread SetBodyGroups( player, thirdPersonProxy ) + FirstPersonPlayAnim( sequence, thirdPersonProxy, player, other ) + + sequence.thirdPersonCameraEntity = ownerProxy + sequence.thirdPersonCameraAttachments = [ attachment ] + + thread CleanupForced1PSequenceAfterAnimDone( sequence, other, cleanupData ) + + return cleanupData +} + +void function CleanupForced1PSequenceAfterAnimDone( FirstPersonSequenceStruct sequence, entity other, Forced1PSequenceData cleanupData ) +{ + cleanupData.ownerProxy.EndSignal( "OnDeath" ) + cleanupData.ownerProxy.EndSignal( "OnDestroy" ) + cleanupData.ownerProxy.EndSignal( "OnAnimationInterrupted" ) + cleanupData.ownerProxy.EndSignal( "OnAnimationDone" ) + + cleanupData.player.EndSignal( "OnDeath" ) + cleanupData.player.EndSignal( "OnDestroy" ) + cleanupData.player.EndSignal( "OnAnimationInterrupted" ) + + OnThreadEnd + ( + function() : ( cleanupData ) + { + thread CleanupForced1PSequence( cleanupData ) + } + ) + + FirstPersonPlayAnim( sequence, cleanupData.ownerProxy, cleanupData.player, other ) + + WaitFrame() + + while ( cleanupData.player.Anim_IsActive() ) + WaitFrame() +} + +void function CleanupForced1PSequence( Forced1PSequenceData cleanupData ) +{ + if ( IsValid( cleanupData.player ) ) + cleanupData.player.Show() + + if ( IsValid( cleanupData.ownerProxy ) ) + { + cleanupData.ownerProxy.kv.VisibilityFlags = ~ENTITY_VISIBLE_TO_EVERYONE + + if ( IsAlive( cleanupData.ownerProxy ) ) + cleanupData.ownerProxy.Die( null, null, { forceKill = true, scriptType = DF_EXPLOSION, damageType = DMG_REMOVENORAGDOLL } ) + } + + if ( IsValid( cleanupData.thirdPersonProxy ) ) + { + cleanupData.thirdPersonProxy.kv.VisibilityFlags = ~ENTITY_VISIBLE_TO_EVERYONE + + if ( IsAlive( cleanupData.thirdPersonProxy ) ) + cleanupData.thirdPersonProxy.Die( null, null, { forceKill = true, scriptType = DF_EXPLOSION, damageType = DMG_REMOVENORAGDOLL } ) + } +} + +void function SetBodyGroups( entity player, entity proxy ) +{ + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) + + proxy.EndSignal( "OnDestroy" ) + proxy.EndSignal( "OnDeath" ) + + while ( true ) + { + proxy.SetFullBodygroup( player.GetFullBodygroup() ) + + WaitFrame() + } +} + +void function FirstPersonPlayAnim( FirstPersonSequenceStruct sequence, entity proxy, entity player, entity other ) +{ + bool savednoparent = sequence.noParent + string savedattachment = sequence.attachment + bool saveduseanimatedrefattachment = sequence.useAnimatedRefAttachment + + if ( !IsPlayerEmbarking( player ) ) + { + sequence.noParent = false + sequence.attachment = "REF" + sequence.useAnimatedRefAttachment = true + + thread FirstPersonSequence( sequence, proxy, player ) + } + else + thread FirstPersonSequence( sequence, proxy, other ) + + sequence.noParent = savednoparent + sequence.attachment = savedattachment + sequence.useAnimatedRefAttachment = saveduseanimatedrefattachment +} + +bool function ShouldRunFirstPersonSequence( entity player, bool isEmbark, bool isExecution ) +{ + if ( !player.IsPlayer() || player.IsBot() ) + return false + + if ( ( isEmbark && GetUserInfoKVBool_Internal( player, "ns_embark_style", false ) ) || ( isExecution && GetUserInfoKVBool_Internal( player, "ns_execution_style", false ) ) ) + return true + + return false +} + +void function ModdedPhaseEmbarkPhaseStart( entity player ) +{ + PlayPhaseShiftDisappearFX( player ) + EmitSoundOnEntity( player, "pilot_phaseembark_activate_3p" ) + + player.PhaseShiftBegin( 0.0, 0.2 ) + + if ( !IsPlayerEmbarking( player.GetOwner() ) ) + { + player.GetOwner().PhaseShiftBegin( 0.0, 1.5 ) + + AddAnimEvent( player.GetOwner(), "phase_shift_stop", ModdedPhaseEmbarkPhaseStop ) + thread ModdedPhaseExecutionPhaseCleanup( player.GetOwner() ) + } + + thread ModdedPhaseEmbarkPhaseCleanup( player ) +} + +void function ModdedPhaseEmbarkPhaseCleanup( entity player ) +{ + EndSignal( player, "OnDeath" ) + + OnThreadEnd( + function() : ( player ) + { + if ( IsValid( player ) && player.FindBodyGroup( "head" ) != -1 ) + player.SetBodygroup( player.FindBodyGroup( "head" ), 1 ) + } + ) + + WaitSignal( player, "PhaseEmbarkPhaseStop" ) +} + +void function ModdedPhaseExecutionPhaseCleanup( entity player ) +{ + EndSignal( player, "OnDeath" ) + + OnThreadEnd( + function() : ( player ) + { + if ( IsValid( player ) ) + player.Hide() + } + ) + + WaitSignal( player, "PhaseEmbarkPhaseStop" ) +} + +void function ModdedPhaseEmbarkPhaseStop( entity player ) +{ + Signal( player, "PhaseEmbarkPhaseStop" ) + PlayPhaseShiftDisappearFX( player ) + EmitSoundOnEntity( player, "pilot_phaseembark_end_3p" ) + + player.PhaseShiftCancel() +} + +void function ModdedPhaseShiftExplodeSound( entity ent ) +{ + if ( ent.IsMechanical() ) + EmitSoundOnEntity( ent, "Pilot_Mvmt_Execution_Phaseshift_Pt4_Explo_Robo_3P" ) + else + EmitSoundOnEntity( ent, "Pilot_Mvmt_Execution_Phaseshift_Pt4_Explo_3P" ) +} + +void function ModdedAnimEvent_Cloak_On( entity player ) +{ + EmitSoundOnEntity( player, "cloak_on_3P" ) + EmitSoundOnEntity( player, "cloak_sustain_loop_3P" ) + + float cloakDuration = 1.5 - 0.35 + + player.SetCanCloak( true ) + + player.SetCloakDuration( 0.35, cloakDuration, 1.0 ) +} + +void function ModdedAnimEvent_Cloak_Off( entity player ) +{ + StopSoundOnEntity( player, "cloak_sustain_loop_1P" ) + StopSoundOnEntity( player, "cloak_sustain_loop_3P" ) + + bool wasCloaked = player.IsCloaked( CLOAK_INCLUDE_FADE_IN_TIME ) + + if ( wasCloaked ) + { + EmitSoundOnEntity( player, "cloak_interruptend_3P" ) + StopSoundOnEntity( player, "cloak_warningtoend_1P" ) + StopSoundOnEntity( player, "cloak_warningtoend_3P" ) + } + + player.SetCloakDuration( 0, 0, 0.35 ) +} \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut index 515ffd9db..12db16436 100644 --- a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut @@ -188,7 +188,7 @@ void function ShInitBoostStoreForMode() } } file.availableBoosts.sort( SortCompareBoostCost ) - printt( file.availableBoosts.len() ) + //printt( file.availableBoosts.len() ) } int function SortCompareBoostCost( BoostStoreData a, BoostStoreData b ) @@ -208,6 +208,7 @@ int function SortCompareBoostCost( BoostStoreData a, BoostStoreData b ) array function GetAvailableBoosts() { // custom stuff for arena + // TODO: make an API for doing this and remove this file from Northstar.Custom string boostStoreMode = GetCurrentPlaylistVarString( "boost_store_mode", "off" ) if ( boostStoreMode == "arena" ) { @@ -254,19 +255,19 @@ bool function ClientCommand_PurchaseBoost( entity player, array args ) if ( !BoostStoreOpen() ) return true - if ( player.IsPhaseShifted() ) - return false - if ( !IsAlive( player ) ) - return false + return true if ( player.IsTitan() ) - return false + return true + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return true array availableBoosts = GetAvailableBoosts() if ( args.len() == 0 ) - return false + return true foreach ( data in availableBoosts ) { @@ -304,8 +305,17 @@ bool function ClientCommand_PurchaseBoost( entity player, array args ) bool function ClientCommand_Deposit( entity player, array args ) { - // if ( !BoostStoreOpen() ) - // return true + if ( !BoostStoreOpen() ) + return true + + if ( !IsAlive( player ) ) + return true + + if ( player.IsTitan() ) + return true + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return true int depositAmount = minint( file.playerBonusData[ player ], BOOST_STORE_DEFAULT_EXCHANGE ) file.teamReserveAmount += depositAmount @@ -325,8 +335,17 @@ bool function ClientCommand_Deposit( entity player, array args ) bool function ClientCommand_Withdraw( entity player, array args ) { - // if ( !BoostStoreOpen() ) - // return true + if ( !BoostStoreOpen() ) + return true + + if ( !IsAlive( player ) ) + return true + + if ( player.IsTitan() ) + return true + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return true if ( GetPlayerMoney( player ) >= MAX_MONEY ) return true @@ -445,7 +464,7 @@ void function CreateBoostStoreHintTrigger( entity crate ) entity trig = CreateEntity( "trigger_cylinder" ) trig.SetRadius( BOOST_STORE_TRIGGER_RADIUS ) trig.SetAboveHeight( 200 ) - trig.SetBelowHeight( 0) + trig.SetBelowHeight( 0 ) trig.SetOrigin( crate.GetOrigin() ) trig.kv.triggerFilterNpc = "none" trig.kv.triggerFilterPlayer = "all" @@ -483,14 +502,14 @@ void function CloseBoostStores() { foreach ( crate in file.storeLocations ) thread DisableBoostStoreCrate( crate ) - SetGlobalNetBool("boostStoreOpen", false) + SetGlobalNetBool( "boostStoreOpen", false ) } void function OpenBoostStores() { foreach ( crate in file.storeLocations ) thread EnableBoostStoreCrate( crate ) - SetGlobalNetBool("boostStoreOpen", true) + SetGlobalNetBool( "boostStoreOpen", true ) } array function GetBoostStores() @@ -544,7 +563,7 @@ void function BoostStoreThink( entity crate ) while( IsValid( crate ) ) { entity player = expect entity( crate.WaitSignal( "OnPlayerUse" ).player ) - if ( IsValid( player ) ) + if ( IsValid( player ) && Distance( player.GetOrigin(), crate.GetOrigin() ) < BOOST_STORE_TRIGGER_RADIUS ) OpenBoostStoreMenu( player ) } } @@ -553,6 +572,9 @@ void function OpenBoostStoreMenu( entity player ) { if ( !BoostStoreEnabled() ) return + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return CalculatePlayerTurretCount( player ) Remote_CallFunction_UI( player, "ServerCallback_UpdateMoney", file.playerBonusData[ player ] ) @@ -561,6 +583,18 @@ void function OpenBoostStoreMenu( entity player ) Remote_CallFunction_UI( player, "ServerCallback_UpdateAmpedWeaponState", PlayerHasAmpedWeapons( player ) ) Remote_CallFunction_UI( player, "ServerCallback_OpenBoostStore" ) } + +bool function IsPlayerNearbyAnyBoostStore( entity player ) +{ + bool playerNearStore = false + foreach ( entity crate in GetBoostStores() ) + { + if ( Distance( player.GetOrigin(), crate.GetOrigin() ) < BOOST_STORE_TRIGGER_RADIUS ) + playerNearStore = true + } + + return playerNearStore +} #endif #if CLIENT diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_arena.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_arena.gnut index 1765fd9ba..e9d8111cf 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_arena.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_arena.gnut @@ -16,7 +16,6 @@ void function GameModeArena_Init() SetShouldUseRoundWinningKillReplay( true ) SetRoundBased( true ) - SetRespawnsEnabled( false ) SetLoadoutGracePeriodEnabled( false ) // prevent modifying loadouts with grace period Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut index 409d5ec01..ea66b79dd 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut @@ -19,7 +19,6 @@ void function GamemodeFastball_Init() SetShouldUseRoundWinningKillReplay( true ) SetRoundBased( true ) SetSwitchSidesBased( true ) - SetRespawnsEnabled( false ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) ScoreEvent_SetupEarnMeterValuesForMixedModes() @@ -283,10 +282,11 @@ function FastballOnPanelHacked( panel, player ) // respawn dead players foreach ( entity deadPlayer in GetPlayerArrayOfTeam( player.GetTeam() ) ) { - if ( !IsAlive( deadPlayer ) && !IsPrivateMatchSpectator( deadPlayer ) ) + if ( PlayerCanSpawn( player ) && !IsPrivateMatchSpectator( deadPlayer ) ) { + deadPlayer.Signal( "RespawnMe" ) + DoRespawnPlayer( deadPlayer, null ) deadPlayer.SetOrigin( panel.s.startOrigin ) - deadPlayer.RespawnPlayer( null ) Remote_CallFunction_NonReplay( deadPlayer, "ServerCallback_FastballRespawnPlayer" ) } } diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index 5d53d50d4..8405c875f 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -865,7 +865,7 @@ void function FW_SpawnDroppodSquad( CampSiteStruct campsite, string aiType ) // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnDropPod( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), FW_AI_TEAM, aiType, void function( array guys ) : ( campsite, aiType ) + AiGameModes_SpawnDropPod( spawnpoint, FW_AI_TEAM, aiType, void function( array guys ) : ( campsite, aiType ) { FW_HandleSquadSpawn( guys, campsite, aiType ) }) @@ -900,7 +900,7 @@ void function FW_SpawnReaper( CampSiteStruct campsite ) // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnReaper( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), FW_AI_TEAM, "npc_super_spectre_aitdm",void function( entity reaper ) : ( campsite ) + AiGameModes_SpawnReaper( spawnpoint, FW_AI_TEAM, "npc_super_spectre_aitdm",void function( entity reaper ) : ( campsite ) { reaper.SetScriptName( FW_NPC_SCRIPTNAME ) // no neet rn // show on minimap to let players kill them diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut index ad46b42e2..bde89485e 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut @@ -163,6 +163,6 @@ void function UpdateLoadout( entity player ) void function OnWinnerDetermined() { - SetRespawnsEnabled( false ) - SetKillcamsEnabled( false ) + Riff_ForceSetEliminationMode( eEliminationMode.PilotsTitans ) + SetServerVar( "replayDisabled", true ) } diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut index c3bdd4849..e6cd03f03 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut @@ -10,7 +10,6 @@ void function GamemodeHidden_Init() SetShouldUseRoundWinningKillReplay( true ) SetLoadoutGracePeriodEnabled( false ) // prevent modifying loadouts with grace period SetWeaponDropsEnabled( false ) - SetRespawnsEnabled( false ) SetGamemodeAllowsTeamSwitch( false ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut index 4fb45a740..afcb3f10e 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut @@ -15,7 +15,6 @@ void function GamemodeHideAndSeek_Init() SetSpawnpointGamemodeOverride( FFA ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) - SetRespawnsEnabled( false ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) SetLoadoutGracePeriodEnabled( false ) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut index e03f01adf..c820659ba 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut @@ -221,6 +221,6 @@ bool function InfectionShouldPlayerStartBleedout( entity player, var damageInfo void function OnWinnerDetermined() { - SetRespawnsEnabled( false ) - SetKillcamsEnabled( false ) + Riff_ForceSetEliminationMode( eEliminationMode.PilotsTitans ) + SetServerVar( "replayDisabled", true ) } diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_sns.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_sns.gnut index 812c21ee6..b5cf5e68e 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_sns.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_sns.gnut @@ -122,8 +122,8 @@ void function bankrupt(entity player, entity attacker) { void function OnWinnerDetermined() { - SetRespawnsEnabled( false ) - SetKillcamsEnabled( false ) + Riff_ForceSetEliminationMode( eEliminationMode.PilotsTitans ) + SetServerVar( "replayDisabled", true ) } void function OnPlayerRespawned( entity player ) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut index 3b75e725c..1fc625f17 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut @@ -66,7 +66,7 @@ void function PlayerWatchesTFFAIntroIntermissionCam( entity player ) if ( !IsValid( player ) ) // if player leaves during the intro sequence return - RespawnAsTitan( player, false ) + RespawnAsTitan( player ) TryGameModeAnnouncement( player ) } diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_arena_loadouts.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_arena_loadouts.gnut index ae0fa7d68..d74a63ee1 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_arena_loadouts.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_arena_loadouts.gnut @@ -39,7 +39,7 @@ void function InitialiseArenaLoadouts() file.tier0Weapons.append( respawnData ) #if SERVER - SetBoostPurchaseCallback( GivePlayerArenaLoadoutItem ) + //SetBoostPurchaseCallback( GivePlayerArenaLoadoutItem ) #endif } diff --git a/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_human.gnut b/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_human.gnut index 2f94e7599..3ead10aad 100644 --- a/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_human.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_human.gnut @@ -23,6 +23,19 @@ bool function MeleeThread_PilotVsEnemyInternal( SyncedMelee action, entity attac bool isAttackerRef = IsAttackerRef( action, target ) + if ( GetCurrentPlaylistVarInt( "classic_executions", 0 ) ) + { + action = clone action + action.attackerAnimation1p = "" + action.attackerAnimation3p = "pt_rspn101_melee_necksnap_rear" + action.targetAnimation1p = "" + action.targetAnimation3p = "pt_melee_necksnap_rear_attacked" + action.isAttackerRef = false + action.minDot = 0.2 + + isAttackerRef = false + } + vector attackerOrigin = attacker.GetOrigin() vector targetOrigin = target.GetOrigin() @@ -50,7 +63,7 @@ bool function MeleeThread_PilotVsEnemyInternal( SyncedMelee action, entity attac target.ClearParent() - if ( IsValid( attacker ) ) + if ( IsValid( attacker ) && attacker.IsPlayer() ) { attacker.PlayerMelee_SetState( PLAYER_MELEE_STATE_NONE ) } @@ -259,7 +272,7 @@ void function MeleeThread_PilotVsEnemy_Attacker( SyncedMelee action, entity atta if ( isAttackerRef ) { #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) + if ( !GetCurrentPlaylistVarInt( "classic_executions", 0 ) && ShouldRunFirstPersonSequence( attacker, false, true ) ) FirstPersonSequenceForce1P( attackerSequence, attacker ) #endif @@ -268,7 +281,7 @@ void function MeleeThread_PilotVsEnemy_Attacker( SyncedMelee action, entity atta else { #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) + if ( !GetCurrentPlaylistVarInt( "classic_executions", 0 ) && ShouldRunFirstPersonSequence( attacker, false, true ) ) FirstPersonSequenceForce1P( attackerSequence, attacker, target ) #endif @@ -410,7 +423,7 @@ void function MeleeThread_PilotVsEnemy_Target( SyncedMelee action, entity attack if ( isAttackerRef ) { #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) + if ( !GetCurrentPlaylistVarInt( "classic_executions", 0 ) && ShouldRunFirstPersonSequence( target, false, true ) ) FirstPersonSequenceForce1P( targetSequence, target, attacker ) #endif @@ -419,7 +432,7 @@ void function MeleeThread_PilotVsEnemy_Target( SyncedMelee action, entity attack else { #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) + if ( !GetCurrentPlaylistVarInt( "classic_executions", 0 ) && ShouldRunFirstPersonSequence( target, false, true ) ) FirstPersonSequenceForce1P( targetSequence, target ) #endif diff --git a/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_titan.gnut b/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_titan.gnut index d9e995f7a..dfaaee60c 100644 --- a/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_titan.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/melee/_melee_synced_titan.gnut @@ -192,8 +192,8 @@ bool function MeleeThread_TitanVsTitan_Internal( SyncedMelee action, entity atta if ( dataStruct.setAttackerDemigod ) DisableDemigod( attacker ) - - attacker.PlayerMelee_SetState( PLAYER_MELEE_STATE_NONE ) + if( attacker.IsPlayer() ) + attacker.PlayerMelee_SetState( PLAYER_MELEE_STATE_NONE ) } } ) @@ -212,10 +212,12 @@ bool function MeleeThread_TitanVsTitan_Internal( SyncedMelee action, entity atta burnCardTarget = target } - attacker.PlayerMelee_ExecutionStartAttacker( 0 ) + if( attacker.IsPlayer() ) + attacker.PlayerMelee_ExecutionStartAttacker( 0 ) target.PlayerMelee_ExecutionStartTarget( attacker ) - attacker.Lunge_ClearTarget() + if( attacker.IsPlayer() ) + attacker.Lunge_ClearTarget() ForceTitanSustainedDischargeEnd( target ) @@ -242,7 +244,7 @@ bool function MeleeThread_TitanVsTitan_Internal( SyncedMelee action, entity atta void functionref( SyncedMelee action, entity attacker, entity target ) function GetTitanSyncedMeleeFunc( entity attacker, entity target ) { - if ( GetCurrentPlaylistVarInt( "titan_executions_always_short", 0 ) != 0 ) + if ( GetCurrentPlaylistVarInt( "titan_executions_always_short", 0 ) ) return MeleeThread_AtlasVsTitanShort entity soul = attacker.GetTitanSoul() @@ -255,14 +257,17 @@ void functionref( SyncedMelee action, entity attacker, entity target ) function if ( SoulHasPassive( soul, ePassives.PAS_VANGUARD_COREMETER ) ) executionRef = "execution_vanguard_kit" - if ( executionRef in file.executionData_3p ) + if ( executionRef in file.executionData_3p && !GetCurrentPlaylistVarInt( "classic_executions", 0 ) ) return TitanVsTitan_3p if ( target.IsNPC() ) { - entity bossPlayer = target.GetBossPlayer() - if ( IsValid( bossPlayer ) || !IsVDUTitan( target ) ) + #if HAS_BOSS_AI + if ( !IsBossTitan( target ) ) + return MeleeThread_AtlasVsTitanShort + #else return MeleeThread_AtlasVsTitanShort + #endif } string attackerType = GetSoulTitanSubClass( soul ) @@ -270,7 +275,7 @@ void functionref( SyncedMelee action, entity attacker, entity target ) function switch ( attackerType ) { case "stryder": - return MeleeThread_StyderVsTitan + return MeleeThread_StryderVsTitan case "ogre": return MeleeThread_OgreVsTitan @@ -313,7 +318,9 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker attackerSequence.thirdPersonAnim = attackerAnimation3p // attackerSequence.thirdPersonAnimIdle = "at_melee_sync_frontkill_end_idle" - attackerSequence.firstPersonAnim = attackerAnimation1p + if ( attacker.IsPlayer() ) + attackerSequence.firstPersonAnim = attackerAnimation1p + targetSequence.thirdPersonAnim = targetAnimation3p targetSequence.blendTime = 0.25 @@ -324,10 +331,10 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker //HACK! This function was originally for NPCs only, but now that it is being used for players, we need to holster their weapon if ( target.IsPlayer() ) - HolsterAndDisableWeapons( target ) + HolsterViewModelAndDisableWeapons( target ) - if ( ShouldHolsterWeaponForSyncedMelee( attacker ) ) - HolsterAndDisableWeapons( attacker ) + if ( attacker.IsPlayer() ) + HolsterViewModelAndDisableWeapons( attacker ) local attackerViewBody @@ -339,8 +346,6 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker AddAnimEvent( target, "rider_rodeo_over", ForceTitanRodeoToEnd ) - target.SetInvulnerable() //Setting target of execution as invulnerable to prevent them dying mid-way - OnThreadEnd( function() : ( ref, attacker, target, e ) { @@ -359,31 +364,45 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker if ( IsValid( attacker ) ) { //attacker.ClearInvulnerable() - attacker.UnforceStand() + if ( attacker.IsPlayer() ) + attacker.UnforceStand() + attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - DeployAndEnableWeapons( attacker ) - attacker.PlayerMelee_ExecutionEndAttacker() + + if ( attacker.IsPlayer() ) + { + ClearPlayerAnimViewEntity( attacker ) + DeployViewModelAndEnableWeapons( attacker ) + attacker.PlayerMelee_ExecutionEndAttacker() + } if ( IsAlive( attacker ) ) { // if we got into solid, teleport back to safe place if ( !PutEntityInSafeSpot( attacker, null, null, expect vector( e.attackerStartOrg ), attacker.GetOrigin() ) ) - { + { printt( "PutEntityInSafeSpot failed, putting him back at the start origin" ) attacker.SetOrigin( expect vector( e.attackerStartOrg ) ) - } + } } + + vector noRollAngle = attacker.GetAngles() + + noRollAngle.x = 0 + + attacker.SetAngles( noRollAngle ) } if ( IsValid( target ) ) { + target.ClearInvulnerable() + if ( !target.IsNPC() ) { target.PlayerMelee_ExecutionEndTarget() ClearPlayerAnimViewEntity( target ) - DeployAndEnableWeapons( target ) + DeployViewModelAndEnableWeapons( target ) } @@ -404,6 +423,12 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker } ) + attacker.EndSignal( "OnDeath" ) + attacker.EndSignal( "OnDestroy" ) + + target.EndSignal( "OnRespawnPlayer" ) + target.EndSignal( "OnDestroy" ) + thread FirstPersonSequence( targetSequence, target, ref ) waitthread FirstPersonSequence( attackerSequence, attacker, ref ) @@ -411,7 +436,7 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker } -void function MeleeThread_StyderVsTitan( SyncedMelee action, entity attacker, entity target ) +void function MeleeThread_StryderVsTitan( SyncedMelee action, entity attacker, entity target ) { table e e.gib <- true @@ -460,7 +485,9 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke attackerSequence.thirdPersonAnim = expect string ( e.attackerAnimation3p ) // attackerSequence.thirdPersonAnimIdle = "at_melee_sync_frontkill_end_idle" - attackerSequence.firstPersonAnim = expect string( e.attackerAnimation1p ) + if ( attacker.IsPlayer() ) + attackerSequence.firstPersonAnim = expect string( e.attackerAnimation1p ) + targetSequence.thirdPersonAnim = expect string ( e.targetAnimation3p ) targetSequence.blendTime = 0.25 @@ -468,11 +495,11 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke // attacker.SetInvulnerable() target.SetInvulnerable() //HACK: Have to SetInvulnerable first before attacker holsters weapon, because if the attacker is vortexing, holster will release bullets caught and kill off the victim if low enough health - if ( ShouldHolsterWeaponForSyncedMelee( attacker ) ) - HolsterAndDisableWeapons( attacker ) + if ( attacker.IsPlayer() ) + HolsterViewModelAndDisableWeapons( attacker ) if ( !target.IsNPC() ) - HolsterAndDisableWeapons( target ) + HolsterViewModelAndDisableWeapons( target ) EmitDifferentSoundsOnEntityForPlayerAndWorld( expect string ( e.TitanSpecific1pSyncMeleeSound ), expect string ( e.TitanSpecific3pSyncMeleeSound ), attacker, attacker ) @@ -504,12 +531,26 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke targetBodySequence.attachment = "ref" targetBodySequence.blendTime = 0.25 targetBodySequence.thirdPersonAnim = expect string ( e.targetPilotAnimationForObserver ) - targetBodySequence.firstPersonAnim = expect string ( e.targetPilotAnimationForObserver1st ) + + if ( targetIsPlayer ) + targetBodySequence.firstPersonAnim = expect string ( e.targetPilotAnimationForObserver1st ) entity targetSoul = target.GetTitanSoul() targetSoul.SetInvalidHealthBarEnt( true ) + vector refAngles = GetRefAnglesBetweenEnts( attacker, target ) + + if ( !attacker.IsOnGround() ) + refAngles = < 0, refAngles.y, 0 > + + vector fwd = AnglesToForward( refAngles ) * -1 + vector targetAngles = VectorToAngles( fwd ) + + targetAngles.x = 0 + + target.SetAngles( targetAngles ) + entity targetTitan if ( targetIsPlayer ) { @@ -529,9 +570,7 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke { targetTitan = target - // target is now a random dude - target = CreateSoldier( target.GetTeam(), Vector(0,0,0), Vector(0,0,0) ) - DispatchSpawn( target ) + target = CreateNpcTitanPilotModel( target, true ) e.target <- target } @@ -539,7 +578,8 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke AddAnimEvent( targetTitan, "rider_rodeo_over", ForceTitanRodeoToEnd ) AddAnimEvent( targetTitan, "melee_killed_ragdoll", MeleeKilledRagdoll, attacker ) - targetTitan.SetInvulnerable() //Setting target of execution as invulnerable to prevent them dying mid-way + targetTitan.SetInvulnerable() + target.SetInvulnerable() target.SetOwner( attacker ) target.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) //owner cant see @@ -553,41 +593,34 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke { if ( IsValid( ref ) ) { - if ( IsValid( attacker ) ) - { - attacker.ClearParent() - } - else - { - TryClearParent( attacker ) - } + ClearChildren( ref ) - if ( IsValid( target ) ) - { - target.ClearParent() - } - else - { - TryClearParent( target ) - } - - AssertNoPlayerChildren( ref ) ref.Kill_Deprecated_UseDestroyInstead() } if ( IsValid( attacker ) ) { - attacker.UnforceStand() + attacker.ClearInvulnerable() attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - DeployAndEnableWeapons( attacker ) - attacker.PlayerMelee_ExecutionEndAttacker() + if( attacker.IsPlayer() ) + { + attacker.UnforceStand() + ClearPlayerAnimViewEntity( attacker ) + attacker.PlayerMelee_ExecutionEndAttacker() + DeployViewModelAndEnableWeapons( attacker ) + } if ( IsAlive( attacker ) ) { - // if we got into solid, teleport back to safe place PutEntityInSafeSpot( attacker, null, null, expect vector( e.attackerStartOrg ), attacker.GetOrigin() ) + attacker.SetActiveWeaponBySlot( 0 ) } + + vector noRollAngle = attacker.GetAngles() + + noRollAngle.x = 0 + + attacker.SetAngles( noRollAngle ) } if ( IsValid( target ) ) @@ -596,7 +629,7 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke { target.PlayerMelee_ExecutionEndTarget() ClearPlayerAnimViewEntity( target ) - DeployAndEnableWeapons( target ) + DeployViewModelAndEnableWeapons( target ) } if ( HasAnimEvent( target, "pink_mist" ) ) @@ -627,15 +660,38 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke } ) + attacker.EndSignal( "OnDeath" ) + attacker.EndSignal( "OnDestroy" ) + target.EndSignal( "OnRespawnPlayer" ) + target.EndSignal( "OnDestroy" ) waitthread TitanSyncedMeleeAnimationsPlay( attackerBodySequence, attackerViewBody, ref, targetBodySequence, target, attackerSequence, attacker, targetSequence, targetTitan, e ) } -entity function CreateNpcTitanPilotModel( entity titan ) +entity function CreateNpcTitanPilotModel( entity titan, bool createEntity = false ) { asset modelName = GetNpcTitanPilotModel( titan ) - return CreatePropDynamic( modelName ) + + if ( modelName == $"" ) + modelName = TEAM_IMC_GRUNT_MODEL + + if ( createEntity ) + { + entity pilot = CreateElitePilot( titan.GetTeam(), titan.GetOrigin(), titan.GetAngles() ) + + DispatchSpawn( pilot ) + + pilot.SetModel( modelName ) + + return pilot + } + + entity model = CreatePropDynamic( modelName ) + + SetTeam( model, titan.GetTeam() ) + + return model } @@ -662,14 +718,20 @@ function TitanSyncedMeleeAnimationsPlay( FirstPersonSequenceStruct attackerBodyS { // insure visibility if ( IsValid( targetTitan ) ) - targetTitan.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + { + targetTitan.ClearInvulnerable() + + if ( IsAlive( targetTitan ) ) + targetTitan.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) + } if ( !IsAlive( attacker ) ) { attacker.Anim_Stop() - if ( !e.thrown && IsAlive( target ) ) + if ( !e.thrown && IsAlive( target ) && target.IsPlayer() ) { + target.ClearInvulnerable() target.Anim_Stop() target.SetOwner( null ) target.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE @@ -679,8 +741,9 @@ function TitanSyncedMeleeAnimationsPlay( FirstPersonSequenceStruct attackerBodyS target.GetFirstPersonProxy().Anim_Stop() target.SetPlayerSettings( e.oldPlayerSettings ) } - } + else if ( IsAlive( target ) ) + target.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) } } ) @@ -895,7 +958,9 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti FirstPersonSequenceStruct targetSequence = clone attackerSequence attackerSequence.thirdPersonAnim = attackerAnimation3p - attackerSequence.firstPersonAnim = attackerAnimation1p + + if ( attacker.IsPlayer() ) + attackerSequence.firstPersonAnim = attackerAnimation1p if ( target.IsPlayer() ) targetSequence.firstPersonAnim = targetAnimation1p @@ -904,8 +969,12 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti targetSequence.blendTime = 0.25 target.e.syncedMeleeAttacker = attacker - DisableWeapons( attacker, [] ) - DisableWeapons( target, [] ) + + if ( attacker.IsPlayer() ) + HolsterViewModelAndDisableWeapons( attacker ) + + if ( target.IsPlayer() ) + HolsterViewModelAndDisableWeapons( target ) // attacker.SetInvulnerable() target.SetInvulnerable() @@ -918,23 +987,29 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti { if ( IsValid( ref ) ) { - if ( IsValid( attacker ) ) - attacker.ClearParent() + ClearChildren( ref ) - if ( IsValid( target ) ) - target.ClearParent() - - AssertNoPlayerChildren( ref ) ref.Kill_Deprecated_UseDestroyInstead() } if ( IsValid( attacker ) ) { - attacker.UnforceStand() + if ( attacker.IsPlayer() ) + attacker.UnforceStand() + + attacker.ClearInvulnerable() attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - EnableWeapons( attacker, [] ) - attacker.PlayerMelee_ExecutionEndAttacker() + + if ( attacker.IsPlayer() ) + { + ClearPlayerAnimViewEntity( attacker ) + DeployViewModelAndEnableWeapons( attacker ) + } + + attacker.SetActiveWeaponBySlot( 0 ) + + if ( attacker.IsPlayer() ) + attacker.PlayerMelee_ExecutionEndAttacker() if ( IsAlive( attacker ) ) { @@ -956,7 +1031,8 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti ClearPlayerAnimViewEntity( target ) } - EnableWeapons( target, [] ) + if ( target.IsPlayer() ) + DeployViewModelAndEnableWeapons( target ) if ( !target.IsNPC() ) target.PlayerMelee_ExecutionEndTarget() @@ -975,11 +1051,26 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti ) attacker.EndSignal( "OnDeath" ) + attacker.EndSignal( "OnDestroy" ) + + target.EndSignal( "OnRespawnPlayer" ) + target.EndSignal( "OnDestroy" ) EmitDifferentSoundsOnEntityForPlayerAndWorld( "Ogre_1p_Sync_Melee", "Ogre_3p_Sync_Melee", attacker, attacker ) AddAnimEvent( target, "lost_arm", TitanLostArm, e ) + vector refAngles = GetRefAnglesBetweenEnts( attacker, target ) + + if ( !attacker.IsOnGround() ) + refAngles = < 0, refAngles.y, 0 > + + vector fwd = AnglesToForward( refAngles ) * -1 + vector targetAngles = VectorToAngles( fwd ) + + targetAngles.x = 0 + + target.SetAngles( targetAngles ) thread FirstPersonSequence( targetSequence, target, ref ) waitthread FirstPersonSequence( attackerSequence, attacker, ref ) @@ -1071,15 +1162,31 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe // END HACK FOR SP!!! if ( !target.IsNPC() ) + { HolsterViewModelAndDisableWeapons( target ) //Melee anims need to use this to stop players from firing weapons but for the weapon to still show up in the 3p anims + if ( attacker.IsNPC() ) //Defensive fix for the anim events not happening when the attacker is a NPC + { + ForceTitanRodeoToEnd( target ) + DisableTitanRodeo( target ) + } + } else + { + target.EnableNPCFlag( NPC_IGNORE_ALL | NPC_DISABLE_SENSING ) DisableWeapons( target, [] ) + } if ( attacker.IsPlayer() ) { HolsterViewModelAndDisableWeapons( attacker ) //Melee anims need to use this to stop players from firing weapons but for the weapon to still show up in the 3p anims attacker.Anim_StopGesture( DEFAULT_SCRIPTED_ANIMATION_BLEND_TIME ) } + else + { + attacker.EnableNPCFlag( NPC_IGNORE_ALL | NPC_DISABLE_SENSING ) + ForceTitanRodeoToEnd( attacker ) //Anim event of disabling Rodeos on attacker like players does, does not happen to NPCs + DisableTitanRodeo( attacker ) + } // attacker.SetInvulnerable() target.SetInvulnerable() @@ -1158,12 +1265,24 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe DeleteAnimEvent( attacker, "rocket_pod_fire_left" ) DeleteAnimEvent( attacker, "rocket_pod_fire_right" ) - attacker.UnforceStand() attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - attacker.PlayerMelee_ExecutionEndAttacker() ForceTitanSustainedDischargeEnd( attacker ) - DeployViewModelAndEnableWeapons( attacker ) //Melee anims need to use this to stop players from firing weapons but for the weapon to still show up in the 3p anims + if( attacker.IsPlayer() ) + { + attacker.UnforceStand() + ClearPlayerAnimViewEntity( attacker ) + attacker.PlayerMelee_ExecutionEndAttacker() + DeployViewModelAndEnableWeapons( attacker ) + } + + else + { + attacker.DisableNPCFlag( NPC_IGNORE_ALL | NPC_DISABLE_SENSING ) + EnableWeapons( attacker, [] ) + attacker.SetActiveWeaponBySlot( 0 ) + EnableTitanRodeo( attacker ) //Assuming everything went alright, re-enable rodeos on NPC Titans + } + if ( IsAlive( attacker ) ) { if ( !isAttackerRef && IsValid( target ) ) @@ -1177,7 +1296,8 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe if ( attacker.IsTitan() ) { - Remote_CallFunction_Replay( attacker, "SCB_PlayTitanCockpitSounds" ) + if ( attacker.IsPlayer() ) + Remote_CallFunction_Replay( attacker, "SCB_PlayTitanCockpitSounds" ) #if TITAN_EXECUTION_GIVES_BATTERY Rodeo_GiveExecutingTitanABattery( attacker ) #else @@ -1197,6 +1317,12 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe { attacker.Anim_Stop() // if you are fighting an NPC, then they can get destroyed early the moment they explode. But sometimes, your animation isn't done playing yet so you can't move } + + vector noRollAngle = attacker.GetAngles() + + noRollAngle.x = 0 + + attacker.SetAngles( noRollAngle ) } } @@ -1239,6 +1365,9 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe PutEntityInSafeSpot( target, attacker, null, target.GetOrigin(), target.GetOrigin() ) } } + int attachID = target.LookupAttachment( "HEADFOCUS" ) + vector explodeorigin = target.GetAttachmentOrigin( attachID ) + PlayFX( $"xo_exp_death", explodeorigin ) //This is because many execution animations plays the sound but does not spawn the explosion particle FX } if ( IsValid( attackerViewBody ) ) @@ -1307,18 +1436,12 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe vector refAngles = GetRefAnglesBetweenEnts( attacker, target ) if ( !attacker.IsOnGround() ) - { - refAngles = <0,refAngles.y,0> - } + refAngles = < 0, refAngles.y, 0 > - vector fwd = AnglesToForward( refAngles ) - fwd *= -1 + vector fwd = AnglesToForward( refAngles ) * -1 vector targetAngles = VectorToAngles( fwd ) - if ( !target.IsNPC() ) - { - targetAngles.x = 0 - target.SetAngles( targetAngles ) - } + + targetAngles.x = 0 target.SetAngles( targetAngles ) @@ -1327,17 +1450,15 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe if ( attackerViewBody != null ) { attackerDoing1PViewbodyAnim = true - + attackerBodySequence.useAnimatedRefAttachment = true - + #if MP - // could use FirstPersonSequenceForce1P here, but since this uses a propdynamic rather than a player, easier to do it manually - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) + if ( ShouldRunFirstPersonSequence( attacker, false, true ) ) { - // hide from everyone else attackerViewBody.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE & ~ENTITY_VISIBLE_TO_OWNER attackerViewBody.SetOwner( attacker ) - + entity attackerViewBodyProxy = Wallrun_CreateCopyOfPilotModel( attacker ) attackerViewBodyProxy.SetOrigin( attacker.GetOrigin() ) attackerViewBodyProxy.SetRagdollImpactFX( RAGDOLL_IMPACT_TABLE_IDX ) @@ -1345,20 +1466,15 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe attackerViewBodyProxy.SetBodygroup( attackerViewBodyProxy.FindBodyGroup( "head" ), 1 ) attackerViewBodyProxy.SetOwner( attacker ) attackerViewBodyProxy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER - - // create the viewpoint entity - entity camera = CreateEntity( "point_viewcontrol" ) - camera.SetParent( attackerViewBodyProxy, FORCE1P_PILOT_1P_ATTACHMENT ) - camera.kv.spawnflags = 56 - DispatchSpawn( camera ) - attacker.SetViewEntity( camera, false ) - - Remote_CallFunction_NonReplay( attacker, "ServerCallback_HideHudForFPHackAnim" ) + + attackerSequence.thirdPersonCameraEntity = attackerViewBodyProxy + attackerSequence.thirdPersonCameraAttachments = [ FORCE1P_PILOT_1P_ATTACHMENT ] + ScreenFadeFromBlack( attacker, 1.0, 0.5 ) - thread Forced1PAttackerViewBodySequence( attackerBodySequence, attackerViewBodyProxy, attacker, camera ) + thread Forced1PAttackerViewBodySequence( attackerBodySequence, attackerViewBodyProxy, attacker ) } #endif - + thread FirstPersonSequence( attackerBodySequence, attackerViewBody, attacker ) } @@ -1372,14 +1488,11 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe if ( isAttackerRef ) { #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) - { - if ( attacker.IsPlayer() && !attackerDoing1PViewbodyAnim ) - FirstPersonSequenceForce1P( attackerSequence, attacker ) + if ( attacker.IsPlayer() && !attackerDoing1PViewbodyAnim && ShouldRunFirstPersonSequence( attacker, false, true ) ) + FirstPersonSequenceForce1P( attackerSequence, attacker ) - if ( target.IsPlayer() ) - FirstPersonSequenceForce1P( targetSequence, target, attacker ) - } + if ( target.IsPlayer() && ShouldRunFirstPersonSequence( target, false, true ) ) + FirstPersonSequenceForce1P( targetSequence, target, attacker ) #endif thread FirstPersonSequence( attackerSequence, attacker ) @@ -1388,14 +1501,11 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe else { #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) - { - if ( target.IsPlayer() ) - FirstPersonSequenceForce1P( targetSequence, target ) - - if ( attacker.IsPlayer() && !attackerDoing1PViewbodyAnim ) - FirstPersonSequenceForce1P( attackerSequence, attacker, target ) - } + if ( target.IsPlayer() && ShouldRunFirstPersonSequence( target, false, true ) ) + FirstPersonSequenceForce1P( targetSequence, target ) + + if ( attacker.IsPlayer() && !attackerDoing1PViewbodyAnim && ShouldRunFirstPersonSequence( attacker, false, true ) ) + FirstPersonSequenceForce1P( attackerSequence, attacker, target ) #endif thread FirstPersonSequence( targetSequence, target ) @@ -1403,18 +1513,20 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe } } -void function Forced1PAttackerViewBodySequence( FirstPersonSequenceStruct attackerBodySequence, entity attackerViewBody, entity attacker, entity camera ) +void function Forced1PAttackerViewBodySequence( FirstPersonSequenceStruct attackerBodySequence, entity attackerViewBody, entity attacker ) { attacker.EndSignal( "OnDestroy" ) attacker.EndSignal( "OnDeath" ) attacker.EndSignal( "OnAnimationDone" ) - - OnThreadEnd( function() : ( attackerViewBody, attacker, camera ) - { - attacker.ClearViewEntity() - camera.Destroy() - attackerViewBody.Destroy() - }) + + OnThreadEnd + ( + function() : ( attackerViewBody, attacker ) + { + if ( IsValid( attackerViewBody ) ) + attackerViewBody.Destroy() + } + ) FirstPersonSequence( attackerBodySequence, attackerViewBody, attacker ) } @@ -1552,7 +1664,10 @@ void function MeleeKilledRagdoll( entity titan ) if ( !IsValid( attacker ) ) return - titan.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) + + if ( IsAlive( titan ) ) + titan.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) + titan.SetContinueAnimatingAfterRagdoll( true ) titan.BecomeRagdoll( < 0, 0, 0 >, false ) } diff --git a/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut index 89ea38f03..d38300c8f 100644 --- a/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut @@ -194,7 +194,7 @@ bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity { if ( attacker == target ) return false - + if ( !ShouldPlayerExecuteTarget( attacker, target ) ) return false @@ -219,20 +219,17 @@ bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity if ( attacker.IsTitan() && target.IsTitan() ) { - // no melee execute for berserker - if ( PlayerHasPassive( attacker, ePassives.PAS_BERSERKER ) ) + entity meleeWeapon = attacker.GetMeleeWeapon() + if( !IsValid( meleeWeapon ) ) return false - - if ( PlayerHasPassive( attacker, ePassives.PAS_SHIFT_CORE ) ) + + if ( meleeWeapon.HasMod( "berserker_core_punch" ) || meleeWeapon.HasMod( "super_charged" ) || meleeWeapon.HasMod( "super_charged_SP" ) ) return false if ( HasSoul( target ) && target.GetTitanSoul().IsEjecting() ) return false - if ( attacker.ContextAction_IsActive() ) - return false - - if ( target.ContextAction_IsActive() ) + if ( attacker.ContextAction_IsActive() || target.ContextAction_IsActive() ) return false if ( GetCurrentPlaylistVarInt( "vortex_blocks_melee", 0 ) == 1 ) @@ -247,19 +244,22 @@ bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity } } - if ( !CheckVerticallyCloseEnough( attacker, target ) ) - return false + // npc execution case + if ( attacker.IsPlayer() ) + { + if ( !CheckVerticallyCloseEnough( attacker, target ) ) + return false - //No necksnaps while wall running or mantling - if ( attacker.IsWallRunning() ) - return false + //No necksnaps while wall running or mantling + if ( attacker.IsWallRunning() ) + return false - if ( attacker.IsTraversing() ) - return false + if ( attacker.IsTraversing() ) + return false + } if ( target.IsPlayer() ) //Disallow execution on a bunch of player-only actions { - if ( target.IsHuman() ) { if ( target.IsWallRunning() ) @@ -313,9 +313,14 @@ bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity if ( action == null ) return false - if ( !PlayerMelee_IsExecutionReachable( attacker, target, 0.3 ) ) - return false + // npc execution case + if ( attacker.IsPlayer() ) + { + if ( !PlayerMelee_IsExecutionReachable( attacker, target, 0.3 ) ) + return false + } + // modified callback from northstar foreach ( callbackFunc in file.isValidMeleeExecutionTargetCallBacks ) { if ( !callbackFunc( attacker, target ) ) @@ -378,12 +383,17 @@ bool function CodeCallback_IsValidMeleeAttackTarget( entity attacker, entity tar void function CodeCallback_OnMeleePressed( entity player ) { +#if SERVER && DEV + print( "SERVER: " + player + " pressed melee\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " pressed melee\n" ) +#endif if ( !Melee_IsAllowed( player ) ) { -#if SERVER +#if SERVER && DEV print( "SERVER: Melee_IsAllowed() for " + player + " is false\n" ) -#else +#elseif CLIENT && DEV print( "CLIENT: Melee_IsAllowed() for " + player + " is false\n" ) #endif return @@ -396,19 +406,33 @@ void function CodeCallback_OnMeleePressed( entity player ) if ( player.IsWeaponDisabled() ) { -#if SERVER +#if SERVER && DEV print( "SERVER: IsWeaponDisabled() for " + player + " is true\n" ) -#else +#elseif CLIENT && DEV print( "CLIENT: IsWeaponDisabled() for " + player + " is true\n" ) #endif return } if ( player.PlayerMelee_GetState() != PLAYER_MELEE_STATE_NONE ) + { +#if SERVER && DEV + print( "SERVER: PlayerMelee_GetState() for " + player + " is " + player.PlayerMelee_GetState() + "\n" ) +#elseif CLIENT && DEV + print( "CLIENT: PlayerMelee_GetState() for " + player + " is " + player.PlayerMelee_GetState() + "\n" ) +#endif return + } if ( !IsAlive( player ) ) + { +#if SERVER && DEV + print( "SERVER: " + player + " is dead\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " is dead\n" ) +#endif return + } thread CodeCallback_OnMeleePressed_InternalThread( player ) } @@ -490,25 +514,35 @@ bool function PlayerTriesSyncedMelee( entity player, entity target ) if ( target.ContextAction_IsBusy() ) return false - if ( player.IsTitan() ) + if( player.IsPlayer() ) { + if ( player.IsTitan() ) + { #if SERVER - player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION ) + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION ) #else - player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION_PREDICTED ) + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION_PREDICTED ) #endif - } - else - { + } + else + { #if SERVER - player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION ) + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION ) #else - player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED ) + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED ) #endif + } } - if ( !player.Lunge_IsActive() || !player.Lunge_IsGroundExecute() || !player.Lunge_IsLungingToEntity() || (player.Lunge_GetTargetEntity() != target) ) + if ( player.IsPlayer() && (!player.Lunge_IsActive() || !player.Lunge_IsGroundExecute() || !player.Lunge_IsLungingToEntity() || (player.Lunge_GetTargetEntity() != target)) ) + { +#if SERVER && DEV + print( "SERVER: " + player + " is calling Lunge_SetTargetEntity() from PlayerTriesSyncedMelee()\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " is calling Lunge_SetTargetEntity() from PlayerTriesSyncedMelee()\n" ) +#endif player.Lunge_SetTargetEntity( target, false ) + } #if SERVER OnThreadEnd( @@ -537,14 +571,15 @@ bool function PlayerTriesSyncedMelee( entity player, entity target ) if ( IsValid( target ) && target.IsPlayer() ) { AddCinematicFlag( target, CE_FLAG_TITAN_3P_CAM ) - AddCinematicFlag( player, CE_FLAG_EXECUTION ) + AddCinematicFlag( target, CE_FLAG_EXECUTION ) } #endif bool success = DoSyncedMelee( player, target ) if ( !success ) { - player.Lunge_ClearTarget() + if( player.IsPlayer() ) + player.Lunge_ClearTarget() } return success @@ -566,7 +601,8 @@ bool function DoSyncedMelee( entity player, entity target ) #if SERVER if ( player.IsPlayer() ) { - PlayerMelee_StartLagCompensateTargetForLunge( player, target ) + if ( player.Lunge_IsActive() ) + PlayerMelee_StartLagCompensateTargetForLunge( player, target ) } #endif // #if SERVER @@ -578,7 +614,8 @@ bool function DoSyncedMelee( entity player, entity target ) player.ForceStand() player.UnforceStand() - PlayerMelee_FinishLagCompensateTarget( player ) + if ( player.Lunge_IsActive() ) + PlayerMelee_FinishLagCompensateTarget( player ) } #endif // #if SERVER @@ -595,7 +632,8 @@ bool function DoSyncedMelee( entity player, entity target ) target.Signal( "OnSyncedMeleeVictim" ) #if SERVER - player.p.lastExecutionUsed = action.ref + if ( player.IsPlayer() ) + player.p.lastExecutionUsed = action.ref if ( actions in file.syncedMeleeServerCallbacks ) thread SyncedMeleeServerCallbacks( actions, action, player, target ) @@ -998,7 +1036,11 @@ SyncedMeleeChooser ornull function GetSyncedMeleeChooserForPlayerVsTarget( entit void function CodeCallback_OnMeleeAttackAnimEvent( entity player ) { Assert( IsValid( player ) ) - +#if SERVER && DEV + print( "SERVER: " + player + " is calling CodeCallback_OnMeleeAttackAnimEvent()\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " is calling CodeCallback_OnMeleeAttackAnimEvent()\n" ) +#endif if ( player.PlayerMelee_IsAttackActive() ) { if ( player.IsTitan() ) diff --git a/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut b/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut index 9aa86a437..1902ca919 100644 --- a/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut @@ -336,24 +336,38 @@ void function RodeoBatteryRemoval( entity pilot ) RodeoBatteryPackRemovalDamage( pilot, titan, soul ) bool playerHadBattery = PlayerHasBattery( pilot ) - - if ( !playerHadBattery ) + + vector direction = CalculateDirectionToThrowOffBatteryThief( pilot, titan ) + + if ( !playerHadBattery || GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) == 1 ) { - AddPlayerScore( pilot, "PilotBatteryStolen" ) + AddPlayerScore( pilot, "PilotBatteryStolen", pilot ) entity battery = Rodeo_CreateBatteryPack( titan ) - Rodeo_PilotPicksUpBattery( pilot, battery ) - thread BatteryThiefHighlight( pilot ) + + if( GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) == 1 ) + { + int attachID = pilot.LookupAttachment( "FLAG" ) + vector tossOrigin = pilot.GetAttachmentOrigin( attachID ) + tossOrigin = PositionOffsetFromOriginAngles( tossOrigin, pilot.GetAngles(), -10, 0, 0 ) + battery.SetOrigin( tossOrigin ) + battery.SetVelocity( direction ) + } + else + { + Rodeo_PilotPicksUpBattery( pilot, battery ) + thread BatteryThiefHighlight( pilot ) + } if ( titan.IsPlayer() ) - { EmitSoundOnEntityOnlyToPlayer( titan, titan, TITAN_GOT_BATTERY_RIPPED_SOUND ) //Consider playing this in world once we get sounds that aren't just notification beeps - } } - vector direction = CalculateDirectionToThrowOffBatteryThief( pilot, titan ) - + bool shouldJumpOff = true // for classic rodeo, let them stay on - if ( GetCurrentPlaylistVarInt( "classic_rodeo", 0 ) == 0 ) + if ( GetCurrentPlaylistVarInt( "classic_rodeo", 0 ) == 1 || GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) == 1 ) + shouldJumpOff = false + + if( shouldJumpOff ) ThrowRiderOff( pilot, titan, direction ) //This signals RodeoOver #if MP @@ -613,14 +627,22 @@ function PlayerBeginsTitanRodeo( entity player, RodeoPackageStruct rodeoPackage, if ( IsAlive( player ) ) { - int attachIndex = newRodeoTitan.LookupAttachment( rodeoPackage.attachPoint ) - vector startPos = newRodeoTitan.GetAttachmentOrigin( attachIndex ) - - if ( !PlayerCanTeleportHere( player, startPos, newRodeoTitan ) ) + vector startPos + if( IsValid( newRodeoTitan ) ) { - startPos = newRodeoTitan.GetOrigin() + int attachIndex = newRodeoTitan.LookupAttachment( rodeoPackage.attachPoint ) + startPos = newRodeoTitan.GetAttachmentOrigin( attachIndex ) + if ( !PlayerCanTeleportHere( player, startPos, newRodeoTitan ) ) - startPos = player.GetOrigin() + { + startPos = newRodeoTitan.GetOrigin() + if ( !PlayerCanTeleportHere( player, startPos, newRodeoTitan ) ) + startPos = player.GetOrigin() + } + } + else + { + startPos = player.GetOrigin() } thread PlayerJumpsOffRodeoTarget( player, newRodeoTitan, startPos ) @@ -686,6 +708,12 @@ function PlayerBeginsTitanRodeo( entity player, RodeoPackageStruct rodeoPackage, waitthread PlayerClimbsIntoRodeoPosition( player, rodeoTitan, rodeoPackage, playerWasEjecting ) #if MP + // for classic rodeo, let them stay on + bool shouldCloseNukeWindow = true + if ( GetCurrentPlaylistVarInt( "classic_rodeo", 0 ) == 1 || GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) == 1 ) + shouldCloseNukeWindow = false + + if( shouldCloseNukeWindow ) //Allow the player to insert Overload Battery at any point of Rodeo player.Signal( "RodeoNukeWindowEnded" ) #endif @@ -706,6 +734,7 @@ function PlayerBeginsTitanRodeo( entity player, RodeoPackageStruct rodeoPackage, void function PlayRodeoFactionDialogueAfterDelay( entity player, float delay = 0.5 ) { player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) player.EndSignal( "RodeoOver" ) wait delay @@ -804,12 +833,24 @@ void function RodeoPilotPullsOutWeapon( entity rodeoPilot, entity rodeoTitan, st void function TryBatteryStyleRodeo( entity rodeoPilot, entity rodeoTitan, entity titanSoul, RodeoPackageStruct rodeoPackage ) { titanSoul.EndSignal( "OnTitanDeath" ) + titanSoul.EndSignal( "OnDestroy" ) string rodeoTitanType = rodeoPackage.rodeoTargetType + rodeoTitan = titanSoul.GetTitan() if ( rodeoPilot.GetTeam() == rodeoTitan.GetTeam() ) { - if ( PilotCanApplyBattery( rodeoPilot, rodeoTitan ) ) + while ( PilotCanApplyBattery( rodeoPilot, rodeoTitan ) ) //Changed from if to while so it keeps repeating until player has no more batteries + { + rodeoTitan = titanSoul.GetTitan() + titanSoul.soul.batteryContainerBeingUsed = true waitthread PlayerAppliesBatteryPack( rodeoPilot, rodeoTitan, titanSoul, rodeoPackage ) + titanSoul.soul.batteryMovedDown = false + if ( GetPlayerBatteryCount( rodeoPilot ) > 0 ) + { + Rodeo_MoveBatteryDown( titanSoul ) + wait 0.2 //Synced Entity cleanup stuff + } + } rodeoTitan = titanSoul.GetTitan() Assert( IsAlive( rodeoTitan ) ) @@ -826,7 +867,6 @@ void function TryBatteryStyleRodeo( entity rodeoPilot, entity rodeoTitan, entity RodeoPilotPullsOutWeapon( rodeoPilot, rodeoTitan, rodeoTitanType ) WaitForever() - } #if MP @@ -849,33 +889,47 @@ void function TryBatteryStyleRodeo( entity rodeoPilot, entity rodeoTitan, entity waitthread PlayerRemovesBatteryPack( rodeoPilot, rodeoTitan, titanSoul, rodeoPackage ) //This ends rodeo at the end of the sequence } + if( GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) == 1 ) + waitthread ReTryBatteryStyleRodeo( rodeoPilot, rodeoTitan, titanSoul, rodeoPackage ) + #if MP if ( classicRodeo ) { - RodeoBatteryRemoval_ShowBattery( rodeoPilot ) // hide battery, will be shown at the end of a battery removal rodeo - //This is default R1 style rodeo, with the panel ripped and ready to be shot at FirstPersonSequenceStruct sequence sequence.attachment = "hijack" - sequence.thirdPersonAnimIdle = GetAnimFromAlias( rodeoTitanType, "pt_rodeo_back_right_idle" ) - sequence.firstPersonAnimIdle = GetAnimFromAlias( rodeoTitanType, "ptpov_rodeo_back_right_idle" ) - sequence.useAnimatedRefAttachment = true + sequence.thirdPersonAnimIdle = GetAnimFromAlias( rodeoTitanType, "pt_rodeo_back_right_idle" ) + sequence.firstPersonAnimIdle = GetAnimFromAlias( rodeoTitanType, "ptpov_rodeo_back_right_idle" ) + sequence.useAnimatedRefAttachment = true thread FirstPersonSequence( sequence, rodeoPilot, rodeoTitan ) RodeoPilotPullsOutWeapon( rodeoPilot, rodeoTitan, rodeoTitanType ) + + entity batteryContainer = titanSoul.soul.batteryContainer + Highlight_SetEnemyHighlight( batteryContainer, "titan_weakpoint" ) + entity weakpointHitbox = CreateClassicRodeoWeakpoint( rodeoPilot, rodeoTitan ) - OnThreadEnd( function() : ( weakpointHitbox ) + OnThreadEnd( function() : ( weakpointHitbox, batteryContainer ) { if ( IsValid( weakpointHitbox ) ) + { + Highlight_ClearEnemyHighlight( batteryContainer ) weakpointHitbox.Destroy() + } }) while ( true ) { // the point of no return stuff breaks jumping if you pulled a battery, so do this manually, sucks but whatever if ( rodeoPilot.IsInputCommandHeld( IN_JUMP ) ) + { + rodeoPilot.Signal( "RodeoNukeWindowEnded" ) //Cancel the window to insert Nuke Rodeo ThrowRiderOff( rodeoPilot, rodeoTitan, CalculateDirectionToThrowOffBatteryThief( rodeoPilot, rodeoTitan ) ) //This signals RodeoOver + } + + if ( PlayerWantsToThrowNukeGrenade( rodeoPilot ) ) + waitthread ReTryBatteryStyleRodeo( rodeoPilot, rodeoTitan, titanSoul, rodeoPackage ) WaitFrame() } @@ -883,6 +937,53 @@ void function TryBatteryStyleRodeo( entity rodeoPilot, entity rodeoTitan, entity #endif } +void function ReTryBatteryStyleRodeo( entity rodeoPilot, entity rodeoTitan, entity titanSoul, RodeoPackageStruct rodeoPackage ) +{ + titanSoul.EndSignal( "OnTitanDeath" ) + titanSoul.EndSignal( "OnDestroy" ) + + thread WatchForPlayerJumpingOffConstantRodeo( rodeoPilot ) //Allows player to Jump Off at any point + while( true ) + { + #if MP + thread OpenRodeoNukeWindow( rodeoPilot, rodeoTitan ) //Keep repeating because the the end of the animation signals RodeoOver which ends this thread + if ( PlayerWantsToThrowNukeGrenade( rodeoPilot ) ) + { + waitthread PlayerAppliesBatteryPack( rodeoPilot, rodeoTitan, titanSoul, rodeoPackage ) + return + } + #endif + + waitthread PlayerRemovesBatteryPack( rodeoPilot, rodeoTitan, titanSoul, rodeoPackage ) + } +} + +void function WatchForPlayerJumpingOffConstantRodeo( entity player ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "RodeoOver" ) + + AddButtonPressedPlayerInputCallback( player, IN_JUMP, ForceEndRodeo ) + + OnThreadEnd( + function() : ( player ) + { + RemoveButtonPressedPlayerInputCallback( player, IN_JUMP, ForceEndRodeo ) + player.Signal( "RodeoNukeWindowEnded" ) + if ( player in file.playersThatWantToUseRodeoGrenade ) + delete file.playersThatWantToUseRodeoGrenade[ player ] + } + ) + + WaitForever() +} + +void function ForceEndRodeo( entity player ) +{ + player.Signal( "RodeoOver" ) +} + struct RodeoRiderSequenceStruct { bool wasCloaked = false @@ -1089,19 +1190,13 @@ void function PlayerThrowsGrenadeInHatch( entity rodeoPilot, entity rodeoTitan, void function PlayerAppliesBatteryPack_DelayedClearSyncedEntity( entity rodeoPilot, entity titanSoul ) { if ( !IsValid( rodeoPilot ) ) - { return - } if ( !IsValid( titanSoul ) ) - { return - } if ( titanSoul.soul.batteryContainerBeingUsed ) - { return - } rodeoPilot.SetSyncedEntity( null ) } @@ -1120,7 +1215,6 @@ void function PlayerAppliesBatteryPack( entity rodeoPilot, entity rodeoTitan, en } else { - battery = GetBatteryOnBack( rodeoPilot ) battery.Hide() //Hide it because the animation has a battery model already } @@ -1143,7 +1237,10 @@ void function PlayerAppliesBatteryPack( entity rodeoPilot, entity rodeoTitan, en #if MP if ( nukeVersion ) + { tempBattery1p.SetSkin( 1 ) + tempBattery3p.SetSkin( 1 ) + } #endif if ( IsAmpedBattery( battery ) ) { @@ -1262,7 +1359,7 @@ void function RodeoBatteryPackRemovalDamage( entity attacker, entity victim, ent int damageAmount = GetSegmentHealthForTitan( victim ) - if ( PlayerHasBattery( attacker ) ) //i.e. you are throwing a grenade + if ( PlayerHasBattery( attacker ) && GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) != 1 ) //i.e. you are throwing a grenade damageAmount /= 2 SetSoulBatteryCount( victimTitanSoul, GetSoulBatteryCount( victimTitanSoul ) - 1 ) @@ -1341,7 +1438,8 @@ void function Rodeo_ApplyBatteryDelayed( entity player, table e ) entity battery = Rodeo_TakeBatteryAwayFromPilot( player ) e[ "hadAmped" ] = e[ "hadAmped" ] || IsAmpedBattery( battery ) int skin = battery.GetSkin() - battery.Destroy() + if( GetPlayerBatteryCount( player ) == 0 ) + battery.Destroy() entity dummyBattery = CreatePropDynamic( RODEO_BATTERY_MODEL_FOR_RODEO_ANIMS ) dummyBattery.SetSkin( skin ) @@ -1619,7 +1717,7 @@ entity function Rodeo_TakeBatteryAwayFromPilot( entity pilot ) } else { - return null + return GetBatteryOnBack( pilot ) } unreachable @@ -1647,6 +1745,10 @@ void function Rodeo_PilotThrowsBattery( entity pilot ) //printt( "viewVector: " + viewVector ) entity playerBattery = Rodeo_TakeBatteryAwayFromPilot( pilot ) + + if ( GetPlayerBatteryCount( pilot ) > 0 ) + battery = Rodeo_CreateBatteryPack() + Assert( playerBattery == battery ) //battery.SetPhysics( MOVETYPE_FLYGRAVITY ) @@ -1735,7 +1837,7 @@ void function Rodeo_RemoveAllBatteriesOffPlayer( entity player ) //Meant to be u } } -void function Rodeo_ApplyBatteryToTitan( entity battery, entity titan ) +void function Rodeo_ApplyBatteryToTitan( entity battery, entity titan, int batteryCounter = 0 ) { entity soul = titan.GetTitanSoul() @@ -1815,10 +1917,12 @@ void function Rodeo_ApplyBatteryToTitan( entity battery, entity titan ) { titan.SetHealth( totalHealth ) soul.SetShieldHealth( soul.GetShieldHealthMax() ) + if( titan.GetHealth() >= maxHealth && !soul.IsDoomed() ) + UndoomTitan_Body( titan ) } } - if ( battery != null ) + if ( battery != null && batteryCounter == 0 ) { Assert( battery.GetParent() == null ) battery.Destroy() @@ -1893,7 +1997,7 @@ void function Rodeo_OnTouchBatteryPack_Internal( entity player, entity batteryPa Battery_StopFX( batteryPack ) //Will be turned on again when player loses cloak Rodeo_PilotPicksUpBattery( player, batteryPack ) - AddPlayerScore( player, "PilotBatteryPickup" ) + AddPlayerScore( player, "PilotBatteryPickup", player ) // MessageToPlayer( player, eEventNotifications.Rodeo_PilotPickedUpBattery ) return } @@ -1916,9 +2020,9 @@ void function Rodeo_PilotAddsBatteryToFriendlyTitan( entity rider, entity titan if ( file.applyBatteryCallback != null ) file.applyBatteryCallback( rider, titan, battery ) - Rodeo_ApplyBatteryToTitan( battery, titan ) //This destroys the battery + Rodeo_ApplyBatteryToTitan( battery, titan, GetPlayerBatteryCount( rider ) ) //This destroys the battery - AddPlayerScore( rider, "PilotBatteryApplied" ) + AddPlayerScore( rider, "PilotBatteryApplied", rider ) EmitSoundOnEntityOnlyToPlayer( rider, rider, PILOT_APPLIES_BATTERY_TO_TITAN_HEALTH_RESTORED_SOUND ) @@ -2017,17 +2121,12 @@ bool function ClientCommand_RequestRodeoBattery( entity player, array ar return true player.SetPlayerNetTime( "requestRodeoBatteryLastUsedTime", Time() ) - foreach( friendlyPlayer in GetPlayerArrayOfTeam( player.GetTeam() ) ) { - if ( friendlyPlayer == player ) + if ( friendlyPlayer == player || friendlyPlayer.IsTitan() ) continue - - if ( friendlyPlayer.IsTitan() ) - continue - - //Could check to see if players actually have a battery here, but that stops players from being told that they should pick up a battery for someone in need - MessageToPlayer( friendlyPlayer, eEventNotifications.Rodeo_RequestBattery, player ) + if( PlayerHasBattery( friendlyPlayer ) ) + MessageToPlayer( friendlyPlayer, eEventNotifications.Rodeo_RequestBattery, player ) } return true @@ -2090,7 +2189,9 @@ bool function PilotCanApplyBattery( entity rodeoPilot, entity rodeoTitan ) return false entity titanSoul = rodeoTitan.GetTitanSoul() - Assert( IsValid( titanSoul ) ) + + if( !IsValid( titanSoul ) ) + return false string titanType = GetSoulTitanSubClass( titanSoul ) @@ -2358,7 +2459,7 @@ bool function ShouldThrowGrenadeInHatch( entity rodeoPilot ) return true #if MP - if ( PlayerWantsToThrowNukeGrenade( rodeoPilot ) ) + if ( PlayerWantsToThrowNukeGrenade( rodeoPilot ) || !PlayerHasMaxBatteryCount( rodeoPilot ) || GetCurrentPlaylistVarInt( "rodeo_titan_lobotomy", 0 ) == 1 ) return false #endif @@ -2433,7 +2534,26 @@ void function RodeoForceNuke( entity pilot ) // THROW RODEO RIDER OFF entity soul = titan.GetTitanSoul() soul.soul.nukeAttacker = pilot - NPC_SetNuclearPayload( titan ) + + if ( titan.IsNPC() ) + { + NPC_SetNuclearPayload( titan ) + } + else + { + GivePassive( titan, ePassives.PAS_NUCLEAR_CORE ) + + if ( PlayerHasPassive( titan, ePassives.PAS_AUTO_EJECT ) ) + TakePassive( titan, ePassives.PAS_AUTO_EJECT ) + + titan.TakeDamage( 1, pilot, pilot, damageTable ) + + if ( HasSoul( titan ) && !titan.GetTitanSoul().IsDoomed() ) + { + titan.GetTitanSoul().EnableDoomed() + titan.SetDoomed() + } + } vector ejectAngles = titan.GetAngles() ejectAngles.x = 270 @@ -2477,13 +2597,15 @@ void function OpenRodeoNukeWindow( entity player, entity titan ) player.WaitSignal( "TryNukeGrenade" ) - if ( !HasSuperRodeoGrenade( player ) ) + entity newtitan = GetTitanBeingRodeoed( player ) + + if ( !HasSuperRodeoGrenade( player ) || !IsValid( newtitan ) || !newtitan.IsTitan() || !HasSoul( newtitan ) ) return file.playersThatWantToUseRodeoGrenade[ player ] <- true MessageToPlayer( player, eEventNotifications.FD_SuperRodeoUsed ) - Rodeo_MoveBatteryDown( titan.GetTitanSoul() ) + Rodeo_MoveBatteryDown( newtitan.GetTitanSoul() ) } bool function ClientCommand_TryNukeGrenade( entity player, array args ) @@ -2493,4 +2615,4 @@ bool function ClientCommand_TryNukeGrenade( entity player, array args ) return true } -#endif +#endif \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/rodeo/sh_classic_rodeo.gnut b/Northstar.Custom/mod/scripts/vscripts/rodeo/sh_classic_rodeo.gnut index af7f4a4d2..ab7588a67 100644 --- a/Northstar.Custom/mod/scripts/vscripts/rodeo/sh_classic_rodeo.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/rodeo/sh_classic_rodeo.gnut @@ -11,6 +11,8 @@ const asset RODEO_WEAKPOINT_HITBOX_MODEL = $"models/Weapons/ammoboxes/backpack_s void function ClassicRodeo_InitPlaylistVars() { AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_TITAN", "classic_rodeo", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_TITAN", "rodeo_titan_lobotomy", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) + AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_TITAN", "pilot_battery_inventory_size", "1" ) } #if SERVER @@ -20,6 +22,7 @@ entity function CreateClassicRodeoWeakpoint( entity player, entity titan ) weakpoint.SetParent( titan, "RODEO_BATTERY" ) weakpoint.SetLocalAngles( < 90, -90, 0 > ) weakpoint.SetTakeDamageType( DAMAGE_YES ) + weakpoint.SetDamageNotifications( true ) SetTeam( weakpoint, TEAM_UNASSIGNED ) SetObjectCanBeMeleed( weakpoint, false ) weakpoint.kv.solid = 6 @@ -34,6 +37,8 @@ entity function CreateClassicRodeoWeakpoint( entity player, entity titan ) weakpoint.s.titan <- titan AddEntityCallback_OnDamaged( weakpoint, OnRodeoWeakpointDamaged ) + + return weakpoint } void function OnRodeoWeakpointDamaged( entity weakpoint, var damageInfo ) @@ -47,7 +52,10 @@ void function OnRodeoWeakpointDamaged( entity weakpoint, var damageInfo ) return // hitmarker - attacker.NotifyDidDamage( weakpoint, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamagePosition( damageInfo ), DamageInfo_GetCustomDamageType( damageInfo ) | DF_CRITICAL, damageAmount, DamageInfo_GetDamageFlags( damageInfo ), DamageInfo_GetHitGroup( damageInfo ), DamageInfo_GetWeapon( damageInfo ), DamageInfo_GetDistFromAttackOrigin( damageInfo ) ) + int customDamageType = DamageInfo_GetCustomDamageType( damageInfo ) + customDamageType = customDamageType | DF_CRITICAL + + attacker.NotifyDidDamage( weakpoint, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamagePosition( damageInfo ), customDamageType, damageAmount, DamageInfo_GetDamageFlags( damageInfo ), DamageInfo_GetHitGroup( damageInfo ), DamageInfo_GetWeapon( damageInfo ), DamageInfo_GetDistFromAttackOrigin( damageInfo ) ) // figure out damage to deal to titan entity attackerWeapon = DamageInfo_GetWeapon( damageInfo ) @@ -59,6 +67,7 @@ void function OnRodeoWeakpointDamaged( entity weakpoint, var damageInfo ) rodeoDamage = int( attackerWeapon.GetWeaponSettingInt( eWeaponVar.damage_near_value_titanarmor ) * ( attackerWeapon.GetWeaponSettingFloat( eWeaponVar.damage_headshot_scale ) * 1.5 ) ) // damage titan, make sure DF_BYPASS_SHIELD is a thing for proper behaviour - titan.TakeDamage( rodeoDamage, attacker, attackerWeapon, { damageSourceId = eDamageSourceId.rodeo, scriptType = DamageInfo_GetCustomDamageType( damageInfo ) | DF_BYPASS_SHIELD } ) + customDamageType = customDamageType | DF_BYPASS_SHIELD + titan.TakeDamage( rodeoDamage, attacker, attackerWeapon, { damageSourceId = eDamageSourceId.rodeo, scriptType = customDamageType } ) } #endif \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_3psequence_to_1p_hacks.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_3psequence_to_1p_hacks.gnut deleted file mode 100644 index 4d4d27440..000000000 --- a/Northstar.Custom/mod/scripts/vscripts/sh_3psequence_to_1p_hacks.gnut +++ /dev/null @@ -1,193 +0,0 @@ -global function FirstPersonSequenceForce1P_Init -global function FirstPersonSequenceForce1P_InitPlaylistVars - -#if SERVER - global function FirstPersonSequenceForce1P -#endif - -#if CLIENT - global function ServerCallback_HideHudForFPHackAnim -#endif - -global const string FORCE1P_PILOT_1P_ATTACHMENT = "HEADFOCUS" -global const string FORCE1P_TITAN_1P_ATTACHMENT = "HATCH_HEAD" // CHEST_LASER could be better, but is only on atlas titans - -global const string FORCE1P_PILOT_1P_HIDDEN_BODYGROUP = "head" -global const string FORCE1P_TITAN_1P_HIDDEN_BODYGROUP = "torso" - -global const string FORCE1P_PILOT_ENTITYCLASS = "npc_pilot_elite" -global const string FORCE1P_TITAN_ENTITYCLASS = "npc_titan" - -global struct Forced1PSequenceData -{ - entity player - entity camera - entity ownerProxy - entity thirdPersonProxy -} - -void function FirstPersonSequenceForce1P_Init() -{ - // atm do this no matter what playlist we're on since playlist overrides seem to get sent to clients after networkvar registration - // not nice but whatever lol - AddCallback_OnRegisteringCustomNetworkVars( FirstPersonSequenceForce1P_RegisterCustomNetworkFunctions ) -} - -void function FirstPersonSequenceForce1P_InitPlaylistVars() -{ - AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_RIFF", "fp_embark_enabled", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) -} - -void function FirstPersonSequenceForce1P_RegisterCustomNetworkFunctions() -{ - Remote_RegisterFunction( "ServerCallback_HideHudForFPHackAnim" ) -} - -#if SERVER -Forced1PSequenceData function FirstPersonSequenceForce1P( FirstPersonSequenceStruct sequence, entity player, entity other = null ) -{ - string attachment = FORCE1P_PILOT_1P_ATTACHMENT - string hiddenBodygroup = FORCE1P_PILOT_1P_HIDDEN_BODYGROUP - string entityclass = FORCE1P_PILOT_ENTITYCLASS - - if ( player.IsTitan() ) - { - attachment = FORCE1P_TITAN_1P_ATTACHMENT - hiddenBodygroup = FORCE1P_TITAN_1P_HIDDEN_BODYGROUP - entityclass = FORCE1P_TITAN_ENTITYCLASS - } - - // hide player from everyone, unlike VisibilityFlags, this won't hide children, which is way easier to deal with - player.Hide() - - Forced1PSequenceData cleanupData - cleanupData.player = player - - // for some melee sequences, player.GetAngles() will be the angles the player had before they began the melee, which can cause desyncs - // eyeangles are fine though - vector angles = player.GetAngles() - angles.y = player.EyeAngles().y - - // create the first proxy entity, this should visually be identical to the player, but only visible to them, and with head/torso hidden - // this is an npc because some firstpersonsequences use animation features that only work on npcs and pilots, not props, so need to do this - entity ownerProxy = CreateEntity( entityclass ) //CreatePropDynamic( player.GetModelName(), player.GetOrigin(), player.GetAngles() ) - ownerProxy.SetModel( player.GetModelName() ) - ownerProxy.SetValueForModelKey( player.GetModelName() ) - ownerProxy.SetOrigin( player.GetOrigin() ) - ownerProxy.SetAngles( angles ) - ownerProxy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER - ownerProxy.kv.solid = 0 // nonsolid - SetTeam( ownerProxy, player.GetTeam() ) - ownerProxy.SetOwner( player ) - ownerProxy.SetSkin( player.GetSkin() ) - ownerProxy.SetCamo( player.GetCamo() ) // note: this seems weird, doesn't set right - DispatchSpawn( ownerProxy ) - ownerProxy.SetModel( player.GetModelName() ) - ownerProxy.SetValueForModelKey( player.GetModelName() ) - ownerProxy.SetInvulnerable() - HideName( ownerProxy ) - cleanupData.ownerProxy = ownerProxy - - int bodygroupValue = 1 - if ( hiddenBodygroup == "torso" ) - bodygroupValue = 2 - - // hide annoying bodygroup - ownerProxy.SetBodygroup( ownerProxy.FindBodyGroup( hiddenBodygroup ), bodygroupValue ) - // don't play anim until later so we can do cleanup stuff - - // create the second proxy entity, this visible to everyone else - entity thirdPersonProxy = CreateEntity( entityclass ) //CreatePropDynamic( player.GetModelName(), player.GetOrigin(), player.GetAngles() ) - thirdPersonProxy.SetModel( player.GetModelName() ) - thirdPersonProxy.SetValueForModelKey( player.GetModelName() ) - thirdPersonProxy.SetOrigin( player.GetOrigin() ) - thirdPersonProxy.SetAngles( angles ) - thirdPersonProxy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE & ~ENTITY_VISIBLE_TO_OWNER - thirdPersonProxy.kv.solid = 0 // nonsolid - SetTeam( thirdPersonProxy, player.GetTeam() ) - thirdPersonProxy.SetOwner( player ) - thirdPersonProxy.SetSkin( player.GetSkin() ) - thirdPersonProxy.SetCamo( player.GetCamo() ) // note: this seems weird, doesn't set right - DispatchSpawn( thirdPersonProxy ) - thirdPersonProxy.SetModel( player.GetModelName() ) - thirdPersonProxy.SetValueForModelKey( player.GetModelName() ) - thirdPersonProxy.SetInvulnerable() - HideName( thirdPersonProxy ) - cleanupData.thirdPersonProxy = thirdPersonProxy - - if ( player.IsTitan() ) - Highlight_SetEnemyHighlight( thirdPersonProxy, "enemy_titan" ) - else - Highlight_SetEnemyHighlight( thirdPersonProxy, "enemy_player" ) - - thread FirstPersonSequence( sequence, thirdPersonProxy, other ) - - // create the viewpoint entity - if ( player.IsPlayer() ) // Check if the victim is an NPC - { - entity camera = CreateEntity( "point_viewcontrol" ) - camera.SetParent( ownerProxy, attachment ) - camera.kv.spawnflags = 56 - DispatchSpawn( camera ) - player.SetViewEntity( camera, true ) - cleanupData.camera = camera - } - - // note for potential thing that could be done - // entity e = CreatePropDynamic($"models/weapons/arms/pov_titan_light_cockpit.mdl"); e.SetParent(GetPlayerArray()[0].GetPetTitan(), "HATCH_HEAD"); e.SetOrigin(<0.75,0,-195>) - // this is so we get a cockpit in these anims, issue with it is that the cockpit seems to break alot of rendering stuff - // which really sucks since it'd be awesome to have a cockpit over these anims, really makes them better, even the client func to render through cockpits doesn't seem to work for it, just makes stuff rendering through the cockpit invisible rather than rendering in a broken way - - if ( player.IsPlayer() ) // Check if the victim is an NPC - Remote_CallFunction_NonReplay( player, "ServerCallback_HideHudForFPHackAnim" ) - // play this anim now, so we can cleanup after it's done - thread CleanupForced1PSequenceAfterAnimDone( sequence, ownerProxy, other, cleanupData ) - return cleanupData -} - -void function CleanupForced1PSequenceAfterAnimDone( FirstPersonSequenceStruct sequence, entity player, entity other, Forced1PSequenceData cleanupData ) -{ - player.EndSignal( "OnDestroy" ) - player.EndSignal( "OnAnimationDone" ) - - OnThreadEnd( function() : ( cleanupData ) - { - if ( IsValid( cleanupData.player ) && cleanupData.player.IsPlayer() ) - CleanupForced1PSequence( cleanupData ) - }) - - FirstPersonSequence( sequence, player, other ) -} - -void function CleanupForced1PSequence( Forced1PSequenceData cleanupData ) -{ - cleanupData.player.Show() - cleanupData.player.ClearViewEntity() - cleanupData.camera.Destroy() - cleanupData.ownerProxy.Destroy() - cleanupData.thirdPersonProxy.Destroy() -} -#endif - -#if CLIENT -void function ServerCallback_HideHudForFPHackAnim() -{ - // these functions just set hud positions to infront of/behind the camera, manually set them up here so they'll be far enough away so we don't see them in these anims - // in an ideal world we wouldn't even have to turn off this rui stuff because it would be parented to our camera but unfortunately we do not live in an ideal world - //thread MainHud_TurnOff_RUI( true ) - //HidePermanentCockpitRui() - RuiTopology_UpdatePos( clGlobal.topoCockpitHud, < -1000, -1000, -1000 >, < -1000, -1000, -1000 >, < -1000, -1000, -1000 > ) - RuiTopology_UpdatePos( clGlobal.topoCockpitHudPermanent, < -1000, -1000, -1000 >, < -1000, -1000, -1000 >, < -1000, -1000, -1000 > ) - - thread EnableHudOnViewRestored() -} - -void function EnableHudOnViewRestored() -{ - while ( GetViewEntity() != GetLocalClientPlayer() ) - WaitFrame() - - thread MainHud_TurnOn_RUI( true ) - ShowPermanentCockpitRui() -} -#endif \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_bleedout_damage.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_bleedout_damage.gnut index d7373a9ba..4857232d1 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_bleedout_damage.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_bleedout_damage.gnut @@ -121,6 +121,9 @@ void function OnPlayerBleedoutBegin( entity player ) { file.bleedingPlayers.append( player ) EmitSoundOnEntityOnlyToPlayer( player, player, "Player_Death_Begin" ) + NSCreateStatusMessageOnPlayer( player, "Incapacitated!", "", "incapmsg" ) + player.Signal( "RodeoOver" ) + player.ClearParent() thread PlayerBleedoutGracePeriod( player ) @@ -140,6 +143,7 @@ void function PlayerBleedoutGracePeriod( entity player ) }) player.SetInvulnerable() + player.SetHealth( player.GetMaxHealth() ) wait 0.25 } @@ -148,13 +152,32 @@ void function TrackPlayerBleedout( entity player ) player.EndSignal( "OnDeath" ) player.EndSignal( "OnDestroy" ) - OnThreadEnd( function() : ( player ) + bool playerCouldEmbark = CanEmbark( player ) + + OnThreadEnd( function() : ( player, playerCouldEmbark ) { file.bleedingPlayers.remove( file.bleedingPlayers.find( player ) ) + + if( IsValidPlayer( player ) ) + { + if ( playerCouldEmbark ) + Embark_Allow( player ) + + Rodeo_Allow( player ) + SyncedMelee_Enable( player ) + Leech_Allow( player ) + NSDeleteStatusMessageOnPlayer( player, "incapmsg" ) + } }) WaitFrame() // wait a frame, since this gets called before this status effect is added + if( playerCouldEmbark ) + Embark_Disallow( player ) + + Rodeo_Disallow( player ) + SyncedMelee_Disable( player ) + Leech_Disallow( player ) while ( StatusEffect_Get( player, eStatusEffect.bleedoutDOF ) != 0 ) WaitFrame() } diff --git a/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut b/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut index 814e44303..add81c005 100644 --- a/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut @@ -164,10 +164,18 @@ void function AddPanelToTitan( entity soul ) var model = Dev_GetPlayerSettingAssetByKeyField_Global( settings, "hatchmodel" ) if ( model == $"" ) return + expect asset( model ) entity rodeoPanel = CreatePropDynamic( model ) - + + bool classicRodeo = MP && GetCurrentPlaylistVarInt( "classic_rodeo", 0 ) == 1 + if ( classicRodeo ) + { + Highlight_SetEnemyHighlight( rodeoPanel, "titan_weakpoint" ) + Highlight_ClearEnemyHighlight( rodeoPanel ) + } + string titanType = GetSoulTitanSubClass( soul ) rodeoPanel.NotSolid() @@ -195,10 +203,13 @@ void function UpdateTitanPanel( entity soul ) var model = Dev_GetPlayerSettingAssetByKeyField_Global( settings, "hatchmodel" ) if ( model == $"" ) return + expect asset( model ) entity batteryContainer = soul.soul.batteryContainer - + if( !IsValid( batteryContainer ) ) + return + if ( soul.soul.batteryContainerBeingUsed ) return diff --git a/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan_embark.gnut b/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan_embark.gnut index 4fd4d0c67..5e3e39d86 100644 --- a/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan_embark.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan_embark.gnut @@ -931,8 +931,6 @@ function TitanEmbark_PlayerEmbarks( entity player, entity titan, table e ) //thread DelayedDisableEmbarkPlayerHud( player, sequence ) - AddAnimEvent( player, "phase_shift_start", PhaseEmbarkPhaseStart ) - AddAnimEvent( player, "phase_shift_stop", PhaseEmbarkPhaseStop ) AddAnimEvent( titan, "cockpit_light_start", CockpitLightStart ) AddAnimEvent( titan, "cockpit_light_stop", CockpitLightStop ) @@ -952,10 +950,17 @@ function TitanEmbark_PlayerEmbarks( entity player, entity titan, table e ) ) #if MP - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 && !doFirstPersonAnim ) - FirstPersonSequenceForce1P( sequence, player, titan ) + if ( !doFirstPersonAnim && ShouldRunFirstPersonSequence( player, true, false ) ) + { + FirstPersonSequenceForce1P( sequence, player, titan ) + AddAnimEvent( player, "phase_shift_start", PhaseEmbarkPhaseStart_FP ) + AddAnimEvent( player, "phase_shift_stop", PhaseEmbarkPhaseStop_FP ) + } #endif + AddAnimEvent( player, "phase_shift_start", PhaseEmbarkPhaseStart ) + AddAnimEvent( player, "phase_shift_stop", PhaseEmbarkPhaseStop ) + thread FirstPersonSequence( sequence, player, titan ) // EmitDifferentSoundsOnEntityForPlayerAndWorld( firstPersonAudio, thirdPersonAudio, titan, player ) @@ -1015,7 +1020,13 @@ void function Embark_DelayedFadeOut( entity player, entity titan, float delay ) wait delay - EMBARK_FADE_TIME - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 0 ) + bool firstPerson = false + + #if MP + firstPerson = ShouldRunFirstPersonSequence( player, true, false ) + #endif + + if ( firstPerson ) { ScreenFadeToBlack( player, EMBARK_FADE_TIME, EMBARK_FADE_TIME + 0.2 ) // a little extra so we stay black wait EMBARK_FADE_TIME @@ -1088,8 +1099,15 @@ void function PhaseEmbarkPhaseStart( entity player ) PlayPhaseShiftDisappearFX( player ) EmitSoundOnEntity( player, "pilot_phaseembark_activate_3p" ) - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) - player.PhaseShiftBegin( 0.0, 0.2 ) + thread PhaseEmbarkPhaseCleanup( player ) +} + +void function PhaseEmbarkPhaseStart_FP( entity player ) +{ + player.MakeInvisible() + PlayPhaseShiftDisappearFX( player ) + EmitSoundOnEntity( player, "pilot_phaseembark_activate_3p" ) + player.PhaseShiftBegin( 0.0, 0.2 ) thread PhaseEmbarkPhaseCleanup( player ) } @@ -1116,9 +1134,14 @@ void function PhaseEmbarkPhaseStop( entity player ) Signal( player, "PhaseEmbarkPhaseStop" ) PlayPhaseShiftDisappearFX( player ) EmitSoundOnEntity( player, "pilot_phaseembark_end_3p" ) - - if ( GetCurrentPlaylistVarInt( "fp_embark_enabled", 0 ) == 1 ) - player.PhaseShiftCancel() +} + +void function PhaseEmbarkPhaseStop_FP( entity player ) +{ + Signal( player, "PhaseEmbarkPhaseStop" ) + PlayPhaseShiftDisappearFX( player ) + EmitSoundOnEntity( player, "pilot_phaseembark_end_3p" ) + player.PhaseShiftCancel() } function ShouldSkipAheadIntoEmbark( standing, player, titan, e ) diff --git a/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut index 5a7d80b76..7d1d80d66 100644 --- a/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut @@ -2,7 +2,10 @@ global function NSCustomModSettings void function NSCustomModSettings() { - ModSettings_AddModTitle( "Northstar Custom" , 2 ) + ModSettings_AddModTitle( "Northstar Custom", 2 ) ModSettings_AddModCategory( "Event Models" ) ModSettings_AddEnumSetting( "ns_show_event_models", "Show Event Models", [ "#SETTING_OFF", "#SETTING_ON" ], 2 ) -} + ModSettings_AddModCategory( "First Person Anims" ) + ModSettings_AddEnumSetting( "ns_embark_style", "First Person Embarks", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], 2 ) + ModSettings_AddEnumSetting( "ns_execution_style", "First Person Executions", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], 2 ) +} \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titancore_lasercannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titancore_lasercannon.nut index d8e6b0ac2..4e672a5ab 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titancore_lasercannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titancore_lasercannon.nut @@ -50,7 +50,7 @@ void function LaserCore_OnPlayedOrNPCKilled( entity victim, entity attacker, var return entity soul = attacker.GetTitanSoul() - if ( !IsValid( soul ) ) + if ( !IsValid( soul ) || attacker.GetPlayerNetInt( EARNMETER_MODE ) != eEarnMeterMode.CORE_ACTIVE ) return entity weapon = attacker.GetOffhandWeapon( OFFHAND_EQUIPMENT ) @@ -74,12 +74,31 @@ void function LaserCore_OnPlayedOrNPCKilled( entity victim, entity attacker, var duration = 3.0 float coreFrac = min( 1.0, remainingTime / duration ) //Defensive fix for this sometimes resulting in a negative value. - if ( coreFrac > 0.0 ) + if ( coreFrac > 0.01 ) { soul.SetTitanSoulNetFloat( "coreExpireFrac", coreFrac ) soul.SetTitanSoulNetFloatOverTime( "coreExpireFrac", 0.0, remainingTime ) soul.SetCoreChargeExpireTime( remainingTime + curTime ) + } +} + +void function LaserCannonPassiveDuration( entity soul, entity weapon ) +{ + entity titan = soul.GetTitan() + + soul.EndSignal( "OnDestroy" ) + weapon.EndSignal( "OnDestroy" ) + soul.EndSignal( "OnDeath" ) + titan.EndSignal( "CoreEnd" ) + + wait 1.0 + + float coreFrac = soul.GetTitanSoulNetFloat( "coreExpireFrac" ) + while( IsValid( weapon ) && coreFrac > 0.01 ) + { + coreFrac = soul.GetTitanSoulNetFloat( "coreExpireFrac" ) weapon.SetSustainedDischargeFractionForced( coreFrac ) + WaitFrame() } } #endif @@ -202,6 +221,7 @@ bool function OnAbilityStart_LaserCannon( entity weapon ) EmitSoundOnEntityOnlyToPlayer( player, player, LASER_FIRE_SOUND_1P ) EmitSoundOnEntityExceptToPlayer( player, player, "Titan_Core_Laser_FireStart_3P" ) EmitSoundOnEntityExceptToPlayer( player, player, "Titan_Core_Laser_FireBeam_3P" ) + thread LaserCannonPassiveDuration( soul, weapon ) } else { diff --git a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt index 0ef3ed33b..0f7995418 100644 --- a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt +++ b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt @@ -100,6 +100,17 @@ WeaponData "allow_headshots" "0" "bypass_semiauto_hold_protection" "1" "vortex_drain" ".15" + "charge_sound_1p" "MegaTurret_Laser_ChargeUp_3P" + "charge_sound_3p" "MegaTurret_Laser_ChargeUp_3P" + "charge_sound_stop_when_full" "1" + "charge_sound_seek_to_charge_fraction" "1" + "charge_drain_sound_1p" "Weapon_ChargeRifle_WindDown_1P" + "charge_drain_sound_3p" "Weapon_ChargeRifle_WindDown_3P" + "charge_drain_sound_stop_when_empty" "1" + "charge_drain_sound_seek_to_charge_fraction" "1" + "fire_sound_1_player_1p" "MegaTurret_Laser_Fire_3P" + "fire_sound_1_player_3p" "MegaTurret_Laser_Fire_3P" + "fire_sound_1_npc" "MegaTurret_Laser_Fire_3P" "charge_effect_1p" "wpn_arc_cannon_charge_fp" "charge_effect_3p" "wpn_arc_cannon_charge" "charge_effect_attachment" "muzzle_flash" diff --git a/Northstar.CustomServers/keyvalues/playlists_v2.txt b/Northstar.CustomServers/keyvalues/playlists_v2.txt index 823cf720d..4a0d66ee0 100644 --- a/Northstar.CustomServers/keyvalues/playlists_v2.txt +++ b/Northstar.CustomServers/keyvalues/playlists_v2.txt @@ -11,4 +11,4 @@ playlists } } } -} +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index be1a2f37d..7027704cd 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -21,6 +21,14 @@ "Name": "ns_private_match_last_map", "DefaultValue": "mp_forwardbase_kodai" }, + { + "Name": "ns_private_match_auto_rotation_start", + "DefaultValue": "0" + }, + { + "Name": "ns_private_match_map_rotation", + "DefaultValue": "" + }, { "Name": "ns_private_match_only_host_can_change_settings", "DefaultValue": "0" @@ -34,8 +42,8 @@ "DefaultValue": "15" }, { - "Name": "ns_private_match_override_maxplayers", - "DefaultValue": "1" + "Name": "ns_maxplayers_override", + "DefaultValue": "0" }, { "Name": "ns_should_log_unknown_clientcommands", @@ -54,6 +62,18 @@ "Name": "ns_allow_team_change", "DefaultValue": "1", "Flags": "REPLICATED" + }, + { + "Name": "ns_autobalance_teams_on_player_join", + "DefaultValue": "0" + }, + { + "Name": "ns_use_phase_fix", + "DefaultValue": "1" + }, + { + "Name": "ns_server_idle_time_refresh_max_time", + "DefaultValue": "240" } ], "Scripts": [ @@ -166,7 +186,17 @@ } }, { - "Path": "sh_northstar_http_requests.gnut", + "Path": "drop_battery_command.nut", + "RunOn": "( CLIENT || SERVER ) && MP", + "ClientCallback": { + "After": "DropBatteryCommand_Init" + }, + "ServerCallback": { + "After": "DropBatteryCommand_Init" + } + }, + { + "Path": "sh_northstar_http_requests.gnut", "RunOn": "CLIENT || SERVER || UI" }, { diff --git a/Northstar.CustomServers/mod/playlists_v2.txt b/Northstar.CustomServers/mod/playlists_v2.txt new file mode 100644 index 000000000..398b6ea86 --- /dev/null +++ b/Northstar.CustomServers/mod/playlists_v2.txt @@ -0,0 +1,5684 @@ +playlists +{ + version stable + versionNum 3325 // Never forget to bump this for every playlist update. + Gamemodes + { + defaults + { + vars + { + pve_menu 0 + enable_emotes 0 + boost_store_mode off + + pick_loadout_extension 0 + pick_loadout_every_round 0 + pick_loadout_warp_sound 1 + tts_menu_join_in_progress 0 + tts_menu_show_score 1 + ingame_menu_fd_mode 0 + limited_editions_available 1 + + ai_attack_tethers 1 + enable_sun_flare_mp_thaw 0 + enable_sun_flare_mp_forwardbase_kodai 0 + enable_sun_flare_mp_colony02 0 + enable_coliseum_updates 1 + enable_coliseum_party 1 + enable_spectre_hacking 0 + maphack_on_minimap_only 0 + mp_angel_city_available 1 + angel_city_replacement groundwar + angel_city_replacement_index 8 + skyshow_enabled 0 + loadout_selection_enabled 1 + ai_kill_credit 3 + always_enable_autotitans 1 + at_turrets_enabled 1 + burn_meter_enabled 1 + classic_mp 1 + cmdlineMapLoad 0 + em_npc_fast_kills 20 + em_npc_kills 20 + em_player_fast_kills 5 + em_player_kills 8 + enable_titanfalls 1 + evac_dropship_kill_credit 60 + event_airdrops_enabled 0 + event_airdrops_respawnTime 180 + firstpersonspectate_enabled 1 + gamemode_uses_custom_countdown 0 + hud_score_enabled 1 + infinite_doomed_state 1 + loadout_grace_period 20.0 + lobby_countdown 60 + lobby_countdown_min 30 + max_players 16 + max_teams 2 + matchLossProtectionThreshold 10 + megaturret_kill_credit 20 + minimap_sonar_pulse_on_respawn 0 + player_embark_in_solid_checks 1 + player_kill_credit 10 + power_ups_enabled 0 + r2_titan_models 1 + ranked_wlpct_at 0.05 + ranked_wlpct_cp 0.15 + ranked_wlpct_ctf 0.15 + ranked_wlpct_def 0.1 + ranked_wlpct_lts 0.15 + ranked_wlpct_mfd 0.1 + ranked_wlpct_ps 0.05 + ranking_supported 1 + riff_ai_lethality 1 + riff_allow_npcs 2 + riff_ammo_limit 0 + riff_elimination 0 + riff_floorislava 0 + riff_minimap_state 0 + riff_osp 0 + riff_spawn_as_titan 0 + riff_titan_availability 0 + riff_titan_exit_enabled 0 + riff_titan_queue 0 + riff_wave_spawn 0 + rodeo_battery_disembark_to_pickup 1 + maxExtraRounds -1 + rts_style_health_bars 1 + run_evac 0 + script_leak 0 + spectre_kill_credit 9 + target_health_bar 1 + titan_build_credit_enabled 1 + titan_build_time 180 + titan_build_time_use_set_file 0 + titan_core_build_time 200 + titan_core_from_titan_damage 1 + titan_doomstate_variation default + titan_health_bar_display default + titan_health_chicklet_fx 0 + titan_kill_credit 30 + titan_mode_change_allowed 1 + titan_rebuild_time 180 + titan_shield_decay 0 + titan_shield_regen 0 + titan_spawn_deploy_enabled 1 + vortex_blocks_melee 0 + waiting_for_players_countdown_seconds 0 + waiting_for_players_percentage_desired 70 + waiting_for_players_timeout_seconds 45 + wait_before_restarting_matchmaking_time 20 + gm_hardcore_settings 0 + spawn_zone_enabled 0 + is_e3_mode 0 + fast_tdm 0 + arena_loadout 0 + fd_difficulty 0 + featured_mode_amped_tacticals 0 + featured_mode_tactikill 0 + featured_mode_all_grapple 0 + featured_mode_all_holopilot 0 + featured_mode_all_phase 0 + featured_mode_all_ticks 0 + featured_mode_rocket_arena 0 + featured_mode_turbo_titans 0 + featured_mode_shotguns_snipers 0 + + // defaults for private_match settings, as all gamemodes don't explicitly set their own + boosts_enabled 0 + respawn_delay 0.0 + + //No longer used? No references in script for these + xp2coins_modifier 0.1 + titan_shield_health 0 + titan_rodeo_variation 1 + titan_segmented_health 0 + titan_health_regen 0 + titan_burncard_rate 28 + shop_price_modifier 1.0 + show_enemy_death_icons 0 + show_friendly_icon 1 + rtdm_roundscorelimit 2 + rtdm_roundtimelimit 4 + rtdm_scorelimit 20 + prematch_time 30 + always_titan 0 + amped_capture_points 0 + nwrp_enabled 1 + pilot_burncard_rate 55 + kill_for_titan 6 + hud_weapons_enabled 1 + grunt_burncard_rate 95 + bc_base_cards 46 + bc_stash_bonus_per_gen 6 + burncards_enabled 0 + cinematic_mode 0 + coins_bc_sale_modifier 1.0 + coins_earn_modifier 1.0 + em_decay_hold 10 + force_quick_play 0 + //End of list + + falldamage 0 + falldamage_min_distance 20 + falldamage_max_distance 60 + falldamage_max_damage 100 + + + // Event defaults + double_xp_enabled 0 + + faq_patchnotes_version 11 + faq_patchnotes_count 10 + + faq_community_version 10 // Yes we have looked into the lobby issues. + faq_community_url_00 "https://www.youtube.com/embed/SbdQPdaPme4?autoplay=1" + faq_community_url_01 "https://forums.titanfall.com/en-us/discussion/14073/postcards-from-the-frontier-the-patch-notes#latest" + faq_community_url_02 "https://www.youtube.com/embed/KyywlZHh3-Q?autoplay=1" + faq_community_url_03 "https://www.youtube.com/embed/1LAlKi6E8DY?autoplay=1" + faq_community_url_04 "https://www.youtube.com/embed/pzmrZBiLyhE?autoplay=1" + faq_community_url_05 "https://www.youtube.com/embed/XBP3Ic0UiQY?autoplay=1" + faq_community_url_06 "https://gfycat.com/gifs/detail/ScornfulAnyHamadryad" + faq_community_url_07 "https://www.youtube.com/embed/fE7_tVG_t28?autoplay=1" + faq_community_url_08 "https://www.youtube.com/embed/RO7QJ5YEa24?autoplay=1" + faq_community_url_09 "https://www.youtube.com/embed/rMeaxj8k_3U?autoplay=1" + faq_community_url_10 "https://www.youtube.com/embed/JKiuY3Ocwzo?autoplay=1" + faq_community_url_11 "https://www.youtube.com/embed/fCCckqclBoA?autoplay=1" + faq_community_url_12 "https://www.youtube.com/embed/4MMtDSrcXYU?autoplay=1" + faq_community_url_13 "http://www.youtube.com/embed/I_6hViuy3kc?autoplay=1" + faq_community_url_14 "http://www.youtube.com/embed/Wtu3fUs9i7M?autoplay=1" + faq_community_url_15 "http://www.youtube.com/embed/EXwdWuSuiYA?autoplay=1" + faq_community_url_16 "http://www.youtube.com/embed/nHvoaAAhGno?autoplay=1" + faq_community_count 17 + + mixtape_matchmaking 1 // 0 = old style, 1 = new style + mixtape_version 2 // bump to re-trigger the "NEW!" notify. + mixtape_checkbox_memory_version 2 // bump to re-enable all checkboxes + mixtape_skip_button 0 // disable to not show the 'Y Skip' prompt + mixtape_onboarding "aitdm,cp,aitdm,cp,ffa " + + gamemode_name "" + gamemode_hint "" + gamemode_score_hint "" + gamemode_bullet_001 "" + gamemode_bullet_002 "" + gamemode_bullet_003 "" + gamemode_bullet_004 "" + gamemode_bullet_005 "" + + idlekick_minutes 3 + idlekick_min_alive_seconds 40 + + fd_tutorial_title "#WATCH_TUTORIAL" + fd_tutorial_url "https://www.youtube.com/watch?v=8wS8NQ0XW-w" + + "generic_dialog_header_30" "#MATCHMAKING_PENALTY_ACTIVE" + "generic_dialog_message_36" "#MATCHMAKING_PENALTY_GE_5" + "generic_dialog_message_35" "#MATCHMAKING_PENALTY_5" + "generic_dialog_message_34" "#MATCHMAKING_PENALTY_4" + "generic_dialog_message_33" "#MATCHMAKING_PENALTY_3" + "generic_dialog_message_32" "#MATCHMAKING_PENALTY_2" + "generic_dialog_message_31" "#MATCHMAKING_PENALTY_1" + } + maps + { + mp_black_water_canal 1 + mp_complex3 1 + mp_crashsite3 1 + mp_drydock 1 + mp_eden 1 + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 + mp_wargames 1 + mp_glitch 1 + mp_rise 1 + } + } + at + { + inherit defaults + vars + { + name #PL_attrition + lobbytitle #PL_attrition_lobby + description #PL_attrition_desc + hint #PL_attrition_hint + abbreviation #PL_attrition_abbr + em_player_fast_kills 12 + em_player_kills 15 + max_players 10 + riff_allow_npcs 1 + scorelimit 5000 + suddendeath_timelimit 2 + timelimit 15 + titan_build_time 240 + titan_rebuild_time 240 + spawn_zone_enabled 1 + color "183 60 0 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_AT + gamemode_bullet_001 #GAMEMODE_BULLET_AT_001 + gamemode_bullet_002 #GAMEMODE_BULLET_AT_002 + gamemode_bullet_003 #GAMEMODE_BULLET_AT_003 + gamemode_bullet_004 #GAMEMODE_BULLET_AT_004 + gamemode_bullet_005 #GAMEMODE_BULLET_AT_005 + } + } + coliseum + { + inherit defaults + vars + { + name #PL_coliseum + lobbytitle #PL_coliseum_lobby + description #PL_coliseum_desc + hint #PL_coliseum_hint + image coliseum + classic_mp 1 + infinite_doomed_state 0 + power_ups_enabled 1 + roundscorelimit 3 + roundtimelimit 3.0 + suddendeath_timelimit 0.5 + max_players 2 + scorelimit 3 + timelimit 15 + loadout_selection_enabled 0 + waiting_for_players_countdown_seconds 10 + waiting_for_players_percentage_desired 100 + waiting_for_players_timeout_seconds 60 + + color "88 151 220 255" + + fast_set 1 + custom_pilot_loadout 1 + pilot_loadout_primary "mp_weapon_lstar" + pilot_loadout_primary_attachment "" + pilot_loadout_primary_mod1 "" + pilot_loadout_primary_mod2 "" + pilot_loadout_primary_mod3 "" + pilot_loadout_secondary "mp_weapon_softball" + pilot_loadout_secondary_mod1 "" + pilot_loadout_secondary_mod2 "" + pilot_loadout_secondary_mod3 "" + pilot_loadout_weapon3 "" + pilot_loadout_weapon3_mod1 "" + pilot_loadout_weapon3_mod2 "" + pilot_loadout_weapon3_mod3 "" + pilot_loadout_melee "melee_pilot_sword" + pilot_loadout_special "mp_ability_heal" + pilot_loadout_ordnance "mp_weapon_frag_drone" + pilot_loadout_passive1 "pas_fast_health_regen" + pilot_loadout_passive2 "pas_wallhang" + } + maps + { + mp_coliseum 1 + mp_coliseum_column 1 + } + } + cp + { + inherit defaults + vars + { + name #PL_hardpoint + lobbytitle #PL_hardpoint_lobby + description #PL_hardpoint_desc + hint #PL_hardpoint_hint + abbreviation #PL_hardpoint_abbr + image cp + amped_capture_points 1 + scorelimit 400 + suddendeath_timelimit 2 + timelimit 10 + max_players 12 + color "161 204 255 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_CP + gamemode_bullet_001 #GAMEMODE_BULLET_CP_001 + gamemode_bullet_002 #GAMEMODE_BULLET_CP_002 + gamemode_bullet_003 #GAMEMODE_BULLET_CP_003 + gamemode_bullet_004 #GAMEMODE_BULLET_CP_004 + gamemode_bullet_005 #GAMEMODE_BULLET_CP_005 + } + } + ctf + { + inherit defaults + vars + { + name #PL_capture_the_flag + lobbytitle #PL_capture_the_flag_lobby + description #PL_capture_the_flag_desc + hint #PL_capture_the_flag_hint + abbreviation #PL_capture_the_flag_abbr + image ctf + respawn_delay 8 + scorelimit 5 + suddendeath_timelimit 2 + timelimit 12 + max_players 10 + phase_shift_drop_flag 1 + ctf_flag_return_time 1 + color "0 119 245 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_CTF + gamemode_bullet_001 #GAMEMODE_BULLET_CTF_001 + gamemode_bullet_002 #GAMEMODE_BULLET_CTF_002 + gamemode_bullet_003 #GAMEMODE_BULLET_CTF_003 + gamemode_bullet_004 #GAMEMODE_BULLET_CTF_004 + gamemode_bullet_005 #GAMEMODE_BULLET_CTF_005 + } + } + ffa + { + inherit defaults + vars + { + name #PL_ffa + lobbytitle #PL_ffa_lobby + description #PL_ffa_desc + hint #PL_ffa_hint + abbreviation #PL_ffa_abbr + image ffa + at_turrets_enabled 1 + max_players 12 + max_teams 12 + scorelimit 25 + waiting_for_players_countdown_seconds 1 + waiting_for_players_percentage_desired 10 + color "246 127 1 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_FFA + gamemode_bullet_001 #GAMEMODE_BULLET_FFA_001 + gamemode_bullet_002 #GAMEMODE_BULLET_FFA_002 + gamemode_bullet_003 #GAMEMODE_BULLET_FFA_003 + gamemode_bullet_004 #GAMEMODE_BULLET_FFA_004 + gamemode_bullet_005 #GAMEMODE_BULLET_FFA_005 + } + } + fra + { + inherit defaults + vars + { + name #PL_fra + lobbytitle #PL_fra_lobby + description #PL_fra_desc + hint #PL_fra_hint + abbreviation #PL_fra_abbr + image ffa + at_turrets_enabled 1 + min_players 6 + max_players 12 + max_teams 12 + scorelimit 35 + waiting_for_players_countdown_seconds 1 + waiting_for_players_percentage_desired 10 + earn_meter_tick_disabled 1 + color "254 184 0 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_FFA + gamemode_bullet_001 #GAMEMODE_BULLET_FFA_001 + gamemode_bullet_002 #GAMEMODE_BULLET_FFA_002 + gamemode_bullet_003 #GAMEMODE_BULLET_FFA_003 + gamemode_bullet_004 #GAMEMODE_BULLET_FFA_004 + gamemode_bullet_005 #GAMEMODE_BULLET_FFA_005 + } + } + lts + { + inherit defaults + vars + { + name #PL_last_titan_standing + lobbytitle #PL_last_titan_standing_lobby + description #PL_last_titan_standing_desc + hint #PL_last_titan_standing_hint + abbreviation #PL_last_titan_standing_abbr + image lts + pick_loadout_extension 20.0 + pick_loadout_every_round 1 + pick_loadout_warp_sound 0 + tts_menu_join_in_progress 0 + tts_menu_show_score 1 + loadout_grace_period 0.0 + max_players 10 + roundscorelimit 3 + roundtimelimit 3.0 + scorelimit 0 + timelimit 3.0 + waiting_for_players_percentage_desired 100 + waiting_for_players_countdown_seconds 30 + maxExtraRounds 3 + color "128 128 128 255" + + idlekick_minutes 1 + + gamemode_score_hint #GAMEMODE_SCORE_HINT_LTS + gamemode_bullet_001 #GAMEMODE_BULLET_LTS_001 + gamemode_bullet_002 #GAMEMODE_BULLET_LTS_002 + gamemode_bullet_003 #GAMEMODE_BULLET_LTS_003 + gamemode_bullet_004 #GAMEMODE_BULLET_LTS_004 + gamemode_bullet_005 #GAMEMODE_BULLET_LTS_005 + } + } + ps + { + inherit defaults + vars + { + name #PL_pilot_skirmish + lobbytitle #PL_pilot_skirmish_lobby + description #PL_pilot_skirmish_desc + hint #PL_pilot_skirmish_hint + abbreviation #PL_pilot_skirmish_abbr + image ps + scorelimit 25 + timelimit 10 + max_players 16 + spawn_zone_enabled 1 + color "193 23 23 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_PS + gamemode_bullet_001 #GAMEMODE_BULLET_PS_001 + gamemode_bullet_002 #GAMEMODE_BULLET_PS_002 + gamemode_bullet_003 #GAMEMODE_BULLET_PS_003 + gamemode_bullet_004 #GAMEMODE_BULLET_PS_004 + gamemode_bullet_005 #GAMEMODE_BULLET_PS_005 + } + } + tdm + { + inherit defaults + vars + { + name #PL_pilot_hunter + lobbytitle #PL_pilot_hunter_lobby + description #PL_pilot_hunter_desc + hint #PL_pilot_hunter_hint + abbreviation #PL_pilot_hunter_abbr + image tdm + scorelimit 75 + suddendeath_timelimit 2 + timelimit 10 + max_players 12 + gm_hardcore_settings 0 + spawn_zone_enabled 1 + color "60 183 0 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM + gamemode_bullet_001 #GAMEMODE_BULLET_TDM_001 + gamemode_bullet_002 #GAMEMODE_BULLET_TDM_002 + gamemode_bullet_003 #GAMEMODE_BULLET_TDM_003 + gamemode_bullet_004 #GAMEMODE_BULLET_TDM_004 + gamemode_bullet_005 #GAMEMODE_BULLET_TDM_005 + } + } + ttdm + { + inherit defaults + vars + { + name #PL_titan_brawl + lobbytitle #PL_titan_brawl_lobby + description #PL_titan_brawl_desc + hint #PL_titan_brawl_hint + abbreviation #PL_titan_brawl_abbr + image lts + scorelimit 30 + suddendeath_timelimit 2 + timelimit 10 + max_players 10 + respawn_delay 10 + color "23 193 23 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_TTDM + gamemode_bullet_001 #GAMEMODE_BULLET_TTDM_001 + gamemode_bullet_002 #GAMEMODE_BULLET_TTDM_002 + gamemode_bullet_003 #GAMEMODE_BULLET_TTDM_003 + gamemode_bullet_004 #GAMEMODE_BULLET_TTDM_004 + gamemode_bullet_005 #GAMEMODE_BULLET_TTDM_005 + } + } + aitdm + { + inherit defaults + vars + { + name "#PL_aitdm" + lobbytitle #PL_aitdm_lobby + description #PL_aitdm_desc + hint #PL_aitdm_hint + abbreviation #PL_aitdm_abbr + scorelimit 650 + suddendeath_timelimit 2 + timelimit 15 + max_players 12 + gm_hardcore_settings 0 + spawn_zone_enabled 0 + earn_meter_tick_frac 0 + escalation_enabled 1 + skyshow_enabled 1 + riff_allow_npcs 1 + enable_spectre_hacking 1 + color "88 220 151 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM + gamemode_bullet_001 #GAMEMODE_BULLET_TDM_001 + gamemode_bullet_002 #GAMEMODE_BULLET_TDM_002 + gamemode_bullet_003 #GAMEMODE_BULLET_TDM_003 + gamemode_bullet_004 #GAMEMODE_BULLET_TDM_004 + gamemode_bullet_005 #GAMEMODE_BULLET_TDM_005 + } + } + mfd + { + inherit defaults + vars + { + name #PL_marked_for_death + lobbytitle #PL_marked_for_death_lobby + description #PL_marked_for_death_desc + hint #PL_marked_for_death_hint + abbreviation #PL_marked_for_death_abbr + image mfd + scorelimit 5 + timelimit 12 + max_players 12 + gm_hardcore_settings 0 + spawn_zone_enabled 1 + earn_meter_tick_rate 3.6 + earn_meter_pilot_multiplier 0.8 + color "0 245 119 255" + + gamemode_score_hint #GAMEMODE_SCORE_HINT_MFD + } + } + speedball + { + inherit defaults + vars + { + name #PL_live_fire + lobbytitle #PL_live_fire_lobby + description #PL_live_fire_desc + hint #PL_speedball_hint + abbreviation #PL_live_fire_abbr + image lf + scorelimit 5 + roundscorelimit 5 + roundtimelimit 1.0 + suddendeath_timelimit 0 + timelimit 12 + max_players 12 + maxExtraRounds 3 + phase_shift_drop_flag 1 + ctf_flag_return_time 1 + color "127 246 1 255" + + idlekick_minutes 1 + idlekick_min_alive_seconds 20 + + gamemode_score_hint #GAMEMODE_SCORE_HINT_SPEEDBALL + gamemode_bullet_001 #GAMEMODE_BULLET_PS_001 + gamemode_bullet_002 #GAMEMODE_BULLET_PS_002 + gamemode_bullet_003 #GAMEMODE_BULLET_PS_003 + gamemode_bullet_004 #GAMEMODE_BULLET_PS_004 + gamemode_bullet_005 #GAMEMODE_BULLET_PS_005 + } + } + fd + { + inherit defaults + vars + { + hint #PL_fd_desc + ingame_menu_fd_mode 1 + pick_loadout_extension 30.0 + pick_loadout_every_round 0 + pick_loadout_warp_sound 1 + tts_menu_join_in_progress 1 + tts_menu_show_score 0 + roundscorelimit 3 + roundtimelimit 60.0 + em_player_fast_kills 12 + em_player_kills 15 + max_players 4 + riff_allow_npcs 1 + scorelimit 2500 + suddendeath_timelimit 2 + titan_build_time 240 + titan_rebuild_time 240 + spawn_zone_enabled 1 + respawn_delay 4 + timelimit 30 + skyshow_enabled 1 + max_teams 1 + riff_wave_spawn 4 + wave_spawn_interval 25 + boost_store_mode fd + titan_loadout_experiment 0 + use_new_tacticals 0 + earn_meter_tick_frac 0 + ai_attack_tethers 0 + waiting_for_players_percentage_desired 100 + fd_titan_health_adjust 0 + fd_reaper_health_adjust 0 + fd_mortar_spectre_setup_time 5 + fd_grunt_at_weapon_users 0 + fd_grunt_shield_captains 0 + fd_player_damage_scalar 1.0 + fd_harvester_health 25000 + fd_harvester_shield 6000 + fd_harvester_regen_delay 10.0 + fd_harvester_regen_time 10.0 + fd_money_per_round 600 + fd_wave_buy_time 60.0 + fd_pro_titan_shields 0 + fd_at_unlimited_ammo 1 + enable_match_progress_update 0 + color "0 184 254 255" + aegis_upgrades 1 + + riff_team_share_earn_meter 2 + riff_team_share_earn_meter_scale 0.25 + earn_meter_titan_multiplier 0.5 + earn_meter_pilot_multiplier 0.5 + + override_boost_cost_burnmeter_harvester_shield -1 + override_boost_cost_burnmeter_arc_trap -1 + override_boost_cost_burnmeter_ap_turret_weapon_infinite -1 + override_boost_cost_burnmeter_rodeo_grenade -1 + override_boost_cost_burnmeter_amped_weapons_permanent -1 + override_boost_cost_burnmeter_instant_battery -1 + + gamemode_score_hint #GAMEMODE_SCORE_HINT_FD + gamemode_bullet_001 #GAMEMODE_BULLET_FD_001 + gamemode_bullet_002 #GAMEMODE_BULLET_FD_002 + gamemode_bullet_003 #GAMEMODE_BULLET_FD_003 + gamemode_bullet_004 #GAMEMODE_BULLET_FD_004 + gamemode_bullet_005 #GAMEMODE_BULLET_FD_005 + } + maps + { + mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_homestead 1 + mp_wargames 1 + mp_rise 1 + mp_thaw 1 + mp_drydock 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 + } + } + fd_easy + { + inherit fd + vars + { + name #PL_fd_easy + lobbytitle #PL_fd_easy_lobby + description #PL_fd_easy_desc + abbreviation #FD_DIFFICULTY_EASY + + image fd_easy + fd_difficulty 0 + boost_store_team_reserve 1 + fd_titan_health_adjust -5000 + fd_reaper_health_adjust -2000 + fd_mortar_spectre_setup_time 10 + fd_grunt_at_weapon_users 0 + fd_grunt_shield_captains 0 + fd_player_damage_scalar 1.0 + fd_money_per_round 700 + fd_pro_titan_shields 0 + fd_harvester_shield 6000 + fd_at_unlimited_ammo 1 + + earn_meter_pilot_multiplier 0.7 + } + } + fd_normal + { + inherit fd + vars + { + name #PL_fd_normal + lobbytitle #PL_fd_normal_lobby + description #PL_fd_normal_desc + abbreviation #FD_DIFFICULTY_NORMAL + image fd_normal + + fd_difficulty 1 + boost_store_team_reserve 1 + fd_titan_health_adjust -2500 + fd_reaper_health_adjust -1000 + fd_mortar_spectre_setup_time 10 + fd_grunt_at_weapon_users 0 + fd_grunt_shield_captains 0 + fd_player_damage_scalar 1.0 + fd_money_per_round 700 + fd_pro_titan_shields 0 + fd_harvester_shield 6000 + fd_at_unlimited_ammo 1 + + earn_meter_pilot_multiplier 0.7 + } + } + fd_hard + { + inherit fd + vars + { + name #PL_fd_hard + lobbytitle #PL_fd_hard_lobby + description #PL_fd_hard_desc + abbreviation #FD_DIFFICULTY_HARD + image fd_hard + fd_difficulty 2 + boost_store_team_reserve 1 + fd_titan_health_adjust 0 + fd_reaper_health_adjust 0 + fd_mortar_spectre_setup_time 5 + fd_grunt_at_weapon_users 2 + fd_grunt_shield_captains 0 + fd_player_damage_scalar 1.5 + fd_money_per_round 600 + fd_pro_titan_shields 0 + fd_harvester_shield 5000 + fd_at_unlimited_ammo 1 + + earn_meter_pilot_multiplier 0.7 + } + } + fd_master + { + inherit fd + vars + { + name #PL_fd_master + lobbytitle #PL_fd_master_lobby + description #PL_fd_master_desc + abbreviation #FD_DIFFICULTY_MASTER + image fd_master + fd_difficulty 3 + boost_store_team_reserve 1 + + fd_titan_health_adjust 0 + fd_reaper_health_adjust 0 + fd_mortar_spectre_setup_time 5 + fd_grunt_at_weapon_users 4 + fd_grunt_shield_captains 1 + fd_player_damage_scalar 2.5 + fd_money_per_round 600 + fd_pro_titan_shields 1 + fd_harvester_shield 4000 + fd_at_unlimited_ammo 0 + + earn_meter_pilot_multiplier 0.7 + } + } + fd_insane + { + inherit fd + vars + { + name #PL_fd_insane + lobbytitle #PL_fd_insane_lobby + description #PL_fd_insane_desc + abbreviation #FD_DIFFICULTY_INSANE + image fd_insane + + fd_difficulty 4 + boost_store_team_reserve 1 + riff_minimap_state 1 + roundscorelimit 1 + + fd_titan_health_adjust 0 + fd_reaper_health_adjust 0 + fd_mortar_spectre_setup_time 5 + fd_grunt_at_weapon_users 4 + fd_grunt_shield_captains 1 + fd_player_damage_scalar 2.5 + fd_money_per_round 600 + fd_pro_titan_shields 1 + fd_harvester_shield 4000 + fd_at_unlimited_ammo 0 + + earn_meter_pilot_multiplier 0.5 + } + } +// END OF MP GAMEMODES LINE ---------------------------------------------------- + solo + { + inherit defaults + maps + { + sp_beacon 1 + } + } + } + Playlists + { + defaults + { + vars + { + name #PL_default_name + lobbytitle #PL_default_lobbytitle + description #PL_default_description + image default + visible 0 + } + } + angelcity_247 + { + inherit defaults + vars + { + name #MP_ANGEL_CITY + lobbytitle #PL_ANGEL_CITY + description #PL_angel_city_desc + abbreviation #PL_angel_city_abbr + image aitdm + } + gamemodes + { + ctf + { + maps + { + mp_angel_city 1 + } + } + aitdm + { + maps + { + mp_angel_city 1 + } + } + cp + { + maps + { + mp_angel_city 1 + } + } + at + { + maps + { + mp_angel_city 1 + } + } + lts + { + maps + { + mp_angel_city 1 + } + } + } + } + aitdm + { + inherit defaults + vars + { + name "#PL_aitdm" + lobbytitle #PL_aitdm_lobby + description #PL_aitdm_desc + abbreviation #PL_aitdm_abbr + image aitdm + mixtape_slot 0 + visible 1 + } + gamemodes + { + aitdm + { + } + } + } + amped_tacticals_aitdm + { + inherit defaults + vars + { + name "#PL_amped_tacticals" + lobbytitle #PL_amped_tacticals_lobby + description #PL_amped_tacticals_desc + abbreviation #PL_amped_tacticals_abbr + image aitdm + visible 0 + featured_mode_amped_tacticals 1 + } + gamemodes + { + aitdm + { + } + } + } + tactikill_aitdm + { + inherit defaults + vars + { + name "#PL_tactikill" + lobbytitle #PL_tactikill_lobby + description #PL_tactikill_desc + abbreviation #PL_tactikill_abbr + image aitdm + visible 0 + featured_mode_tactikill 1 + } + gamemodes + { + aitdm + { + } + } + } + grapple_aitdm + { + inherit defaults + vars + { + name "#PL_all_grapple" + lobbytitle #PL_all_grapple_lobby + description #PL_all_grapple_desc + abbreviation #PL_all_grapple_abbr + image aitdm + featured_mode_all_grapple 1 + } + gamemodes + { + aitdm + { + } + } + } + phase_aitdm + { + inherit defaults + vars + { + name "#PL_all_phase" + lobbytitle #PL_all_phase_lobby + description #PL_all_phase_desc + abbreviation #PL_all_phase_abbr + image aitdm + featured_mode_all_phase 1 + + visible 0 + } + gamemodes + { + aitdm + { + } + } + } + spicy_aitdm + { + inherit defaults + vars + { + name "#PL_all_spicy" + lobbytitle #PL_all_spicy_lobby + description #PL_all_spicy_desc + abbreviation #PL_all_spicy_abbr + image aitdm + featured_mode_all_ticks 1 + } + gamemodes + { + aitdm + { + } + } + } + at + { + inherit defaults + vars + { + name #PL_attrition + lobbytitle #PL_attrition_lobby + description #PL_attrition_desc + abbreviation #PL_attrition_abbr + image at + mixtape_slot 1 + visible 1 + } + gamemodes + { + at + { + } + } + } + cp + { + inherit defaults + vars + { + name #PL_hardpoint + lobbytitle #PL_hardpoint_lobby + description #PL_hardpoint_desc + abbreviation #PL_hardpoint_abbr + image cp + + visible 1 + mixtape_slot 2 + } + gamemodes + { + cp + { + } + } + } + lts + { + inherit defaults + vars + { + name #PL_last_titan_standing + lobbytitle #PL_last_titan_standing_lobby + description #PL_last_titan_standing_desc + abbreviation #PL_last_titan_standing_abbr + image lts + + visible 1 + mixtape_slot 3 + } + gamemodes + { + lts + { + } + } + } + alts + { + inherit defaults + vars + { + name #PL_aegis_last_titan_standing + lobbytitle #PL_aegis_last_titan_standing_lobby + description #PL_aegis_last_titan_standing_desc + abbreviation #PL_aegis_last_titan_standing_abbr + image lts + + aegis_upgrades 1 + ingame_menu_fd_mode 1 + + visible 0 + //mixtape_slot 3 + } + gamemodes + { + lts + { + } + } + } + turbo_lts + { + inherit defaults + vars + { + name #PL_turbo_last_titan_standing + lobbytitle #PL_turbo_last_titan_standing_lobby + description #PL_turbo_last_titan_standing_desc + abbreviation #PL_turbo_last_titan_standing_abbr + image lts + featured_mode_turbo_titans 1 + earn_meter_titan_multiplier 2.0 + } + gamemodes + { + lts + { + } + } + } + ctf + { + inherit defaults + vars + { + name #PL_capture_the_flag + lobbytitle #PL_capture_the_flag_lobby + description #PL_capture_the_flag_desc + abbreviation #PL_capture_the_flag_abbr + image ctf + + visible 1 + mixtape_slot 4 + } + gamemodes + { + ctf + { + vars + { + scorelimit 5 + } + + maps + { + mp_complex3 1 + mp_drydock 2 + mp_glitch 1 + mp_homestead 2 + mp_eden 2 + mp_forwardbase_kodai 1 + mp_black_water_canal 2 + mp_glitch 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 + mp_grave 2 + mp_homestead 2 + mp_drydock 2 + mp_glitch 1 + mp_thaw 1 + mp_eden 2 + mp_black_water_canal 2 + mp_glitch 1 + mp_relic02 1 + } + } + } + } + ps + { + inherit defaults + vars + { + name #PL_pilot_skirmish + lobbytitle #PL_pilot_skirmish_lobby + description #PL_pilot_skirmish_desc + abbreviation #PL_pilot_skirmish_abbr + image ps + scorelimit 100 + mixtape_slot 5 + visible 1 + } + gamemodes + { + ps + { + vars + { + + } + + maps + { + mp_black_water_canal 1 + mp_complex3 1 + mp_crashsite3 1 + mp_drydock 1 + mp_eden 1 + mp_forwardbase_kodai 1 + mp_angel_city 1 + mp_colony02 1 + mp_relic02 1 + mp_grave 1 + mp_thaw 1 + mp_homestead 1 + mp_glitch 1 + mp_wargames 1 + } + } + } + } + ttdm + { + inherit defaults + vars + { + name #PL_titan_brawl + lobbytitle #PL_titan_brawl_lobby + description #PL_titan_brawl_desc + abbreviation #PL_titan_brawl_abbr + image ttdm + max_players 10 + scorelimit 30 + boosts_enabled 1 + respawn_delay 10 + + visible 1 + mixtape_slot 7 + } + gamemodes + { + ttdm + { + maps + { + mp_glitch 1 + mp_colony02 1 + mp_wargames 1 + mp_eden 1 + mp_drydock 1 + mp_black_water_canal 1 + mp_thaw 1 + mp_homestead 1 + mp_forwardbase_kodai 1 + mp_angel_city 1 + mp_grave 1 + mp_rise 1 + } + } + } + } + turbo_ttdm + { + inherit defaults + vars + { + name #PL_titan_brawl_turbo + lobbytitle #PL_titan_brawl_turbo_lobby + description #PL_titan_brawl_turbo_desc + abbreviation #PL_titan_brawl_turbo_abbr + image ttdm + max_players 10 + scorelimit 30 + boosts_enabled 1 + respawn_delay 10 + + featured_mode_turbo_titans 1 + earn_meter_titan_multiplier 2.0 + } + gamemodes + { + ttdm + { + maps + { + mp_glitch 1 + mp_colony02 1 + mp_wargames 1 + mp_eden 1 + mp_drydock 1 + mp_black_water_canal 1 + mp_thaw 1 + mp_homestead 1 + mp_forwardbase_kodai 1 + mp_angel_city 1 + mp_grave 1 + mp_rise 1 + } + } + } + } + attdm + { + inherit defaults + vars + { + name #PL_aegis_titan_brawl + lobbytitle #PL_aegis_titan_brawl_lobby + description #PL_aegis_titan_brawl_desc + abbreviation #PL_aegis_titan_brawl_abbr + image ttdm + max_players 10 + scorelimit 30 + boosts_enabled 1 + respawn_delay 10 + aegis_upgrades 1 + ingame_menu_fd_mode 1 + + visible 0 + //mixtape_slot 10 + } + gamemodes + { + ttdm + { + maps + { + mp_glitch 1 + mp_colony02 1 + mp_wargames 1 + mp_eden 1 + mp_drydock 1 + mp_black_water_canal 1 + mp_thaw 1 + mp_homestead 1 + mp_forwardbase_kodai 1 + mp_angel_city 1 + mp_grave 1 + mp_rise 1 + } + } + } + } + tdm + { + inherit defaults + vars + { + name #PL_pilot_hunter + lobbytitle #PL_pilot_hunter_lobby + description #PL_pilot_hunter_desc + abbreviation #PL_pilot_hunter_abbr + image tdm + visible 0 + max_players 16 + } + gamemodes + { + tdm {} + } + } + tdm_arena_hardcore + { + inherit defaults + vars + { + name "EPG Arena" + abbreviation EPG + description "All EPG, reduced health." + + image fw + scorelimit 75 + suddendeath_timelimit 2 + timelimit 10 + max_players 10 + spawn_zone_enabled 1 + gm_hardcore_settings 1 + fast_set 1 + custom_pilot_loadout 1 + loadout_selection_enabled 0 + + pilot_loadout_primary mp_weapon_epg + pilot_loadout_primary_mod1 jump_kit + pilot_loadout_primary_mod2 pas_fast_swap + pilot_loadout_secondary mp_weapon_defender + pilot_loadout_secondary_mod1 quick_charge + pilot_loadout_secondary_mod2 pas_fast_swap + pilot_loadout_weapon3 "" + pilot_loadout_weapon3_mod1 "" + pilot_loadout_weapon3_mod2 "" + pilot_loadout_weapon3_mod3 "" + pilot_loadout_melee melee_pilot_sword + pilot_loadout_special mp_ability_shifter + pilot_loadout_ordnance mp_weapon_thermite_grenade + + boosts_enabled 1 // stop people smart pistoling :c + riff_force_boost_override 1 + + visible 0 + //mixtape_promo_slot 0 + //mixtape_slot 8 + //double_xp_enabled 1 + } + gamemodes + { + tdm + { + maps + { + mp_lf_deck 1 + mp_glitch 1 + mp_lf_township 1 + mp_angel_city 1 + mp_lf_uma 1 + mp_colony02 1 + mp_lf_stacks 1 + } + } + } + } + tdm_arena_smr + { + inherit defaults + vars + { + name "SMR Arena" + abbreviation SMR + description "All SMR, Deadly Ground." + + image fw + scorelimit 75 + suddendeath_timelimit 2 + timelimit 10 + max_players 10 + spawn_zone_enabled 1 + fast_set 1 + custom_pilot_loadout 1 + loadout_selection_enabled 0 + riff_floorislava 1 // deadly ground + + pilot_loadout_primary mp_weapon_smr + pilot_loadout_primary_mod1 jump_kit + pilot_loadout_primary_mod2 pas_fast_reload + pilot_loadout_secondary mp_weapon_wingman_n + pilot_loadout_secondary_mod1 silencer + pilot_loadout_secondary_mod2 ricochet + pilot_loadout_weapon3 "" + pilot_loadout_weapon3_mod1 "" + pilot_loadout_weapon3_mod2 "" + pilot_loadout_weapon3_mod3 "" + pilot_loadout_melee melee_pilot_sword + pilot_loadout_special mp_ability_shifter + pilot_loadout_ordnance mp_weapon_grenade_sonar + + boosts_enabled 1 + riff_force_boost_override 1 + + falldamage 1 + fallDamageMaxDamage 90 + + visible 0 + //mixtape_promo_slot 0 + //mixtape_slot 8 + //double_xp_enabled 1 + } + gamemodes + { + tdm + { + maps + { + mp_lf_township 1 + mp_lf_uma 1 + } + } + } + } + ffa_arena_energy + { + inherit defaults + vars + { + name "Energy Chaos" + abbreviation EC + description #SCORE_EVENT_MAYHEM + + image cp + scorelimit 35 + spawn_zone_enabled 1 + fast_set 1 + pilot_health_multiplier 1.5 + custom_pilot_loadout 1 + loadout_selection_enabled 0 + + pilot_loadout_primary mp_weapon_epg + pilot_loadout_primary_mod1 jump_kit + pilot_loadout_primary_mod2 pas_fast_reload + pilot_loadout_secondary mp_weapon_hemlok_smg + pilot_loadout_secondary_mod1 pas_fast_ads + pilot_loadout_secondary_mod2 pas_fast_reload + pilot_loadout_weapon3 mp_weapon_defender + pilot_loadout_weapon3_mod1 quick_charge + pilot_loadout_weapon3_mod2 pas_fast_swap + pilot_loadout_weapon3_mod3 "" + pilot_loadout_melee melee_pilot_sword + pilot_loadout_special mp_ability_holopilot + pilot_loadout_ordnance mp_weapon_grenade_sonar + + boosts_enabled 1 + riff_force_boost_override 1 + + visible 0 + //mixtape_promo_slot 0 + //mixtape_slot 8 + double_xp_enabled 1 + } + gamemodes + { + ffa + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_deck 1 + } + } + } + } + hardpoint_twist + { + inherit defaults + vars + { + name #PL_hardpoint_non_amp + lobbytitle #PL_hardpoint_lobby_non_amp + description #MP_DRYDOCK_FD_WAVE_3 + abbreviation HTW + image angel_city_247 + + scorelimit 300 + gm_hardcore_settings 1 + pilot_health_multiplier 1.3 + earn_meter_titan_multiplier 5.0 + earn_meter_pilot_multiplier 0.7 + earn_meter_pilot_overdrive 1 + capture_point_amping 0 + skyshow_enabled 1 + + visible 0 + //mixtape_slot 10 + //double_xp_enabled 1 + } + gamemodes + { + cp + { + maps + { + mp_thaw 1 + mp_angel_city 1 + mp_colony02 1 + mp_forwardbase_kodai 1 + mp_wargames 1 + mp_glitch 1 + mp_eden 1 + } + } + } + } + ffa + { + inherit defaults + vars + { + name #PL_ffa + lobbytitle #PL_ffa_lobby + description #PL_ffa_desc + abbreviation #PL_ffa_abbr + image ffa + + //visible 1 + //mixtape_promo_slot 0 + //mixtape_slot 8 + double_xp_enabled 1 + } + gamemodes + { + ffa + { + } + } + } + fra + { + inherit defaults + vars + { + name #PL_fra + lobbytitle #PL_fra_lobby + description #PL_fra_desc + abbreviation #PL_fra_abbr + image ffa + + visible 0 + } + gamemodes + { + fra + { + } + } + } + coliseum + { + inherit defaults + vars + { + name #PL_coliseum + lobbytitle #PL_coliseum_lobby + description #PL_coliseum_desc + image coliseum + mixtape_promo_slot 4 + visible 1 + } + gamemodes + { + coliseum {} + } + } + private_match + { + inherit defaults + vars + { + name #PL_private_match + lobbytitle #PL_private_match_lobby + description #PL_private_match_desc + image private_match + + max_players 16 + lobby_countdown 15 + ranking_supported 0 + mixtape_promo_slot 1 + double_xp_enabled 0 + visible 1 + + // default custom settings + match_visibility 2 + pilot_health_multiplier 1.0 + earn_meter_pilot_multiplier 1.0 + earn_meter_pilot_overdrive 1 + earn_meter_titan_multiplier 1.0 + } + gamemodes + { + aitdm + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + tdm + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + cp + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_lf_stacks 1 + mp_lf_deck 1 + mp_lf_meadow 1 + mp_lf_traffic 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + at + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + ctf + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_lf_stacks 1 + mp_lf_deck 1 + mp_lf_meadow 1 + mp_lf_traffic 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + lts + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + ps + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_lf_stacks 1 + mp_lf_deck 1 + mp_lf_meadow 1 + mp_lf_traffic 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + speedball + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_lf_stacks 1 + mp_lf_deck 1 + mp_lf_meadow 1 + mp_lf_traffic 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + mfd + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_lf_stacks 1 + mp_lf_deck 1 + mp_lf_meadow 1 + mp_lf_traffic 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + ttdm + { + maps + { + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 + } + } + + fd_easy + { + maps + { + mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_homestead 1 + mp_wargames 1 + mp_rise 1 + mp_thaw 1 + mp_drydock 1 + mp_angel_city 1 + //mp_relic02 1 + mp_colony02 1 + } + } + + fd_normal + { + maps + { + mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_homestead 1 + mp_wargames 1 + mp_rise 1 + mp_thaw 1 + mp_drydock 1 + mp_angel_city 1 + //mp_relic02 1 + mp_colony02 1 + } + } + + fd_hard + { + maps + { + mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_homestead 1 + mp_wargames 1 + mp_rise 1 + mp_thaw 1 + mp_drydock 1 + mp_angel_city 1 + //mp_relic02 1 + mp_colony02 1 + } + } + + fd_master + { + maps + { + mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_homestead 1 + mp_wargames 1 + mp_rise 1 + mp_thaw 1 + mp_drydock 1 + mp_angel_city 1 + //mp_relic02 1 + mp_colony02 1 + } + } + + fd_insane + { + maps + { + mp_forwardbase_kodai 1 + mp_black_water_canal 1 + mp_homestead 1 + mp_wargames 1 + mp_rise 1 + mp_thaw 1 + mp_drydock 1 + mp_angel_city 1 + //mp_relic02 1 + mp_colony02 1 + } + } + } + } + nitro_mixtape + { + inherit defaults + vars + { + name #PL_nitro_mixtape + lobbytitle #PL_nitro_mixtape_lobby + description #PL_nitro_mixtape_desc + abbreviation #PL_nitro_mixtape_abbr + image lf + boosts_enabled 1 + phase_shift_drop_flag 1 + ctf_flag_return_time 1 + visible 0 + } + gamemodes + { + ctf + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + mfd + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + ps + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + } + } + nitro_ffa + { + inherit defaults + vars + { + name #PL_nitro_ffa + lobbytitle #PL_nitro_ffa_lobby + description #PL_nitro_ffa_desc + abbreviation #PL_nitro_ffa_abbr + image lf + scorelimit 5 + boosts_enabled 1 + phase_shift_drop_flag 1 + max_players 6 + max_teams 6 + visible 0 + } + gamemodes + { + ffa + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + } + } + ctf_lf + { + inherit defaults + vars + { + name #PL_ctf_lf + lobbytitle #PL_ctf_lf_lobby + description #PL_ctf_lf_desc + abbreviation #PL_ctf_lf_abbr + image lf + scorelimit 5 + boosts_enabled 1 + phase_shift_drop_flag 1 + ctf_flag_return_time 1 + + visible 0 + //mixtape_slot 4 + } + gamemodes + { + ctf + { + maps + { + mp_lf_stacks 1 + mp_lf_deck 1 + mp_lf_meadow 1 + mp_lf_traffic 1 + //mp_glitch 1 + mp_lf_township 1 + mp_lf_uma 1 + } + } + } + } + lf + { + inherit defaults + vars + { + name #PL_live_fire + lobbytitle #PL_live_fire_lobby + description #PL_live_fire_desc + abbreviation #PL_live_fire_abbr + image lf + scorelimit 50 + + visible 1 + mixtape_slot 6 + } + gamemodes + { + speedball + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + } + } + rocket_lf + { + inherit defaults + vars + { + name #PL_rocket_arena + lobbytitle #PL_rocket_arena_lobby + description #PL_rocket_arena_desc + abbreviation #PL_rocket_arena_abbr + image lf + scorelimit 50 + roundtimelimit 2.0 + featured_mode_rocket_arena 1 + boosts_enabled 1 + + visible 0 + //mixtape_slot 6 + } + gamemodes + { + speedball + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + } + } + holopilot_lf + { + inherit defaults + vars + { + name #PL_all_holopilot + lobbytitle #PL_all_holopilot_lobby + description #PL_all_holopilot_desc + abbreviation #PL_all_holopilot_abbr + image lf + visible 0 + scorelimit 50 + featured_mode_all_holopilot 1 + } + gamemodes + { + speedball + { + maps + { + mp_lf_stacks 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_traffic 1 + mp_lf_deck 1 + mp_lf_meadow 1 + } + } + } + } + mfd + { + inherit defaults + vars + { + name #PL_marked_for_death + lobbytitle #PL_marked_for_death_lobby + description #PL_marked_for_death_desc + abbreviation #PL_marked_for_death_abbr + image mfd + scorelimit 10 + + //visible 1 + //mixtape_promo_slot 0 + //mixtape_slot 8 + //double_xp_enabled 1 + } + gamemodes + { + mfd {} + } + } + titan_mfd + { + inherit defaults + vars + { + name #GAMEMODE_TMFD + lobbytitle #PL_marked_for_death_lobby + description #PL_marked_for_death_desc + abbreviation TMFD + image mfd + + scorelimit 10 + titan_marked_for_death 1 + } + gamemodes + { + mfd {} + } + } + anniversary_7th + { + inherit defaults + vars + { + name "Anniversary 2023" // Or as my past-self would say.. anniversiary.. + promo_note "EVENT" + abbreviation ANN + description "Happy 7th Anniversary to all Pilots!" + image fw + + // Fireworks!.. in form of fighting ships.. + skyshow_enabled 1 + max_players 12 + + visible 0 + //mixtape_promo_slot 0 + //mixtape_slot 8 + double_xp_enabled 1 + } + gamemodes + { + // FYI on server vars, they are server only, client does not process them, some vars still show up on client due to networked vars but not all. + // Hardcore hardpoint + cp + { + vars_server + { + scorelimit 300 // Affected by mention above. + gm_hardcore_settings 1 + capture_point_amping 0 + boosts_enabled 1 + riff_force_boost_override 1 + } + maps + { + mp_thaw 1 + mp_angel_city 1 + mp_colony02 1 + mp_forwardbase_kodai 1 + mp_wargames 1 + mp_glitch 1 + mp_eden 1 + } + } + // PVP Attrition, I think we can do more here in the future to bend the rules of attrition. + aitdm + { + vars_server + { + // Featured vars. + riff_force_titan_avail_override 3 + earn_meter_pilot_overdrive 1 + earn_meter_pilot_multiplier 1.2 + featured_mode_all_holopilot 1 + enable_spectre_hacking 1 + + // Attrition setup + riff_allow_npcs 1 + spawn_zone_enabled 0 + scorelimit 650 + suddendeath_timelimit 2 + timelimit 15 + } + } + // Hardcore TDM + tdm + { + vars_server + { + scorelimit 75 + suddendeath_timelimit 2 + timelimit 10 + spawn_zone_enabled 1 + gm_hardcore_settings 1 + fast_set 1 + falldamage 1 + falldamage_max_damage 30 + + boosts_enabled 1 + riff_force_boost_override 1 + } + maps + { + mp_lf_deck 1 + mp_lf_township 1 + mp_lf_uma 1 + mp_lf_stacks 1 + } + } + } + } + //DEV + fnf + { + inherit defaults + vars + { + name "Friday Night Fights" + lobbytitle "Friday Night Fights Lobby" + description "Fights on Friday" + image varietypack + visible 0 + } + gamemodes + { + ctf + { + maps + { + mp_relic02 1 + + } + } + + lts + { + maps + { + mp_relic02 1 + } + } + } + } + variety_pack + { + inherit defaults + vars + { + name #PL_variety_pack + lobbytitle #PL_variety_pack_lobby + description "Variety Pack Rotation\n^FFC83200Playlist rotates every 24 hours" + image hunted + abbreviation MT + + visible 1 + mixtape_promo_slot 0 + mixtape_slot 8 + } + gamemodes + { + aitdm {} + } + } + //DEV + fd + { + inherit defaults + vars + { + name #MATCHMAKING_PVE_PLAY_BUTTON + lobbytitle #PL_fd_lobby + description #COOP_DESC + image ffa + visible 1 + mixtape_promo_slot 9 + riff_team_share_earn_meter 2 + riff_team_share_earn_meter_scale 0.25 + earn_meter_titan_multiplier 0.5 + ingame_menu_fd_mode 1 + promo_note #PL_promo_coop + } + gamemodes + { + fd + {} + } + } + //DEV + fd_easy + { + inherit defaults + vars + { + name #PL_fd_easy + lobbytitle #PL_fd_easy_lobby + description #PL_fd_easy_desc + abbreviation #FD_DIFFICULTY_EASY + image fd_easy + visible 1 + } + gamemodes + { + fd + {} + } + gamemodesWithAncestor + { + fd_easy + {} + } + } + //DEV + fd_normal + { + inherit defaults + vars + { + name #PL_fd_normal + lobbytitle #PL_fd_normal_lobby + description #PL_fd_normal_desc + abbreviation #FD_DIFFICULTY_NORMAL + image fd_normal + visible 1 + } + gamemodes + { + fd + {} + } + gamemodesWithAncestor + { + fd_normal + {} + } + } + //DEV + fd_hard + { + inherit defaults + vars + { + name #PL_fd_hard + lobbytitle #PL_fd_hard_lobby + description #PL_fd_hard_desc + abbreviation #FD_DIFFICULTY_HARD + image fd_hard + visible 1 + } + gamemodes + { + fd + {} + } + gamemodesWithAncestor + { + fd_hard + {} + } + } + //DEV + fd_master + { + inherit defaults + vars + { + name #PL_fd_master + lobbytitle #PL_fd_master_lobby + description #PL_fd_master_desc + abbreviation #FD_DIFFICULTY_MASTER + image fd_master + visible 1 + } + gamemodes + { + fd + {} + } + gamemodesWithAncestor + { + fd_master + {} + } + } + fd_insane + { + inherit fd + vars + { + name #PL_fd_insane + lobbytitle #PL_fd_insane_lobby + description #PL_fd_insane_desc + image fd_insane + visible 1 + mixtape_promo_slot 5 + promo_note #MP_THAW + double_xp_enabled 1 + } + gamemodes + { + fd + {} + } + gamemodesWithAncestor + { + fd_insane + { + maps + { + mp_thaw 1 + } + } + } + } + //DEV + fd_dev + { + inherit fd_hard + vars + { + pick_loadout_extension 0 + } + } + +// END OF MP PLAYLISTS LINE ---------------------------------------------------- + + "Load a map on the command line" + { + inherit defaults + vars + { + name #PL_load_a_map_on_the_command_line + description #PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work + + cmdlineMapLoad 1 + + classic_mp 0 + prematch_time 4 + titan_build_time 5 + titan_build_time_use_set_file 0 + titan_rebuild_time 5 + } + gamemodes + { + tdm + { + maps + { + mp_lobby 1 + } + } + } + } + solo + { + inherit defaults + vars + { + always_enable_autotitans 1 + burn_meter_enabled 0 + cinematic_mode 1 + classic_mp 0 + hud_score_enabled 0 + max_players 1 + max_teams 1 + ranking_supported 0 + riff_allow_npcs 1 + riff_minimap_state 1 + riff_titan_availability 3 + riff_titan_exit_enabled 3 + rodeo_battery_disembark_to_pickup 0 + titan_build_time 300 + titan_health_bar_display default + titan_mode_change_allowed 0 + titan_rebuild_time 195 + titan_segmented_health 0 + titan_shield_regen 1 + } + gamemodes + { + solo {} + } + } + new_titan_models + { + inherit defaults + vars + { + classic_mp 0 + prematch_time 4 + r2_titan_models 1 + titan_build_time 20 + titan_rebuild_time 20 + } + gamemodes + { + solo + { + maps + { + sp_enemies 1 + } + } + } + } + } + PlaylistRotation // Variety Pack V1 + { + playlist "variety_pack" + rotationStartTime "2023-12-01 08:00:00 -08:00" // must be in YYYY-MM-DD HH:MM:SS +/-HH:00, local 24H time with timezone offset + + rotation + { + mfd 1440 + ffa_arena_energy 1440 + spicy_aitdm 1440 + fra 1440 + titan_mfd 1440 + tdm_arena_hardcore 1440 + grapple_aitdm 1440 + rocket_lf 1440 + ffa 1440 + tactikill_aitdm 1440 + } + } + "LocalizedStrings" + { + "lang" + { + "Language" "german" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Dein Abenteuer in der beeindruckenden Welt des Grenzlandes geht mit \"Postkarten aus dem Grenzland\", dem neuesten DLC für Titanfall 2, weiter. Mit neuen und bekannten Schauplätzen und einer neuen Sammlung von Elitewaffen-Kriegslackierungen hat das Grenzland nie besser ausgesehen.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_00_Q" "\"Postkarten aus dem Grenzland\"-Trailer" + "COMMUNITYUPDATE_01_A" "Informiere dich über alle im \"Postkarten aus dem Grenzland\"-Patch enthaltenen Änderungen.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_01_Q" "Postkarten aus dem Grenzland: Die Patch-Notizen" + "COMMUNITYUPDATE_02_A" "Das demnächst für Mobilgeräte erscheinende Titanfall: Assault ist ein Echtzeit-RTS im Titanfall-Universum, das wir mit Particle City entwickeln. Hier siehst du das Spiel in Aktion.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_02_Q" "Titanfall: Assault-Veröffentlichungstrailer" + "COMMUNITYUPDATE_03_A" "Iniquity führt uns durch das Tutorial und gibt uns grundlegende Tipps zu Titanfall: Assault. Der perfekte Weg, mehr über das Spiel zu erfahren.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_03_Q" "Titanfall: Assault: \"Die Grundlagen\"-Video" + "COMMUNITYUPDATE_04_A" "Höre den Machern von Grenzlandverteidigung zu, wenn sie über die Geschichte und Entwicklung des Modus sprechen und sieh uns zu, wie wir einige Runden spielen!\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_04_Q" "Respawn spielt Grenzlandverteidigung" + "COMMUNITYUPDATE_05_A" "Kevin Younger hat eine witzige Montage aus zahlreichen coolen Moves mit der Impulsklinge zusammengestellt!\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_05_Q" "Community-Beiträge: Komm zum Punkt" + "COMMUNITYUPDATE_06_A" "ConzeyG zeigt uns über reddit die brutale Effizienz des Northstar, wenn er im Todgeweiht-Modus Piloten erledigt.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_06_Q" "Community-Beiträge - Northstar-Pilotenjagd" + "COMMUNITYUPDATE_07_A" "Jetzt verfügbar! Grenzlandverteidigung und Rise kehren mit brandneuen, kaufbaren Kriegslackierungen und einer neuen Live Fire-Karte zurück. Hier siehst du alles in Aktion.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_07_Q" "\"Operation Frontier Shield\" Gameplay-Trailer" + "COMMUNITYUPDATE_08_A" "Jetzt verfügbar! Die legendäre Kriegsspiele-Karte kehrt in Titanfall 2 zurück und sieht besser denn je aus. Erlebe außerdem die neue Exekution und die neue Live Fire-Karte \"Verkehr\" in Aktion.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_08_Q" "\"Die Kriegsspiele\" Gameplay-Trailer" + "COMMUNITYUPDATE_09_A" "Dieser DLC enthält mit dem Monarch den 7. Multiplayer-Titan, eine überarbeitete Version der Relikt-Karte, eine neue Exekution sowie kaufbare Ronin- und Tone-Prime-Titans, mehr Tarnungen, Banner und Nose-Arts. Hier kannst du dir die Action ansehen.\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_09_Q" "\"Monarch's Reign\" Gameplay-Trailer" + "COMMUNITYUPDATE_10_A" "Im Grenzland ist nicht alles so, wie es scheint – bereite dich auf den neuesten kostenlosen Inhaltspack zum Herunterladen für Titanfall 2 vor: Störimpuls im Grenzland – mit der neuen Karte \"Glitch\". Die Inspiration dafür war Captain Lastimosas Heimatplanet Harmony, wo vertikale Höhenunterschiede und lange, gewundene Pfade das Landschaftsbild dominieren – ideal, um mit Wandlaufkombinationen elegant über die Karte zu gleiten. Eine neue Live Fire-Karte ist ebenfalls am Start: Deck, mit engen Innenräumen, offenen Höfen und wachsamen Drohnen, die über dir kreisen. Falls du dich überfordert fühlst, kannst du auf die hilfreichen M.R.V.N.s zugreifen, die dir jetzt als brandneue Gruppierung ihre fröhliche Roboterhand reichen. Und zu guter Letzt kannst du noch die neue Impulsklingen-Exekution freischalten, wann immer du es für notwendig hältst, dich durchzusetzen.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_10_Q" "\"Störimpuls im Grenzland\" Gameplay-Trailer" + "COMMUNITYUPDATE_11_A" "Kehre auf eine der Lieblingskarten der Fans aus Titanfall 1 zurück: Kolonie. Bringe all die neuen Taktiken und Titans aus Titanfall 2 ein, die alle Piloten & Titans nutzen müssen, um an diesem idyllischen Ort voller enger und verwinkelter Gassen und ungeschützter Dächer zu überleben. Ab dem 30. März für alle Spieler kostenlos erhältlich! Der Kolonierückkehr-DLC enthält außerdem klassische Waffen wie das Sturmgewehr R-101, eine neue Haken-Exekution sowie neue kosmetische Optionen, damit du perfekt aussiehst, wenn du die Stadt im Chaos versinken lässt.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_11_Q" "Trailer - Kolonierückkehr-DLC" + "COMMUNITYUPDATE_12_A" "Vorstellung von Live Fire: ein rasanter 6 vs. 6 Piloten-Modus, der aufregende Nahkämpfe an vorderster Front bietet. Enthält zwei neue, speziell für Live Fire entworfene Karten: Stacks und Meadow. Die beiden kostenlosen Karten sind eng umgrenzte Todeszonen, die perfekt auf die Rasanz und Intensität des Modus abgestimmt sind.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_12_Q" "Trailer - Live Fire-DLC" + "COMMUNITYUPDATE_13_A" "Erlebe eine Neuauflage der beliebten `1Angel City`0-Karte aus dem ersten Titanfall. Mach dich bereit für die ersten kostenlosen Inhalte zum Herunterladen für Titanfall 2. `1Angel City's Most Wanted`0 ist ab dem 1. Dezember für alle Spieler verfügbar. Die Inhalte bieten neue kosmetische Optionen, die dem Grenzland noch mehr Flair verleihen. \n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_13_Q" "Trailer - Angel City-DLC" + "COMMUNITYUPDATE_14_A" "Willkommen zurück!\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_14_Q" "Trailer - Encore" + "COMMUNITYUPDATE_15_A" "Zwei Legenden, ein Erbe.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_15_Q" "Trailer - Become One" + "COMMUNITYUPDATE_16_A" "Grenzenlos.\n\n\nZum Ansehen `2%[A_BUTTON|MOUSE1]%`0 drücken." + "COMMUNITYUPDATE_16_Q" "Trailer - Piloten-Gameplay" + "COMMUNITYUPDATE_DESC" "`3Titanfall Community-Updates`0\n\nInfos und Links aus dem ganzen Netz.\n\nWeitere Infos:\n`2%$rui/bullet_point%`0Folge uns auf Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Folge uns auf `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Besuche uns auf `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "Community" + "KNB_SUBJECT_00_DESC" "`3Was ist neu in Titanfall?`0\n\nHier erfährst du, was sich in Titanfall 2 geändert hat!" + "KNB_SUBJECT_00_NAME" "Spiel-Updates" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 Neue Rufzeichen-Banner der Community\n\n`2%$rui/bullet_point%`0Alle Fürsprechergeschenke können jetzt mit Credits erworben werden\n\n`2%$rui/bullet_point%`0Neue kaufbare Store-Inhalte\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28. November - Erntezeit" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Pistolen-Primärslot\n\n`2%$rui/bullet_point%`0Halloween-Banner\n\n`2%$rui/bullet_point%`0Balance-Änderungen\n\n`2%$rui/bullet_point%`0Neue kaufbare Store-Inhalte\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31. Oktober - Süßes und Saures" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Grenzlandverteidigung - Unterstützung für 3 weitere Karten - Drydock, Angel City und Exoplanet.\n\n`2%$rui/bullet_point%`0Neue Live Fire-Karte - UMA\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution - Loch in der Wand\n\n`2%$rui/bullet_point%`0Neue kaufbare Store-Inhalte" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29. August - Postkarten aus dem Grenzland" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Grenzlandverteidigung - Ein neuer Koop-Modus, bei dem du mit drei anderen Spielern ein wichtiges Einsatzziel gegen immer stärker werdende Wellen von KI-Einheiten verteidigst. Kommunikation und Anpassung sind hier entscheidend, um zu überleben.\n\n`2%$rui/bullet_point%`0Neue Karte - Aufstieg\n\n`2%$rui/bullet_point%`0Neue Live Fire-Karte - Township\n\n`2%$rui/bullet_point%`0Neue kaufbare Store-Inhalte" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25. Juli - Operation Frontier Shield" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Neue Karte - Kriegsspiele\n\n`2%$rui/bullet_point%`0Neue Live Fire-Karte - Verkehr\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution - Schattenboxen\n\n`2%$rui/bullet_point%`03. Waffenslot\n\n`2%$rui/bullet_point%`0Privatspiel-Einstellungen" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27. Juni - Kriegsspiele" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Neuer Titan – Monarch\n\n`2%$rui/bullet_point%`0Neue Karte – Relikt\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution – Jetzt siehst du mich\n\n`2%$rui/bullet_point%`0Neue, käuflich zu erwerbende Store-Inhalte" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30. Mai – Monarch's Reign" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Neue Karte – Glitch\n\n`2%$rui/bullet_point%`0Neue Live Fire-Karte – Deck\n\n`2%$rui/bullet_point%`0Neue Gruppierung – M.R.V.N.\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution – Komm zum Punkt\n\n`2%$rui/bullet_point%`0Maximalgeneration auf 100 erhöht" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25. April – Störimpuls im Grenzland" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Neue Karte – Kolonie\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution – Curb-Check\n\n`2%$rui/bullet_point%`0Neue Waffe – R-101\n\n`2%$rui/bullet_point%`0Neue, käuflich zu erwerbende Store-Inhalte" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30. März – Kolonierückkehr" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Live Fire – ein neuer Pilot vs. Pilot Eliminierungsmodus! In diesem rundenbasierten 6 vs. 6-Modus ohne Respawns habt ihr nur eine Minute Zeit, das gegnerische Team zu besiegen und die Runde zu gewinnen. Ihr gewinnt die Runde aber auch, wenn euer Team am Ende der Runde die neutrale Flagge hält. Das Team, das zuerst 5 Runden gewinnt, wird zum Sieger erklärt.\n\n`2%$rui/bullet_point%`0Neue Live Fire-Karte – Meadow\n\n`2%$rui/bullet_point%`0Neue Live Fire-Karte – Stacks\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution – Später Treffer" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23. Februar – Live Fire" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Neue Karte – Angel City\n\n`2%$rui/bullet_point%`0Neue Waffe – B3 Wingman Elite\n\n`2%$rui/bullet_point%`0Neue Piloten-Exekution – Innenleben\n\n`2%$rui/bullet_point%`0Neue Titan-Kits\n\n`2%$rui/bullet_point%`0Neue, käuflich zu erwerbende Store-Inhalte" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30. November – Angel City's Most Wanted" + "MP_ANGEL_CITY_FD_WAVE_1" "An den Himmel gekettet" + "MP_ANGEL_CITY_FD_WAVE_2" "Formlosigkeit" + "MP_ANGEL_CITY_FD_WAVE_3" "Auflehnung" + "MP_ANGEL_CITY_FD_WAVE_4" "Ein störrischer Haufen" + "MP_ANGEL_CITY_FD_WAVE_5" "Reißleine" + "MP_DRYDOCK_FD_WAVE_1" "Auf in fremde Gewässer" + "MP_DRYDOCK_FD_WAVE_2" "Sie haben keine Kugeln!" + "MP_DRYDOCK_FD_WAVE_3" "Von der Forschung geblendet" + "MP_DRYDOCK_FD_WAVE_4" "Hochdrucksystem" + "MP_DRYDOCK_FD_WAVE_5" "Auge des Sturms" + "MP_THAW_FD_WAVE_1" "Lagebewusstsein" + "MP_THAW_FD_WAVE_2" "Zahlenmäßige Stärke" + "MP_THAW_FD_WAVE_3" "Handlanger 21" + "MP_THAW_FD_WAVE_4" "Spaß im Feuer" + "MP_THAW_FD_WAVE_5" "Nutzt eure Waffen" + "NO_PRICE" "Angebot abgelaufen" + "NO_PRICE_TWO_LINES" "Angebot\nabgelaufen" + "PL_aegis_last_titan_standing" "Aegis-LTS" + "PL_aegis_last_titan_standing_abbr" "ALTS" + "PL_aegis_last_titan_standing_desc" "Aegis-Upgrades aktiviert. Rundenbasiertes Eliminierungsmatch. Sieger ist, wer zuerst 3 Runden für sich entscheidet.\n^FFC83200Spieler: 5 vs. 5 * Starte als Titan\nZeitlimit: 3 Min. pro Runde * Keine Respawns\nMax. Party-Größe: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Aegis Titan Brawl" + "PL_aegis_titan_brawl_abbr" "ATB" + "PL_aegis_titan_brawl_desc" "Eliminiere gegnerische Titans. Aegis-Upgrades aktiviert.\n^FFC83200Spieler: 5 vs. 5\nZeitlimit: 10 Min.\nMax. Party-Größe: 5" + "PL_aegis_titan_brawl_hint" "Neutralisiere gegnerische Titans.\nKein Ausstieg" + "PL_aegis_titan_brawl_lobby" "Aegis Titan Brawl-Lobby" + "PL_aitdm" "Materialschlacht" + "PL_aitdm_abbr" "MAT" + "PL_aitdm_desc" "Töte alle Gegner.\n^FFC83200Spieler: 6 vs. 6 *KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_aitdm_lobby" "Materialschlacht-Lobby" + "PL_all_grapple" "Angriff auf Titanfall" + "PL_all_grapple_abbr" "MAT" + "PL_all_grapple_desc" "Klassische Materialschlacht-Regeln, allerdings werden alle Taktikfähigkeiten durch \"Haken\" ersetzt.\n^FFC83200Spieler: 6 vs. 6 *KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_all_grapple_lobby" "Angriff auf Titanfall-Lobby" + "PL_all_holopilot" "Totale Verwirrung" + "PL_all_holopilot_abbr" "LF" + "PL_all_holopilot_desc" "Klassische Live-Fire-Regeln, allerdings werden alle Taktikfähigkeiten durch \"Holopilot\" ersetzt.^FFC83200\nSpieler: 6 vs. 6 *Keine Titans\nZeitlimit: 60 Sek. *Keine Respawns\nMax. Party-Größe: 6" + "PL_all_holopilot_lobby" "Totale Verwirrung-Lobby" + "PL_all_phase" "Die andere Seite" + "PL_all_phase_abbr" "MAT" + "PL_all_phase_desc" "Klassische Materialschlacht-Regeln, allerdings werden alle Taktikfähigkeiten durch \"Phase\" ersetzt.\n^FFC83200Spieler: 6 vs. 6 *KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_all_phase_lobby" "Die andere Seite-Lobby" + "PL_all_spicy" "Würzige Materialschlacht" + "PL_all_spicy_abbr" "MAT" + "PL_all_spicy_desc" "Klassische Materialschlacht-Regeln, allerdings werden alle Taktikfähigkeiten durch Ticks ersetzt.\n^FFC83200Spieler: 6 vs. 6 *KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_all_spicy_lobby" "Würzige Materialschlacht-Lobby" + "PL_amped_tacticals" "Verstärkte Taktiken" + "PL_amped_tacticals_abbr" "MAT" + "PL_amped_tacticals_desc" "Klassische Materialschlacht-Regeln, allerdings sind alle Taktikfähigkeiten effektiver.\n^FFC83200Spieler: 6 vs. 6 *KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_amped_tacticals_lobby" "Verstärkte Taktiken-Lobby" + "PL_ANGEL_CITY" "Angel City 24/7" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "Nur Angel City, die ganze Zeit." + "PL_angel_city_lobby" "Angel City 24/7-Lobby" + "PL_at_coop" "Flucht (Koop)" + "PL_at_coop_desc" "Du bist nur mit einer Pistole bewaffnet aus einem Gefängnis entkommen. Überlebe, bis du evakuiert werden kannst. Neutralisiere Gegner, um Geld zu erhalten und Waffen zu kaufen. \n^FFC83200Spieler: 6\nMax. Party-Größe: 6" + "PL_at_coop_lobby" "Flucht-Lobby" + "PL_attrition" "Kopfgeldjagd" + "PL_attrition_abbr" "KGJ" + "PL_attrition_desc" "Neutralisiere Gegner, um Geld zu erhalten. Verdiene mehr, indem du deine Boni an ausgewiesenen Stellen 'auf die Bank bringst'.\n^FFC83200Spieler: 5 vs. 5 * KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 5" + "PL_attrition_lobby" "Kopfgeldjagd-Lobby" + "PL_capture_the_flag" "Capture the Flag" + "PL_capture_the_flag_abbr" "CTF" + "PL_capture_the_flag_desc" "Stiehl die feindliche Flagge und bringe sie zu deiner Basis, während du das feindliche Team davon abhältst, sich deine Flagge zu schnappen!\n^FFC83200Spieler: 5 vs. 5\nZeitlimit: 12 Min.\nMax. Party-Größe: 5" + "PL_capture_the_flag_lobby" "CTF-Lobby" + "PL_coliseum" "Kolosseum" + "PL_coliseum_desc" "Duell mit erweiterter Beweglichkeit in einem Käfig. Schalte deinen Gegner aus, um zu gewinnen. Wer 3 von 5 Runden gewinnt, erhält ein Freund-Geschenk.^FFC83200\nSpieler: 1 vs. 1 *Keine Titans\nZeitlimit: 3 Min. *Keine Respawns\n**^FFFFFF00ERFORDERT KOLOSSEUM-TICKET oder BEZAHLTE TEILNAHMEGEBÜHR" + "PL_coliseum_lobby" "Kolosseum-Lobby" + "PL_colony" "Kolonie 24/7" + "PL_colony_abbr" "KOL" + "PL_colony_desc" "Kolonie, rund um die Uhr. ^CCCCCC00Sucht nach Spielen in den Modi ^FFC83200Materialschlacht^CCCCCC00, ^FFC83200Piloten vs. Piloten^CCCCCC00 und ^FFC83200Last Titan Standing^CCCCCC00." + "PL_colony_lobby" "Kolonie 24/7-Lobby" + "PL_ctf_lf" "CTF (Nitro)" + "PL_ctf_lf_abbr" "CTF-N" + "PL_ctf_lf_desc" "Rasantes Capture the Flag auf ausgewählten Karten.\n^FFC83200Spieler: 5 vs. 5\nMax. Party-Größe: 5\n^F4D5A600Flagge wird sofort zurückgebracht" + "PL_ctf_lf_lobby" "CTF Nitro-Lobby" + "PL_default_description" "Standardbeschreibung" + "PL_default_lobbytitle" "Standard-Lobbytitel" + "PL_default_name" "Standardname" + "PL_don" "Doppelt oder nichts" + "PL_fd" "Grenzlandverteidigung" + "PL_fd_desc" "Verteidige dich gegen Wellen von Truppen der Restflotte" + "PL_fd_easy" "Grenzlandverteidigung: Leicht" + "PL_fd_easy_desc" "Zerschlage den Gegner" + "PL_fd_easy_lobby" "Grenzlandverteidigung: Leicht-Lobby" + "PL_fd_hard" "Grenzlandverteidigung: Schwer" + "PL_fd_hard_desc" "Können ist erforderlich" + "PL_fd_hard_lobby" "Grenzlandverteidigung: Schwer-Lobby" + "PL_fd_insane" "Grenzlandverteidigung: Wahnsinn" + "PL_fd_insane_desc" "Du wirst nicht überleben" + "PL_fd_insane_lobby" "Grenzlandverteidigung: Wahnsinn – Lobby" + "PL_fd_lobby" "Grenzlandverteidigung-Lobby" + "PL_fd_master" "Grenzlandverteidigung: Meister" + "PL_fd_master_desc" "Nur die Besten der Besten werden erfolgreich sein" + "PL_fd_master_lobby" "Grenzlandverteidigung: Meister – Lobby" + "PL_fd_normal" "Grenzlandverteidigung: Normal" + "PL_fd_normal_desc" "Empfohlen für erfahrene Spieler" + "PL_fd_normal_lobby" "Grenzlandverteidigung: Normal – Lobby" + "PL_ffa" "Frei für alle" + "PL_ffa_abbr" "FFA" + "PL_ffa_desc" "Jeder Pilot kämpft für sich selbst. Eliminiere alle Gegner.\n^FFC83200Spieler: 1 vs. 11\nZeitlimit: 10 Min.\nMax. Party-Größe: 1" + "PL_ffa_lobby" "Frei für alle-Lobby" + "PL_fra" "Free Agents" + "PL_fra_abbr" "FRA" + "PL_fra_desc" "Du kämpfst für dich selbst. Eliminiere Gegner, um zu siegen. Sammle 3 Batterien für einen Titanfall.\n^FFC83200Spieler: 1 vs. 11\nZeitlimit: 15 Min.\nMax. Party-Größe: 1" + "PL_fra_lobby" "Free Agents-Lobby" + "PL_groud_war_lobby" "8 vs. 8 Mixtape-Lobby" + "PL_ground_war" "8 vs. 8 Mixtape" + "PL_ground_war_abbr" "8 vs. 8" + "PL_ground_war_desc" "Enthält Gefecht und Verstärkter Hardpoint mit einer hohen Spielerzahl auf allen Karten.\n^FFC83200Spieler: 8 vs. 8" + "PL_hardpoint" "Verstärkter Hardpoint" + "PL_hardpoint_abbr" "VHP" + "PL_hardpoint_desc" "Erobere und halte einen Hardpoint, um Punkte zu erringen. Verstärkte Hardpoints bringen die doppelte Punktzahl.\n^FFC83200Spieler: 6 vs. 6\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_hardpoint_lobby" "Verstärkter Hardpoint-Lobby" + "PL_hardpoint_non_amp" "Hardpoint" + "PL_hardpoint_lobby_non_amp" "Hardpoint Lobby" + "PL_hunted" "Gejagt" + "PL_iron_last_titan_standing" "Eiserner LTS" + "PL_iron_last_titan_standing_abbr" "ELTS" + "PL_iron_last_titan_standing_desc" "Nur Titans. Rundenbasiertes Eliminierungsmatch. Sieger ist, wer zuerst 3 Runden gewinnt.\n^FFC83200Spieler: 5 vs. 5 *KEINE PILOTEN\nZeitlimit: 3 Min. pro Runde * Keine Respawns\nMax. Party-Größe: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Last Titan Standing" + "PL_last_titan_standing_abbr" "LTS" + "PL_last_titan_standing_desc" "Alle Spieler beginnen dieses rundenbasierte Eliminierungsmatch in Titans. Sieger ist, wer zuerst 3 Runden für sich entscheidet.\n^FFC83200Spieler: 5 vs. 5 * Starte als Titan\nZeitlimit: 3 Min. pro Runde * Keine Respawns\nMax. Party-Größe: 5" + "PL_last_titan_standing_lobby" "LTS-Lobby" + "PL_limited_time_mode" "Befristeter Modus" + "PL_live_fire" "Live Fire" + "PL_live_fire_abbr" "LF" + "PL_live_fire_desc" "Rasanter Kampf in einer Live Fire-Arena. Gewinne die Runde, indem du alle gegnerischen Piloten neutralisierst oder am Ende der Runde die Flagge hältst.^FFC83200\nSpieler: 6 vs. 6 *Keine Titans\nZeitlimit: 60 Sek. *Keine Respawns\nMax. Party-Größe: 6" + "PL_live_fire_lobby" "Live Fire-Lobby" + "PL_load_a_map_on_the_command_line" "Lade eine Karte auf der Befehlszeile -devonly" + "PL_marked_for_death" "Todgeweiht" + "PL_marked_for_death_abbr" "TG" + "PL_marked_for_death_desc" "Eliminiere oder beschütze die markierten Ziele.\n^FFC83200Spieler: 6 vs. 6 \nZeitlimit: 12 Min.\nMax. Party-Größe: 6" + "PL_marked_for_death_lobby" "Todgeweiht-Lobby" + "PL_nitro_ffa" "FFA (Nitro)" + "PL_nitro_ffa_abbr" "FFA-N" + "PL_nitro_ffa_desc" "Rasantes Free for All auf ausgewählten Karten.\n^FFC83200Spieler: 6\n^F4D5A600Keine Titans\nKeine Boosts" + "PL_nitro_ffa_lobby" "FFA Nitro-Lobby" + "PL_nitro_mixtape" "Mixtape (Nitro)" + "PL_nitro_mixtape_abbr" "MXT-N" + "PL_nitro_mixtape_desc" "Rasantes CTF, TG und PvP auf ausgewählten Karten.\n^FFC83200Spieler: 5 vs. 5\nMax. Party-Größe: 5\n^F4D5A600Flagge wird sofort zurückgebracht" + "PL_nitro_mixtape_lobby" "Mixtape-Lobby" + "PL_pilot_hunter" "Gefecht" + "PL_pilot_hunter_abbr" "GEF" + "PL_pilot_hunter_desc" "Neutralisiere gegnerische Piloten und Titans. \n^FFC83200Spieler: 8 vs. 8\nZeitlimit: 10 Min.\nMax. Party-Größe: 8" + "PL_pilot_hunter_lobby" "Gefecht-Lobby" + "PL_pilot_skirmish" "Piloten vs. Piloten" + "PL_pilot_skirmish_abbr" "PvP" + "PL_pilot_skirmish_desc" "Neutralisiere gegnerische Piloten. Titanfalls nicht erlaubt.\n^FFC83200Spieler: 8 vs. 8 * Keine Titans\nZeitlimit: 10 Min.\nMax. Party-Größe: 8" + "PL_pilot_skirmish_lobby" "PvP-Lobby" + "PL_pl_rebuild_all_paths" "Neuaufbau aller Wege" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Mit ai_ainRebuildOnMapStart 2 laufen lassen" + "PL_private_match" "Privatspiel" + "PL_private_match_desc" "Spiele ein benutzerdefiniertes Privatspiel auf einer Karte und einem Modus deiner Wahl.\n^FFC83200Wähle NETWORK EINLADEN oder FREUNDE EINLADEN, um zu spielen\n^FFC83200Spieler: 1-16\nKeine Fortschritte" + "PL_private_match_lobby" "Privatspiel-Lobby" + "PL_promo_coop" "4-Spieler-KOOP" + "PL_raid" "Überfall" + "PL_glitch" "Glitch 24/7" + "PL_glitch_abbr" "GLI" + "PL_glitch_desc" "Glitch, rund um die Uhr. ^CCCCCC00Sucht nach Spielen in den Modi ^FFC83200CTF^CCCCCC00, ^FFC83200Verstärkter Hardpoint^CCCCCC00, ^FFC83200Piloten vs. Piloten^CCCCCC00, ^FFC83200Live Fire^CCCCCC00 und ^FFC83200Last Titan Standing^CCCCCC00." + "PL_glitch_lobby" "Glitch 24/7-Lobby" + "PL_rocket_arena" "Raketenarena" + "PL_rocket_arena_abbr" "LF" + "PL_rocket_arena_desc" "Klassische Live-Fire-Regeln mit modifizierten EPGs.^FFC83200\nSpieler: 6 vs. 6 *Keine Titans\nZeitlimit: 90 Sek. *Keine Respawns\nMax. Party-Größe: 6" + "PL_rocket_arena_lobby" "Raketenarena-Lobby" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Einstellungen, wenn jemand eine Karte auf der Befehlszeile lädt. Nicht cmdlineMapLoad 1 bearbeiten - dadurch funktioniert es." + "PL_speedball" "Live Fire" + "PL_speedball_desc" "Kämpfe um die neutrale Flagge. Eliminiere das gegnerische Team oder halte am Ende der Spielzeit die Flagge, um die Runde zu gewinnen. Wer zuerst 5 Runden für sich entscheidet, gewinnt.\n^FFC83200Spieler: 6 vs. 6 *Keine Titans\nZeitlimit: 60 Sekunden pro Runde *Keine Respawns\nMax. Party-Größe: 6" + "PL_speedball_lobby" "Live Fire-Lobby" + "PL_tactikill" "Taktikill-Materialschlacht" + "PL_tactikill_abbr" "MAT" + "PL_tactikill_desc" "Klassische Materialschlacht-Regeln, allerdings werden alle Taktikfähigkeiten durch einen Kill zurückgesetzt.\n^FFC83200Spieler: 6 vs. 6 *KI\nZeitlimit: 10 Min.\nMax. Party-Größe: 6" + "PL_tactikill_lobby" "Taktikill-Materialschlacht-Lobby" + "PL_titan_brawl" "Titan Brawl" + "PL_titan_brawl_abbr" "TB" + "PL_titan_brawl_desc" "Eliminiere gegnerische Titans. Piloten nicht erlaubt.\n^FFC83200Spieler: 5 vs. 5\nZeitlimit: 10 Min.\nMax. Party-Größe: 5" + "PL_titan_brawl_hint" "Neutralisiere gegnerische Titans.\nKein Ausstieg." + "PL_titan_brawl_lobby" "Titan Brawl-Lobby" + "PL_titan_brawl_turbo" "Turbo-Titan-Brawl" + "PL_titan_brawl_turbo_abbr" "TTDM" + "PL_titan_brawl_turbo_desc" "Klassische Titan-Brawl-Regeln mit schnellerer Jetschub-und System-Regeneration.\n^FFC83200Spieler: 5 vs. 5\nZeitlimit: 10 Min.\nMax. Party-Größe: 5" + "PL_titan_brawl_turbo_hint" "Neutralisiere gegnerische Titans.\nKein Ausstieg" + "PL_titan_brawl_turbo_lobby" "Turbo-Titan-Brawl-Lobby" + "PL_turbo_last_titan_standing" "Turbo-LTS" + "PL_turbo_last_titan_standing_abbr" "LTS" + "PL_turbo_last_titan_standing_desc" "Klassische LTS-Regeln mit schnellerer Jetschub-und System-Regeneration.\n^FFC83200Spieler: 5 vs. 5 *Starte als Titan\nZeitlimit: 3 Min. pro Runde\nMax. Party-Größe: 5" + "PL_turbo_last_titan_standing_lobby" "Turbo-LTS-Lobby" + "PL_variety_pack" "Mixtape" + "PL_variety_pack_desc" "Variierende Spielerzahlen und verschiedene Karten in diesen Modi:\n^FFC83200*Kopfgeldjagd *Materialschlacht\n*Last Titan Standing *Verstärkter Hardpoint\n*Piloten vs. Piloten *Capture the Flag" + "PL_variety_pack_lobby" "Mixtape-Lobby" + "PL_wargames" "Kriegsspiele 24/7" + "PL_wargames_abbr" "KSP" + "PL_wargames_desc" "Alle Kriegsspiele, rund um die Uhr. ^CCCCCC00Sucht nach Spielen in den Modi ^FFC83200Materialschlacht^CCCCCC00, ^FFC83200CTF^CCCCCC00, ^FFC83200Piloten vs. Piloten^CCCCCC00, ^FFC83200Verstärkter Hardpoint^CCCCCC00 und ^FFC83200Last Titan Standing^CCCCCC00." + "PL_wargames_lobby" "Kriegsspiele 24/7 – Lobby" + "WATCH_TUTORIAL" "TUTORIAL ANSEHEN" + "GAMEMODE_TMFD" "Titan Todgeweiht" + "MP_RELIC02_FD_WAVE_1" "Wir kämpfen vereint" + "MP_RELIC02_FD_WAVE_2" "Suche nach dem Weg" + "MP_RELIC02_FD_WAVE_3" "Ein anderer Weg" + "MP_RELIC02_FD_WAVE_4" "Blindenbinde" + "MP_RELIC02_FD_WAVE_5" "Geteilter Hinterhalt" + } + } + "lang" + { + "Language" "portuguese" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Sua aventura pelas paisagens incríveis da Fronteira continua com o mais recente DLC para Titanfall 2: Cartões-postais da Fronteira. Trazendo locais novos e familiares junto de uma nova coleção de Pinturas de Guerra para Armas de Elite, a Fronteira nunca esteve tão apresentável.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_00_Q" "Trailer de Cartões-postais da Fronteira" + "COMMUNITYUPDATE_01_A" "Leia sobre todas as mudanças trazidas pelo patch Cartões-postais da Fronteira.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_01_Q" "Cartões-postais da Fronteira: Detalhes" + "COMMUNITYUPDATE_02_A" "Em breve nos dispositivos móveis, Titanfall: Assault é um empolgante jogo de estratégia em tempo real situado no universo de Titanfall criado em parceria com Particle City. Veja o jogo em ação aqui!\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_02_Q" "Trailer de lançamento de Titanfall: Assault" + "COMMUNITYUPDATE_03_A" "Iniquity nos guia pelo tutorial e oferece dicas básicas para Titanfall: Assault, a forma perfeita de conhecer o jogo.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_03_Q" "Titanfall: Assault - Vídeo \"Aprenda o básico\"" + "COMMUNITYUPDATE_04_A" "Ouça algumas das principais pessoas por trás de Defesa da Fronteira falarem sobre a história e criação do modo e nos veja jogar algumas rodadas!\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_04_Q" "Respawn Joga: Defesa da Fronteira" + "COMMUNITYUPDATE_05_A" "Kevin Younger criou uma montagem divertida mostrando vários movimentos impressionantes com a Lâmina Sônica.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_05_Q" "Criações da Comunidade: Direto ao Ponto" + "COMMUNITYUPDATE_06_A" "ConzeyG via Reddit demonstra eficiência brutal com a Northstar eliminando Pilotos no modo Marcado para Morrer.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_06_Q" "Criações da Comunidade: Caça com a Northstar" + "COMMUNITYUPDATE_07_A" "Já disponível! Defesa da Fronteira retorna junto de Elevação, além de novas pinturas de guerra à venda e um novo mapa de Queima-roupa. Veja tudo aqui.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_07_Q" "Trailer de Operação Escudo da Fronteira" + "COMMUNITYUPDATE_08_A" "Já disponível! O icônico mapa Jogos de Guerra retorna para Titanfall 2 mais bonito do que nunca. Confira também a nova execução e o novo mapa de Queima-roupa, Tráfego, em ação.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_08_Q" "Trailer de jogabilidade de \"Jogos de Guerra\"" + "COMMUNITYUPDATE_09_A" "Este DLC adiciona o 7º Titã do multiplayer: Monarch, uma versão remasterizada do mapa Relíquia, uma nova execução, além de colocar à venda os Titãs Prime Ronin e Tone, mais camuflagens, fundos de distintivo e decorações. Assista à ação aqui.\n\n\nAperte `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_09_Q" "Trailer de jogabilidade: Reino do Monarca" + "COMMUNITYUPDATE_10_A" "Nem tudo é o que parece na Fronteira - prepare-se para entrar no mais novo pacote de DLC gratuito para Titanfall 2: Falha na Fronteira, trazendo o novo mapa \"Falha\". Inspirado no planeta natal do Capitão Lastimosa, Harmony, o ambiente é dominado por quedas verticais e longos caminhos tortuosos, em um cenário perfeito para encadear longas corridas por paredões e pairar por toda parte. E um novo mapa de Queima-roupa se junta ao conjunto: Convés, com seus espaços internos estreitos, pátios expostos e drones vigilantes circulando sobre sua cabeça. Se você se sentir sobrecarregado, os sempre prestativos Marvins agora estão na área como uma facção inteiramente nova, para dar aquela mãozinha robótica. Finalmente, está disponível a nova execução Lâmina Sônica, para ser usada sempre que for preciso marcar presença.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_10_Q" "Trailer de jogabilidade: Falha na Fronteira" + "COMMUNITYUPDATE_11_A" "É o retorno de um mapa icônico para multiplayer, favorito dos fãs do primeiro Titanfall: Colônia. Com a adição das novas táticas e Titãs de Titanfall 2, os Pilotos e Titãs terão que redobrar a atenção para sobreviver nesta vila idílica e compacta, cheia de becos estreitos, curvas cegas e telhados expostos. Disponível gratuitamente para todos os jogadores a partir do dia 30 de março. O pacote do DLC \"Colônia Renascida\" inclui o retorno de armas clássicas, como o fuzil de assalto modificado R-101, uma nova execução corpo a corpo e novas opções estéticas para você ter o melhor visual enquanto pinta a cidade de vermelho.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_11_Q" "Trailer de jogabilidade: Colônia Renascida" + "COMMUNITYUPDATE_12_A" "Apresentamos Queima-roupa, um modo de jogo ultrarrápido exclusivo para confrontos 6 contra 6 entre Pilotos, com foco na competição e no combate a curta distância. Contém dois novos mapas, criados especialmente para esse modo: Pilhas e Prado. São ambientes fechados e mortais, criados sob medida para a natureza ágil e intensa desse modo. \n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_12_Q" "Trailer: Bem-vindo a Queima-roupa" + "COMMUNITYUPDATE_13_A" "Experimente a versão renovada de um mapa favorito dos fãs no primeiro Titanfall: `1Angel City`0. Aguarde o primeiro DLC grátis de Titanfall 2, `1O Mais Procurado de Angel City`0, disponível dia 1º de dezembro para todos os jogadores. Esse conteúdo inclui novas opções estéticas para adicionar ainda mais bom gosto à Fronteira. \n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_13_Q" "Trailer: Bem-vindo a Angel City" + "COMMUNITYUPDATE_14_A" "Que bom que você voltou.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_14_Q" "Trailer: \"Bis\"" + "COMMUNITYUPDATE_15_A" "Duas lendas, um legado.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_15_Q" "Trailer de jogabilidade: Tornem-se Um" + "COMMUNITYUPDATE_16_A" "Sem limites.\n\n\nPressione `2%[A_BUTTON|MOUSE1]%`0 para visualizar." + "COMMUNITYUPDATE_16_Q" "Trailer de jogabilidade (multiplayer): Pilotos" + "COMMUNITYUPDATE_DESC" "`3Atualizações da Comunidade de Titanfall`0\n\nInformações e links da web.\n\nPara mais:\n`2%$rui/bullet_point%`0Siga-nos no Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Curta nossa página em `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Junte-se a nós em `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "Comunidade" + "KNB_SUBJECT_00_DESC" "`3Quais as novidades de Titanfall?`0\n\nConfira aqui o que mudou em Titanfall 2!" + "KNB_SUBJECT_00_NAME" "Atualizações do jogo" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 Novas insígnias de Distintivos criadas pela comunidade\n\n`2%$rui/bullet_point%`0Agora é possível comprar todos os presentes do colaborador com créditos\n\n`2%$rui/bullet_point%`0Novo conteúdo da loja para comprar\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 de novembro - Época de Colheita" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Espaço Principal de Pistola\n\n`2%$rui/bullet_point%`0Insígnias de Dia das Bruxas\n\n`2%$rui/bullet_point%`0Alterações no Equilíbrio\n\n`2%$rui/bullet_point%`0Novo Conteúdo Para Compras na Loja\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 de outubro - Travessuras e Gostosuras" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Defesa da Fronteira - Suporte para mais 3 mapas - Doca Seca, Angel City e Exoplaneta.\n\n`2%$rui/bullet_point%`0Novo mapa do Queima-roupa - UMA\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - Parede Perfurada\n\n`2%$rui/bullet_point%`0Novo conteúdo à venda na Loja" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 de agosto - Cartões-postais da Fronteira" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Defesa da Fronteira - Um novo modo cooperativo no qual você une forças com até três jogadores para defender um objetivo vital contra as ondas cada vez mais intensas de combatentes da IA. Comunicação e adaptabilidade são as chaves para sobreviver.\n\n`2%$rui/bullet_point%`0Novo Mapa - Elevação\n\n`2%$rui/bullet_point%`0Novo mapa do Queima-roupa - Cidade\n\n`2%$rui/bullet_point%`0Novo conteúdo na Loja" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25/07 - Operação Escudo da Fronteira" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Novo mapa - Jogos de Guerra\n\n`2%$rui/bullet_point%`0Novo mapa de Queima-roupa - Tráfego\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - Boxe Simulado\n\n`2%$rui/bullet_point%`03º espaço de arma\n\n`2%$rui/bullet_point%`0Configurações de partida privada" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27/06 - Jogos de Guerra" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Novo Titã - Monarch\n\n`2%$rui/bullet_point%`0Novo mapa - Relíquia\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - Agora Você Me Vê\n\n`2%$rui/bullet_point%`0Novo conteúdo à venda na Loja" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30/05 - Reino do Monarca" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Novo mapa - Falha\n\n`2%$rui/bullet_point%`0Novo mapa de Queima-roupa - Convés\n\n`2%$rui/bullet_point%`0Nova facção - M.R.V.N.\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - Direto ao Ponto\n\n`2%$rui/bullet_point%`0Geração máxima aumentada para 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25/04 - Falha na Fronteira" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Novo mapa - Colônia\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - Esmaga-crânio\n\n`2%$rui/bullet_point%`0Nova arma - R-101\n\n`2%$rui/bullet_point%`0Novo conteúdo à venda na Loja" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30/03 - Colônia Renascida" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Queima-roupa - Um novo modo de eliminação entre Pilotos! As partidas são disputadas em rodadas de 6v6 sem reaparecimento. Você terá um minuto para eliminar a equipe inimiga e vencer a rodada. Também é possível vencer se sua equipe estiver em posse da bandeira neutra quando o tempo acabar. A primeira equipe a vencer 5 rodadas ganha a partida.\n\n`2%$rui/bullet_point%`0Novo mapa de Queima-roupa - Prado\n\n`2%$rui/bullet_point%`0Novo mapa de Queima-roupa - Pilhas\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - Golpe Atrasado" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23/02 - Queima-roupa" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Novo mapa - Angel City\n\n`2%$rui/bullet_point%`0Nova arma - B3 Wingman de Elite\n\n`2%$rui/bullet_point%`0Nova execução de Piloto - De Dentro para Fora\n\n`2%$rui/bullet_point%`0Novos kits de Titã\n\n`2%$rui/bullet_point%`0Novo conteúdo à venda na Loja" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30/11 - O Mais Procurado de Angel City" + "MP_ANGEL_CITY_FD_WAVE_1" "Ligados aos Céus" + "MP_ANGEL_CITY_FD_WAVE_2" "Sem Formas" + "MP_ANGEL_CITY_FD_WAVE_3" "Insurgência" + "MP_ANGEL_CITY_FD_WAVE_4" "Uma Turma Aguerrida" + "MP_ANGEL_CITY_FD_WAVE_5" "Rolando os Dados" + "MP_DRYDOCK_FD_WAVE_1" "Nadando Contra a Corrente" + "MP_DRYDOCK_FD_WAVE_2" "Eles estão sem balas!" + "MP_DRYDOCK_FD_WAVE_3" "Ofuscado pela ciência" + "MP_DRYDOCK_FD_WAVE_4" "Sistema de Alta Pressão" + "MP_DRYDOCK_FD_WAVE_5" "Olho do Furacão" + "MP_THAW_FD_WAVE_1" "Consciência da Situação" + "MP_THAW_FD_WAVE_2" "A União Faz a Força" + "MP_THAW_FD_WAVE_3" "Capanga 21" + "MP_THAW_FD_WAVE_4" "Brincando com Fogo" + "MP_THAW_FD_WAVE_5" "Sirva Bem à s Armas" + "NO_PRICE" "Oferta expirada" + "NO_PRICE_TWO_LINES" "Oferta\nexpirada" + "PL_aegis_last_titan_standing" "SdT Égide" + "PL_aegis_last_titan_standing_abbr" "SdTE" + "PL_aegis_last_titan_standing_desc" "Melhorias Égide ativadas. Partida de eliminação por rodada. O primeiro a ganhar 3 rodadas vence.\n^FFC83200Jogadores: 5v5 *Começa como Titã\nLimite de tempo: 3 minutos por rodada *Sem reaparecimento\nTamanho máximo do grupo: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Disputa de Titãs Égide" + "PL_aegis_titan_brawl_abbr" "DdTE" + "PL_aegis_titan_brawl_desc" "Elimine Titãs inimigos. Melhorias Égide ativadas.\n^FFC83200Jogadores: 5v5\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 5" + "PL_aegis_titan_brawl_hint" "Elimine Titãs inimigos.\nSem ejeção" + "PL_aegis_titan_brawl_lobby" "Sala de espera: Disputa de Titãs Égide" + "PL_aitdm" "Exaustão" + "PL_aitdm_abbr" "EXA" + "PL_aitdm_desc" "Elimine todos os inimigos.\n^FFC83200Jogadores: 6v6 *IA\nLimite de tempo: 10 min\nTamanho máximo do grupo: 6" + "PL_aitdm_lobby" "Sala de espera: Exaustão" + "PL_all_grapple" "Ataque com Gancho" + "PL_all_grapple_abbr" "EXA" + "PL_all_grapple_desc" "Regras de Exaustão clássicas, exceto todas as habilidades Táticas, são substituídas com Gancho.\n^FFC83200Jogadores: 6v6 *IA\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 6" + "PL_all_grapple_lobby" "Sala de espera: Ataque com Gancho" + "PL_all_holopilot" "A Grande Trapaça" + "PL_all_holopilot_abbr" "QR" + "PL_all_holopilot_desc" "Regras de Queima-roupa clássicas, exceto todas as habilidades Táticas, são substituídas com Holopiloto.\n^FFC83200Jogadores: 6v6 *Sem Titãs\nLimite de tempo: 60 seg.\nTamanho máximo do grupo: 6" + "PL_all_holopilot_lobby" "Sala de espera: A Grande Trapaça" + "PL_all_phase" "O Outrolado" + "PL_all_phase_abbr" "EXA" + "PL_all_phase_desc" "Regras de Exaustão clássicas, exceto todas as habilidades Táticas, são substituídas com Cronossalto.\n^FFC83200Jogadores: 6v6 *IA\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 6" + "PL_all_phase_lobby" "Sala de espera: O Outrolado" + "PL_all_spicy" "Exaustão Apimentada" + "PL_all_spicy_abbr" "EXA" + "PL_all_spicy_desc" "Regras de Exaustão clássicas, exceto todas as habilidades Táticas, são substituídas com Pulgões.\n^FFC83200Jogadores: 6v6 *IA\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 6" + "PL_all_spicy_lobby" "Sala de espera: Exaustão Apimentada" + "PL_amped_tacticals" "Táticas Melhoradas" + "PL_amped_tacticals_abbr" "EXA" + "PL_amped_tacticals_desc" "Regras de Exaustão clássicas, exceto que todas as habilidades Táticas são mais potentes.\n^FFC83200Jogadores: 6v6 *IA\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 6" + "PL_amped_tacticals_lobby" "Sala de espera: Táticas Melhoradas" + "PL_ANGEL_CITY" "Angel City Permanente" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "Somente Angel City, o tempo todo." + "PL_angel_city_lobby" "Sala de espera: Angel City Permanente" + "PL_at_coop" "Fuga (Coop)" + "PL_at_coop_desc" "Você acaba de fugir da prisão só com uma pistola. Sobreviva até o transporte de evacuação chegar. Elimine inimigos para ganhar dinheiro e comprar armas. \n^FFC83200Jogadores: 6\nTamanho máximo do grupo: 6" + "PL_at_coop_lobby" "Sala de espera de Fuga" + "PL_attrition" "Recompensa" + "PL_attrition_abbr" "REC" + "PL_attrition_desc" "Elimine os inimigos para ganhar dinheiro. Deposite os bônus em locais específicos para receber ainda mais.\n^FFC83200Jogadores: 5v5 *IA\nLimite de tempo: 10 min\nTamanho máximo do grupo: 5" + "PL_attrition_lobby" "Sala de espera: Recompensa" + "PL_capture_the_flag" "Captura de Bandeira" + "PL_capture_the_flag_abbr" "CDB" + "PL_capture_the_flag_desc" "Roube a bandeira do inimigo e leve-a para a sua base. Não deixe os inimigos pegarem a sua bandeira!\n^FFC83200Jogadores: 5v5\nLimite de tempo: 12 min\nTamanho máximo do grupo: 5" + "PL_capture_the_flag_lobby" "Sala de espera: CdB" + "PL_coliseum" "Coliseu" + "PL_coliseum_desc" "Duelo com mobilidade extra numa jaula. Elimine seu oponente para vencer a rodada. Melhor de 5 ganha um Presente do Colaborador.^FFC83200\nJogadores: 1v1 *Sem Titãs\nLimite de tempo: 3 min. *Sem reaparecimento\n**^FFFFFF00REQUER BILHETE DO COLISEU ou PAGAMENTO DA TAXA DE ENTRADA" + "PL_coliseum_lobby" "Sala de espera: Coliseu" + "PL_colony" "Colônia Permanente" + "PL_colony_abbr" "COL" + "PL_colony_desc" "Somente Colônia, o tempo todo. ^CCCCCC00Isto vai buscar partidas de ^FFC83200Exaustão^CCCCCC00, ^FFC83200Pilotos vs Pilotos^CCCCCC00 e ^FFC83200Sobrevivência de Titã^CCCCCC00." + "PL_colony_lobby" "Sala de espera de Colônia Permanente" + "PL_ctf_lf" "CdB (Nitro)" + "PL_ctf_lf_abbr" "CdB-N" + "PL_ctf_lf_desc" "Captura de Bandeira frenética em mapas selecionados.\n^FFC83200Jogadores: 5v5\nTamanho máximo do grupo: 5\n^F4D5A600Retorno Imediato de Bandeira" + "PL_ctf_lf_lobby" "Sala de espera: CdB Nitro" + "PL_default_description" "Descrição padrão" + "PL_default_lobbytitle" "Título de sala padrão" + "PL_default_name" "Nome padrão" + "PL_don" "Dobro ou Nada" + "PL_fd" "Defesa da Fronteira" + "PL_fd_desc" "Defenda-se contra ondas da Frota Remanescente" + "PL_fd_easy" "Defesa da Fronteira: Fácil" + "PL_fd_easy_desc" "Destrua a oposição" + "PL_fd_easy_lobby" "Defesa da Fronteira: Sala de espera (Fácil)" + "PL_fd_hard" "Defesa da Fronteira: Difícil" + "PL_fd_hard_desc" "Requer habilidade" + "PL_fd_hard_lobby" "Defesa da Fronteira: Sala de espera (Difícil)" + "PL_fd_insane" "Defesa da Fronteira: Insana" + "PL_fd_insane_desc" "Você não vai sobreviver" + "PL_fd_insane_lobby" "Sala de espera: Defesa da Fronteira (Insana)" + "PL_fd_lobby" "Sala de espera Defesa da Fronteira" + "PL_fd_master" "Defesa da Fronteira: Mestre" + "PL_fd_master_desc" "Somente os melhores entre os melhores têm êxito" + "PL_fd_master_lobby" "Sala de espera: Defesa da Fronteira (Mestre)" + "PL_fd_normal" "Defesa da Fronteira: Normal" + "PL_fd_normal_desc" "Recomendado para jogadores experientes" + "PL_fd_normal_lobby" "Defesa da Fronteira: Sala de espera (Normal)" + "PL_ffa" "Cada Um por Si" + "PL_ffa_abbr" "CPS" + "PL_ffa_desc" "Salve-se quem puder, elimine todos os inimigos.\n^FFC83200Jogadores: 1v11\nLimite de tempo: 10 min\nTamanho máximo do grupo: 1" + "PL_ffa_lobby" "Sala de espera: CUPS" + "PL_fra" "Contrato Livre" + "PL_fra_abbr" "CL" + "PL_fra_desc" "Você está por conta própria. Elimine inimigos para vencer. Junte 3 baterias para chamar um Titã.\n^FFC83200Jogadores: 1v11\nLimite de tempo: 15 min.\nTamanho máximo do grupo: 1" + "PL_fra_lobby" "Sala de espera: CL" + "PL_groud_war_lobby" "Sala de espera: Variedade 8v8" + "PL_ground_war" "Variedade 8v8" + "PL_ground_war_abbr" "8v8" + "PL_ground_war_desc" "Inclui Duelos e Ponto de Controle Amplificado com mais jogadores em todos os mapas.\n^FFC83200Jogadores: 8v8" + "PL_hardpoint" "PCA" + "PL_hardpoint_abbr" "PCA" + "PL_hardpoint_desc" "Capture e mantenha um ponto de controle para acumular pontos. Os Pontos de Controle Amplificados dão pontos em dobro.\n^FFC83200Jogadores: 6v6\nLimite de tempo: 10 min\nTamanho máximo do grupo: 6" + "PL_hardpoint_lobby" "Sala de espera: PCA" + "PL_hardpoint_non_amp" "Ponto de Controle" + "PL_hardpoint_lobby_non_amp" "Sala de espera: Domínio Ponto Controle" + "PL_hunted" "Caçada" + "PL_iron_last_titan_standing" "SdT - Aço" + "PL_iron_last_titan_standing_abbr" "SdTA" + "PL_iron_last_titan_standing_desc" "Partida de rodadas eliminatórias, exclusiva para Titãs. Vence quem conquistar 3 rodadas primeiro.\n^FFC83200Jogadores: 5v5 *SEM PILOTOS\nLimite de tempo: 3 minutos por rodada *Sem reaparecimento\nTamanho máximo do grupo: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Sobrevivência de Titã" + "PL_last_titan_standing_abbr" "SdT" + "PL_last_titan_standing_desc" "Todos os jogadores já começam com Titãs nessa partida de eliminação por rodada. O primeiro a ganhar 3 rodadas vence.\n^FFC83200Jogadores: 5v5 *Começa com Titã\nLimite de tempo: 3 min por rodada *Sem reaparecimento\nTamanho máximo do grupo: 5" + "PL_last_titan_standing_lobby" "Sala de espera: SdT" + "PL_limited_time_mode" "Por tempo limitado" + "PL_live_fire" "Queima-roupa" + "PL_live_fire_abbr" "QR" + "PL_live_fire_desc" "Combate frenético em uma arena de Queima-roupa. Vença a rodada eliminando todos os Pilotos inimigos ou controlando a bandeira quando o tempo acabar.^FFC83200\nJogadores: 6v6 *Sem Titãs\nLimite de tempo: 60 seg. *Sem reaparecimentos\nTamanho máximo do grupo: 6" + "PL_live_fire_lobby" "Sala de Espera: Queima-roupa" + "PL_load_a_map_on_the_command_line" "Carregue um mapa na linha de comando -apenas desenvolvedores" + "PL_marked_for_death" "Marcado para Morrer" + "PL_marked_for_death_abbr" "MPM" + "PL_marked_for_death_desc" "Elimine ou proteja os alvos marcados.\n^FFC83200Jogadores: 6v6 \nLimite de tempo: 12m\nTamanho máximo do grupo: 6" + "PL_marked_for_death_lobby" "Sala de espera: Marcado para Morrer" + "PL_nitro_ffa" "CPS (Nitro)" + "PL_nitro_ffa_abbr" "CPS-N" + "PL_nitro_ffa_desc" "Cada Um Por Si frenético nos mapas selecionados.\n^FFC83200Jogadores: 6\n^F4D5A600Sem Titãs\nSem reforços" + "PL_nitro_ffa_lobby" "Sala de espera: CPS Nitro" + "PL_nitro_mixtape" "Variedade (Nitro)" + "PL_nitro_mixtape_abbr" "VAR-N" + "PL_nitro_mixtape_desc" "CdB, MPM e JxJ frenéticos em mapas selecionados.\n^FFC83200Jogadores: 5v5\nTamanho máximo do grupo: 5\n^F4D5A600Retorno Imediato de Bandeira" + "PL_nitro_mixtape_lobby" "Sala de espera: Variedade" + "PL_pilot_hunter" "Duelos" + "PL_pilot_hunter_abbr" "DUE" + "PL_pilot_hunter_desc" "Elimine Pilotos e Titãs inimigos. \n^FFC83200Jogadores: 8v8\nLimite de tempo: 10 min\nTamanho máximo do grupo: 8" + "PL_pilot_hunter_lobby" "Sala de espera: Duelos" + "PL_pilot_skirmish" "Pilotos vs. Pilotos" + "PL_pilot_skirmish_abbr" "PvP" + "PL_pilot_skirmish_desc" "Elimine os Pilotos inimigos. Não há lançamentos de Titãs.\n^FFC83200Jogadores: 8v8 *Sem Titãs\nLimite de tempo: 10 min\nTamanho máximo do grupo: 8" + "PL_pilot_skirmish_lobby" "Sala de espera: PvP" + "PL_pl_rebuild_all_paths" "Reconstruir todos os caminhos" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Executar com ai_ainRebuildOnMapStart 2" + "PL_private_match" "Partida Privada" + "PL_private_match_desc" "Jogue uma partida privada personalizada em um mapa ou modo de sua escolha.\n^FFC83200CONVIDE A REDE ou CONVIDE OS AMIGOS para jogar.\n^FFC83200Jogadores: 1 a 16\nSem progresso" + "PL_private_match_lobby" "Sala de Espera Privada" + "PL_promo_coop" "Cooperação para 4 jogadores" + "PL_raid" "Incursão" + "PL_glitch" "Falha Permanente" + "PL_glitch_abbr" "FAL" + "PL_glitch_desc" "Somente Falha, o tempo todo. ^CCCCCC00Isto vai buscar partidas de ^FFC83200Captura de Bandeira^CCCCCC00, ^FFC83200Ponto de Controle Amplificado^CCCCCC00, ^FFC83200Pilotos vs Pilotos^CCCCCC00, ^FFC83200Queima-roupa^CCCCCC00 e ^FFC83200Sobrevivência de Titã^CCCCCC00." + "PL_glitch_lobby" "Sala de espera: Falha Permanente" + "PL_rocket_arena" "Arena de Foguetes" + "PL_rocket_arena_abbr" "QR" + "PL_rocket_arena_desc" "Regras de Queima-roupa clássicas, com EPGs modificadas.^FFC83200Jogadores: 6v6 *Sem Titãs\nLimite de tempo: 90 seg.\nTamanho máximo do grupo: 6" + "PL_rocket_arena_lobby" "Sala de espera: Arena de Foguetes" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Configurações para quando alguém carrega um mapa na linha de comando. Não edite cmdlineMapLoad 1 abaixo - isso faz isso funcionar." + "PL_speedball" "Queima-roupa" + "PL_speedball_desc" "Lute pela posse de uma bandeira neutra. Elimine a equipe inimiga ou esteja com a bandeira quando o tempo acabar para vencer a rodada. Vence a equipe que ganhar 5 rodadas primeiro.\n^FFC83200Jogadores: 6v6 *Sem Titãs\nLimite de tempo: 60 segundos por rodada *Sem reaparecimento\nTamanho máximo do grupo: 6" + "PL_speedball_lobby" "Sala de Espera: Queima-roupa" + "PL_tactikill" "Exaustão em Eliminação Tática" + "PL_tactikill_abbr" "EXA" + "PL_tactikill_desc" "Regras de Exaustão clássicas, exceto que todas as habilidades Táticas são totalmente reiniciadas com uma eliminação.\n^FFC83200Jogadores: 6v6 *IA\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 6" + "PL_tactikill_lobby" "Sala de espera: Exaustão em Eliminação Tática" + "PL_titan_brawl" "Disputa de Titãs" + "PL_titan_brawl_abbr" "DdT" + "PL_titan_brawl_desc" "Elimine Titãs inimigos. Proibido Pilotos.\n^FFC83200Jogadores: 5v5\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 5" + "PL_titan_brawl_hint" "Elimine Titãs inimigos.\nSem ejeção" + "PL_titan_brawl_lobby" "Sala de espera: Disputa de Titãs" + "PL_titan_brawl_turbo" "Disputa de Titãs Turbo" + "PL_titan_brawl_turbo_abbr" "DdT" + "PL_titan_brawl_turbo_desc" "Regras de Disputa de Titãs clássicas com regeneração de Arrancada e geração de Núcleo mais rápidas.\n^FFC83200Jogadores: 5v5\nLimite de tempo: 10 min.\nTamanho máximo do grupo: 5" + "PL_titan_brawl_turbo_hint" "Elimine Titãs inimigos.\nSem ejeção" + "PL_titan_brawl_turbo_lobby" "Sala de espera: Disputa de Titãs Turbo" + "PL_turbo_last_titan_standing" "SdT Turbo" + "PL_turbo_last_titan_standing_abbr" "SdT" + "PL_turbo_last_titan_standing_desc" "Regras de SdT clássicas com regeneração de Arrancada e geração de Núcleo mais rápidas.\n^FFC83200Jogadores: 5v5 *Inicia como Titã\nLimite de tempo: 3 min. por rodada *Sem reaparecimentos\nTamanho máximo do grupo: 5" + "PL_turbo_last_titan_standing_lobby" "Sala de espera: SdT Turbo" + "PL_variety_pack" "Variedade" + "PL_variety_pack_desc" "Número variável de jogadores e inclui uma variedade de mapas nos seguintes modos:\n^FFC83200*Recompensa *Exaustão\n*Sobrevivência de Titã *Ponto de Controle Amplificado\n*Pilotos vs. Pilotos *Captura de Bandeira" + "PL_variety_pack_lobby" "Sala de espera: Variedade" + "PL_wargames" "Jogos de Guerra Permanente" + "PL_wargames_abbr" "JDG" + "PL_wargames_desc" "Somente Jogos de Guerra, o tempo todo. ^CCCCCC00Isto vai buscar partidas de ^FFC83200Exaustão^CCCCCC00, ^FFC83200Pilotos vs Pilotos^CCCCCC00, ^FFC83200Ponto de Controle Amplificado^CCCCCC00 e ^FFC83200Sobrevivência de Titã^CCCCCC00." + "PL_wargames_lobby" "Sala de espera: Jogos de Guerra Permanente" + "WATCH_TUTORIAL" "ASSISTA AO TUTORIAL" + "GAMEMODE_TMFD" "Titãs Marcado para Morrer" + "MP_RELIC02_FD_WAVE_1" "Unidos Venceremos" + "MP_RELIC02_FD_WAVE_2" "Buscando o Caminho Correto" + "MP_RELIC02_FD_WAVE_3" "Cortando um Atalho" + "MP_RELIC02_FD_WAVE_4" "Ponto Cego" + "MP_RELIC02_FD_WAVE_5" "Dividir e Emboscar" + } + } + "lang" + { + "Language" "japanese" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "フロンティアの絶景を巡る冒険は、タイタンフォール 2の最新DLCã€ãƒ•ãƒ­ãƒ³ãƒ†ã‚£ã‚¢ã‹ã‚‰ã®ãƒã‚¹ãƒˆã‚«ãƒ¼ãƒ‰ã®ç™»å ´ã§ã•ã‚‰ã«ç¶šãã¾ã™ã€‚æ–°ã‚¹ãƒãƒƒãƒˆã‚„ãŠé¦´æŸ“ã¿ã®ã‚¹ãƒãƒƒãƒˆã«åŠ ãˆã€å¤šå½©ãªæ–°ã—ã„æ­¦å™¨ç”¨ã‚¨ãƒªãƒ¼ãƒˆã‚¦ã‚©ãƒ¼ãƒšã‚¤ãƒ³ãƒˆãŒåŠ ã‚ã£ã¦ã€ãƒ•ãƒ­ãƒ³ãƒ†ã‚£ã‚¢ã®å½©ã‚ŠãŒã‹ã¤ã¦ãªãè±Šã‹ã«ãªã‚Šã¾ã—ãŸã€‚\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴。" + "COMMUNITYUPDATE_00_Q" "「フロンティアからのポストカード」トレーラー" + "COMMUNITYUPDATE_01_A" "フロンティアからのポストカードのパッチで変更された点をすべてご紹介します。\n\n\n`2%[A_BUTTON|MOUSE1]% `0で表示。" + "COMMUNITYUPDATE_01_Q" "フロンティアからのポストカード:パッチノート" + "COMMUNITYUPDATE_02_A" "「タイタンフォール ã‚¢ã‚µãƒ«ãƒˆã€ãŒãƒ¢ãƒã‚¤ãƒ«ã«è¿‘æ—¥ç™»å ´ã€‚Particle Cityとの提携で生まれた、タイタンフォールの世界を舞台にした白熱のリアルタイム・ストラテジーゲームです。ゲーム動画はこちら!\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴。" + "COMMUNITYUPDATE_02_Q" "タイタンフォール アサルト「ローンチ」トレーラー" + "COMMUNITYUPDATE_03_A" "Iniquity氏が「タイタンフォール アサルト」のチュートリアルをプレイしながら、基本的なアドバイスを紹介します。ゲームの初歩を覚えるのに最適です。\n\n\n`2%[A_BUTTON|MOUSE1]% `0で表示。" + "COMMUNITYUPDATE_03_Q" "タイタンフォール アサルト:「入門」動画" + "COMMUNITYUPDATE_04_A" "フロンティアディフェンスの主な製作スタッフが、モードの歴史と制作について語り、ラウンドをプレイします!\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴" + "COMMUNITYUPDATE_04_Q" "スタッフプレイ:フロンティアディフェンス" + "COMMUNITYUPDATE_05_A" "Kevin Younger氏から、華麗にパルスブレードを操る様子を大量に収めた楽しいダイジェスト動画が届きました。\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴" + "COMMUNITYUPDATE_05_Q" "コミュニティー作品:敵はそこだ" + "COMMUNITYUPDATE_06_A" "redditのConzeyGæ°ãŒã€ãƒžãƒ¼ã‚¯ãƒ»ãƒ•ã‚©ãƒ¼ãƒ»ãƒ‡ã‚¹ã§ãƒŽãƒ¼ã‚¹ã‚¹ã‚¿ãƒ¼ãŒæ®‹é…·ãªã¾ã§ã®åŠ¹çŽ‡ã§ãƒ‘ã‚¤ãƒ­ãƒƒãƒˆã®æ¯ã®æ ¹ã‚’æ­¢ã‚ã‚‹æ§˜å­ã‚’æŠ«éœ²ã—ã¦ãã‚Œã¾ã—ãŸã€‚\n\n\n`2%[A_BUTTON|MOUSE1]% `0で表示。" + "COMMUNITYUPDATE_06_Q" "コミュニティー作品:ノーススターのハント" + "COMMUNITYUPDATE_07_A" "å¥½è©•é…ä¿¡ä¸­ï¼ãƒ•ãƒ­ãƒ³ãƒ†ã‚£ã‚¢ãƒ‡ã‚£ãƒ•ã‚§ãƒ³ã‚¹ã¨ãƒžãƒƒãƒ—ã€Œãƒ©ã‚¤ã‚ºã€ãŒå¾©æ´»ã€‚ã•ã‚‰ã«æ–°ã‚¦ã‚©ãƒ¼ãƒšã‚¤ãƒ³ãƒˆã®è²©å£²ãŒå§‹ã¾ã‚Šã€ãƒ©ã‚¤ãƒ–ãƒ•ã‚¡ã‚¤ã‚¢ã«æ–°ãƒžãƒƒãƒ—ãŒç™»å ´ã€‚å®Ÿéš›ã®ãƒ—ãƒ¬ã‚¤ã®æ§˜å­ã‚’ã”è¦§ãã ã•ã„ã€‚\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴。" + "COMMUNITYUPDATE_07_Q" "「フロンティアシールド作戦」GPトレーラー" + "COMMUNITYUPDATE_08_A" "配信開始!シリーズを代表するマップ「ウォーゲームズ」が美しさを増してタイタンフォール 2に戻ってきました。また、新処刑攻撃とライブファイアの新マップ「交通」もご紹介します。\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴。" + "COMMUNITYUPDATE_08_Q" "「ウォーゲームズ」ゲームプレイトレーラー" + "COMMUNITYUPDATE_09_A" "今回のDLCでは、7ä½“ç›®ã®ãƒžãƒ«ãƒãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ç”¨æ–°ã‚¿ã‚¤ã‚¿ãƒ³ã€Œãƒ¢ãƒŠãƒ¼ã‚¯ã€ã¨ãƒªãƒžã‚¹ã‚¿ãƒ¼ç‰ˆãƒžãƒƒãƒ—ã€Œãƒ¬ãƒªãƒƒã‚¯ã€ã€æ–°å‡¦åˆ‘æ”»æ’ƒã®é…ä¿¡ã«åŠ ãˆã€è²©å£²ã‚¢ã‚¤ãƒ†ãƒ ã«ãƒ­ãƒ¼ãƒ‹ãƒ³ãƒ»ãƒˆãƒ¼ãƒ³ç”¨ã®ãƒ—ãƒ©ã‚¤ãƒ ã‚¿ã‚¤ã‚¿ãƒ³ã¨æ–°ã—ã„è¿·å½©ã€ãƒãƒŠãƒ¼ã€ãƒŽãƒ¼ã‚ºã‚¢ãƒ¼ãƒˆãŒç™»å ´ã—ã¾ã™ã€‚å‹•ç”»ã¯ã“ã¡ã‚‰ã€‚\n\n\n`2%[A_BUTTON|MOUSE1]% `0で視聴。" + "COMMUNITYUPDATE_09_Q" "「モナークレイン」ゲームプレイトレーラー" + "COMMUNITYUPDATE_10_A" "ãƒ•ãƒ­ãƒ³ãƒ†ã‚£ã‚¢ã§ã¯ç›®ã«æ˜ ã‚‹ã‚‚ã®ãŒã™ã¹ã¦ã§ã¯ãªã„ã€‚æ–°ãƒžãƒƒãƒ—ã€Œã‚°ãƒªãƒƒãƒã€ã‚’åŽéŒ²ã—ãŸã‚¿ã‚¤ã‚¿ãƒ³ãƒ•ã‚©ãƒ¼ãƒ« 2用最新無料DLCãƒ‘ãƒƒã‚¯ã€ã€Œãƒ•ãƒ­ãƒ³ãƒ†ã‚£ã‚¢ã®ã‚°ãƒªãƒƒãƒã€ã®ç™»å ´ã«å‚™ãˆã‚ˆã†ã€‚ãƒ©ã‚¹ãƒ†ã‚£ãƒ¢ãƒ¼ã‚µå¤§å°‰ã®æ•…éƒ·ã€æƒ‘æ˜Ÿãƒãƒ¼ãƒ¢ãƒ‹ãƒ¼ã‚’ãƒ¢ãƒãƒ¼ãƒ•ã«ä½œæˆã•ã‚ŒãŸã€åž‚ç›´ã«ãã³ãˆã‚‹å£ã¨é•·ãè›‡è¡Œã—ãŸé“ãŒå¤§åŠã‚’å ã‚ã‚‹ãƒžãƒƒãƒ—ã§ã€é•·è·é›¢ã®ã‚¦ã‚©ãƒ¼ãƒ«ãƒ©ãƒ³ã‚’ç¹‹ã’ã€ãƒžãƒƒãƒ—ä¸­ã‚’æ»‘ã‚‰ã‹ã«ç–¾èµ°ã™ã‚‹ã®ã«ã´ã£ãŸã‚Šã®æ§‹æˆã¨ãªã£ã¦ã„ã¾ã™ã€‚ãƒ©ã‚¤ãƒ–ãƒ•ã‚¡ã‚¤ã‚¢ç”¨æ–°ãƒžãƒƒãƒ—ã€ãƒ‡ãƒƒã‚­ã‚‚ç™»å ´ã€‚ã‚¿ã‚¤ãƒˆãªå†…éƒ¨ç©ºé–“ã¨é–‹ã‘ãŸä¸­åº­ã€ä¸Šç©ºã‚’æ—‹å›žã™ã‚‹ç›£è¦–ãƒ‰ãƒ­ãƒ¼ãƒ³ãŒç‰¹å¾´ã§ã™ã€‚ãƒ”ãƒ³ãƒãªæ™‚ã¯ã€ãƒžãƒ¼ãƒ“ãƒ³ãŸã¡ãŒåŠ›ã‚’è²¸ã—ã¦ãã‚Œã¾ã™ã€‚ãã—ã¦ã€ãƒ‘ãƒ«ã‚¹ãƒ–ãƒ¬ãƒ¼ãƒ‰ã‚’ä½¿ã£ãŸã€æ•µã‚’åˆƒã§è²«ãæ–°å‡¦åˆ‘æ”»æ’ƒãŒã‚¢ãƒ³ãƒ­ãƒƒã‚¯å¯èƒ½ã¨ãªã‚Šã¾ã—ãŸã€‚\n\n\n`2%[A_BUTTON|MOUSE1]%`0 で再生。" + "COMMUNITYUPDATE_10_Q" "「フロンティアのグリッチ」 トレーラー" + "COMMUNITYUPDATE_11_A" "ファンの間で人気の高い初代の伝説のマルチプレイヤーマップ「植民地」に戻りましょう。「タイタンフォール 2ã€ã‹ã‚‰ç™»å ´ã—ãŸæ–°ã—ã„æˆ¦è¡“ã‚¢ãƒ“ãƒªãƒ†ã‚£ã¨ã‚¿ã‚¤ã‚¿ãƒ³ã®çŸ¥è­˜ã‚’æ´»ã‹ã•ãªã‘ã‚Œã°ã€è£é€šã‚Šã‚„è¦‹é€šã—ã®åˆ©ã‹ãªã„æ›²ãŒã‚Šè§’ã€ã‚€ãå‡ºã—ã®å±‹ä¸Šã‚¨ãƒªã‚¢ã‹ã‚‰æˆã‚‹å¯†é›†åº¦ã®é«˜ã„ç‰§æ­Œçš„ãªæ‘è½ã§ã€ãƒ‘ã‚¤ãƒ­ãƒƒãƒˆã¨ã‚¿ã‚¤ã‚¿ãƒ³ãŒç”Ÿãå»¶ã³ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ã€‚ãƒžãƒƒãƒ—ã¯3月30日より全プレイヤーに無料配信。DLCパック「コロニーリボーン」には他にも、新デザインのR-101ã‚¢ã‚µãƒ«ãƒˆãƒ©ã‚¤ãƒ•ãƒ«ã¨ã„ã£ãŸå‰ä½œã§ãŠé¦´æŸ“ã¿ã®æ­¦å™¨ã«åŠ ãˆã€ã‚°ãƒ©ãƒƒãƒ—ãƒ«ã‚’ä½¿ã£ãŸæ–°ã—ã„å‡¦åˆ‘æ”»æ’ƒã€è¡—ã‚’æœ€é«˜ã«æ ¼å¥½è‰¯ãè¡€ã«æŸ“ã‚ã‚‹æœ‰æ–™ã®æ–°è£…é£¾ã‚¢ã‚¤ãƒ†ãƒ ã‚’åŽéŒ²ã—ã¦ã„ã¾ã™ã€‚\n\n\n`2%[A_BUTTON|MOUSE1]%`0 で再生。" + "COMMUNITYUPDATE_11_Q" "「コロニーリボーン」ゲームプレイトレーラー" + "COMMUNITYUPDATE_12_A" "`1ライブファイア`0ç™»å ´:パイロット専用、超高速な6対6の接近戦です。ライブファイア専用の最新マップ2種、`1スタック`0と`1草原`0を収録しています。これら2種類の無料マップは、高速の激戦が展開するモード特性に合わせて制作された、タイトで密閉された死のリングです。\n\n\n`2%[A_BUTTON|MOUSE1]%`0で再生。" + "COMMUNITYUPDATE_12_Q" "「ライブファイア」ゲームプレイトレーラー" + "COMMUNITYUPDATE_13_A" "元祖タイタンフォールの人気マップ、`1エンジェルシティ`0のリマスター版を体験せよ!2016å¹´12月1日より全プレイヤーへ配信される無料DLC第1弾、`1エンジェルシティ・モスト・ウォンテッド`0に向けてスタンバイしましょう。フロンティアを彩る新しい装飾オプションも収録しています。\n\n\n`2%[A_BUTTON|MOUSE1]%`0で再生。" + "COMMUNITYUPDATE_13_Q" "「エンジェルシティ」ゲームプレイトレーラー" + "COMMUNITYUPDATE_14_A" "お帰りなさい。\n\n\n`2%[A_BUTTON|MOUSE1]%`0で再生。" + "COMMUNITYUPDATE_14_Q" "絶賛「アンコール」トレーラー" + "COMMUNITYUPDATE_15_A" "2人の伝説、1つの物語。\n\n\n`2%[A_BUTTON|MOUSE1]%`0で再生。" + "COMMUNITYUPDATE_15_Q" "「Become One」ゲームプレイトレーラー" + "COMMUNITYUPDATE_16_A" "無限の可能性。\n\n\n`2%[A_BUTTON|MOUSE1]%`0で再生。" + "COMMUNITYUPDATE_16_Q" "「パイロット」ゲームプレイトレーラー" + "COMMUNITYUPDATE_DESC" "`3ã‚¿ã‚¤ã‚¿ãƒ³ãƒ•ã‚©ãƒ¼ãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã®æœ€æ–°æƒ…å ±`0\n\nã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã‹ã‚‰ã€æƒ…å ±ã‚’ãŸã£ã·ã‚Šã¨ãŠå±Šã‘ã—ã¾ã™ã€‚\n\nè©³ç´°ã¯ã€æ¬¡ã®æ‰‹é †ã§ã”è¦§ãã ã•ã„ã€‚\n`2%$rui/bullet_point%`0Twitterで`1@Respawn`0をフォロー\n`2%$rui/bullet_point%`0`1facebook.com/RespawnEntertainment`0で「いいね!」\n`2%$rui/bullet_point%`0 `1www.respawn.com`0をチェック" + "COMMUNITYUPDATE_NAME" "コミュニティ" + "KNB_SUBJECT_00_DESC" "`3タイタンフォール更新履歴`0\n\nこちらをチェックして、タイタンフォール 2の変更点を確認しましょう!" + "KNB_SUBJECT_00_NAME" "アップデート一覧" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ãƒ¼ç™ºã®æ–°ã‚³ãƒ¼ãƒ«ã‚µã‚¤ãƒ³ã¨ãƒãƒŠãƒ¼ãŒç™»å ´\n\n`2%$rui/bullet_point%`0支持者のギフトがすべてクレジットで購入可能に\n\n`2%$rui/bullet_point%`0ストアに販売アイテムを新入荷\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 11月28æ—¥ - ハーベストタイム" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0メインスロットのピストル装備\n\n`2%$rui/bullet_point%`0ハロウィン仕様バナー\n\n`2%$rui/bullet_point%`0各種バランス調整\n\n`2%$rui/bullet_point%`0ストアに販売アイテムを新入荷\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 10月31æ—¥ - トリック&トリート" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0フロンティアディフェンス - å¯¾å¿œãƒžãƒƒãƒ—ã«ãƒ‰ãƒ©ã‚¤ãƒ‰ãƒƒã‚¯ã€ã‚¨ãƒ³ã‚¸ã‚§ãƒ«ã‚·ãƒ†ã‚£ã€å¤–æƒ‘æ˜Ÿã‚’è¿½åŠ ã€‚\n\n`2%$rui/bullet_point%`0ライブファイアの新マップ - UMA\n\n`2%$rui/bullet_point%`0パイロットの処刑攻撃 - ホール・イン・ザ・ウォール\n\n`2%$rui/bullet_point%`0ã‚¹ãƒˆã‚¢ã«æ–°ç€å•†å“ãŒç™»å ´" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 8月29æ—¥ - フロンティアからのポストカード" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0フロンティアディフェンス - 自分を含め最大4人のプレイヤーでプレイできる協力プレイモード。ゴールは重要な防衛対象を、次第に激しさを増すAIユニットのウェーブから守り通すこと。緊密な連携と臨機応変の対応が勝利のカギになる。\n\n`2%$rui/bullet_point%`0新マップ - ライズ\n\n`2%$rui/bullet_point%`0新ライブファイアマップ - タウンシップ\n\n`2%$rui/bullet_point%`0ストアの新販売アイテム" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 7月25æ—¥ - フロンティアシールド作戦" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0新マップ - ウォーゲーム\n\n`2%$rui/bullet_point%`0ライブファイア用の新マップ - 交通\n\n`2%$rui/bullet_point%`0新パイロット処刑攻撃 - シャドウボクシング\n\n`2%$rui/bullet_point%`0第3の武器スロット\n\n`2%$rui/bullet_point%`0プライベートマッチ設定" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 6月27æ—¥ - ウォーゲーム" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point% `0新型タイタン - モナーク\n\n`2%$rui/bullet_point% `0新マップ - レリック\n\n`2%$rui/bullet_point% `0パイロットの新処刑攻撃 - 俺が見えるな\n\n`2%$rui/bullet_point% `0ã‚¹ãƒˆã‚¢ã«æ–°ç€å•†å“ã‚’è¿½åŠ " + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 5月30æ—¥ - モナークレイン" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point% `0新マップ - グリッチ\n\n`2%$rui/bullet_point% `0ライブファイア用新マップ - デッキ\n\n`2%$rui/bullet_point% `0新勢力 - M.R.V.N.\n\n`2%$rui/bullet_point% `0パイロットの新処刑攻撃 - 敵はそこだ\n\n`2%$rui/bullet_point% `0世代上限を100に上昇" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 4月25æ—¥ - フロンティアのグリッチ" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point% `0新マップ - 植民地\n\n`2%$rui/bullet_point% `0パイロットの新処刑攻撃 - ロードチェック\n\n`2%$rui/bullet_point% `0新兵器 - R-101\n\n`2%$rui/bullet_point% `0ã‚¹ãƒˆã‚¢ã«æ–°ç€å•†å“ã‚’è¿½åŠ " + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 3月30æ—¥ - コロニーリボーン" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point% `0ライブファイア - パイロット同士が、勝ち残りを賭けて戦います!リスポーンなし、6対6のラウンド制マッチで、1åˆ†ä»¥å†…ã«æ•µã‚’å…¨æ»…ã•ã›ã‚‹ã¨ãƒ©ã‚¦ãƒ³ãƒ‰å‹åˆ©ã§ã™ã€‚ã¾ãŸã€ãƒ©ã‚¦ãƒ³ãƒ‰çµ‚äº†æ™‚ã«è‡ªåˆ†ã®ãƒãƒ¼ãƒ ãŒä¸­ç«‹ã®ãƒ•ãƒ©ãƒƒã‚°ã‚’æ‰€æŒã—ã¦ã„ãŸå ´åˆã‚‚å‹åˆ©ã¨ãªã‚Šã¾ã™ã€‚5ラウンド先取したチームがマッチの勝者となります。\n\n`2%$rui/bullet_point% `0ライブファイア用新マップ - 草原\n\n`2%$rui/bullet_point% `0ライブファイア用新マップ - スタック\n\n`2%$rui/bullet_point% `0パイロットの新処刑攻撃 - レイトアタック" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 2月23æ—¥ - ライブファイア" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point% `0新マップ - エンジェルシティ\n\n`2%$rui/bullet_point% `0新兵器 - B3ウィングマン・エリート\n\n`2%$rui/bullet_point% `0パイロットの新処刑攻撃 - インナーピース\n\n`2%$rui/bullet_point% `0新タイタンキット\n\n`2%$rui/bullet_point% `0ã‚¹ãƒˆã‚¢ã«æ–°ç€å•†å“ã‚’è¿½åŠ " + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan%11月30æ—¥ - エンジェルシティモストウォンテッド" + "MP_ANGEL_CITY_FD_WAVE_1" "空に繋がれ" + "MP_ANGEL_CITY_FD_WAVE_2" "不定形" + "MP_ANGEL_CITY_FD_WAVE_3" "æš´å‹•" + "MP_ANGEL_CITY_FD_WAVE_4" "é ‘å¼·ãªä¸€ç¾¤" + "MP_ANGEL_CITY_FD_WAVE_5" "危険な賭け" + "MP_DRYDOCK_FD_WAVE_1" "知らぬ海を泳げ" + "MP_DRYDOCK_FD_WAVE_2" "弾を持たぬ敵" + "MP_DRYDOCK_FD_WAVE_3" "ç§‘å­¦ã®ç›®éš ã—" + "MP_DRYDOCK_FD_WAVE_4" "高圧力システム" + "MP_DRYDOCK_FD_WAVE_5" "台風の目" + "MP_THAW_FD_WAVE_1" "状況把握" + "MP_THAW_FD_WAVE_2" "数の脅威" + "MP_THAW_FD_WAVE_3" "ヘンチマン21" + "MP_THAW_FD_WAVE_4" "銃火器の喜び" + "MP_THAW_FD_WAVE_5" "銃器を活かし切れ" + "NO_PRICE" "オファー終了" + "NO_PRICE_TWO_LINES" "オファー\n終了" + "PL_aegis_last_titan_standing" "イージスLTS" + "PL_aegis_last_titan_standing_abbr" "ALTS" + "PL_aegis_last_titan_standing_desc" "イージスアップグレードが有効。ラウンド単位で勝ち残りを狙う。先に3ラウンド勝利したチームが勝者となる。\n^FFC83200プレイヤー数:5対5 *タイタンでスタート\n時間制限:1ラウンド3分 *リスポーンなし\n最大パーティー人数:5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "イージスタイタンブロール" + "PL_aegis_titan_brawl_abbr" "ATB" + "PL_aegis_titan_brawl_desc" "敵のタイタンを倒せ。イージスアップグレードが有効。\n^FFC83200プレイヤー数:5対5\n時間制限:10分\n最大パーティー人数:5" + "PL_aegis_titan_brawl_hint" "敵のタイタンを倒せ。\n脱出なし" + "PL_aegis_titan_brawl_lobby" "イージスタイタンブロールのロビー" + "PL_aitdm" "消耗戦" + "PL_aitdm_abbr" "ATT" + "PL_aitdm_desc" "敵をすべて片付けろ。\n^FFC83200プレイヤー数:6対6 *AI\n時間制限:10分\n最大パーティー人数:6" + "PL_aitdm_lobby" "消耗戦ロビー" + "PL_all_grapple" "アタック・オン・タイタンフォール" + "PL_all_grapple_abbr" "ATT" + "PL_all_grapple_desc" "戦術アビリティがすべてグラップルに置き換わる以外は、従来の消耗戦と同じルール。\n^FFC83200プレイヤー数:6対6 *AI\n時間制限:10分\n最大パーティー人数:6" + "PL_all_grapple_lobby" "アタック・オン・タイタンフォールのロビー" + "PL_all_holopilot" "華麗なる謀略" + "PL_all_holopilot_abbr" "LF" + "PL_all_holopilot_desc" "戦術アビリティがすべてホロパイロットに置き換わる以外は、従来のライブファイアと同じルール。^FFC83200\nプレイヤー数:6対6 *タイタンなし\n時間制限:60ç§’ *リスポーンなし\n最大パーティー人数:6" + "PL_all_holopilot_lobby" "華麗なる謀略のロビー" + "PL_all_phase" "異次元" + "PL_all_phase_abbr" "ATT" + "PL_all_phase_desc" "戦術アビリティがすべてフェーズに置き換わる以外は、従来の消耗戦と同じルール。\n^FFC83200プレイヤー数:6対6 *AI\n時間制限:10分\n最大パーティー人数:6" + "PL_all_phase_lobby" "異次元のロビー" + "PL_all_spicy" "辛口消耗戦" + "PL_all_spicy_abbr" "ATT" + "PL_all_spicy_desc" "戦術アビリティがすべてティックに置き換わる以外は、従来の消耗戦と同じルール。\n^FFC83200プレイヤー数:6対6 *AI\n時間制限:10分\n最大パーティー人数:6" + "PL_all_spicy_lobby" "辛口消耗戦のロビー" + "PL_amped_tacticals" "戦術強化" + "PL_amped_tacticals_abbr" "ATT" + "PL_amped_tacticals_desc" "戦術アビリティが強化される以外は、従来の消耗戦と同じルール。\n^FFC83200プレイヤー数:6対6 *AI\n時間制限:10分\n最大パーティー人数:6" + "PL_amped_tacticals_lobby" "戦術強化のロビー" + "PL_ANGEL_CITY" "エンジェルシティ24/7" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "エンジェルシティ" + "PL_angel_city_lobby" "エンジェルシティ24/7ロビー" + "PL_at_coop" "脱出(協力プレイ)" + "PL_at_coop_desc" "ピストルだけを手に監獄を脱出した。脱出艇が到着するまで生き残れ。敵を倒して金を稼ぎ、武器を購入しよう。\n^FFC83200プレイヤー数:6\n最大パーティー人数:6" + "PL_at_coop_lobby" "脱出ロビー" + "PL_attrition" "賞金稼ぎ" + "PL_attrition_abbr" "BH" + "PL_attrition_desc" "敵を倒して金を稼げ。稼いだボーナスを特定の地点で「アップロード」すればさらに獲得額が上昇。\n^FFC83200プレイヤー数:5対5 *AI\n時間制限:10分\n最大パーティー人数:5" + "PL_attrition_lobby" "賞金稼ぎロビー" + "PL_capture_the_flag" "キャプチャー・ザ・フラッグ" + "PL_capture_the_flag_abbr" "CTF" + "PL_capture_the_flag_desc" "敵のフラッグを奪って基地へ持ち帰れ。その間も敵チームにこちらのフラッグを奪わせるな!\n^FFC83200プレイヤー数:5対5\n時間制限:12分\n最大パーティー人数:5" + "PL_capture_the_flag_lobby" "CTFロビー" + "PL_coliseum" "コロシアム" + "PL_coliseum_desc" "機動力を強化して、檻の中で1対1で戦う。敵を倒すとラウンド勝利となる。3本先取で支持者のギフトを獲得。^FFC83200\nプレイヤー数:1対1 *タイタンなし\n時間制限:3分 *リスポーンなし\n**^FFFFFF00ã‚³ãƒ­ã‚·ã‚¢ãƒ ãƒã‚±ãƒƒãƒˆã¾ãŸã¯å…¥å ´æ–™ã®æ”¯æ‰•ã„ãŒå¿…è¦" + "PL_coliseum_lobby" "コロシアムロビー" + "PL_colony" "植民地24/7" + "PL_colony_abbr" "植民地" + "PL_colony_desc" "いつでも植民地だけを。^CCCCCC00このリストでは、^FFC83200消耗戦^CCCCCC00、^FFC83200パイロット対パイロット^CCCCCC00と^FFC83200ラスト・タイタン・スタンディング^CCCCCC00のマッチを検索します。" + "PL_colony_lobby" "植民地24/7ロビー" + "PL_ctf_lf" "CTF(ニトロ)" + "PL_ctf_lf_abbr" "CTF-N" + "PL_ctf_lf_desc" "選択したマップで繰り広げる高速のキャプチャー・ザ・フラッグ。\n^FFC83200プレイヤー数:5対5\n最大パーティー人数:5\n^F4D5A600フラッグを即時返還" + "PL_ctf_lf_lobby" "CTFニトロのロビー" + "PL_default_description" "デフォルトの説明" + "PL_default_lobbytitle" "デフォルトのロビータイトル" + "PL_default_name" "デフォルトの名前" + "PL_don" "ダブル・オア・ナッシング" + "PL_fd" "フロンティアディフェンス" + "PL_fd_desc" "残留艦隊の波状攻撃を防ぎきれ" + "PL_fd_easy" "フロンティアディフェンス:イージー" + "PL_fd_easy_desc" "æ•µè»ã‚’æ‰“ã¡ç •ã‘" + "PL_fd_easy_lobby" "フロンティアディフェンス:イージー用ロビー" + "PL_fd_hard" "フロンティアディフェンス:ハード" + "PL_fd_hard_desc" "巧みなプレイが必要" + "PL_fd_hard_lobby" "フロンティアディフェンス:ハード用ロビー" + "PL_fd_insane" "フロンティアディフェンス:マックス" + "PL_fd_insane_desc" "生き残りは不可能" + "PL_fd_insane_lobby" "フロンティアディフェンス:マックスのロビー" + "PL_fd_lobby" "フロンティアディフェンスのロビー" + "PL_fd_master" "フロンティアディフェンス:マスター" + "PL_fd_master_desc" "真の実力者だけが成功をつかむ" + "PL_fd_master_lobby" "フロンティアディフェンス:マスターのロビー" + "PL_fd_normal" "フロンティアディフェンス:レギュラー" + "PL_fd_normal_desc" "熟練プレイヤー向け" + "PL_fd_normal_lobby" "フロンティアディフェンス:レギュラーのロビー" + "PL_ffa" "フリー・フォー・オール" + "PL_ffa_abbr" "FFA" + "PL_ffa_desc" "全パイロットが自分のために戦う。敵をすべて始末しろ。\n^FFC83200プレイヤー数:1対11\n時間制限:10分\n最大パーティー人数:1" + "PL_ffa_lobby" "フリー・フォー・オールロビー" + "PL_fra" "フリー・エージェント" + "PL_fra_abbr" "FRA" + "PL_fra_desc" "1人きりの戦いに挑戦。敵を倒せば勝利だ。バッテリーを3個回収し、タイタンフォールを要請せよ。\n^FFC83200プレイヤー数:1対11\n時間制限:15分\n最大パーティー人数:1" + "PL_fra_lobby" "フリー・エージェントロビー" + "PL_groud_war_lobby" "8v8ミックステープロビー" + "PL_ground_war" "8v8ミックステープ" + "PL_ground_war_abbr" "8v8" + "PL_ground_war_desc" "ã‚¹ã‚«ãƒ¼ãƒŸãƒƒã‚·ãƒ¥ã¨æ‹ ç‚¹å¢—å¹…ã‚’å…¨ãƒžãƒƒãƒ—ã«ãŠã„ã¦å¤§äººæ•°ã§ãƒ—ãƒ¬ã‚¤ã§ãã¾ã™ã€‚\n^FFC83200プレイヤー数:8対8" + "PL_hardpoint" "æ‹ ç‚¹å¢—å¹…" + "PL_hardpoint_abbr" "AHP" + "PL_hardpoint_desc" "æ‹ ç‚¹ã‚’åˆ¶åœ§ã—ã¦å®ˆã‚Šåˆ‡ã‚Œã°ãƒã‚¤ãƒ³ãƒˆã‚’ç²å¾—ã€‚å¢—å¹…ã—ãŸæ‹ ç‚¹ã¯ç²å¾—ãƒã‚¤ãƒ³ãƒˆãŒ2倍になる。\n^FFC83200プレイヤー数:6対6\n時間制限:10分\n最大パーティー人数:6" + "PL_hardpoint_lobby" "æ‹ ç‚¹å¢—å¹…ãƒ­ãƒ“ãƒ¼" + "PL_hardpoint_non_amp" "æ‹ ç‚¹æˆ¦" + "PL_hardpoint_lobby_non_amp" "æ‹ ç‚¹æˆ¦ãƒ­ãƒ“ãƒ¼" + "PL_hunted" "逃亡者" + "PL_iron_last_titan_standing" "アイアンLTS" + "PL_iron_last_titan_standing_abbr" "ILTS" + "PL_iron_last_titan_standing_desc" "タイタンのみ、ラウンド制の勝ち抜き戦。3ラウンド先取で勝利。\n^FFC83200プレイヤー数:5対5 *パイロットなし\n時間制限:1ラウンド3分 *リスポーンなし\n最大パーティー人数:5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "ラスト・タイタン・スタンディング" + "PL_last_titan_standing_abbr" "LTS" + "PL_last_titan_standing_desc" "全員がタイタンに乗った状態で開始し、ラウンド単位で勝ち残りを狙う。先に3ラウンド勝利したチームが勝者となる。\n^FFC83200プレイヤー数:5対5 *タイタンでスタート\n時間制限:1ラウンド3分 *リスポーンなし\n最大パーティー人数:5" + "PL_last_titan_standing_lobby" "LTSロビー" + "PL_limited_time_mode" "期間限定モード" + "PL_live_fire" "ライブファイア" + "PL_live_fire_abbr" "LF" + "PL_live_fire_desc" "高速の戦闘がライブファイア・アリーナで展開。敵パイロットを全滅させるか、タイムオーバー時にフラッグを所持しているとラウンド勝利。^FFC83200\nプレイヤー数:6対6 *タイタンなし\n時間制限:60ç§’ *リスポーンなし\n最大パーティー人数:6" + "PL_live_fire_lobby" "ライブファイアロビー" + "PL_load_a_map_on_the_command_line" "コマンド行でマップをロード -devonly" + "PL_marked_for_death" "マーク・フォー・デス" + "PL_marked_for_death_abbr" "MFD" + "PL_marked_for_death_desc" "マークされた標的の命をめぐる攻防戦。\n^FFC83200プレイヤー数:6対6 \n時間制限:12分\n最大パーティー人数:6" + "PL_marked_for_death_lobby" "マーク・フォー・デス・ロビー" + "PL_nitro_ffa" "FFA(ニトロ)" + "PL_nitro_ffa_abbr" "FFA-N" + "PL_nitro_ffa_desc" "選択したマップで繰り広げる高速のフリー・フォー・オール。\n^FFC83200プレイヤー数:6\n^F4D5A600タイタンなし\nブーストなし" + "PL_nitro_ffa_lobby" "FFAニトロのロビー" + "PL_nitro_mixtape" "ミックステープ(ニトロ)" + "PL_nitro_mixtape_abbr" "MXT-N" + "PL_nitro_mixtape_desc" "選択したマップで繰り広げる高速のCTF、MFDおよびPvP。\n^FFC83200プレイヤー数:5対5\n最大パーティー人数:5\n^F4D5A600フラッグを即時返還" + "PL_nitro_mixtape_lobby" "ミックステープロビー" + "PL_pilot_hunter" "スカーミッシュ" + "PL_pilot_hunter_abbr" "SKM" + "PL_pilot_hunter_desc" "敵のパイロットやタイタンを倒せ。\n^FFC83200プレイヤー数:8対8\n時間制限:10分\n最大パーティー人数:8" + "PL_pilot_hunter_lobby" "スカーミッシュのロビー" + "PL_pilot_skirmish" "パイロット対パイロット" + "PL_pilot_skirmish_abbr" "PvP" + "PL_pilot_skirmish_desc" "æ•µãƒ‘ã‚¤ãƒ­ãƒƒãƒˆã‚’æ’ƒç ´ã›ã‚ˆã€‚ã‚¿ã‚¤ã‚¿ãƒ³ãƒ•ã‚©ãƒ¼ãƒ«ç¦æ­¢ã€‚\n^FFC83200プレイヤー数:8対8 *タイタンなし\n時間制限:10分\n最大パーティー人数:8" + "PL_pilot_skirmish_lobby" "PvPロビー" + "PL_pl_rebuild_all_paths" "進路再建" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "ai_ainRebuildOnMapStart 2 で実行" + "PL_private_match" "プライベートマッチ" + "PL_private_match_desc" "好きなマップとモードを選んで、カスタマイズしたプライベートマッチをプレイしよう。\n^FFC83200ネットワークかフレンドを招待してプレイ。\n^FFC83200プレイヤー数:1~16人\n進行なし" + "PL_private_match_lobby" "プライベートマッチ・ロビー" + "PL_promo_coop" "4人協力プレイ" + "PL_raid" "レイド" + "PL_glitch" "グリッチ24/7" + "PL_glitch_abbr" "GLI" + "PL_glitch_desc" "いつでもグリッチ。^CCCCCC00このリストでは^FFC83200キャプチャー・ザ・フラッグ^CCCCCC00、^FFC83200æ‹ ç‚¹å¢—å¹…^CCCCCC00、^FFC83200パイロット対パイロット^CCCCCC00、^FFC83200ライブファイア^CCCCCC00と^FFC83200ラスト・タイタン・スタンディング^CCCCCC00のマッチを検索します。" + "PL_glitch_lobby" "グリッチ24/7ロビー" + "PL_rocket_arena" "ロケットアリーナ" + "PL_rocket_arena_abbr" "LF" + "PL_rocket_arena_desc" "å¾“æ¥ã®ãƒ©ã‚¤ãƒ–ãƒ•ã‚¡ã‚¤ã‚¢ã¨åŒã˜ãƒ«ãƒ¼ãƒ«ã§ã€æ”¹é€ ã—ãŸEPGを使用する。^FFC83200\nプレイヤー数:6対6 *タイタンなし\n時間制限:90ç§’ *リスポーンなし\n最大パーティー人数:6" + "PL_rocket_arena_lobby" "ロケットアリーナのロビー" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "コマンド行でマップをロードする際の設定。以下のcmdlineMapLoad 1は実行に必要なので編集しないでください。" + "PL_speedball" "ライブファイア" + "PL_speedball_desc" "中立のフラッグを奪い合う。敵チームを排除するか、制限時間終了時に自チームがフラッグを所有していればラウンドに勝利。5ラウンド先取制。\n^FFC83200プレイヤー数:6対6 *タイタンなし\n時間制限:1ラウンドにつき60ç§’ *リスポーンなし\n最大パーティー人数:6" + "PL_speedball_lobby" "ライブファイアロビー" + "PL_tactikill" "戦術キル消耗戦" + "PL_tactikill_abbr" "ATT" + "PL_tactikill_desc" "キル時に戦術アビリティが完全にリセットされる以外は、従来の消耗戦と同じルール。\n^FFC83200プレイヤー数:6対6 *AI\n時間制限:10分\n最大パーティー人数:6" + "PL_tactikill_lobby" "戦術キル消耗戦のロビー" + "PL_titan_brawl" "タイタンブロール" + "PL_titan_brawl_abbr" "TB" + "PL_titan_brawl_desc" "敵のタイタンを倒せ。パイロットは参戦禁止。\n^FFC83200プレイヤー数:5対5\n時間制限:10分\n最大パーティー人数:5" + "PL_titan_brawl_hint" "敵のタイタンを倒せ。\n降機なし。" + "PL_titan_brawl_lobby" "タイタンブロールのロビー" + "PL_titan_brawl_turbo" "ターボタイタンブロール" + "PL_titan_brawl_turbo_abbr" "TTDM" + "PL_titan_brawl_turbo_desc" "ダッシュとコアの回復が早まった状態で、従来のタイタンブロールのルールで戦う。\n^FFC83200プレイヤー数:5対5\n時間制限:10分\n最大パーティー人数:5" + "PL_titan_brawl_turbo_hint" "敵のタイタンを倒せ。\n脱出なし" + "PL_titan_brawl_turbo_lobby" "ターボタイタンブロールのロビー" + "PL_turbo_last_titan_standing" "ターボLTS" + "PL_turbo_last_titan_standing_abbr" "LTS" + "PL_turbo_last_titan_standing_desc" "ダッシュとコアの回復が早まった状態で、従来のLTSのルールで戦う。\n^FFC83200プレイヤー数:5対5 *タイタンでスタート\n時間制限:1ラウンド3分 *リスポーン\n最大パーティー人数:5" + "PL_turbo_last_titan_standing_lobby" "ターボLTSのロビー" + "PL_variety_pack" "ミックステープ" + "PL_variety_pack_desc" "様々なプレイヤー数やマップで、次のモードをプレイできます。\n^FFC83200*賞金稼ぎ *消耗戦\n*ラスト・タイタン・スタンディング *æ‹ ç‚¹å¢—å¹…\n*パイロット対パイロット *キャプチャー・ザ・フラッグ" + "PL_variety_pack_lobby" "ミックステープロビー" + "PL_wargames" "ウォーゲーム24/7" + "PL_wargames_abbr" "WGM" + "PL_wargames_desc" "いつでもウォーゲームだけを。^CCCCCC00このリストでは^FFC83200消耗戦^CCCCCC00、^FFC83200CTF^CCCCCC00、^FFC83200パイロット対パイロット^CCCCCC00、^FFC83200æ‹ ç‚¹å¢—å¹…^CCCCCC00と^FFC83200ラスト・タイタン・スタンディング^CCCCCC00のマッチを検索します。" + "PL_wargames_lobby" "ウォーゲーム24/7のロビー" + "WATCH_TUTORIAL" "チュートリアルを見る" + "GAMEMODE_TMFD" "死ぬべきタイタン" + "MP_RELIC02_FD_WAVE_1" "団結して粘りを" + "MP_RELIC02_FD_WAVE_2" "本道を探して" + "MP_RELIC02_FD_WAVE_3" "他の道を越えて" + "MP_RELIC02_FD_WAVE_4" "ç›®éš ã—æ¿" + "MP_RELIC02_FD_WAVE_5" "別れて待ち伏せを" + } + } + "lang" + { + "Language" "russian" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Продолжите свое приключение на чарующем Фронтире в новом DLC для Titanfall 2 — «Открытки с Фронтира». В нем вас ждут новые и знакомые локации, а также свежая коллекция элитных раскрасок оружия — таким Фронтир вы еще не видели!\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_00_Q" "Трейлер «Открыток с Фронтира»" + "COMMUNITYUPDATE_01_A" "Узнайте, что ждет вас в обновлении «Открытки с Фронтира». \n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_01_Q" "Открытки с Фронтира: изменения" + "COMMUNITYUPDATE_02_A" "Titanfall: Assault — это стратегия в реальном времени во вселенной Titanfall, которую мы разрабатываем для мобильных устройств совместно со студией Particle City. Посмотреть на ее игровой процесс можно здесь! \n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_02_Q" "Трейлер к выходу Titanfall: Assault" + "COMMUNITYUPDATE_03_A" "На канале Iniquity Games разобрано обучение и даются советы по игре Titanfall Assault. Это самый лучший способ ознакомиться с игрой.\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_03_Q" "Titanfall: Assault: видео «Основы игры»" + "COMMUNITYUPDATE_04_A" "Узнайте историю разработки режима «Оборона Фронтира» от нескольких ведущих разработчков и посмотрите, как мы играем в него!\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_04_Q" "Respawn играет в «Оборону Фронтира»" + "COMMUNITYUPDATE_05_A" "Kevin Younger создал забавный ролик, в котором демонстрирует различные приемчики с пульсирующим клинком.\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_05_Q" "Творчество сообщества: На острие" + "COMMUNITYUPDATE_06_A" "ConzeyG с reddit демонстрирует жестокую эффективность «Нордстара», одного за другим уничтожая пилотов в режиме «Приговор — смерть».\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_06_Q" "Сообщество: Охота на пилотов «Нордстара»" + "COMMUNITYUPDATE_07_A" "Уже в игре! «Оборона Фронтира» возвращается вместе с картой «Восход», для покупки доступны новые боевые раскраски, а также появилась новая карта для режима «Перестрелка». Ознакомьтесь с нововведениями здесь. \n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_07_Q" "Трейлер \"Операция «Щит Фронтира»\"" + "COMMUNITYUPDATE_08_A" "Уже в игре! Знаменитая карта «Военные игры» возвращается — и такой вы ее еще не видели! А еще не пропустите новую казнь и карту для «Перестрелки» — «Траффик».\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_08_Q" "Трейлер «Военные игры»" + "COMMUNITYUPDATE_09_A" "Это DLC добавляет «Монарха» (седьмого Титана для сетевой игры), переделанную карту «Святыня», новую казнь, а также «Ронина Прайм», «Тона Прайм», камуфляжи, фоны и рисунки на корпус в магазин. Ознакомиться с игровым процессом можно здесь.\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_09_Q" "Трейлер «Власть монарха»" + "COMMUNITYUPDATE_10_A" "Новое в бесплатном DLC «Разлом на Фронтире»: nкарта для режима «Перестрелка»: «Палуба», nфракция: «Марвины», nказнь для пилота: «Пульсирующий клинок».\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_10_Q" "Трейлер «Разлом на Фронтире»" + "COMMUNITYUPDATE_11_A" "Ставшая культовой карта для сетевого режима оригинального Titanfall «Колония» теперь доступна и в сиквеле! Пилоты Titanfall 2 могут опробовать свои силы в боях на тихих узких улочках, крышах и закрытых двориках небольшой деревеньки. Переосмыслить старые тактики с новыми Титанами и оружием игроки смогут уже с 30 марта — и совершенно бесплатно! Ð’ наборе DLC «Новая колония» вы найдете и новые версии классического оружия (например, винтовку R-101), новую казнь с помощью крюка и улучшения внешнего вида — устраивать резню на улицах города нужно по последней моде!\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_11_Q" "Трейлер «Новая колония»" + "COMMUNITYUPDATE_12_A" "«Перестрелка» — новый адреналиновый режим, в котором две команды из шести пилотов сражаются до последней капли крови. Для этого режима мы специально создали две новые бесплатные карты: «Луг» и «Склад». Это компактные закрытые арены, идеально подходящие для напряженных боев на близких дистанциях.\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_12_Q" "Трейлер «Перестрелка»" + "COMMUNITYUPDATE_13_A" "Всеми любимая карта `1Город Ангелов`0 из первой части Titanfall снова в строю. Первое бесплатное DLC для Titanfall 2 под названием `1Особо опасные в Городе Ангелов`0 доступно для всех игроков с 1 декабря. Ð’ обновлении также есть улучшения внешнего вида, которые немного изменят Фронтир. \n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_13_Q" "Трейлер «Город Ангелов»" + "COMMUNITYUPDATE_14_A" "С возвращением!\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_14_Q" "Трейлер «На бис»" + "COMMUNITYUPDATE_15_A" "Две легенды. Одно наследие.\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_15_Q" "Трейлер одиночной игры «Единое целое»" + "COMMUNITYUPDATE_16_A" "Никаких ограничений.\n\n\nДля просмотра нажмите `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_16_Q" "Трейлер сетевой игры «Пилоты»" + "COMMUNITYUPDATE_DESC" "`3Новости сообщества Titanfall`0\n\nНовости и ссылки со всего Интернета.\n\nХотите еще?\n`2%$rui/bullet_point%`0Подпишитесь на нас в Twitter: `1@Respawn`0\n`2%$rui/bullet_point%`0Поставьте «Нравится» на `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Заходите на `1www.respawn.com`0." + "COMMUNITYUPDATE_NAME" "Сообщество" + "KNB_SUBJECT_00_DESC" "`3Что нового в Titanfall?`0\n\nНовости обновлений Titanfall 2!" + "KNB_SUBJECT_00_NAME" "Обновления игры" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 Новые фоны эмблем от сообщества\n\n`2%$rui/bullet_point%`0Все подарки сторонника теперь доступны за кредиты\n\n`2%$rui/bullet_point%`0Новый платный контент в магазине\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 ноября — время жатвы" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Главная ячейка для пистолета\n\n`2%$rui/bullet_point%`0Фоны на Хэллоуин\n\n`2%$rui/bullet_point%`0Изменения баланса\n\n`2%$rui/bullet_point%`0Новый доступный для покупки контент в магазине\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 октября: «Сласти и страсти»" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0«Оборона Фронтира» — добавлена поддержка 3 карт: Док, Город Ангелов и Экзопланета.\n\n`2%$rui/bullet_point%`0Новая карта для «Перестрелки» — UMA\n\n`2%$rui/bullet_point%`0Новая казнь пилота — Дырявая стена\n\n`2%$rui/bullet_point%`0Новый доступный для покупки контент в магазине" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 августа — Открытки с Фронтира" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Оборона Фронтира — новый совместный режим, в котором вам придется вместе с другими игроками защищать важную цель от усиливающихся волн противников под управлением ИИ. Без общения и умения адаптироваться тут не победить.\n\n`2%$rui/bullet_point%`0Новая карта: «Восход»\n\n`2%$rui/bullet_point%`0Новая карта для «Перестрелки»: «Поселок»\n\n`2%$rui/bullet_point%`0Новый доступный для покупки контент в магазине" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25 июля: операция «Щит Фронтира»" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Новая карта — «Военные игры»\n\n`2%$rui/bullet_point%`0Новая карта для режима «Перестрелка» — «Траффик»\n\n`2%$rui/bullet_point%`0Новая казнь пилота — «Бой с тенью»\n\n`2%$rui/bullet_point%`03 ячейка для оружия\n\n`2%$rui/bullet_point%`0Настройки частных матчей" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27 июня: «Военные игры»" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Новый Титан: «Монарх»\n\n`2%$rui/bullet_point%`0Новая карта: «Святыня»\n\n`2%$rui/bullet_point%`0Новая казнь пилота: «Иллюзия обмана»\n\n`2%$rui/bullet_point%`0Новый контент в магазине" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30 мая: Власть монарха" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Новая карта: «Разлом»\n\n`2%$rui/bullet_point%`0Новая карта для «Перестрелки»: «Палуба»\n\n`2%$rui/bullet_point%`0Новая фракция: МРВН\n\n`2%$rui/bullet_point%`0Новая казнь пилота: «На острие»\n\n`2%$rui/bullet_point%`0Увеличение макс. поколения до 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25 апреля: Разлом на Фронтире" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Новая карта: «Колония»\n\n`2%$rui/bullet_point%`0Новая казнь пилота: «Череподав»\n\n`2%$rui/bullet_point%`0Новое оружие: R-101\n\n`2%$rui/bullet_point%`0Новый контент в магазине" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30 марта: Новая колония" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0«Перестрелка» — новый режим на выбывание для пилотов! Вас ждут битвы 6 на 6 без возможности возрождения. Выигрывает та команда, которая уничтожит соперника за одну минуту или будет удерживать нейтральный флаг по окончании отсчета. Первая команда, выигравшая в пяти раундах, побеждает.\n\n`2%$rui/bullet_point%`0Новые карты для «Перестрелки»: «Луг» и «Склад»\n\n`2%$rui/bullet_point%`0Новая казнь пилота: «Поздний удар»" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23 февраля: Перестрелка" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Новая карта: «Город Ангелов»\n\n`2%$rui/bullet_point%`0Новое оружие: «Элитный ведомый B3»\n\n`2%$rui/bullet_point%`0Новая казнь пилота: «Внутренности»\n\n`2%$rui/bullet_point%`0Новые наборы для Титанов\n\n`2%$rui/bullet_point%`0Новый контент в магазине" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30 ноября: Особо опасные в Городе Ангелов" + "MP_ANGEL_CITY_FD_WAVE_1" "Пленники небес" + "MP_ANGEL_CITY_FD_WAVE_2" "Бесформенность" + "MP_ANGEL_CITY_FD_WAVE_3" "Мятеж" + "MP_ANGEL_CITY_FD_WAVE_4" "Неумолимый жребий" + "MP_ANGEL_CITY_FD_WAVE_5" "Пойти ва-банк" + "MP_DRYDOCK_FD_WAVE_1" "Неизведанные воды" + "MP_DRYDOCK_FD_WAVE_2" "У них кончились патроны!" + "MP_DRYDOCK_FD_WAVE_3" "Ослепленные наукой" + "MP_DRYDOCK_FD_WAVE_4" "Система высокого давления" + "MP_DRYDOCK_FD_WAVE_5" "Око бури" + "MP_THAW_FD_WAVE_1" "Действия по ситуации" + "MP_THAW_FD_WAVE_2" "Сила в количестве" + "MP_THAW_FD_WAVE_3" "Приспешник-21" + "MP_THAW_FD_WAVE_4" "Игры с огнем" + "MP_THAW_FD_WAVE_5" "Одним великанам под силу" + "NO_PRICE" "Истекло" + "NO_PRICE_TWO_LINES" "Истекло" + "PL_aegis_last_titan_standing" "ПиТ «Эгида»" + "PL_aegis_last_titan_standing_abbr" "ПиТЭ" + "PL_aegis_last_titan_standing_desc" "Доступны улучшения Эгиды. Многораундовая игра до последнего выжившего. Побеждает команда, которая первой выиграет 3 раунда.\n^FFC83200Игроки: 5 на 5 *Сразу есть Титан\nЛимит времени: 3 минуты на раунд *Без возрождений\nРазмер команды: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Битва Титанов «Эгида»" + "PL_aegis_titan_brawl_abbr" "ДТЭ" + "PL_aegis_titan_brawl_desc" "Убивайте вражеских Титанов. Доступны улучшения Эгиды.\n^FFC83200Игроки: 5 на 5\nЛимит времени: 10 минут\nРазмер команды: 5" + "PL_aegis_titan_brawl_hint" "Убивайте вражеских Титанов.\nКатапультирование запрещено" + "PL_aegis_titan_brawl_lobby" "Лобби: Битва Титанов «Эгида»" + "PL_aitdm" "Истребление" + "PL_aitdm_abbr" "ИСТ" + "PL_aitdm_desc" "Убить всех врагов.\n^FFC83200Игроки: 6 на 6 *ИИ\nВремя: 10 мин\nРазмер команды: 6" + "PL_aitdm_lobby" "Лобби: Истребление" + "PL_all_grapple" "Атака на Titanfall" + "PL_all_grapple_abbr" "ИСТ" + "PL_all_grapple_desc" "Классическое «Истребление», где все тактические умения заменены на крюк-кошку.\n^FFC83200Игроки: 6 на 6 * ИИ\nВремя: 10 мин\nРазмер команды: 6" + "PL_all_grapple_lobby" "Лобби «Атака на Titanfall»" + "PL_all_holopilot" "Великая разводка" + "PL_all_holopilot_abbr" "ПС" + "PL_all_holopilot_desc" "Классическая «Перестрелка», где все тактические умения заменены голопилотом.^FFC83200\nИгроки: 6 на 6 * Без Титанов\nВремя: 60 с * Без возрождений\nРазмер команды: 6" + "PL_all_holopilot_lobby" "Лобби «Великая разводка»" + "PL_all_phase" "Иная сторона" + "PL_all_phase_abbr" "ИСТ" + "PL_all_phase_desc" "Классическое «Истребление», где все тактические умения заменены на фазовый сдвиг.\n^FFC83200Игроки: 6 на 6 * ИИ\nВремя: 10 мин\nРазмер команды: 6" + "PL_all_phase_lobby" "Лобби: Иная сторона" + "PL_all_spicy" "Острое истребление" + "PL_all_spicy_abbr" "ИСТ" + "PL_all_spicy_desc" "Классическое «Истребление», где все тактические умения заменены на клещи.\n^FFC83200Игроки: 6 на 6 * ИИ\nВремя: 10 мин\nРазмер команды: 6" + "PL_all_spicy_lobby" "Лобби: Острое истребление" + "PL_amped_tacticals" "Усиленная тактика" + "PL_amped_tacticals_abbr" "ИСТ" + "PL_amped_tacticals_desc" "Классическое «Истребление», где все тактические умения значительно усилены.\n^FFC83200Игроки: 6 на 6 * ИИ\nВремя: 10 мин\nРазмер команды: 6" + "PL_amped_tacticals_lobby" "Лобби «Усиленная тактика»" + "PL_ANGEL_CITY" "Город Ангелов 24/7" + "PL_angel_city_abbr" "ГА" + "PL_angel_city_desc" "Город Ангелов в трех режимах." + "PL_angel_city_lobby" "Лобби: Город Ангелов 24/7" + "PL_at_coop" "Побег (совместно)" + "PL_at_coop_desc" "Ð’Ñ‹ сбежали из тюрьмы с одним лишь пистолетом. Продержитесь до прибытия спасательного транспорта. Убивайте врагов, чтобы заработать деньги на оружие. \n^FFC83200Игроки: 6\nРазмер команды: 6" + "PL_at_coop_lobby" "Лобби: Побег" + "PL_attrition" "Охота за наживой" + "PL_attrition_abbr" "ОН" + "PL_attrition_desc" "Зарабатывайте деньги, убивая врагов. Заработайте больше, сдавая бонус в банк в указанных местах.\n^FFC83200Игроки: 5 на 5 *ИИ\nЛимит времени: 10 мин\nРазмер команды: 5" + "PL_attrition_lobby" "Лобби: Охота за наживой" + "PL_capture_the_flag" "Захват флага" + "PL_capture_the_flag_abbr" "ЗФ" + "PL_capture_the_flag_desc" "Захватите вражеский флаг и доставьте его на свою базу. Не дайте команде противника захватить ваш флаг!\n^FFC83200Игроки: 5 на 5\nЛимит времени: 12 мин\nРазмер команды: 5" + "PL_capture_the_flag_lobby" "Лобби: Захват флага" + "PL_coliseum" "Колизей" + "PL_coliseum_desc" "Поединок в «клетке» с повышенной мобильностью. Чтобы выиграть раунд, убейте противника. Игрок, выигравший 3 из 5 раундов, получает подарок сторонника.^FFC83200\nИгроки: 1 на 1 *Без Титанов\nЛимит времени: 3 мин *Без возрождения\n**^FFFFFF00Требуется БИЛЕТ или ВНЕСЕНИЕ ПЛАТЫ" + "PL_coliseum_lobby" "Лобби: Колизей" + "PL_colony" "«Колония» 24/7" + "PL_colony_abbr" "КОЛ" + "PL_colony_desc" "«Колония» круглосуточно. ^CCCCCC00Поиск матчей в режимах ^FFC83200«Истребление»^CCCCCC00, ^FFC83200«Пилоты против пилотов»^CCCCCC00 и ^FFC83200«Последний из Титанов»^CCCCCC00." + "PL_colony_lobby" "Лобби: «Колония» 24/7" + "PL_ctf_lf" "ЗФ (Нитро)" + "PL_ctf_lf_abbr" "ЗФ-Н" + "PL_ctf_lf_desc" "Быстрая игра в режиме «Захват флага» на картах режима «Перестрелка».\n^FFC83200Игроки: 5 на 5\nРазмер команды: 5\n^F4D5A600Мгновенный возврат флага" + "PL_ctf_lf_lobby" "Лобби: ЗФ Нитро" + "PL_default_description" "Описание по умолчанию" + "PL_default_lobbytitle" "Название лобби по умолчанию" + "PL_default_name" "Название по умолчанию" + "PL_don" "Все или ничего" + "PL_fd" "Оборона Фронтира" + "PL_fd_desc" "Обороняйтесь от волн наступающих врагов" + "PL_fd_easy" "Оборона Фронтира: легко" + "PL_fd_easy_desc" "Сокрушите противника" + "PL_fd_easy_lobby" "Оборона Фронтира: лобби, легко" + "PL_fd_hard" "Оборона Фронтира: сложно" + "PL_fd_hard_desc" "Требуется хорошее умение игры" + "PL_fd_hard_lobby" "Оборона Фронтира: лобби, тяжело" + "PL_fd_insane" "Оборона Фронтира: безумие" + "PL_fd_insane_desc" "Вам не выжить" + "PL_fd_insane_lobby" "Лобби: Оборона Фронтира - безумие" + "PL_fd_lobby" "Лобби: Оборона Фронтира" + "PL_fd_master" "Оборона Фронтира: мастер" + "PL_fd_master_desc" "Преуспеют только лучшие из лучших" + "PL_fd_master_lobby" "Лобби: Оборона Фронтира - мастер" + "PL_fd_normal" "Оборона Фронтира: нормально" + "PL_fd_normal_desc" "Рекомендуется для опытных игроков" + "PL_fd_normal_lobby" "Лобби: «Оборона Фронтира», нормально" + "PL_ffa" "Все против всех" + "PL_ffa_abbr" "ВПВ" + "PL_ffa_desc" "Каждый сам за себя. Убейте всех пилотов.\n^FFC83200Игроки: 1 на 11\nЛимит времени: 10 мин\nРазмер команды: 1" + "PL_ffa_lobby" "Лобби: Все против всех" + "PL_fra" "Вольные пилоты" + "PL_fra_abbr" "ВПЛ" + "PL_fra_desc" "Каждый за себя. Убивайте врагов, чтобы победить. Соберите 3 батареи, чтобы вызвать Титана.\n^FFC83200Игроки: 1 на 11\nЛимит времени: 15 мин\nРазмер команды: 1" + "PL_fra_lobby" "Лобби: Вольные пилоты" + "PL_groud_war_lobby" "Смешанный набор 8 на 8: лобби" + "PL_ground_war" "Смешанный набор 8 на 8" + "PL_ground_war_abbr" "8 на 8" + "PL_ground_war_desc" "Ð’ составе: «Схватка» и «Усиленные опорные пункты». Большое количество игроков на всех картах.\n^FFC83200Игроки: 8 на 8" + "PL_hardpoint" "Усиленные опорные пункты" + "PL_hardpoint_abbr" "УОП" + "PL_hardpoint_desc" "Захватите и удерживайте опорные пункты, чтобы заработать очки. Усиленные опорные пункты приносят в 2 раза больше очков.\n^FFC83200Игроки: 6 на 6\nЛимит времени: 10 мин\nРазмер команды: 6" + "PL_hardpoint_lobby" "Лобби: Усиленные опорные пункты" + "PL_hardpoint_non_amp" "Захват опорных пунктов" + "PL_hardpoint_lobby_non_amp" "Лобби (Захват опорных пунктов" + "PL_hunted" "Добыча" + "PL_iron_last_titan_standing" "Железный ПИТ" + "PL_iron_last_titan_standing_abbr" "ЖЛЗН" + "PL_iron_last_titan_standing_desc" "Только Титаны, многораундовая игра до последнего выжившего. Побеждает игрок, который первым выиграет в 3 раундах.\n^FFC83200Игроки: 5 на 5 *БЕЗ ПИЛОТОВ\nЛимит времени: 3 мин на раунд *Без возрождений\nРазмер команды: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Последний из Титанов" + "PL_last_titan_standing_abbr" "ПИТ" + "PL_last_titan_standing_desc" "Ð’ этой многораундовой игре на выбывание у каждого игрока сразу есть Титан. Побеждает команда, которая первой выиграет 3 раунда.\n^FFC83200Игроки: 5 на 5 *Сразу есть Титан\nЛимит времени: 3 минуты на раунд *Без возрождений\nРазмер команды: 5" + "PL_last_titan_standing_lobby" "Лобби: Последний из Титанов" + "PL_limited_time_mode" "(временно)" + "PL_live_fire" "Перестрелка" + "PL_live_fire_abbr" "ПЕР" + "PL_live_fire_desc" "Динамичные бои на арене. Для победы необходимо перебить всех вражеских пилотов или удерживать флаг на момент истечения таймера.^FFC83200\nИгроки: 6 на 6 * Без Титанов\nВремя: 60 с * Без возрождений\nРазмер команды: 6" + "PL_live_fire_lobby" "Лобби: Перестрелка" + "PL_load_a_map_on_the_command_line" "Загрузка карты из командной строки -devonly" + "PL_marked_for_death" "Приговор — смерть" + "PL_marked_for_death_abbr" "П-С" + "PL_marked_for_death_desc" "Убивайте или защищайте приговоренные цели.\n^FFC83200Игроки: 6 на 6\nВремя: 12 мин\nРазмер команды: 6" + "PL_marked_for_death_lobby" "Лобби: Приговор — смерть" + "PL_nitro_ffa" "ВПВ (Нитро)" + "PL_nitro_ffa_abbr" "ВПВ-Н" + "PL_nitro_ffa_desc" "Стремительные битвы «Все против всех» на избранных картах.\n^FFC83200Игроки: 6\n^F4D5A600Без Титанов\nБез усилений" + "PL_nitro_ffa_lobby" "ВПВ (Нитро): лобби" + "PL_nitro_mixtape" "Смешанный набор (Нитро)" + "PL_nitro_mixtape_abbr" "СН-Н" + "PL_nitro_mixtape_desc" "Стремительные битвы ЗФ, П-С и PvP на избранных картах.\n^FFC83200Игроки: 5 на 5\nРазмер команды: 5\n^F4D5A600Мгновенный возврат флага" + "PL_nitro_mixtape_lobby" "Смешанный набор: лобби" + "PL_pilot_hunter" "Схватка" + "PL_pilot_hunter_abbr" "СХВ" + "PL_pilot_hunter_desc" "Убивайте вражеских пилотов и Титанов. \n^FFC83200Игроки: 8 на 8\nЛимит времени: 10 мин\nРазмер команды: 8" + "PL_pilot_hunter_lobby" "Лобби (Схватка)" + "PL_pilot_skirmish" "Пилоты против пилотов" + "PL_pilot_skirmish_abbr" "ППП" + "PL_pilot_skirmish_desc" "Убивайте вражеских пилотов. Высадка Титана не разрешена.\n^FFC83200Игроки: 8 на 8 *Без Титанов\nЛимит времени: 10 мин\nРазмер команды: 8" + "PL_pilot_skirmish_lobby" "Лобби: Пилоты против пилотов" + "PL_pl_rebuild_all_paths" "Восстановить все пути" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Запуск с ai_ainRebuildOnMapStart 2" + "PL_private_match" "Частный матч" + "PL_private_match_desc" "Проведите частный матч на карте и в режиме по своему выбору.\n^FFC83200ПРИГЛАШАЙТЕ СЕТЬ или ПРИГЛАШАЙТЕ ДРУЗЕЙ на игру\n^FFC83200Игроки: 1-16\nБез прогресса" + "PL_private_match_lobby" "Лобби частного матча" + "PL_promo_coop" "Совместная игра на 4 игроков" + "PL_raid" "Налет" + "PL_glitch" "«Разлом» 24/7 " + "PL_glitch_abbr" "РЗЛМ" + "PL_glitch_desc" "«Разлом» 24/7. ^CCCCCC00Поиск матчей в режимах ^FFC83200ЗФ^CCCCCC00, ^FFC83200«Усиленные опорные пункты»^CCCCCC00, ^FFC83200«Пилоты против пилотов»^CCCCCC00, ^FFC83200«Перестрелка»^CCCCCC00 и ^FFC83200«Последний из Титанов»^CCCCCC00." + "PL_glitch_lobby" "Лобби: «Разлом» 24/7" + "PL_rocket_arena" "Ракетная арена" + "PL_rocket_arena_abbr" "ПС" + "PL_rocket_arena_desc" "Классическая «Перестрелка» с модифицированными ЭПУ.^FFC83200\nИгроки: 6 на 6 * Без Титанов\nВремя: 90 с * Без возрождений\nРазмер команды: 6" + "PL_rocket_arena_lobby" "Лобби: Ракетная арена" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Настройки на случай загрузки карты из командной строки. Не редактируйте cmdlineMapLoad 1 ниже (благодаря этому все и работает)." + "PL_speedball" "Перестрелка" + "PL_speedball_desc" "Сражение идет за владение нейтральным флагом. Для победы в раунде необходимо уничтожить всех вражеских игроков или захватить флаг до окончания отсчета. Побеждает команда, первой достигшая пяти побед.\n^FFC83200Игроков: 6 на 6 *Без Титанов\nОграничение по времени: 60 секунд на раунд *Без возрождений\nРазмер команды: 6" + "PL_speedball_lobby" "Лобби: Перестрелка" + "PL_tactikill" "Тактическое истребление" + "PL_tactikill_abbr" "ИСТ" + "PL_tactikill_desc" "Классическое «Истребление», где убийства полностью восстанавливают тактические способности.\n^FFC83200Игроки: 6 на 6 * ИИ\nВремя: 10 мин\nРазмер команды: 6" + "PL_tactikill_lobby" "Лобби «Тактическое истребление»" + "PL_titan_brawl" "Битва Титанов" + "PL_titan_brawl_abbr" "БТ" + "PL_titan_brawl_desc" "Убивайте вражеских Титанов. Пилоты в бою не участвуют.\n^FFC83200Игроки: 5 на 5\nЛимит времени: 10 мин\nРазмер команды: 5" + "PL_titan_brawl_hint" "Убивайте вражеских Титанов.\nКатапультирование запрещено" + "PL_titan_brawl_lobby" "Лобби: Битва Титанов" + "PL_titan_brawl_turbo" "Турбодрака Титанов" + "PL_titan_brawl_turbo_abbr" "КМНБ" + "PL_titan_brawl_turbo_desc" "Классическая «Драка Титанов» с ускоренными перезарядкой рывка и зарядом ядра.\n^FFC83200Игроки: 5 на 5\nВремя: 10 мин.\nРазмер команды: 5" + "PL_titan_brawl_turbo_hint" "Убивайте вражеских Титанов.\nКатапультирование запрещено" + "PL_titan_brawl_turbo_lobby" "Лобби: Турбодрака Титанов" + "PL_turbo_last_titan_standing" "Турбо-ПИТ" + "PL_turbo_last_titan_standing_abbr" "ПИТ" + "PL_turbo_last_titan_standing_desc" "Классический «Последний из Титанов» с ускоренными перезарядкой рывка и зарядом ядра.\n^FFC83200Игроки: 5 на 5 * Сразу есть Титан\nВремя: 3 минуты на раунд * Без возрождений\nРазмер команды: 5" + "PL_turbo_last_titan_standing_lobby" "Лобби: Турбо-ПИТ" + "PL_variety_pack" "Смешанный набор" + "PL_variety_pack_desc" "Разное количество игроков и разнообразные карты. Режимы:\n^FFC83200*Охота за наживой *Истребление\n*Последний из Титанов *Усиленные опорные пункты\n*Пилоты против пилотов *Захват флага" + "PL_variety_pack_lobby" "Смешанный набор: лобби" + "PL_wargames" "«Военные игры» 24/7" + "PL_wargames_abbr" "ВНИ" + "PL_wargames_desc" "Круглосуточные «Военные игры». ^CCCCCC00Начинает поиск матчей в режимах ^FFC83200«Истребление»^CCCCCC00, ^FFC83200«ЗФ»^CCCCCC00, ^FFC83200«Пилоты против пилотов»^CCCCCC00, ^FFC83200«Усиленные опорные пункты»^CCCCCC00 и ^FFC83200«Последний из Титанов»^CCCCCC00." + "PL_wargames_lobby" "Лобби: «Военные игры» 24/7" + "WATCH_TUTORIAL" "СМОТРЕТЬ ОБУЧЕНИЕ" + "GAMEMODE_TMFD" "Титанов Приговор — смерть" + "MP_RELIC02_FD_WAVE_1" "Все как один" + "MP_RELIC02_FD_WAVE_2" "Прокладывая путь" + "MP_RELIC02_FD_WAVE_3" "Мы пойдем другим путем" + "MP_RELIC02_FD_WAVE_4" "Слепая зона" + "MP_RELIC02_FD_WAVE_5" "Удар исподтишка" + } + } + "lang" + { + "Language" "spanish" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Tu aventura por los espectaculares paisajes de la Frontera continúa con el nuevo DLC de Titanfall 2: Postales de la Frontera. Con ubicaciones nuevas y familiares, así como una nueva colección de pinturas de guerra de armas de élite, la Frontera ahora es más espectacular que nunca.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_00_Q" "Tráiler de juego de «Postales de la Frontera»" + "COMMUNITYUPDATE_01_A" "Descubre todas las novedades del parche Postales de la Frontera.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_01_Q" "Postales de la Frontera: notas de parche" + "COMMUNITYUPDATE_02_A" "Disponible muy pronto para dispositivos móviles, Titanfall: Assault es un juego de ETR en el universo de Titanfall creado junto a Particle City. ¡Puedes verlo en acción aquí! \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_02_Q" "Tráiler «Lanzamiento» de Titanfall: Assault" + "COMMUNITYUPDATE_03_A" "Iniquity nos guía por el tutorial y nos da consejos básicos para Titanfall Assault, la forma perfecta de iniciarse en este juego.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_03_Q" "Titanfall Assault: vídeo «Fundamentos»" + "COMMUNITYUPDATE_04_A" "¡Escucha a algunos de los desarrolladores claves de Defensa fronteriza hablar de la historia y creación del modo, mientras jugamos unas rondas. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_04_Q" "Respawn Plays: Defensa fronteriza" + "COMMUNITYUPDATE_05_A" "Kevin Younger ha creado un divertido montaje con muchas jugadas espectaculares con el filo de pulso. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_05_Q" "Creaciones de la comunidad: Incisivo" + "COMMUNITYUPDATE_06_A" "ConzeyG en reddit demuestra una eficacia brutal con el Northstar eliminando pilotos en Condenado. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_06_Q" "Creaciones de la comunidad: Cazapilotos Northstar" + "COMMUNITYUPDATE_07_A" "¡Ya disponible! Vuelve Defensa fronteriza junto con Ascenso, y nuevas pinturas a la venta y un nuevo mapa de Munición real. Puedes verlo en acción aquí.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_07_Q" "Tráiler de juego de «Op. Escudo fronterizo»" + "COMMUNITYUPDATE_08_A" "¡Ya disponible! El icónico mapa Juegos de guerra vuelve a Titanfall 2, con mejores gráficos que nunca. Echa también un vistazo a la nueva ejecución y al nuevo mapa de Munición real.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_08_Q" "Tráiler de juego de «Juegos de guerra»" + "COMMUNITYUPDATE_09_A" "Este DLC marca la llegada del 7.º titán de Multijugador, el Monarch; un mapa remasterizado, Reliquia, y una nueva ejecución, así como artículos adquiribles como los nuevos titanes prime Ronin y Tone, más camuflajes, indicativos y decoraciones. Disfruta de la acción aquí.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para ver." + "COMMUNITYUPDATE_09_Q" "Tráiler de juego de «Reino del Monarch»" + "COMMUNITYUPDATE_10_A" "En la Frontera no todo es lo que parece. Prepárate para el nuevo DLC gratuito de Titanfall 2, Un glitch en la Frontera, con el nuevo mapa «Glitch». Inspirado en el planeta natal del capitán Lastimosa, Armonía, aquí encontrarás un paisaje dominado por desniveles verticales y rutas largas y serpenteantes, ideal para encadenar carreras por muros y así cruzar ágilmente el mapa. Y, además, un nuevo mapa de Munición real, «Cubierta», con espacios constreñidos, patios expuestos y drones que acechan patrullando desde arriba. Y si te sientes abrumado(a), los siempre serviciales marvins han llegado como una nueva facción para echarte una mano (robótica). Finalmente, ya se puede desbloquear la nueva ejecución con el filo de pulso, para cuando quieras ponerte «incisivo(a)».\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_10_Q" "Tráiler de juego «Un glitch en la Frontera»" + "COMMUNITYUPDATE_11_A" "Vuelve uno de los mapas multijugador favoritos del Titanfall original: el icónico Colonia. Añádele a esto las nuevas tácticas y titanes de Titanfall 2, y los pilotos y titanes tendrán que exprimir todas sus habilidades para sobrevivir en este asentamiento idílico y denso lleno de callejones, esquinas traicioneras y tejados expuestos. Disponible el 30 de marzo para todos los jugadores. El pack de DLC «Colony Reborn» incluye el retorno de armas clásicas como el rifle de asalto decorado R-101, una nueva ejecución con el garfio y nuevas opciones cosméticas a la venta para destacar en combate mientras arrasas a tus enemigos.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_11_Q" "Tráiler de juego «Colony Reborn»" + "COMMUNITYUPDATE_12_A" "Presentamos Munición real, un frenético modo 6 contra 6 solo para pilotos centrado en combates competitivos a corta distancia. Con dos nuevos mapas diseñados específicamente para este modo: Chimeneas y Prado. Estos dos mapas gratuitos son zonas de combate letales y constreñidas creadas específicamente para este modo frenético e intenso.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_12_Q" "Tráiler de juego «Bienvenidos a Munición real»" + "COMMUNITYUPDATE_13_A" "Disfruta de la versión remasterizada de uno de los mapas favoritos de los fans del Titanfall original: `1Angel City`0. Prepárate para el primer DLC gratis para Titanfall 2 con `1Más buscados de Angel City`0, disponible el 1 de diciembre de 2016 para todos los jugadores. Incluye nuevas opciones cosméticas para darle un toque fresco a la Frontera. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_13_Q" "Tráiler de juego «Bienvenidos a Angel City»" + "COMMUNITYUPDATE_14_A" "Bienvenidos.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_14_Q" "Tráiler de premios «Bis»" + "COMMUNITYUPDATE_15_A" "Dos leyendas, un legado.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_15_Q" "Tráiler Un jugador «Sed uno en combate»" + "COMMUNITYUPDATE_16_A" "Sin límites.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_16_Q" "Tráiler de juego Multijugador «Pilotos»" + "COMMUNITYUPDATE_DESC" "`3Noticias de comunidad de Titanfall`0\n\nInformación y enlaces en la red.\n\nPara más información:\n`2%$rui/bullet_point%`0Síguenos en Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Hazte fan en `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Únete en `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "Comunidad" + "KNB_SUBJECT_00_DESC" "`3¿Qué novedades trae Titanfall?`0\n\n¡Consulta aquí qué ha cambiado en Titanfall 2!" + "KNB_SUBJECT_00_NAME" "Actualizaciones" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 nuevas banderas de indicativos creadas por la comunidad\n\n`2%$rui/bullet_point%`0Todos los regalos de partidario ahora pueden adquirirse con créditos\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 de noviembre: Cosecha" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Espacio principal de pistola\n\n`2%$rui/bullet_point%`0Banderas de Halloween\n\n`2%$rui/bullet_point%`0Cambios de equilibrio\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 de octubre: Trucos o golosinas" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Defensa fronteriza: - Compatibilidad para 3 mapas más - Dique seco, Angel City y Exoplaneta.\n\n`2%$rui/bullet_point%`0Nuevo mapa de Munición real - UMA\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto - Agujero en el muro\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 de agosto - Postales de la Frontera" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Defensa fronteriza: un nuevo modo cooperativo donde unes fuerzas con hasta 3 jugadores más para defender un objetivo crucial de oleadas cada vez más intensas de combatientes de IA. La comunicación y la adaptabilidad son claves para sobrevivir.\n\n`2%$rui/bullet_point%`0Mapa nuevo: Ascenso\n\n`2%$rui/bullet_point%`0Mapa nuevo de Munición real: Municipio\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25 de julio: operación Escudo fronterizo" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Nuevo mapa: Juegos de guerra\n\n`2%$rui/bullet_point%`0Nuevo mapa de Munición real: Tráfico\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Lucha con tu sombra\n\n`2%$rui/bullet_point%`03.er espacio de arma\n\n`2%$rui/bullet_point%`0Ajustes de partida privada" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27 de junio: Juegos de guerra" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Nuevo titán: Monarch\n\n`2%$rui/bullet_point%`0Nuevo mapa: Reliquia\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Ahora me ves\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30 de mayo: Reino del Monarch" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Nuevo mapa: Glitch\n\n`2%$rui/bullet_point%`0Nuevo mapa de Munición real: Cubierta\n\n`2%$rui/bullet_point%`0Nueva facción: Marvins\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Incisivo\n\n`2%$rui/bullet_point%`0Generación máxima aumentada a 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25 de abril: Un glitch en la Frontera" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Nuevo mapa: Colonia\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Aplastacráneos\n\n`2%$rui/bullet_point%`0Nueva arma: R-101\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30 de marzo: Colony Reborn" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Munición real: un nuevo modo de juego de eliminación de pilotos contra pilotos. Modo 6 contra 6 sin reaparición, donde tienes un minuto para eliminar al equipo rival para ganar la ronda. También ganas la ronda si tu equipo conserva la bandera neutral cuando el tiempo se agote. Vence el primero en ganar 5 rondas.\n\n`2%$rui/bullet_point%`0Nuevo mapa de Munición real: Prado\n\n`2%$rui/bullet_point%`0Nuevo mapa de Munición real: Chimeneas\n\n`2%$rui/bullet_point%`0Nueva ejecución: Impacto tardío" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23 de febrero: Munición real" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Nuevo mapa: Angel City\n\n`2%$rui/bullet_point%`0Nueva arma: B3 Wingman de élite\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Destruido desde dentro\n\n`2%$rui/bullet_point%`0Nuevos kits de titán\n\n`2%$rui/bullet_point%`0Nuevo contenido adquirible en la tienda" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30 de noviembre: Más buscados de Angel City" + "MP_ANGEL_CITY_FD_WAVE_1" "Encadenado al cielo" + "MP_ANGEL_CITY_FD_WAVE_2" "Amorfo" + "MP_ANGEL_CITY_FD_WAVE_3" "Insurgencia" + "MP_ANGEL_CITY_FD_WAVE_4" "Grupo obstinado" + "MP_ANGEL_CITY_FD_WAVE_5" "Jugarse el cuello" + "MP_DRYDOCK_FD_WAVE_1" "Nadar en aguas extrañas" + "MP_DRYDOCK_FD_WAVE_2" "¡No tienen balas!" + "MP_DRYDOCK_FD_WAVE_3" "Cegados por la ciencia" + "MP_DRYDOCK_FD_WAVE_4" "Sistema de altas presiones" + "MP_DRYDOCK_FD_WAVE_5" "Ojo de la tormenta" + "MP_THAW_FD_WAVE_1" "Conciencia de situación" + "MP_THAW_FD_WAVE_2" "Superioridad numérica" + "MP_THAW_FD_WAVE_3" "Secuaz 21" + "MP_THAW_FD_WAVE_4" "Diversión en el fuego" + "MP_THAW_FD_WAVE_5" "Aprovecha las armas" + "NO_PRICE" "Promoción expirada" + "NO_PRICE_TWO_LINES" "Promoción\nexpirada" + "PL_aegis_last_titan_standing" "UTEP Aegis" + "PL_aegis_last_titan_standing_abbr" "UTEPA" + "PL_aegis_last_titan_standing_desc" "Mejoras de Aegis activadas. Modo de eliminación por rondas. Vence el primero en ganar 3 rondas.\n^FFC83200Jugadores: 5 contra 5 *Empiezas como titán\nLímite de tiempo: 3 min por ronda *Sin reaparición\nTamaño máximo de grupo: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Batalla de titanes Aegis" + "PL_aegis_titan_brawl_abbr" "BDTA" + "PL_aegis_titan_brawl_desc" "Elimina titanes enemigos. Mejoras de Aegis activadas.\n^FFC83200Jugadores: 5 contra 5\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 5" + "PL_aegis_titan_brawl_hint" "Elimina titanes enemigos.\nSin eyección" + "PL_aegis_titan_brawl_lobby" "Vestíbulo de Batalla de titanes Aegis" + "PL_aitdm" "Desgaste" + "PL_aitdm_abbr" "DGT" + "PL_aitdm_desc" "Elimina a todos los enemigos.\n^FFC83200Jugadores: 6 contra 6 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_aitdm_lobby" "Vestíbulo de Desgaste" + "PL_all_grapple" "Ataque en Titanfall" + "PL_all_grapple_abbr" "DGT" + "PL_all_grapple_desc" "Reglas de Desgaste clásico, excepto que todas las funciones tácticas se reemplazan por el garfio.\n^FFC83200Jugadores: 6 contra 6 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_all_grapple_lobby" "Vestíbulo de Ataque en Titanfall" + "PL_all_holopilot" "El gran engaño" + "PL_all_holopilot_abbr" "MR" + "PL_all_holopilot_desc" "Reglas de Munición real clásico, excepto que todas las funciones tácticas se reemplazan por holopiloto.^FFC83200\nJugadores: 6 contra 6 *Sin titanes\nLímite de tiempo: 60 s *Sin reapariciones\nTamaño máximo de grupo: 6" + "PL_all_holopilot_lobby" "Vestíbulo de El gran engaño" + "PL_all_phase" "El otro lado" + "PL_all_phase_abbr" "DGT" + "PL_all_phase_desc" "Reglas de Desgaste clásico, excepto que todas las funciones tácticas se reemplazan por Fase.\n^FFC83200Jugadores: 6 contra 6 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_all_phase_lobby" "Vestíbulo de El otro lado" + "PL_all_spicy" "Desgaste animado" + "PL_all_spicy_abbr" "DGT" + "PL_all_spicy_desc" "Reglas de Desgaste clásico, excepto que todas las funciones tácticas se reemplazan con garrapatas.\n^FFC83200Jugadores: 6 contra 6 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_all_spicy_lobby" "Vestíbulo de Desgaste animado" + "PL_amped_tacticals" "Tácticas +" + "PL_amped_tacticals_abbr" "DGT" + "PL_amped_tacticals_desc" "Reglas de Desgaste clásico, excepto que las funciones tácticas son más potentes.\n^FFC83200Jugadores: 6 contra 6 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_amped_tacticals_lobby" "Vestíbulo de Tácticas +" + "PL_ANGEL_CITY" "Angel City 24/7" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "Solo Angel City, todo el tiempo." + "PL_angel_city_lobby" "Vestíbulo de Angel City 24/7" + "PL_at_coop" "Evasión (coop.)" + "PL_at_coop_desc" "Acabas de escapar de una prisión con solo una pistola. Sobrevive hasta que llegue un transporte. Elimina enemigos para ganar dinero y comprar armas. \n^FFC83200Jugadores: 6\nTamaño máximo de grupo: 6" + "PL_at_coop_lobby" "Vestíbulo de Evasión" + "PL_attrition" "Cazarrecompensas" + "PL_attrition_abbr" "CR" + "PL_attrition_desc" "Elimina enemigos para ganar dinero. Consigue más ingresando tus bonificaciones en el banco, en los lugares designados.\n^FFC83200Jugadores: 5 contra 5 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 5" + "PL_attrition_lobby" "Vestíbulo de Cazarrecompensas" + "PL_capture_the_flag" "Captura la bandera" + "PL_capture_the_flag_abbr" "CLB" + "PL_capture_the_flag_desc" "¡Hazte con la bandera enemiga y llévala hasta tu base, a la vez que evitas que el enemigo te robe la tuya!\n^FFC83200Jugadores: 5 contra 5\nLímite de tiempo: 12 min\nTamaño máximo de grupo: 5" + "PL_capture_the_flag_lobby" "Vestíbulo de CLB" + "PL_coliseum" "Coliseo" + "PL_coliseum_desc" "Combate 1 contra 1 con movilidad mejorada en una jaula. Elimina a tu rival para ganar una ronda. El vencedor de 3 de 5 gana un regalo de partidario de recompensa.^FFC83200\nJugadores: 1 contra 1 *Sin titanes\nLímite de tiempo: 3 min *Sin reapariciones\n**^FFFFFF00REQUIERE TICKETS DE COLISEO o PAGAR ENTRADA" + "PL_coliseum_lobby" "Vestíbulo de Coliseo" + "PL_colony" "Colonia 24/7" + "PL_colony_abbr" "COL" + "PL_colony_desc" "Mapa Colonia, continuamente. ^CCCCCC00Buscará partidas de ^FFC83200Desgaste^CCCCCC00, ^FFC83200Pilotos contra pilotos^CCCCCC00 y ^FFC83200Último titán en pie^CCCCCC00." + "PL_colony_lobby" "Vestíbulo de Colonia 24/7" + "PL_ctf_lf" "CLB (Nitro)" + "PL_ctf_lf_abbr" "CLB-N" + "PL_ctf_lf_desc" "Frenético Captura la bandera en mapas seleccionados.\n^FFC83200Jugadores: 5 contra 5\nTamaño máximo de grupo: 5\n^F4D5A600Recuperación instantánea de banderas" + "PL_ctf_lf_lobby" "Vestíbulo CLB Nitro" + "PL_default_description" "Descripción predeterminada" + "PL_default_lobbytitle" "Título de vestíbulo por defecto" + "PL_default_name" "Nombre predeterminado" + "PL_don" "Doble o nada" + "PL_fd" "Defensa fronteriza" + "PL_fd_desc" "Defiende contra las oleadas de las fuerzas de la Flota Remanente" + "PL_fd_easy" "Defensa fronteriza: fácil" + "PL_fd_easy_desc" "Aplasta a los rivales." + "PL_fd_easy_lobby" "Defensa fronteriza: vestíbulo fácil" + "PL_fd_hard" "Defensa fronteriza: difícil" + "PL_fd_hard_desc" "Se requiere mucha habilidad" + "PL_fd_hard_lobby" "Defensa fronteriza: vestíbulo difícil" + "PL_fd_insane" "Defensa fronteriza: demencial" + "PL_fd_insane_desc" "No sobrevivirás" + "PL_fd_insane_lobby" "Vestíbulo de Defensa fronteriza: demencial" + "PL_fd_lobby" "Vestíbulo de Defensa fronteriza" + "PL_fd_master" "Defensa fronteriza: maestro" + "PL_fd_master_desc" "Solo los mejores triunfarán" + "PL_fd_master_lobby" "Vestíbulo de Defensa fronteriza: maestro" + "PL_fd_normal" "Defensa fronteriza: normal" + "PL_fd_normal_desc" "Recomendado para jugadores experimentados" + "PL_fd_normal_lobby" "Vestíbulo de Defensa fronteriza: normal" + "PL_ffa" "Batalla campal" + "PL_ffa_abbr" "BC" + "PL_ffa_desc" "Cada piloto por su cuenta; elimina a todos los enemigos.\n^FFC83200Jugadores: 1 contra 11\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 1" + "PL_ffa_lobby" "Vestíbulo de Batalla campal" + "PL_fra" "Agentes libres" + "PL_fra_abbr" "AL" + "PL_fra_desc" "Cada piloto, por su cuenta. Elimina enemigos para ganar. Reúne 3 baterías para pedir un titán.\n^FFC83200Jugadores: 1 contra 11\nLímite de tiempo: 15 min\nTamaño máximo de grupo: 1" + "PL_fra_lobby" "Vestíbulo de Agentes libres" + "PL_groud_war_lobby" "Vestíbulo de Variado 8c8" + "PL_ground_war" "Variado 8c8" + "PL_ground_war_abbr" "8c8" + "PL_ground_war_desc" "Incluye Escaramuza y Fortines cargados, con gran número de pilotos en todos los mapas.\n^FFC83200Jugadores: 8 contra 8" + "PL_hardpoint" "Fortines cargados" + "PL_hardpoint_abbr" "FC" + "PL_hardpoint_desc" "Captura y conserva los fortines para ganar puntos. Los fortines cargados proporcionan el doble de puntos.\n^FFC83200Jugadores: 6 contra 6\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_hardpoint_lobby" "Vestíbulo de Fortines cargados" + "PL_hardpoint_non_amp" "Dominio de fortines" + "PL_hardpoint_lobby_non_amp" "Vestíbulo de Dominio de fortines" + "PL_hunted" "Cazado" + "PL_iron_last_titan_standing" "UTEP de acero" + "PL_iron_last_titan_standing_abbr" "UTEPA" + "PL_iron_last_titan_standing_desc" "Modo de eliminación por rondas, solo titanes. Vence el primero en ganar 3 rondas.\n^FFC83200Jugadores: 5 contra 5 *SIN PILOTOS\nLímite de tiempo: 3 min por ronda *Sin reaparición\nTamaño máximo de grupo: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Último titán en pie" + "PL_last_titan_standing_abbr" "UTEP" + "PL_last_titan_standing_desc" "En esta partida de eliminación por rondas, todos los jugadores empiezan en un titán. Gana el primero en vencer en 3 rondas.\n^FFC83200Jugadores: 5 contra 5 *Empiezas como titán\nLímite de tiempo: 3 min por ronda *Sin reapariciones\nTamaño máximo de grupo: 5" + "PL_last_titan_standing_lobby" "Vestíbulo de UTEP" + "PL_limited_time_mode" "Por tiempo limitado" + "PL_live_fire" "Munición real" + "PL_live_fire_abbr" "MR" + "PL_live_fire_desc" "Combate frenético en una arena de munición real. Gana la ronda eliminando a todos los pilotos enemigos o conservando la bandera cuando se agote el tiempo.^FFC83200\nJugadores: 6 contra 6 *Sin titanes\nLímite de tiempo: 60 s *Sin reapariciones\nTamaño máximo de grupo: 6" + "PL_live_fire_lobby" "Vestíbulo de Munición real" + "PL_load_a_map_on_the_command_line" "Carga un mapa en la línea de comandos. Solo para desarrollo." + "PL_marked_for_death" "Condenado" + "PL_marked_for_death_abbr" "CON" + "PL_marked_for_death_desc" "Elimina o protege los blancos marcados.\n^FFC83200Jugadores: 6 contra 6 \nLímite de tiempo: 12 min\nTamaño máximo de grupo: 6" + "PL_marked_for_death_lobby" "Vestíbulo de Condenado" + "PL_nitro_ffa" "BC (Nitro)" + "PL_nitro_ffa_abbr" "BC-N" + "PL_nitro_ffa_desc" "Frenética Batalla campal en mapas seleccionados.\n^FFC83200Jugadores: 6\n^F4D5A600Sin titanes\nSin potenciadores" + "PL_nitro_ffa_lobby" "Vestíbulo de BC (Nitro)" + "PL_nitro_mixtape" "Variado (Nitro)" + "PL_nitro_mixtape_abbr" "VRD-N" + "PL_nitro_mixtape_desc" "Frenéticos CLB, CON y JcJ en mapas seleccionados.\n^FFC83200Jugadores: 5 contra 5\nTamaño máximo de grupo: 5\n^F4D5A600Recuperación instantánea de banderas" + "PL_nitro_mixtape_lobby" "Vestíbulo de Variado" + "PL_pilot_hunter" "Escaramuza" + "PL_pilot_hunter_abbr" "ECM" + "PL_pilot_hunter_desc" "Elimina pilotos y titanes enemigos. \n^FFC83200Jugadores: 8 contra 8\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 8" + "PL_pilot_hunter_lobby" "Vestíbulo de Escaramuza" + "PL_pilot_skirmish" "Pilotos contra pilotos" + "PL_pilot_skirmish_abbr" "PcP" + "PL_pilot_skirmish_desc" "Elimina pilotos enemigos. No se permiten titanes.\n^FFC83200Jugadores: 8 contra 8 *Sin titanes\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 8" + "PL_pilot_skirmish_lobby" "Vestíbulo de PcP" + "PL_pl_rebuild_all_paths" "Reconstruir todas las rutas" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Ejecutar con ai_ainRebuildOnMapStart 2" + "PL_private_match" "Partida privada" + "PL_private_match_desc" "Juega una partida privada personalizada en el modo y mapa que prefieras.\n^FFC83200Invitar red o Invitar amigos para jugar\n^FFC83200Jugadores: 1-16\nSin progresión" + "PL_private_match_lobby" "Vestíbulo de partida privada" + "PL_promo_coop" "Coop. de 4 jugadores" + "PL_raid" "Incursión" + "PL_glitch" "Glitch 24/7" + "PL_glitch_abbr" "GLI" + "PL_glitch_desc" "Mapa Glitch, continuamente. ^CCCCCC00Buscará partidas de ^FFC83200Captura la bandera^CCCCCC00, ^FFC83200Fortines cargados^CCCCCC00, ^FFC83200Pilotos contra pilotos^CCCCCC00, ^FFC83200Munición real^CCCCCC00 y ^FFC83200Último titán en pie^CCCCCC00." + "PL_glitch_lobby" "Vestíbulo de Glitch 24/7" + "PL_rocket_arena" "Arena balística" + "PL_rocket_arena_abbr" "MR" + "PL_rocket_arena_desc" "Reglas de Munición real clásico con EPG modificadas.^FFC83200\nJugadores: 6 contra 6 *Sin titanes\nLímite de tiempo: 90 s *Sin reapariciones\nTamaño máximo de grupo: 6" + "PL_rocket_arena_lobby" "Vestíbulo de Arena balística" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Ajustes para cuando alguien carga un mapa desde la línea de comandos. No editar cmdlineMapLoad 1: eso hace que esto funcione." + "PL_speedball" "Munición real" + "PL_speedball_desc" "Lucha por la posesión de una bandera neutral. Elimina al equipo enemigo o mantén la posesión de la bandera cuando se agote el tiempo para vencer en la ronda. Gana el primero en imponerse en 5 rondas.\n^FFC83200Jugadores: 6 contra 6 *Sin titanes\nLímite de tiempo: 60 segundos por ronda *Sin reapariciones\nTamaño máximo de grupo: 6" + "PL_speedball_lobby" "Vestíbulo de Munición real" + "PL_tactikill" "Desgaste táctico" + "PL_tactikill_abbr" "DGT" + "PL_tactikill_desc" "Reglas de Desgaste clásico, excepto que las funciones tácticas se recuperan completamente al conseguir eliminaciones.\n^FFC83200Jugadores: 6 contra 6 *IA\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 6" + "PL_tactikill_lobby" "Vestíbulo de Desgaste táctico" + "PL_titan_brawl" "Batalla de titanes" + "PL_titan_brawl_abbr" "BDT" + "PL_titan_brawl_desc" "Elimina titanes enemigos. Pilotos no permitidos.\n^FFC83200Jugadores: 5 contra 5\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 5" + "PL_titan_brawl_hint" "Elimina titanes enemigos.\nSin eyección." + "PL_titan_brawl_lobby" "Vestíbulo de Batalla de titanes" + "PL_titan_brawl_turbo" "Batalla de titanes turbo" + "PL_titan_brawl_turbo_abbr" "BDT" + "PL_titan_brawl_turbo_desc" "Reglas de Batalla de titanes clásico con regeneración de impulso y generación de núcleo más rápidas.\n^FFC83200Jugadores: 5 contra 5\nLímite de tiempo: 10 min\nTamaño máximo de grupo: 5" + "PL_titan_brawl_turbo_hint" "Elimina titanes enemigos.\nSin eyección" + "PL_titan_brawl_turbo_lobby" "Vestíbulo de Batalla de titanes turbo" + "PL_turbo_last_titan_standing" "UTEP turbo" + "PL_turbo_last_titan_standing_abbr" "UTEP" + "PL_turbo_last_titan_standing_desc" "Reglas de UTEP clásico con regeneración de impulso y generación de núcleo más rápidas.\n^FFC83200Jugadores: 5 contra 5 *Empiezas como titán\nLímite de tiempo: 3 min por ronda *Sin reapariciones\nTamaño máximo de grupo: 5" + "PL_turbo_last_titan_standing_lobby" "Vestíbulo de UTEP turbo" + "PL_variety_pack" "Variado" + "PL_variety_pack_desc" "Número de jugadores variables. Incluye diversos mapas de los siguientes modos:\n^FFC83200*Cazarrecompensas *Desgaste\n*Último titán en pie *Fortines cargados\n*Pilotos contra pilotos *Captura la bandera" + "PL_variety_pack_lobby" "Vestíbulo de Variado" + "PL_wargames" "Juegos de guerra 24/7" + "PL_wargames_abbr" "JDG" + "PL_wargames_desc" "Mapa Juegos de guerra, continuamente. ^CCCCCC00Buscará partidas de ^FFC83200Desgaste^CCCCCC00, ^FFC83200CLB^CCCCCC00, ^FFC83200Pilotos contra pilotos^CCCCCC00, ^FFC83200Fortines cargados^CCCCCC00 y ^FFC83200Último titán en pie^CCCCCC00." + "PL_wargames_lobby" "Vestíbulo de Juegos de guerra 24/7" + "WATCH_TUTORIAL" "VER TUTORIAL" + "GAMEMODE_TMFD" "Titan Condenado a morir" + "MP_RELIC02_FD_WAVE_1" "Juntos sobrevivimos" + "MP_RELIC02_FD_WAVE_2" "Buscando la ruta principal" + "MP_RELIC02_FD_WAVE_3" "Abriendo otra ruta" + "MP_RELIC02_FD_WAVE_4" "Zona ciega" + "MP_RELIC02_FD_WAVE_5" "Divididos emboscamos" + } + } + "lang" + { + "Language" "tchinese" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "透過最新發佈的《Titanfall 2:邊境明信片》DLC,您將可以在邊境繼續您的驚奇冒險。內含全新和您熟悉的地點,以及全新的菁英武器戰鬥塗裝收集品,邊境將會有更美好的景觀。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_00_Q" "ã€Œé‚Šå¢ƒæ˜Žä¿¡ç‰‡ã€é å‘Šç‰‡" + "COMMUNITYUPDATE_01_A" "瞭解邊境明信片修補檔的所有變更內容。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_01_Q" "邊境明信片:修補檔說明" + "COMMUNITYUPDATE_02_A" "即將在行動裝置上推出的《Titanfall:突擊》是一款位於 Titanfall 世界中刺激的即時策略遊戲,它是與 Particle City 合作完成。到這裡觀看這些精彩內容!\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_02_Q" "《Titanfall:突擊》\發行\é å‘Šç‰‡" + "COMMUNITYUPDATE_03_A" "Iniquity å¸¶é ˜æˆ‘å€‘å®Œæˆã€ŠTitanfall:突擊》的教學關卡並分享基本的游戲訣竅。這是瞭解這款游戲的絕佳途徑。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_03_Q" "《Titanfall:突擊》:\學習基本操作\影片" + "COMMUNITYUPDATE_04_A" "聽聽邊境防禦幕後的一些重要人物談論關於這個模式的一些歷史和製作過程,並觀看幾回合的遊玩過程!\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_04_Q" "Respawn 一起玩邊境防禦" + "COMMUNITYUPDATE_05_A" "Kevin Younger 製作了一些有趣的集錦,展現使用脈衝刀做出的大量美妙動作。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_05_Q" "社群創作:前往據點" + "COMMUNITYUPDATE_06_A" "ConzeyG 透過 Reddit å±•ç¾åœ¨çµæ®ºæ¨™è¨˜æ¨¡å¼ä¸­ä½¿ç”¨åŒ—æ¥µæ˜Ÿæ“Šç ´éµé¦­çš„é©šäººæ•ˆçŽ‡ã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_06_Q" "社群創作:北極星獵殺鐵馭" + "COMMUNITYUPDATE_07_A" "ç¾å·²é–‹æ”¾ï¼é‚Šå¢ƒé˜²ç¦¦èˆ‡å´›èµ·åœ°åœ–å°‡ä¸€åŒè¿”å›žï¼Œå¦å¤–é‚„æœ‰ä¸€ç³»åˆ—å…¨æ–°æˆ°é¬¥å¡—è£ä¾›ä½ è³¼è²·å’Œä¸€å¼µæ–°çš„çƒˆç«æˆ°å ´åœ°åœ–ã€‚åˆ°é€™è£¡è§€çœ‹é€™äº›ç²¾å½©å…§å®¹ã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_07_Q" "ã€Œé‚Šå¢ƒç¥žç›¾ä»»å‹™ã€çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_08_A" "現已開放!經典的戰爭遊戲地圖以全新姿態重返《Titanfall 2ã€‹ã€‚æ›´åˆ¥éŒ¯éŽå…¨æ–°è™•æ±ºå‹•ç•«èˆ‡çƒˆç«æˆ°å ´åœ°åœ– - 交通。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_08_Q" "ã€Œæˆ°çˆ­éŠæˆ²ã€çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_09_A" "æ­¤ DLC 內含第 7 å…·å¤šäººéŠæˆ²æ³°å¦ï¼šã€Œå¸çŽ‹ã€ï¼Œç‚ºã€Œéºè·¡ã€çš„é‡è£½åœ°åœ–ï¼Œä¸¦æ–°å¢žäº†å¯è³¼è²·çš„è‡³å°Šæµªäººä»¥åŠè‡³å°Šå¼·åŠ›æ³°å¦ã€æ›´å¤šè¿·å½©ã€æ——å¹Ÿå’Œæ©Ÿé ­è—è¡“ã€‚æ–¼æ­¤è™•è§€çœ‹å½±åƒã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_09_Q" "ã€Œå¸çŽ‹çš„çµ±æ²»ã€éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_10_A" "邊境中暗藏危機 - 準備進入《Titanfall 2》最新的免費 DLCï¼šé‚Šå¢ƒæ•…éšœï¼Œå…¶ä¸­å°‡åŒ…å«å…¨æ–°åœ°åœ–ã€Œç•°å¸¸ã€ã€‚å—æ‹‰æ–¯ææ‘©æ²™ä¸Šå°‰çš„å®¶é„‰å“ˆå¢¨å°¼æ˜Ÿæ‰€å•Ÿç™¼çš„ç’°å¢ƒè¨­è¨ˆï¼Œå…¶ä¸­å¤§å¤šç‚ºåž‚ç›´ç©ºé–“èˆ‡é€£ç¶¿æ›²æŠ˜çš„é“è·¯ï¼Œéžå¸¸é©åˆä½¿ç”¨é€£éŽ–è¹¬å£ä¾†æ©«è·¨æ­¤åœ°åœ–ã€‚å¦å¤–é‚„æœ‰ä¸€å¼µå…¨æ–°çƒˆç«æˆ°å ´åœ°åœ–å³å°‡ç™»å ´ï¼šç”²æ¿ï¼Œå…¶ä¸­åŒ…å«ç‹¹çª„çš„å®¤å…§ç©ºé–“ã€ç©ºæ› çš„å»£å ´å’Œåœ¨ç©ºä¸­ç›¤æ—‹çš„æ©Ÿå™¨äººã€‚å¦‚æžœæœ¬æ¬¡æ›´æ–°è®“æ‚¨æ„Ÿåˆ°å£“åŠ›å¤ªå¤§ï¼Œæ‚¨æœ€å¾—åŠ›çš„åŠ©æ‰‹é¦¬æ–‡æ©Ÿå™¨äººç¾åœ¨å°‡æˆç‚ºå…¨æ–°é™£ç‡Ÿä¸¦åŠ©æ‚¨ä¸€è‡‚ä¹‹åŠ›ã€‚æœ€å¾Œï¼Œå…¨æ–°çš„è„ˆè¡åˆ€è™•æ±ºå‹•ç•«å·²é–‹æ”¾ï¼Œä¸¦åœ¨æ‚¨éœ€è¦çš„æ™‚å€™éš¨æ™‚ä¾›æ‚¨ä½¿ç”¨ã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_10_Q" "ã€Œé‚Šå¢ƒæ•…éšœã€éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_11_A" "重返粉絲們最愛的初代《Titanfall》地圖:殖民地。混合了《Titanfall 2ã€‹ä¸­æ‰€æœ‰å…¨æ–°æˆ°è¡“æŠ€èƒ½èˆ‡æ³°å¦ï¼Œæ³°å¦èˆ‡éµé¦­å€‘æƒ³åœ¨é€™å¼µå……æ»¿ç‹¹çª„å··å¼„ã€æ­»è§’èˆ‡é–‹æ”¾å±‹é ‚çš„é„‰æ‘åœ°åœ–ä¸­å­˜æ´»å¿…é ˆéš¨æ™‚ä¿æŒè­¦è¦ºã€‚æ–¼ 3 月 30 日對所有玩家免費開放。「殖民地重生」DLC 組合包中含有酷炫的經典武器 R-101 æ­¥æ§ã€å…¨æ–°å‹¾çˆªè™•æ±ºå‹•ç•«å’Œå…¨æ–°å¤–è§€é¸é …ä¾›æ‚¨è³¼è²·ï¼Œè®“æ‚¨èƒ½å¤ åœ¨æµ´è¡€å¥®æˆ°çš„åŒæ™‚å±•ç¾æ‚¨ç¨æœ‰çš„é­…åŠ›ã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_11_Q" "ã€Œæ®–æ°‘åœ°é‡ç”Ÿã€éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_12_A" "ã€Œçƒˆç«æˆ°å ´ã€ç°¡ä»‹ï¼šè¶…å¿«ç¯€å¥çš„ 6 對 6 éµé¦­å°æˆ°æ¨¡å¼ï¼Œè®“æ‚¨é«”é©—é‚Šå¢ƒä¸Šåˆºæ¿€çš„è¿‘è·é›¢æˆ°é¬¥ã€‚ã€Œçƒˆç«æˆ°å ´ã€åŒ…å«å…©å¼µå…¨æ–°çš„å°ˆå±¬åœ°åœ–ï¼šã€Œå †ç©åœ°ã€å’Œã€Œè‰åŽŸã€ã€‚é€™å…©å¼µå…è²»åœ°åœ–æä¾›äº†å°é–‰å¼çš„å°æˆ°ç©ºé–“ï¼Œæ˜¯å°ˆé–€ç‚ºå¿«ç¯€å¥çš„è¿‘æˆ°æ¨¡å¼è€Œè¨­è¨ˆã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_12_Q" "ã€Œæ­¡è¿Žä¾†åˆ°çƒˆç«æˆ°å ´ã€éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_13_A" "體驗經過重製的初代《Titanfall》玩家最愛的`1天使城`0地圖。為在 12 月 1 日與`1天使城通緝令`0一同向所有玩家發佈的首個免費《Titanfall 2》DLC åšå¥½æº–å‚™ã€‚æ­¤å…§å®¹åŒ…å«æ–°çš„å¤–è§€é¸é …ï¼Œå¯è®“æ‚¨åœ¨é‚Šå¢ƒä¸Šæ›´åŠ è‹±å§¿ç…¥ç™¼ã€‚\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_13_Q" "ã€Œæ­¡è¿Žä¾†åˆ°å¤©ä½¿åŸŽã€éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_14_A" "歡迎回來。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_14_Q" "「Encore」讚譽影片" + "COMMUNITYUPDATE_15_A" "兩位傳奇,一次遺贈。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_15_Q" "ã€Œåˆè€Œç‚ºä¸€ã€å–®äººæ¨¡å¼éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_16_A" "無限的可能。\n\n\n按 `2%[A_BUTTON|MOUSE1]%`0 觀看。" + "COMMUNITYUPDATE_16_Q" "ã€Œéµé¦­ã€å¤šäººæ¨¡å¼éŠæˆ²çŽ©æ³•é å‘Šç‰‡" + "COMMUNITYUPDATE_DESC" "`3Titanfall 社群更新`0\n\n來自網路的資訊和連結。\n\n更多內容:\n`2%$rui/bullet_point%`0在 Twitter 上關注我們 `1@Respawn`0\n`2%$rui/bullet_point%`0在 `1facebook.com/RespawnEntertainment`0 追蹤我們\n`2%$rui/bullet_point%`0é€ è¨ª `1www.respawn.com`0 åŠ å…¥æˆ‘å€‘" + "COMMUNITYUPDATE_NAME" "社群" + "KNB_SUBJECT_00_DESC" "`3《Titanfall》有什麼新內容?`0\n\n從此處瞭解《Titanfall 2》的改變!" + "KNB_SUBJECT_00_NAME" "遊戲更新" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 社群建立的全新呼叫代號旗幟\n\n`2%$rui/bullet_point%`0ç¾åœ¨èƒ½å¤ ä½¿ç”¨é»žæ•¸è³¼è²·æ‰€æœ‰æ“è­·ç¦®åŒ…\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 11 月 28 æ—¥ - 收穫季節" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0主手槍欄\n\n`2%$rui/bullet_point%`0萬聖節旗幟\n\n`2%$rui/bullet_point%`0平衡性變更\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 10 月 31 æ—¥ - 萬聖節活動" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0邊境防禦 - 支援 3 張額外的地圖:乾塢、天使城和系外行星。\n\n`2%$rui/bullet_point%`0å…¨æ–°çƒˆç«æˆ°å ´åœ°åœ– - UMA\n\n`2%$rui/bullet_point%`0全新鐵馭處決動畫 - 穿透障壁\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 8 月 29 æ—¥ - 邊境明信片" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0邊境防禦 - å…¨æ–°åˆä½œæ¨¡å¼è®“ä½ èˆ‡å…¶ä»–ä¸‰åçŽ©å®¶ä¸€åŒä¿è­·é‡è¦ç›®æ¨™ä¸¦æ“Šé€€ä¸€æ³¢æ³¢é€æ¼¸å¢žå¼·çš„ AI 敵人。溝通與適應力將是生存的關鍵。\n\n`2%$rui/bullet_point%`0全新地圖 - 崛起\n\n`2%$rui/bullet_point%`0å…¨æ–°çƒˆç«æˆ°å ´åœ°åœ– - 小鎮\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 7 月 25 æ—¥ - 邊境神盾任務" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0新地圖 - 戰爭遊戲\n\n`2%$rui/bullet_point%`0æ–°çƒˆç«æˆ°å ´åœ°åœ– - 交通\n\n`2%$rui/bullet_point%`0新鐵馭處決動畫 - 幻影拳腳\n\n`2%$rui/bullet_point%`0第三武器欄\n\n`2%$rui/bullet_point%`0私人比賽設置" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 6 月 27 æ—¥ - 戰爭遊戲" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0全新泰坦 - 帝王\n\n`2%$rui/bullet_point%`0全新地圖 - 遺跡\n\n`2%$rui/bullet_point%`0全新鐵馭處決動畫 - 無影無蹤\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 5 月 30 æ—¥ - 帝王的統治" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0全新地圖 - 異常\n\n`2%$rui/bullet_point%`0å…¨æ–°çƒˆç«æˆ°å ´åœ°åœ– - 甲板\n\n`2%$rui/bullet_point%`0全新陣營 - 馬文機器人\n\n`2%$rui/bullet_point%`0全新鐵馭處決動畫 - 刀刀見骨\n\n`2%$rui/bullet_point%`0重生上限提升至 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 4 月 25 æ—¥ - 邊境故障" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0全新地圖 - 殖民地\n\n`2%$rui/bullet_point%`0全新鐵馭處決動畫 - 猛擊\n\n`2%$rui/bullet_point%`0全新武器 - R-101\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 3 月 30 æ—¥ - 殖民地重生" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0çƒˆç«æˆ°å ´ - å…¨æ–°éµé¦­å°éµé¦­æ®²æ»…æ¨¡å¼ï¼é€™æ˜¯ä¸€å ´ 6 對 6 å›žåˆæ¨¡å¼ä¸”ä¸èƒ½é‡ç”Ÿï¼Œä½ å°‡æœ‰ä¸€åˆ†é˜æ™‚é–“æ®²æ»…æ•µéšŠä¾†è´å¾—æ­¤å›žåˆã€‚ä½ ä¹Ÿèƒ½å¤ é€éŽåœ¨è¨ˆæ™‚çµæŸæ™‚æŒæœ‰ä¸­ç«‹æ——å¹Ÿä¾†å–å‹ã€‚å…ˆè´å¾— 5 個回合的隊伍將贏得比賽。\n\n`2%$rui/bullet_point%`0å…¨æ–°çƒˆç«æˆ°å ´åœ°åœ– - 草原\n\n`2%$rui/bullet_point%`0å…¨æ–°çƒˆç«æˆ°å ´åœ°åœ– - å †ç©åœ°\n\n`2%$rui/bullet_point%`0全新鐵馭處決動畫 - 快速攻擊" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 2 月 23 æ—¥ - çƒˆç«æˆ°å ´" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0全新地圖 - 天使城\n\n`2%$rui/bullet_point%`0全新武器 - B3 幫手菁英\n\n`2%$rui/bullet_point%`0全新鐵馭處決動畫 - 瞬間爆炸\n\n`2%$rui/bullet_point%`0全新泰坦裝備\n\n`2%$rui/bullet_point%`0å…¨æ–°å•†åŸŽé“å…·ä¾›ä½ è³¼è²·" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 11 月 30 æ—¥ - 天使城通緝令" + "MP_ANGEL_CITY_FD_WAVE_1" "被縛於天際" + "MP_ANGEL_CITY_FD_WAVE_2" "ç„¡å½¢" + "MP_ANGEL_CITY_FD_WAVE_3" "æš´å‹•" + "MP_ANGEL_CITY_FD_WAVE_4" "一群固執的人" + "MP_ANGEL_CITY_FD_WAVE_5" "手氣絕佳" + "MP_DRYDOCK_FD_WAVE_1" "游入陌生水域" + "MP_DRYDOCK_FD_WAVE_2" "他們沒子彈了!" + "MP_DRYDOCK_FD_WAVE_3" "受科學誤導" + "MP_DRYDOCK_FD_WAVE_4" "高壓系統" + "MP_DRYDOCK_FD_WAVE_5" "風暴之眼" + "MP_THAW_FD_WAVE_1" "狀態意識" + "MP_THAW_FD_WAVE_2" "人多力量大" + "MP_THAW_FD_WAVE_3" "追隨者 21" + "MP_THAW_FD_WAVE_4" "火中作樂" + "MP_THAW_FD_WAVE_5" "嗜槍如命" + "NO_PRICE" "å„ªæƒ å·²éŽæœŸ" + "NO_PRICE_TWO_LINES" "å„ªæƒ \n已過期" + "PL_aegis_last_titan_standing" "神盾泰坦殊死戰" + "PL_aegis_last_titan_standing_abbr" "ALTS" + "PL_aegis_last_titan_standing_desc" "神盾升級啟用。回合制淘汰賽。先贏 3 å ´è€…å‹ã€‚\n^FFC83200玩家:5 對 5 *開始時有泰坦\næ™‚é–“é™åˆ¶ï¼šæ¯å ´ 3 分鐘 *無重生\n最大派對人數:5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "神盾泰坦爭鬥" + "PL_aegis_titan_brawl_abbr" "ATTDM" + "PL_aegis_titan_brawl_desc" "擊殺敵方泰坦。神盾升級啟用。\n^FFC83200玩家:5 對 5\n時間限制:10 分鐘\n最大派對人數:5" + "PL_aegis_titan_brawl_hint" "擊殺敵方泰坦。\n無彈射" + "PL_aegis_titan_brawl_lobby" "神盾泰坦爭鬥大廳" + "PL_aitdm" "消耗戰" + "PL_aitdm_abbr" "ATT" + "PL_aitdm_desc" "擊殺所有敵人。\n^FFC83200玩家:6v6 *AI\n時間限制:10 分鐘\n最大派對人數:6" + "PL_aitdm_lobby" "消耗戰大廳" + "PL_all_grapple" "進擊的泰坦" + "PL_all_grapple_abbr" "消耗戰" + "PL_all_grapple_desc" "傳統消耗戰規則,但是戰術技能被鉤爪取代。\n^FFC83200玩家:6v6 *電腦\n時間限制:10 分鐘\n最大隊伍人數:6" + "PL_all_grapple_lobby" "進擊的泰坦大廳" + "PL_all_holopilot" "大騙局" + "PL_all_holopilot_abbr" "çƒˆç«æˆ°å ´" + "PL_all_holopilot_desc" "å‚³çµ±çƒˆç«æˆ°å ´è¦å‰‡ï¼Œä½†æ˜¯æˆ°è¡“æŠ€èƒ½è¢«å¹»å½±éµé¦­å–ä»£ã€‚\n^FFC83200玩家:6v6 *無泰坦\n時間限制:60 ç§’ *無重生\n最大隊伍人數:6" + "PL_all_holopilot_lobby" "大騙局大廳" + "PL_all_phase" "異次元" + "PL_all_phase_abbr" "消耗戰" + "PL_all_phase_desc" "傳統消耗戰規則,但是戰術技能被轉移取代。\n^FFC83200玩家:6v6 *電腦\n時間限制:10 分鐘\n最大隊伍人數:6" + "PL_all_phase_lobby" "異次元大廳" + "PL_all_spicy" "火熱消耗戰" + "PL_all_spicy_abbr" "消耗戰" + "PL_all_spicy_desc" "傳統消耗戰規則,但是戰術技能被炸蛛取代。\n^FFC83200玩家:6v6 *電腦\n時間限制:10 分鐘\n最大隊伍人數:6" + "PL_all_spicy_lobby" "火熱消耗戰大廳" + "PL_amped_tacticals" "強化戰術技能" + "PL_amped_tacticals_abbr" "消耗戰" + "PL_amped_tacticals_desc" "å‚³çµ±æ¶ˆè€—æˆ°è¦å‰‡ï¼Œä½†æ˜¯æˆ°è¡“æŠ€èƒ½å°‡æ›´åŠ å¼·å¤§ã€‚\n^FFC83200玩家:6v6 *電腦\n時間限制:10 分鐘\n最大隊伍人數:6" + "PL_amped_tacticals_lobby" "強化戰術技能大廳" + "PL_ANGEL_CITY" "天使城 24/7" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "å¤©ä½¿åŸŽï¼Œæ°¸é éƒ½åœ¨ã€‚" + "PL_angel_city_lobby" "天使城 24/7 大廳" + "PL_at_coop" "逃脫(合作模式)" + "PL_at_coop_desc" "您剛剛逃離了監獄且身上只有一把手槍。存活至撤離艦到來。擊殺敵人來獲得金錢並用其購買武器。\n^FFC83200玩家:6\n最大派對人數:6" + "PL_at_coop_lobby" "逃脫大廳" + "PL_attrition" "賞金追緝" + "PL_attrition_abbr" "BH" + "PL_attrition_desc" "擊殺敵人獲取金錢。透過在指定地點「儲存」紅利以獲得額外金錢。\n^FFC83200玩家:5 對 5 *AI\n 時間限制:10 分鐘\n最大派對人數:5" + "PL_attrition_lobby" "賞金追緝大廳" + "PL_capture_the_flag" "奪旗" + "PL_capture_the_flag_abbr" "CTF" + "PL_capture_the_flag_desc" "å¥ªå–æ•µæ–¹æ——å¹Ÿä¸¦å°‡å…¶å¸¶å›žä½ çš„åŸºåœ°ï¼ŒåŒæ™‚é˜»æ­¢å°æ–¹å¥ªå–ä½ çš„æ——å¹Ÿï¼\n^FFC83200玩家:5 對 5\n時間限制:12 分鐘\n最大派對人數:5" + "PL_capture_the_flag_lobby" "奪旗大廳" + "PL_coliseum" "ç«¶æŠ€å ´" + "PL_coliseum_desc" "åœ¨éµç± è£¡ä»¥å¼·åŒ–è¡Œå‹•åŠ›é€²è¡Œä¸€å°ä¸€æˆ°é¬¥ã€‚æ¯æ¬¡æ“Šæ®ºå°æ‰‹ä¾¿è´ä¸€å›žåˆã€‚5 戰 3 勝者可獲得擁護禮包獎勵。^FFC83200\n玩家:1 對 1 *無泰坦\n時間限制:3 分鐘 *無重生\n**^FFFFFF00éœ€è¦ç«¶æŠ€å ´é–€ç¥¨æˆ–æ”¯ä»˜å…¥å ´è²»" + "PL_coliseum_lobby" "ç«¶æŠ€å ´å¤§å»³" + "PL_colony" "殖民地 24/7" + "PL_colony_abbr" "COL" + "PL_colony_desc" "所有殖民地,持續不斷。 ^CCCCCC00這將會搜尋^FFC83200消耗戰^CCCCCC00、^FFC83200鐵馭對鐵馭^CCCCCC00、及^FFC83200泰坦殊死戰^CCCCCC00的比賽。" + "PL_colony_lobby" "殖民地 24/7 大廳" + "PL_ctf_lf" "奪旗(氮氧)" + "PL_ctf_lf_abbr" "氮氧奪旗" + "PL_ctf_lf_desc" "在選擇的地圖中進行快節奏的奪旗比賽。\n^FFC83200玩家:5 對 5\n最大隊伍人數:5\n^F4D5A600立即歸還旗幟" + "PL_ctf_lf_lobby" "氮氧奪旗大廳" + "PL_default_description" "é è¨­èªªæ˜Ž" + "PL_default_lobbytitle" "é è¨­å¤§å»³åç¨±" + "PL_default_name" "é è¨­åç¨±" + "PL_don" "åŠ æ³¨ç¿»å€" + "PL_fd" "邊境防禦" + "PL_fd_desc" "抵抗數波的殘餘部隊勢力" + "PL_fd_easy" "邊境防禦:簡單" + "PL_fd_easy_desc" "粉碎對手" + "PL_fd_easy_lobby" "邊境防禦:簡單大廳" + "PL_fd_hard" "邊境防禦:困難" + "PL_fd_hard_desc" "必備高超的技巧" + "PL_fd_hard_lobby" "邊境防禦:困難大廳" + "PL_fd_insane" "邊境防禦:瘋狂" + "PL_fd_insane_desc" "ä½ å°‡ç„¡æ³•ç”Ÿå­˜" + "PL_fd_insane_lobby" "邊境防禦:瘋狂大廳" + "PL_fd_lobby" "邊境防禦大廳" + "PL_fd_master" "邊境防禦:大師" + "PL_fd_master_desc" "åªæœ‰æœ€é ‚å°–çš„èè‹±èƒ½å¤ æˆåŠŸ" + "PL_fd_master_lobby" "邊境防禦:大師大廳" + "PL_fd_normal" "邊境防守:普通" + "PL_fd_normal_desc" "推薦給資深玩家" + "PL_fd_normal_lobby" "邊境防守:普通大廳" + "PL_ffa" "混戰" + "PL_ffa_abbr" "FFA" + "PL_ffa_desc" "所有鐵馭為自己而戰,擊殺所有敵人。\n^FFC83200玩家:1 對 11\n時間限制:10 分鐘\n最大派對人數:1" + "PL_ffa_lobby" "混戰大廳" + "PL_fra" "自由混戰" + "PL_fra_abbr" "FRA" + "PL_fra_desc" "ä½ å°‡å­¤èº«ä½œæˆ°ã€‚æ“Šæ®ºæ•µäººä¾†å–å‹ã€‚æ”¶é›† 3 æžšé›»æ± å¾Œå¯å‘¼å«æ³°å¦ã€‚\n^FFC83200玩家:1 對 11\n時間限制:15 分鐘\n最大派對人數:1" + "PL_fra_lobby" "自由混戰大廳" + "PL_groud_war_lobby" "8 對 8 綜合大廳" + "PL_ground_war" "8 對 8 綜合" + "PL_ground_war_abbr" "8v8" + "PL_ground_war_desc" "收錄了「小規模戰鬥」和「強化據點」,並在每張地圖上都有高玩家人數。\n^FFC83200玩家:8對8" + "PL_hardpoint" "強化據點" + "PL_hardpoint_abbr" "AHP" + "PL_hardpoint_desc" "ä½”é ˜ä¸¦å …å®ˆé‡åœ°ä¾†ç²å¾—åˆ†æ•¸ã€‚å¼·åŒ–çš„é‡åœ°æä¾›é›™å€åˆ†æ•¸ã€‚\n^FFC83200玩家:6 對 6\n時間限制:10 分鐘\n最大派對人數:6" + "PL_hardpoint_lobby" "強化據點大廳" + "PL_hardpoint_non_amp" "搶攻重地" + "PL_hardpoint_lobby_non_amp" "重要地點大廳" + "PL_hunted" "遭獵殺" + "PL_iron_last_titan_standing" "鐵血泰坦殊死戰" + "PL_iron_last_titan_standing_abbr" "ILTS" + "PL_iron_last_titan_standing_desc" "åƒ…æ³°å¦åƒåŠ çš„å›žåˆåˆ¶æ®²æ»…æˆ°ã€‚å…ˆè´ 3 回合者獲勝。\n^FFC83200玩家:5 對 5 *無鐵馭\n時間限制:每回合 3 分鐘 *無重生\n最大派對人數:5" + "PL_iron_last_titan_standing_lobby" " " + "PL_last_titan_standing" "泰坦殊死戰" + "PL_last_titan_standing_abbr" "LTS" + "PL_last_titan_standing_desc" "所有玩家開始此回合制淘汰賽時皆有泰坦。先贏 3 å ´è€…å‹ã€‚\n^FFC83200玩家:5 對 5 *開始時有泰坦\næ™‚é–“é™åˆ¶ï¼šæ¯å ´ 3 分鐘 *無重生\n最大派對人數:5" + "PL_last_titan_standing_lobby" "殊死大廳" + "PL_limited_time_mode" "限時模式" + "PL_live_fire" "çƒˆç«æˆ°å ´" + "PL_live_fire_abbr" "LF" + "PL_live_fire_desc" "åœ¨çƒˆç«ç«¶æŠ€å ´ä¸­é€²è¡Œå¿«ç¯€å¥çš„æˆ°é¬¥ã€‚åœ¨å›žåˆå…§æ“Šæ®ºæ‰€æœ‰æ•µæ–¹éµé¦­æˆ–æ˜¯åœ¨æ™‚é–“çµæŸæ™‚æŒæœ‰æ——å¹Ÿå³å¯ç²å‹ã€‚^FFC83200\n玩家:6 對 6 *無泰坦\n時間限制:60 ç§’ *無重生\n最大派對人數:6" + "PL_live_fire_lobby" "çƒˆç«æˆ°å ´å¤§å»³" + "PL_load_a_map_on_the_command_line" "在命令行載入地圖-devonly" + "PL_marked_for_death" "獵殺標記" + "PL_marked_for_death_abbr" "MFD" + "PL_marked_for_death_desc" "擊殺或保護被標記的目標。\n^FFC83200玩家:6 對 6\n時間限制:12 分鐘\n最大派對人數:6" + "PL_marked_for_death_lobby" "獵殺標記大廳" + "PL_nitro_ffa" "混戰(氮氧)" + "PL_nitro_ffa_abbr" "混戰-氮氧" + "PL_nitro_ffa_desc" "在特定地圖上進行快節奏的混戰。\n^FFC83200玩家:6\n^F4D5A600無泰坦\n無強化" + "PL_nitro_ffa_lobby" "混戰氮氧大廳" + "PL_nitro_mixtape" "綜合(氮氧)" + "PL_nitro_mixtape_abbr" "綜合-氮氧" + "PL_nitro_mixtape_desc" "在特定地圖上進行快節奏的奪旗、獵殺標記與鐵馭對鐵馭。\n^FFC83200玩家:5 對 5\n最大隊伍人數:5\n^F4D5A600立即歸還旗幟" + "PL_nitro_mixtape_lobby" "綜合大廳" + "PL_pilot_hunter" "小規模戰鬥" + "PL_pilot_hunter_abbr" "SKM" + "PL_pilot_hunter_desc" "擊殺敵方鐵馭與泰坦。\n^FFC83200玩家:8 對 8\n時間限制:10 分鐘\n最大派對人數:8" + "PL_pilot_hunter_lobby" "小規模戰鬥大廳" + "PL_pilot_skirmish" "鐵馭對鐵馭" + "PL_pilot_skirmish_abbr" "PvP" + "PL_pilot_skirmish_desc" "擊殺敵方鐵馭。無法呼叫泰坦。\n^FFC83200玩家:8 對 8 *無泰坦\n時間限制:10 分鐘\n最大派對人數:8" + "PL_pilot_skirmish_lobby" "鐵馭對鐵馭大廳" + "PL_pl_rebuild_all_paths" "重建所有路線" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "執行 ai_ainRebuildOnMapStart 2" + "PL_private_match" "私人比賽" + "PL_private_match_desc" "使用您選擇的地圖和模式進行自訂的私人比賽。\n^FFC83200é‚€è«‹ç¶²è·¯æˆ–é‚€è«‹å¥½å‹åŠ å…¥\n^FFC83200玩家:1-16 人\n無進度" + "PL_private_match_lobby" "私人比賽大廳" + "PL_promo_coop" "4 人合作模式" + "PL_raid" "突襲" + "PL_glitch" "異常24/7" + "PL_glitch_abbr" "GLI" + "PL_glitch_desc" "異常情形持續不斷。^CCCCCC00這將搜尋^FFC83200奪旗^CCCCCC00、^FFC83200強攻佔點^CCCCCC00, ^FFC83200鐵馭對鐵馭^CCCCCC00, ^FFC83200çƒˆç«æˆ°å ´^CCCCCC00,與^FFC83200泰坦殊死戰^CCCCCC00的比賽。" + "PL_glitch_lobby" "異常24/7大廳" + "PL_rocket_arena" "ç«ç®­ç«¶æŠ€å ´" + "PL_rocket_arena_abbr" "çƒˆç«æˆ°å ´" + "PL_rocket_arena_desc" "å‚³çµ±çƒˆç«æˆ°å ´è¦å‰‡ï¼Œä½†æ˜¯é…æœ‰æ”¹è£ç‰ˆ EPG。^FFC83200\n玩家:6v6*無泰坦\n時間限制:90 ç§’*無重生\n最大隊伍人數:6" + "PL_rocket_arena_lobby" "ç«ç®­ç«¶æŠ€å ´å¤§å»³" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "有人在命令行載入地圖時的設定。請勿編輯下面 cmdlineMapLoad 1-有這個才能使用本功能。" + "PL_speedball" "çƒˆç«æˆ°å ´" + "PL_speedball_desc" "搶奪中立旗幟。消滅敵隊或是在比賽結束時持有旗幟者贏得一局。先贏 5 局者勝。\n^FFC83200玩家:6 對 6 *無泰坦\n時間限制:每局 60 ç§’ *無重生\n最大派對人數:6" + "PL_speedball_lobby" "çƒˆç«æˆ°å ´å¤§å»³" + "PL_tactikill" "戰術擊殺消耗戰" + "PL_tactikill_abbr" "消耗戰" + "PL_tactikill_desc" "傳統消耗戰規則,但是戰術技能在擊殺時將會刷新。\n^FFC83200玩家:6v6 *電腦\n時間限制:10 分鐘\n最大隊伍人數:6" + "PL_tactikill_lobby" "戰術擊殺消耗戰大廳" + "PL_titan_brawl" "泰坦爭鬥" + "PL_titan_brawl_abbr" "TTDM" + "PL_titan_brawl_desc" "擊殺敵方泰坦,不可使用鐵馭。\n^FFC83200玩家:5 對 5\n時間限制:10 分鐘\n最大派對人數:5" + "PL_titan_brawl_hint" "擊殺敵方泰坦。\n無彈射" + "PL_titan_brawl_lobby" "泰坦爭鬥大廳" + "PL_titan_brawl_turbo" "渦輪泰坦爭鬥" + "PL_titan_brawl_turbo_abbr" "泰坦爭鬥" + "PL_titan_brawl_turbo_desc" "å‚³çµ±æ³°å¦çˆ­é¬¥è¦å‰‡ï¼Œä½†æ˜¯æ“æœ‰æ›´å¿«çš„è¡åˆºæ¢å¾©èˆ‡æ ¸å¿ƒæå‡çŽ‡ã€‚\n^FFC83200玩家:5 對 5\n時間限制:10 分鐘\n最大隊伍人數:5" + "PL_titan_brawl_turbo_hint" "擊殺敵方泰坦。\n無彈射" + "PL_titan_brawl_turbo_lobby" "渦輪泰坦爭鬥大廳" + "PL_turbo_last_titan_standing" "渦輪殊死戰" + "PL_turbo_last_titan_standing_abbr" "泰坦殊死戰" + "PL_turbo_last_titan_standing_desc" "å‚³çµ±æ³°å¦æ®Šæ­»æˆ°è¦å‰‡ï¼Œä½†æ˜¯æ“æœ‰æ›´å¿«çš„è¡åˆºæ¢å¾©èˆ‡æ ¸å¿ƒæå‡çŽ‡ã€‚\n^FFC83200玩家:5 對 5 *開始時有泰坦\n時間限制:每回合 3 分鐘 *無重生\n最大隊伍人數:5" + "PL_turbo_last_titan_standing_lobby" "渦輪泰坦殊死戰大廳" + "PL_variety_pack" "綜合" + "PL_variety_pack_desc" "綜合玩家包含下列模式中的各種地圖:\n^FFC83200*賞金追緝 *消耗戰\n*泰坦殊死戰 *強化據點\n*鐵馭對鐵馭 *奪旗" + "PL_variety_pack_lobby" "綜合大廳" + "PL_wargames" "戰爭遊戲 24/7" + "PL_wargames_abbr" "WGM" + "PL_wargames_desc" "戰爭遊戲全系列,持續上演。 ^CCCCCC00這將會搜尋^FFC83200消耗戰^CCCCCC00、^FFC83200奪旗^CCCCCC00、^FFC83200鐵馭對鐵馭^CCCCCC00、^FFC83200強化據點^CCCCCC00,及^FFC83200泰坦殊死戰^CCCCCC00等對戰。" + "PL_wargames_lobby" "戰爭遊戲 24/7 大廳" + "WATCH_TUTORIAL" "觀看教學" + "GAMEMODE_TMFD" "泰坦攻防戰" + "MP_RELIC02_FD_WAVE_1" "團結力量大" + "MP_RELIC02_FD_WAVE_2" "搜索主要路線" + "MP_RELIC02_FD_WAVE_3" "切斷其他路線" + "MP_RELIC02_FD_WAVE_4" "蓋補" + "MP_RELIC02_FD_WAVE_5" "分開易伏擊" + } + } + "lang" + { + "Language" "italian" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "La tua avventura nei panorami eccezionali della Frontiera continua con l'ultimo DLC di Titanfall 2: Cartoline dalla Frontiera. Con luoghi nuovi e familiari e una nuova collezione di colori da guerra per armi Elite, la Frontiera non è mai stata così bella.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_00_Q" "Trailer \"Cartoline dalla Frontiera\"" + "COMMUNITYUPDATE_01_A" "Leggi tutte le novità introdotte nella patch Cartoline dalla Frontiera.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_01_Q" "Cartoline dalla Frontiera: note sulla patch" + "COMMUNITYUPDATE_02_A" "Presto disponibile su dispositivi mobili, Titanfall: Assault è un videogioco strategico in tempo reale ambientato nell’universo Titanfall e realizzato in collaborazione con Particle City. Guardalo in azione! \n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_02_Q" "Trailer di \"Lancio\" Titanfall: Assault" + "COMMUNITYUPDATE_03_A" "Iniquity ci illustra il tutorial e ci fornisce suggerimenti di base per Titanfall: Assault. Questo è il modo perfetto per iniziare a conoscere il gioco.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_03_Q" "Video Titanfall Assault: \"Impara le basi\"" + "COMMUNITYUPDATE_04_A" "Ascolta alcune delle persone chiave che hanno lavorato a Difesa Frontiera parlare della storia e della creazione della modalità e giocare a qualche partita! \n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_04_Q" "Respawn gioca a Difesa Frontiera" + "COMMUNITYUPDATE_05_A" "Kevin Younger ha creato un montaggio divertente mostrando innumerevoli mosse con Lama a impulsi. \n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_05_Q" "Creazioni community: Arriva al punto" + "COMMUNITYUPDATE_06_A" "ConzeyG su reddit mostra una brutale efficienza: Northstar che elimina i piloti nella modalità Marchiato a morte. \n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_06_Q" "Creazioni : Cacciatore di piloti Northstar" + "COMMUNITYUPDATE_07_A" "Disponibile ora! Difesa Frontiera torna con Ascesa, nuovi colori da guerra acquistabili e una nuova mappa Live Fire.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_07_Q" "Trailer gameplay \"Scudo frontiera operazioni\"" + "COMMUNITYUPDATE_08_A" "Disponibile ora! L’apprezzata mappa Giochi di guerra torna in Titanfall 2, più bella che mai. Scopri anche la nuova esecuzione e la nuova mappa Live Fire, Traffico in azione.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_08_Q" "Trailer gameplay “Giochi di guerra”" + "COMMUNITYUPDATE_09_A" "In questo DLC presentiamo: Monarch, il settimo Titan per multigiocatore; una rivisitazione della mappa Relitto; una nuova esecuzione e i Titan Ronin Prime e Tone Prime acquistabili; altre mimetiche, bandiere e decorazioni. Non perderti l'azione qui.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_09_Q" "Trailer gameplay “Regno di Monarch”" + "COMMUNITYUPDATE_10_A" "Nulla è come sembra nella Frontiera: preparati a entrare nel nuovo pack DLC gratuito per Titanfall 2: Un Glitch nella Frontiera, che contiene la nuova mappa “Glitch”. Ispirato dal pianeta Harmony del capitano Lastimosa, l’ambiente è dominato da cadute verticali e lunghi percorsi tortuosi, perfetti per concatenare lunghe corse sui muri, per poi planare in tutta la mappa. È inoltre inclusa una nuova mappa Live Fire: Ponte, che vanta spazi interni ristretti, cortili esposti e droni vigili che volteggiano sulla testa. Se dovessi sentirti sopraffatto, non preoccuparti: i M.R.V.N., sempre pronti a darti una mano robotica, si uniscono al gioco come una fazione completamente nuova. Infine, è possibile sbloccare l’esecuzione Lama a impulsi, perché possa essere utilizzata tutte le volte che desideri “far arrivare il messaggio”.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_10_Q" "Trailer gameplay “Un Glitch nella Frontiera”" + "COMMUNITYUPDATE_11_A" "Torna una delle mappe multigiocatore più apprezzate del Titanfall originale: Colonia. Con tutte le nuove tattiche e i nuovi Titan di Titanfall 2, Piloti e Titan dovranno rimanere sempre all’erta per sopravvivere in questo villaggio idilliaco e molto popolato fatto di vicoli, angoli ciechi e tetti esposti; disponibile gratuitamente il 30 marzo per tutti i giocatori. Il pack DLC “Colonia Rinata” comprende il ritorno di armi classiche come il fucile d’assalto R-101 modificato, una nuova esecuzione rampino e nuove opzioni estetiche da acquistare per apparire sempre al meglio mentre dipingi di rosso la città .\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_11_Q" "Trailer gameplay \"Colonia Rinata\"" + "COMMUNITYUPDATE_12_A" "Presentazione di Live Fire: una modalità ultra-rapida 6v6 per piloti che pone in prima linea il combattimento a distanza ravvicinata. Sono incluse due nuove mappe progettate specificamente per Live Fire: Cataste e Prateria. Queste due mappe gratuite sono aree di gioco strette e mortali progettate specificamente per la natura intensa e rapida di questa nuova modalità .\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_12_Q" "Trailer gameplay “Benvenuti in Live Fire”" + "COMMUNITYUPDATE_13_A" "Prova una versione rivisitata di una della mappe preferite del Titanfall originale, `1Angel City`0. Tieniti pronto per il primo DLC gratuito per Titanfall 2 con `1Ricercato di Angel City`0 disponibile il 1 dicembre. Questo contenuto comprende nuove opzioni estetiche per aggiungere un po’ di eleganza alla Frontiera. \n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_13_Q" "Trailer gameplay “Benvenuti in Angel City”" + "COMMUNITYUPDATE_14_A" "Bentornato.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_14_Q" "Trailer \"Encore\"" + "COMMUNITYUPDATE_15_A" "Due leggende, una sola eredità .\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_15_Q" "Trailer “Diventate una cosa sola”" + "COMMUNITYUPDATE_16_A" "Senza limiti.\n\n\nPremi `2%[A_BUTTON|MOUSE1]%`0 per visualizzare." + "COMMUNITYUPDATE_16_Q" "Trailer multigiocatore “Piloti”" + "COMMUNITYUPDATE_DESC" "`3Aggiornamenti community Titanfall`0\n\nInfo e collegamenti da tutto il Web.\n\nPer altre informazioni:\n`2%$rui/bullet_point%`0Seguici su Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Metti un like su `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Unisciti a noi visitando l’indirizzo `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "Community" + "KNB_SUBJECT_00_DESC" "`3Quali sono le novità di Titanfall?`0\n\nQui potrai vedere tutte le novità in Titanfall 2!" + "KNB_SUBJECT_00_NAME" "Aggiornamenti" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 Nuovi banner distintivo creati dalla community\n\n`2%$rui/bullet_point%`0Tutti i regali del difensore sono ora acquistabili con crediti\n\n`2%$rui/bullet_point%`0Nuovo contenuto negozio acquistabile\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 novembre - Momento della raccolta" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Slot primario pistola\n\n`2%$rui/bullet_point%`0Banner Halloween\n\n`2%$rui/bullet_point%`0Modifiche al bilanciamento\n\n`2%$rui/bullet_point%`0Nuovi contenuti del negozio acquistabili\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 ottobre - Dolcetti e scherzetti" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Difesa Frontiera - Supporto per tre mappe aggiuntive - Bacino di carenaggio, Angel City ed Esopianeta.\n\n`2%$rui/bullet_point%`0Nuova mappa Live Fire - UMA\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Buco nel muro\n\n`2%$rui/bullet_point%`0Nuovo contenuto acquistabile nello store" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 agosto - Cartoline dalla frontiera" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Difesa Frontiera: una nuova modalità cooperativa in cui unisci le forze con un massimo di altri tre giocatori per difendere un obiettivo vitale da ondate sempre più intense di combattenti IA. La comunicazione e l'adattamento sono la chiave per la sopravvivenza.\n\n`2%$rui/bullet_point%`0Nuova mappa: Ascesa\n\n`2%$rui/bullet_point%`0Nuova mappa Live Fire: Cittadina\n\n`2%$rui/bullet_point%`0Nuovo contenuto acquistabile nel negozio" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25 luglio - Operazione Scudo Frontiera " + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Nuova mappa - Giochi di guerra\n\n`2%$rui/bullet_point%`0Nuova mappa Live Fire - Traffico\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Scatola ombra\n\n`2%$rui/bullet_point%`03° slot arma\n\n`2%$rui/bullet_point%`0Impostazioni partita privata" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27 giugno - Giochi di guerra" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Nuovo Titan - Monarch\n\n`2%$rui/bullet_point%`0Nuova mappa - Relitto\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Ora mi vedi\n\n`2%$rui/bullet_point%`0Nuovo contenuto acquistabile nello store" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30 maggio - Regno di Monarch" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Nuova mappa - Glitch\n\n`2%$rui/bullet_point%`0Nuova mappa Live Fire - Ponte\n\n`2%$rui/bullet_point%`0Nuova fazione - M.R.V.N.\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Arriva al punto\n\n`2%$rui/bullet_point%`0Generazione max portata a 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25 aprile - Glitch nella Frontiera" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Nuova mappa - Colonia\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Spaccatesta\n\n`2%$rui/bullet_point%`0Nuova arma - R-101\n\n`2%$rui/bullet_point%`0Nuovo contenuto acquistabile nello store" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30 marzo - Colonia Rinata" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Live Fire - Una nuova modalità di gioco a eliminazione Pilota contro Pilota! 6v6 basata su round senza rientri, avrai un minuto per eliminare la squadra rivale per vincere il round. Puoi vincere il round anche se la tua squadra è in possesso della bandiera neutra allo scadere del tempo. Vince la partita la squadra che si aggiudica per prima 5 round.\n\n`2%$rui/bullet_point%`0Nuova mappa Live Fire - Prateria\n\n`2%$rui/bullet_point%`0Nuova mappa Live Fire - Cataste\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Colpo ritardato" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23 febbraio - Live Fire" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Nuova mappa - Angel City\n\n`2%$rui/bullet_point%`0Nuova arma - B3 Wingman Elite\n\n`2%$rui/bullet_point%`0Nuova esecuzione pilota - Dal di dentro\n\n`2%$rui/bullet_point%`0Nuovi kit Titan\n\n`2%$rui/bullet_point%`0Nuovo contenuto acquistabile nello store" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30 novembre - Ricercato di Angel City" + "MP_ANGEL_CITY_FD_WAVE_1" "Incatenato al cielo" + "MP_ANGEL_CITY_FD_WAVE_2" "Informe" + "MP_ANGEL_CITY_FD_WAVE_3" "Insurrezione" + "MP_ANGEL_CITY_FD_WAVE_4" "Un gruppo testardo" + "MP_ANGEL_CITY_FD_WAVE_5" "Sfida la sorte" + "MP_DRYDOCK_FD_WAVE_1" "Nuotare in acque straniere" + "MP_DRYDOCK_FD_WAVE_2" "Non hanno proiettili!" + "MP_DRYDOCK_FD_WAVE_3" "Accecato dalla scienza" + "MP_DRYDOCK_FD_WAVE_4" "Sistema ad alta pressione" + "MP_DRYDOCK_FD_WAVE_5" "Occhio del ciclone" + "MP_THAW_FD_WAVE_1" "Percezione della situazione" + "MP_THAW_FD_WAVE_2" "La forza è nei numeri" + "MP_THAW_FD_WAVE_3" "Scagnozzo 21" + "MP_THAW_FD_WAVE_4" "Divertimento nel fuoco" + "MP_THAW_FD_WAVE_5" "Rendere onore alle pistole" + "NO_PRICE" "Offerta scaduta" + "NO_PRICE_TWO_LINES" "Offerta\nscaduta" + "PL_aegis_last_titan_standing" "Aegis ST" + "PL_aegis_last_titan_standing_abbr" "AST" + "PL_aegis_last_titan_standing_desc" "Aggiornamenti Aegis abilitati. Scontro organizzato in round a eliminazione. La vittoria va a chi vince per primo 3 round.\n^FFC83200Giocatori: 5v5 *Inizia come Titan\nTempo limite: 3 m per round *Nessun rientro\nDimensioni max gruppo: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Scontro tra Titan Aegis" + "PL_aegis_titan_brawl_abbr" "ATTDM" + "PL_aegis_titan_brawl_desc" "Uccidi Titan nemici. Aggiornamenti Aegis abilitati.\n^FFC83200Giocatori: 5v5\nTempo limite: 10m\nDimensioni max gruppo: 5" + "PL_aegis_titan_brawl_hint" "Uccidi i Titan nemici.\nNessuna espulsione" + "PL_aegis_titan_brawl_lobby" "Lobby scontro tra Titan Aegis" + "PL_aitdm" "Logoramento" + "PL_aitdm_abbr" "LOG" + "PL_aitdm_desc" "Uccidi tutti i nemici.\n^FFC83200Giocatori: 6v6 *IA\nTempo limite: 10 min.\nDimensioni max gruppo: 6" + "PL_aitdm_lobby" "Lobby Logoramento" + "PL_all_grapple" "Attacco in Titanfall" + "PL_all_grapple_abbr" "ATT" + "PL_all_grapple_desc" "Regole di logoramento classiche, ad eccezione del fatto che tutte le abilità tattiche sono sostituite con Rampino.\n^FFC83200Giocatori: 6v6 *AI\nTempo limite: 10 m\nDimensioni max gruppo: 6" + "PL_all_grapple_lobby" "Attacco alla Lobby Titanfall" + "PL_all_holopilot" "Il grande inganno" + "PL_all_holopilot_abbr" "LF" + "PL_all_holopilot_desc" "Regole di Live Fire classiche, ad eccezione del fatto che tutte le abilità tattiche sono sostituite con Pilota olografico.^FFC83200\nGiocatori: 6v6 *No Titan\nTempo limite: 60 s *Nessun rientro\nDimensioni max gruppo: 6" + "PL_all_holopilot_lobby" "Loggy Il grande inganno" + "PL_all_phase" "L’Altra Parte" + "PL_all_phase_abbr" "ATT" + "PL_all_phase_desc" "Regole di logoramento classiche, ad eccezione del fatto che tutte le abilità tattiche sono sostituite con Fasico.\n^FFC83200Giocatori: 6v6 *AI\nTempo limite: 10 m\nDimensioni max gruppo: 6" + "PL_all_phase_lobby" "Lobby L’Altra Parte" + "PL_all_spicy" "Logoramento speziato" + "PL_all_spicy_abbr" "ATT" + "PL_all_spicy_desc" "Regole di logoramento classiche, ad eccezione del fatto che tutte le abilità tattiche sono sostituite con Tick.\n^FFC83200Giocatori: 6v6 *AI\nTempo limite: 10 m\nDimensioni max gruppo: 6" + "PL_all_spicy_lobby" "Lobby Logoramento speziato" + "PL_amped_tacticals" "Tattiche amplificate" + "PL_amped_tacticals_abbr" "ATT" + "PL_amped_tacticals_desc" "Regole di logoramento classiche, ad eccezione del fatto che le abilità tattiche sono più potenti.\n^FFC83200Giocatori: 6v6 *AI\nTempo limite: 10 m\nDimensioni max gruppo: 6" + "PL_amped_tacticals_lobby" "Lobby Tattiche amplificate" + "PL_ANGEL_CITY" "Angel City 24/7" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "Sempre e solo Angel City." + "PL_angel_city_lobby" "Lobby Angel City 24/7" + "PL_at_coop" "Fuga (Co-op)" + "PL_at_coop_desc" "Sei appena evaso di prigione e hai con te solo una pistola. Sopravvivi fino all'arrivo di una nave da evacuazione. Uccidi i nemici per guadagnare denaro e acquistare armi. \n^FFC83200Giocatori: 6\nDimensioni max gruppo: 6" + "PL_at_coop_lobby" "Lobby Escape" + "PL_attrition" "Caccia alle taglie" + "PL_attrition_abbr" "CT" + "PL_attrition_desc" "Uccidi i nemici per guadagnare soldi. Ottienine di più depositando i bonus nei luoghi designati.\n^FFC83200Giocatori: 5v5 *IA\nTempo limite: 10 min.\nDimensioni max gruppo: 5" + "PL_attrition_lobby" "Lobby Caccia alle taglie" + "PL_capture_the_flag" "Cattura bandiera" + "PL_capture_the_flag_abbr" "CLB" + "PL_capture_the_flag_desc" "Ruba la bandiera nemica e riportala alla tua base mentre impedisci alla squadra avversaria di prendere la tua!\n^FFC83200Giocatori: 5v5\nTempo limite: 12 min.\nDimensioni max gruppo: 5" + "PL_capture_the_flag_lobby" "Lobby CB" + "PL_coliseum" "Colosseo" + "PL_coliseum_desc" "Uno-contro-uno in gabbia con mobilità incrementata. Vince il round chi uccide l'avversario. Chi si aggiudica 3 round su 5 vince un regalo del difensore.^FFC83200\nGiocatori: 1v1 *Niente Titan\nTempo limite: 3 min. *Nessun rientro\n**^FFFFFF00RICHIEDE BIGLIETTO COLOSSEO o PAGAMENTO DEL COSTO D'INGRESSO" + "PL_coliseum_lobby" "Lobby Colosseo" + "PL_colony" "Colonia 24/7" + "PL_colony_abbr" "COL" + "PL_colony_desc" "Sempre e soltanto Colonia. ^CCCCCC00Questa operazione effettuerà ricerche di corrispondenze di ^FFC83200Logoramento^CCCCCC00, ^FFC83200Piloti contro piloti^CCCCCC00 e ^FFC83200Sopravvivenza Titan^CCCCCC00." + "PL_colony_lobby" "Lobby Colonia 24/7" + "PL_ctf_lf" "CB (Nitro)" + "PL_ctf_lf_abbr" "CB-N" + "PL_ctf_lf_desc" "Un frenetico Cattura bandiera in mappe selezionate.\n^FFC83200Giocatori: 5v5\nDimensioni max gruppo: 5\n^F4D5A600Torna Bandiera istantanea" + "PL_ctf_lf_lobby" "Lobby Nitro CB" + "PL_default_description" "Descrizione predefinita" + "PL_default_lobbytitle" "Titolo lobby predefinito" + "PL_default_name" "Nome predefinito" + "PL_don" "Lascia o raddoppia" + "PL_fd" "Difesa Frontiera" + "PL_fd_desc" "Difenditi contro le ondate delle forze della flotta Remnant" + "PL_fd_easy" "Difesa Frontiera: facile" + "PL_fd_easy_desc" "Sconfiggi l’opposizione" + "PL_fd_easy_lobby" "Difesa Frontiera: Lobby facile" + "PL_fd_hard" "Difesa Frontiera: difficile" + "PL_fd_hard_desc" "Sono necessarie buone abilità di gioco" + "PL_fd_hard_lobby" "Difesa Frontiera: Lobby difficile" + "PL_fd_insane" "Difesa Frontiera: folle" + "PL_fd_insane_desc" "Non sopravviverai" + "PL_fd_insane_lobby" "Difesa Frontiera: Lobby folle" + "PL_fd_lobby" "Lobby Difesa Frontiera" + "PL_fd_master" "Difesa Frontiera: maestro" + "PL_fd_master_desc" "Solo i migliori dei migliori sopravviveranno" + "PL_fd_master_lobby" "Difesa Frontiera: Lobby maestro" + "PL_fd_normal" "Difesa Frontiera: normale" + "PL_fd_normal_desc" "Consigliato per giocatori esperti" + "PL_fd_normal_lobby" "Difesa Frontiera: lobby normale" + "PL_ffa" "Tutti contro tutti" + "PL_ffa_abbr" "TCT" + "PL_ffa_desc" "Ogni pilota è solo. Uccidi tutti i nemici.\n^FFC83200Giocatori: 1v11\nTempo limite: 10 min.\nDimensioni max gruppo: 1" + "PL_ffa_lobby" "Lobby Tutti contro tutti" + "PL_fra" "Azione libera" + "PL_fra_abbr" "AL" + "PL_fra_desc" "Ogni pilota lotta per sé. Uccidi i nemici per vincere. Taccogli 3 batterie per un Titanfall.\n^FFC83200Giocatori: 1v11\nLimite di tempo: 15m\nDimensioni max gruppo: 1" + "PL_fra_lobby" "Lobby Azione libera" + "PL_groud_war_lobby" "Lobby Remix 8v8" + "PL_ground_war" "Remix 8v8" + "PL_ground_war_abbr" "8v8" + "PL_ground_war_desc" "Include Scontro e Punto di controllo amplificato, con elevato numero di giocatori su tutte le mappe.\n^FFC83200Giocatori: 8v8" + "PL_hardpoint" "PCA" + "PL_hardpoint_abbr" "PCA" + "PL_hardpoint_desc" "Cattura e mantieni un punto di controllo per ottenere punti. I punti di controllo amplificati danno punti doppi.\n^FFC83200Giocatori: 6v6\nTempo limite: 10 min.\nDimensioni max gruppo: 6" + "PL_hardpoint_lobby" "Lobby PCA" + "PL_hardpoint_non_amp" "Punti di controllo" + "PL_hardpoint_lobby_non_amp" "Lobby Punti di controllo" + "PL_hunted" "Preda" + "PL_iron_last_titan_standing" "ST d'acciaio" + "PL_iron_last_titan_standing_abbr" "STA" + "PL_iron_last_titan_standing_desc" "Solo Titan, scontro organizzato in round a eliminazione. La vittoria va a chi vince per primo 3 round.\n^FFC83200Giocatori: 5v5 *NO PILOTI\nTempo limite: 3 min per round *Nessun rientro\nDimensioni max gruppo: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Sopravvivenza Titan" + "PL_last_titan_standing_abbr" "ST" + "PL_last_titan_standing_desc" "Tutti i giocatori iniziano a bordo dei Titan in questo scontro organizzato in round a eliminazione. La vittoria va a chi vince per primo 3 round.\n^FFC83200Giocatori: 5v5 *Inizi come Titan\nTempo limite: 3 min. per round *Nessun rientro\nDimensioni max gruppo: 5" + "PL_last_titan_standing_lobby" "Lobby ST" + "PL_limited_time_mode" "A tempo limitato" + "PL_live_fire" "Live Fire" + "PL_live_fire_abbr" "LF" + "PL_live_fire_desc" "Combattimento rapido in un'arena Live Fire. Vinci il round uccidendo tutti i piloti nemici oppure tenendo la bandiera allo scadere del tempo.^FFC83200\nGiocatori: 6v6 *Niente Titan\nTempo limite: 60 s *Nessun rientro\nDimensioni max gruppo: 6" + "PL_live_fire_lobby" "Lobby Live Fire" + "PL_load_a_map_on_the_command_line" "Carica una mappa dalla linea di comando -solo sviluppatori" + "PL_marked_for_death" "Marchiato a morte" + "PL_marked_for_death_abbr" "MAM" + "PL_marked_for_death_desc" "Uccidi o proteggi i bersagli marchiati.\n^FFC83200Giocatori: 6v6 \nTempo limite: 12 m\nDimensioni max gruppo: 6" + "PL_marked_for_death_lobby" "Lobby Marchiato a morte" + "PL_nitro_ffa" "FFA (Nitro)" + "PL_nitro_ffa_abbr" "FFA-N" + "PL_nitro_ffa_desc" "Un frenetico Tutti contro tutti su mappe selezionate.\n^FFC83200Giocatori: 6\n^F4D5A600No Titan\nNo potenziamenti" + "PL_nitro_ffa_lobby" "Lobby Nitro FFA" + "PL_nitro_mixtape" "Remix (Nitro)" + "PL_nitro_mixtape_abbr" "MXT-N" + "PL_nitro_mixtape_desc" "Un frenetico CB, MFD e PvP in mappe selezionate.\n^FFC83200Giocatori: 5v5\nDimensioni max gruppo: 5\n^F4D5A600Torna Bandiera istantanea" + "PL_nitro_mixtape_lobby" "Lobby Remix" + "PL_pilot_hunter" "Scontro" + "PL_pilot_hunter_abbr" "SCN" + "PL_pilot_hunter_desc" "Uccidi piloti e Titan nemici. \n^FFC83200Giocatori: 8v8\nTempo limite: 10 min.\nDimensioni max gruppo: 8" + "PL_pilot_hunter_lobby" "Lobby Scontro" + "PL_pilot_skirmish" "Piloti contro piloti" + "PL_pilot_skirmish_abbr" "PvP" + "PL_pilot_skirmish_desc" "Uccidi i piloti nemici. Titanfall non consentiti.\n^FFC83200Giocatori: 8v8 *Nessun Titan\nTempo limite: 10 min.\nDimensioni max gruppo: 8" + "PL_pilot_skirmish_lobby" "Lobby PvP" + "PL_pl_rebuild_all_paths" "Ricostruisci tutti i percorsi" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Esegui con ai_ainRebuildOnMapStart 2" + "PL_private_match" "Partita privata" + "PL_private_match_desc" "Gioca una partita privata personalizzata in una mappa e modalità a scelta.\n^FFC83200INVITA NETWORK o INVITA AMICI per giocare\n^FFC83200Giocatori: 1-16\nNessun progresso" + "PL_private_match_lobby" "Lobby Partita privata" + "PL_promo_coop" "CO-OP per 4 giocatori" + "PL_raid" "Raid" + "PL_glitch" "Glitch 24/7" + "PL_glitch_abbr" "GLI" + "PL_glitch_desc" "Sempre e soltanto Glitch. ^CCCCCC00Questa operazione effettuerà una ricerca per corrispondenze di ^FFC83200CLB^CCCCCC00, ^FFC83200Punto di controllo amplificato^CCCCCC00, ^FFC83200Piloti contro piloti^CCCCCC00, ^FFC83200Live Fire^CCCCCC00 e ^FFC83200Sopravvivenza Titan^CCCCCC00." + "PL_glitch_lobby" "Lobby Glitch 24/7" + "PL_rocket_arena" "Arena razzi" + "PL_rocket_arena_abbr" "LF" + "PL_rocket_arena_desc" "Regole di Live Fire classiche con EPG modificati.^FFC83200\nGiocatori: 6v6 *No Titan\nTempo limite: 90 s *Nessun rientro\nDimensioni max gruppo: 6" + "PL_rocket_arena_lobby" "Lobby Arena razzi" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Impostazioni per il caricamento di una mappa dalla linea di comando. Non modificare il comando sottostante cmdlineMapLoad 1 perché è essenziale per il funzionamento." + "PL_speedball" "Live Fire" + "PL_speedball_desc" "Combatti per il possesso di una bandiera neutrale. Elimina la squadra nemica o possiedi la bandiera allo scadere del tempo per vincere il round. Vince il primo ad aggiudicarsi 5 round.\n^FFC83200Giocatori: 6v6 *Niente Titan\nTempo limite: 60 secondi per round *Nessun rientro\nDimensioni max gruppo: 6" + "PL_speedball_lobby" "Lobby Live Fire" + "PL_tactikill" "Logoramento Uccisione tattica" + "PL_tactikill_abbr" "ATT" + "PL_tactikill_desc" "Regole di logoramento classiche, ad eccezione del fatto che le abilità tattiche sono ripristinate completamente al momento dell’uccisione.\n^FFC83200Giocatori: 6v6 *AI\nTempo limite: 10 m\nDimensioni max gruppo: 6" + "PL_tactikill_lobby" "Lobby Logoramento Uccisione tattica" + "PL_titan_brawl" "Scontro tra Titan" + "PL_titan_brawl_abbr" "STT" + "PL_titan_brawl_desc" "Uccidi i Titan nemici. Piloti non consentiti.\n^FFC83200Giocatori: 5v5\nTempo limite: 10m\nDimensioni max gruppo: 5" + "PL_titan_brawl_hint" "Uccidi i Titan nemici.\nNessuna espulsione" + "PL_titan_brawl_lobby" "Lobby Scontro tra Titan" + "PL_titan_brawl_turbo" "Scontro tra Titan Turbo" + "PL_titan_brawl_turbo_abbr" "TTDM" + "PL_titan_brawl_turbo_desc" "Regole di Scontro tra Titan classiche con rigenerazione Scatto e generazione Nucleo più rapide.\n^FFC83200Giocatori: 5v5\nTempo limite: 10 m\nDimensioni max gruppo: 5" + "PL_titan_brawl_turbo_hint" "Uccidi i Titan nemici.\nNessuna espulsione" + "PL_titan_brawl_turbo_lobby" "Lobby Scontro tra Titan Turbo" + "PL_turbo_last_titan_standing" "Turbo ST" + "PL_turbo_last_titan_standing_abbr" "ST" + "PL_turbo_last_titan_standing_desc" "Regole ST classiche con rigenerazione Scatto e generazione Nucleo più rapide.\n^FFC83200Giocatori: 5v5 *Inizia come Titan\nTempo limite: 3 m per round *Nessun rientro\nDimensioni max gruppo: 5" + "PL_turbo_last_titan_standing_lobby" "Lobby ST Turbo" + "PL_variety_pack" "Remix" + "PL_variety_pack_desc" "Un numero di giocatori variabile e varie mappe in queste modalità :\n^FFC83200*Caccia alle taglie *Logoramento\n*Sopravvivenza Titan *Punto di controllo amplificato\n*Piloti contro piloti *Cattura bandiera" + "PL_variety_pack_lobby" "Lobby Remix" + "PL_wargames" "Giochi di guerra 24/7" + "PL_wargames_abbr" "GDG" + "PL_wargames_desc" "Sempre e soltanto Giochi di guerra. ^CCCCCC00Questa operazione effettuerà ricerche di corrispondenze di ^FFC83200Logoramento^CCCCCC00, ^FFC83200Cattura Bandiera^CCCCCC00, ^FFC83200Piloti contro piloti^CCCCCC00, ^FFC83200Punto di controllo amplificato^CCCCCC00 e ^FFC83200Sopravvivenza Titan^CCCCCC00." + "PL_wargames_lobby" "Lobby Giochi di guerra 24/7" + "WATCH_TUTORIAL" "GUARDA IL TUTORIAL" + "GAMEMODE_TMFD" "Titan Marchiato a morte" + "MP_RELIC02_FD_WAVE_1" "Insieme vinciamo" + "MP_RELIC02_FD_WAVE_2" "Alla ricerca del percorso principale" + "MP_RELIC02_FD_WAVE_3" "Creazione di un altro percorso" + "MP_RELIC02_FD_WAVE_4" "Patch cieca" + "MP_RELIC02_FD_WAVE_5" "Divisi prepariamo un'imboscata" + } + } + "lang" + { + "Language" "english" + "Tokens" + { + "NO_PRICE" "Offer Expired" + "NO_PRICE_TWO_LINES" "Offer\nExpired" + "WATCH_TUTORIAL" "WATCH TUTORIAL" + "PL_promo_coop" "4 Player CO-OP" + "PL_limited_time_mode" "Limited Time Mode" + "PL_speedball" "Live Fire" + "PL_speedball_lobby" "Live Fire Lobby" + "PL_speedball_desc" "Fight for possession of a netural flag. Eliminate the enemy team or possess the flag when the clock runs out to win the round. Winner is the first to 5 rounds won.\n^FFC83200Players: 6v6 *No Titans\nTime Limit: 60 seconds per round *No Respawns\nMax Party Size: 6" + "PL_raid" "Raid" + "PL_hunted" "Hunted" + "PL_don" "Double or Nothing" + "PL_fd" "Frontier Defense" + "PL_fd_lobby" "Frontier Defense Lobby" + "PL_fd_desc" "Defend against waves of Remnant Fleet forces" + "PL_fd_easy" "Frontier Defense: Easy" + "PL_fd_easy_lobby" "Frontier Defense: Easy Lobby" + "PL_fd_easy_desc" "Crush the opposition" + "PL_fd_normal" "Frontier Defense: Regular" + "PL_fd_normal_lobby" "Frontier Defense: Regular Lobby" + "PL_fd_normal_desc" "Recommended for experienced players" + "PL_fd_hard" "Frontier Defense: Hard" + "PL_fd_hard_lobby" "Frontier Defense: Hard Lobby" + "PL_fd_hard_desc" "Skilled play is required" + "PL_fd_master" "Frontier Defense: Master" + "PL_fd_master_lobby" "Frontier Defense: Master Lobby" + "PL_fd_master_desc" "Only the best of the best will succeed" + "PL_fd_insane" "Frontier Defense: Insane" + "PL_fd_insane_lobby" "Frontier Defense: Insane Lobby" + "PL_fd_insane_desc" "You will not survive" + "PL_angel_city" "Angel City 24/7" + "PL_angel_city_lobby" "Angel City 24/7 Lobby" + "PL_angel_city_desc" "All Angel City, all the time." + "PL_angel_city_abbr" "AC" + "PL_colony" "Colony 24/7" + "PL_colony_lobby" "Colony 24/7 Lobby" + "PL_colony_desc" "All Colony, all the time. ^CCCCCC00This will search for matches of ^FFC83200Attrition^CCCCCC00, ^FFC83200Pilots vs Pilots^CCCCCC00, and ^FFC83200Last Titan Standing^CCCCCC00." + "PL_colony_abbr" "COL" + "PL_glitch" "Glitch 24/7" + "PL_glitch_lobby" "Glitch 24/7 Lobby" + "PL_glitch_desc" "All Glitch, all the time. ^CCCCCC00This will search for matches of ^FFC83200CTF^CCCCCC00, ^FFC83200Amped Hardpoint^CCCCCC00, ^FFC83200Pilots vs Pilots^CCCCCC00, ^FFC83200Live Fire^CCCCCC00, and ^FFC83200Last Titan Standing^CCCCCC00." + "PL_glitch_abbr" "GLI" + "PL_wargames" "Wargames 24/7" + "PL_wargames_lobby" "Wargames 24/7 Lobby" + "PL_wargames_desc" "All Wargames, all the time. ^CCCCCC00This will search for matches of ^FFC83200Attrition^CCCCCC00, ^FFC83200CTF^CCCCCC00, ^FFC83200Pilots vs Pilots^CCCCCC00, ^FFC83200Amped Hardpoint^CCCCCC00, and ^FFC83200Last Titan Standing^CCCCCC00." + "PL_wargames_abbr" "WGM" + "PL_ctf_lf" "CTF (Nitro)" + "PL_ctf_lf_lobby" "CTF Nitro Lobby" + "PL_ctf_lf_desc" "Fast paced Capture the Flag in selected maps.\n^FFC83200Players: 5v5\nMax Party Size: 5\n^F4D5A600Instant Flag Returns // No Titans\nNo Boosts // Phase Shift Drops Flag" + "PL_ctf_lf_abbr" "CTF-N" + + "PL_nitro_mixtape" "Mixtape (Nitro)" + "PL_nitro_mixtape_lobby" "Mixtape Lobby" + "PL_nitro_mixtape_desc" "Fast paced CTF, MFD and PvP on selected maps.\n^FFC83200Players: 5v5\nMax Party Size: 5\n^F4D5A600Instant Flag Returns // No Titans\nNo Boosts // Phase Shift Drops Flag" + "PL_nitro_mixtape_abbr" "MXT-N" + + "PL_nitro_ffa" "FFA (Nitro)" + "PL_nitro_ffa_lobby" "FFA Nitro Lobby" + "PL_nitro_ffa_desc" "Fast paced Free for All on selected maps.\n^FFC83200Players: 6\n^F4D5A600No Titans\nNo Boosts" + "PL_nitro_ffa_abbr" "FFA-N" + + "PL_aitdm" "Attrition" + "PL_aitdm_lobby" "Attrition Lobby" + "PL_aitdm_desc" "Kill all enemies.\n^FFC83200Players: 6v6 *AI\nTime Limit: 10m\nMax Party Size: 6" + "PL_aitdm_abbr" "ATT" + "PL_attrition" "Bounty Hunt" + "PL_attrition_lobby" "Bounty Hunt Lobby" + "PL_attrition_desc" "Kill enemies to earn money. Earn more by 'banking' your bonus at designated locations.\n^FFC83200Players: 5v5 *AI\nTime Limit: 10m\nMax Party Size: 5" + "PL_attrition_abbr" "BH" + "PL_at_coop" "Escape (Co-op)" + "PL_at_coop_lobby" "Escape Lobby" + "PL_at_coop_desc" "You've just escaped prison with nothing more than a pistol. Survive until an evac can arrive. Kill enemies to earn money and buy weapons. \n^FFC83200Players: 6\nMax Party Size: 6" + "PL_pilot_skirmish" "Pilots vs. Pilots" + "PL_pilot_skirmish_lobby" "PvP Lobby" + "PL_pilot_skirmish_desc" "Kill enemy pilots. Titanfalls not permitted.\n^FFC83200Players: 8v8 *No Titans\nTime Limit: 10m\nMax Party Size: 8" + "PL_pilot_skirmish_abbr" "PvP" + "PL_hardpoint" "Amped Hardpoint" + "PL_hardpoint_lobby" "Amped Hardpoint Lobby" + "PL_hardpoint_desc" "Capture and hold a hardpoint to earn points. Amped Hardpoints give double points.\n^FFC83200Players: 6v6\nTime Limit: 10m\nMax Party Size: 6" + "PL_hardpoint_abbr" "AHP" + "PL_hardpoint_non_amp" "Hardpoint" + "PL_hardpoint_lobby_non_amp" "Hardpoint Lobby" + "PL_capture_the_flag" "Capture the Flag" + "PL_capture_the_flag_lobby" "CTF Lobby" + "PL_capture_the_flag_desc" "Steal the enemy flag and return it to your base while stopping the enemy team from taking your flag!\n^FFC83200Players: 5v5\nTime Limit: 12m\nMax Party Size: 5" + "PL_capture_the_flag_abbr" "CTF" + "PL_last_titan_standing" "Last Titan Standing" + "PL_last_titan_standing_lobby" "LTS Lobby" + "PL_last_titan_standing_desc" "All players start in Titans in this round-based elimination match-up. Winner is the first to 3 rounds won.\n^FFC83200Players: 5v5 *Start as Titan\nTime Limit: 3m per round *No Respawns\nMax Party Size: 5" + "PL_last_titan_standing_abbr" "LTS" + "PL_iron_last_titan_standing" "Iron LTS" + "PL_iron_last_titan_standing_lobby" "" + "PL_iron_last_titan_standing_desc" "Titans-only, round-based elimination match-up. Winner is the first to 3 rounds won.\n^FFC83200Players: 5v5 *NO PILOTS\nTime Limit: 3m per round *No Respawns\nMax Party Size: 5" + "PL_iron_last_titan_standing_abbr" "ILTS" + "PL_aegis_last_titan_standing" "Aegis LTS" + "PL_aegis_last_titan_standing_lobby" "" + "PL_aegis_last_titan_standing_desc" "Aegis Upgrades enabled. Round-based elimination match-up. Winner is the first to 3 rounds won.\n^FFC83200Players: 5v5 *Start as Titan\nTime Limit: 3m per round *No Respawns\nMax Party Size: 5" + "PL_aegis_last_titan_standing_abbr" "ALTS" + "PL_pilot_hunter" "Skirmish" + "PL_pilot_hunter_lobby" "Skirmish Lobby" + "PL_pilot_hunter_desc" "Kill enemy pilots and Titans. \n^FFC83200Players: 8v8\nTime Limit: 10m\nMax Party Size: 8" + "PL_pilot_hunter_abbr" "SKM" + "PL_titan_brawl" "Titan Brawl" + "PL_titan_brawl_lobby" "Titan Brawl Lobby" + "PL_titan_brawl_desc" "Kill enemy Titans. Pilots not permitted.\n^FFC83200Players: 5v5\nTime Limit: 10m\nMax Party Size: 5" + "PL_titan_brawl_abbr" "TTDM" + "PL_titan_brawl_hint" "Kill enemy Titans.\nNo Ejection // No Disembark" + "PL_aegis_titan_brawl" "Aegis Titan Brawl" + "PL_aegis_titan_brawl_lobby" "Aegis Titan Brawl Lobby" + "PL_aegis_titan_brawl_desc" "Kill enemy Titans. Aegis Upgrades enabled.\n^FFC83200Players: 5v5\nTime Limit: 10m\nMax Party Size: 5" + "PL_aegis_titan_brawl_abbr" "ATTDM" + "PL_aegis_titan_brawl_hint" "Kill enemy Titans.\nNo Ejection // No Disembark" + "PL_variety_pack" "Mixtape" + "PL_variety_pack_lobby" "Mixtape Lobby" + "PL_variety_pack_desc" "Varying player counts and including a variety of maps on these modes:\n^FFC83200*Bounty Hunt *Attrition\n*Last Titan Standing *Amped Hardpoint\n*Pilots vs. Pilots *Capture the Flag" + "PL_coliseum" "Coliseum" + "PL_coliseum_lobby" "Coliseum Lobby" + "PL_coliseum_desc" "One on one combat with enhanced mobility in a cage. Kill your opponent, win a round. Best 3 out of 5 wins an Advocate Gift reward.^FFC83200\nPlayers: 1v1 *No Titans\nTime Limit: 3m *No Respawns\n**^FFFFFF00REQUIRES COLISEUM TICKET or PAID ENTRY FEE" + "PL_ground_war" "8v8 Mixtape" + "PL_groud_war_lobby" "8v8 Mixtape Lobby" + "PL_ground_war_desc" "Includes Skirmish and Amped Hardpoint, with high player counts on all maps.\n^FFC83200Players: 8v8" + "PL_ground_war_abbr" "8v8" + "PL_ffa" "Free for All" + "PL_ffa_lobby" "Free for All Lobby" + "PL_ffa_desc" "Every pilot for themself, kill all enemies.\n^FFC83200Players: 1v11\nTime Limit: 10m\nMax Party Size: 1" + "PL_ffa_abbr" "FFA" + "PL_fra" "Free Agents" + "PL_fra_lobby" "Free Agents Lobby" + "PL_fra_desc" "You're running solo. Kill enemies to win. Collect 3 batteries for a Titanfall.\n^FFC83200Players: 1v11\nTime Limit: 15m\nMax Party Size: 1" + "PL_fra_abbr" "FRA" + "PL_default_name" "Default name" + "PL_default_lobbytitle" "Default lobbytitle" + "PL_default_description" "Default description" + "PL_load_a_map_on_the_command_line" "Load a map on the command line -devonly" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Settings for when someone loads a map on the command line. Do not edit the cmdlineMapLoad 1 below - this makes this work." + "PL_pl_rebuild_all_paths" "Rebuild all paths" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Run with ai_ainRebuildOnMapStart 2" + "PL_private_match" "Private Match" + "PL_private_match_lobby" "Private Match Lobby" + "PL_private_match_desc" "Play a custom, private match on a map and mode of your choice.\n^FFC83200INVITE NETWORK or INVITE FRIENDS to play\n^FFC83200Players: 1-16\nNo Progression" + + "PL_live_fire" "Live Fire" + "PL_live_fire_lobby" "Live Fire Lobby" + "PL_live_fire_desc" "Fast-paced combat in a Live Fire Arena. Win the round by killing all enemy pilots or possessing the flag when the timer runs out.^FFC83200\nPlayers: 6v6 *No Titans\nTime Limit: 60s *No Respawns\nMax Party Size: 6" + "PL_live_fire_abbr" "LF" + + "PL_marked_for_death" "Marked For Death" + "PL_marked_for_death_lobby" "Marked For Death Lobby" + "PL_marked_for_death_desc" "Kill or protect the marked targets.\n^FFC83200Players: 6v6 \nTime Limit: 12m\nMax Party Size: 6" + "PL_marked_for_death_abbr" "MFD" + + "PL_amped_tacticals" "Amped Tacticals" + "PL_amped_tacticals_lobby" "Amped Tacticals Lobby" + "PL_amped_tacticals_desc" "Classic Attrition rules except Tactical abilities are more powerful.\n^FFC83200Players: 6v6 *AI\nTime Limit: 10m\nMax Party Size: 6" + "PL_amped_tacticals_abbr" "ATT" + + "PL_tactikill" "Tactikill Attrition" + "PL_tactikill_lobby" "Tactikill Attrition Lobby" + "PL_tactikill_desc" "Classic Attrition rules except Tactical abilities are fully reset upon kill.\n^FFC83200Players: 6v6 *AI\nTime Limit: 10m\nMax Party Size: 6" + "PL_tactikill_abbr" "ATT" + + "PL_all_grapple" "Attack on Titanfall" + "PL_all_grapple_lobby" "Attack on Titanfall Lobby" + "PL_all_grapple_desc" "Classic Attrition rules except all Tactical abilities are replaced with Grapple.\n^FFC83200Players: 6v6 *AI\nTime Limit: 10m\nMax Party Size: 6" + "PL_all_grapple_abbr" "ATT" + + "PL_all_holopilot" "The Great Bamboozle" + "PL_all_holopilot_lobby" "The Great Bamboozle Lobby" + "PL_all_holopilot_desc" "Classic Live Fire rules except all Tactical abilities are replaced with Holopilot.^FFC83200\nPlayers: 6v6 *No Titans\nTime Limit: 60s *No Respawns\nMax Party Size: 6" + "PL_all_holopilot_abbr" "LF" + + "PL_all_phase" "The Otherside" + "PL_all_phase_lobby" "The Otherside Lobby" + "PL_all_phase_desc" "Classic Attrition rules except all Tactical abilities are replaced with Phase.\n^FFC83200Players: 6v6 *AI\nTime Limit: 10m\nMax Party Size: 6" + "PL_all_phase_abbr" "ATT" + + "PL_rocket_arena" "Rocket Arena" + "PL_rocket_arena_lobby" "Rocket Arena Lobby" + "PL_rocket_arena_desc" "Classic Live Fire rules with modified EPGs.^FFC83200\nPlayers: 6v6 *No Titans\nTime Limit: 90s *No Respawns\nMax Party Size: 6" + "PL_rocket_arena_abbr" "LF" + + "PL_turbo_last_titan_standing" "Turbo LTS" + "PL_turbo_last_titan_standing_lobby" "Turbo LTS Lobby" + "PL_turbo_last_titan_standing_desc" "Classic LTS rules with faster Dash regen and Core generation.\n^FFC83200Players: 5v5 *Start as Titan\nTime Limit: 3m per round *No Respawns\nMax Party Size: 5" + "PL_turbo_last_titan_standing_abbr" "TLTS" + + "PL_all_spicy" "Spicy Attrition" + "PL_all_spicy_lobby" "Spicy Attrition Lobby" + "PL_all_spicy_desc" "Classic Attrition rules except all Tactical abilities are replaced with Ticks.\n^FFC83200Players: 6v6 *AI\nTime Limit: 10m\nMax Party Size: 6" + "PL_all_spicy_abbr" "ATT" + + "PL_titan_brawl_turbo" "Turbo Titan Brawl" + "PL_titan_brawl_turbo_lobby" "Turbo Titan Brawl Lobby" + "PL_titan_brawl_turbo_desc" "Classic Titan Brawl rules with faster Dash regen and Core generation.\n^FFC83200Players: 5v5\nTime Limit: 10m\nMax Party Size: 5" + "PL_titan_brawl_turbo_abbr" "TTDM" + "PL_titan_brawl_turbo_hint" "Kill enemy Titans.\nNo Ejection // No Disembark" + + + // FAQ - Community + // + + "COMMUNITYUPDATE_NAME" "Community" + "COMMUNITYUPDATE_DESC" "`3Titanfall Community Updates`0\n\nGet latest info and see stuff we think is rad from around the web.\n\nFor more:\n`2%$rui/bullet_point%`0Follow us on Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Like us on `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Join us at `1www.respawn.com`0" + + "COMMUNITYUPDATE_00_Q" "\"Postcards from the Frontier\" Trailer" + "COMMUNITYUPDATE_00_A" "Your adventure across the stunning vistas of the Frontier continues with the latest DLC drop for Titanfall 2: Postcards From the Frontier. Featuring new and familiar locations along with a new collection of Elite Weapon Warpaints, the Frontier has never looked better.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_01_Q" "Postcards from the Frontier: The Patch Notes" + "COMMUNITYUPDATE_01_A" "Read all the changes that come with the Postcards from the Frontier patch.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_02_Q" "Titanfall: Assault \"Launch\" Trailer" + "COMMUNITYUPDATE_02_A" "Coming soon to mobile devices, Titanfall: Assault is an exciting real time RTS set in the Titanfall universe in partnership with Particle City. Watch it in action here! \n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_03_Q" "Titanfall Assault: \"Learn the Basics\" video" + "COMMUNITYUPDATE_03_A" "Iniquity walks us through the tutorial and gives basic tips for Titanfall Assault. This is the perfect way to get started learning about the game.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_04_Q" "Respawn Plays Frontier Defense" + "COMMUNITYUPDATE_04_A" "Listen to some of the key folks behind Frontier Defense talk about the history and making of the mode and watch us play a few rounds! \n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_05_Q" "Community Creations: Get to the Point" + "COMMUNITYUPDATE_05_A" "Kevin Younger created a fun montage showing off a plethora of sweet moves with the Pulse Blade. \n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_06_Q" "Community Creations: Northstar Pilot Hunt" + "COMMUNITYUPDATE_06_A" "ConzeyG via reddit shows off brutal efficiency with Northstar picking off Pilots in Marked for Death mode. \n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_07_Q" "\"Operation Frontier Shield\" Gameplay Trailer" + "COMMUNITYUPDATE_07_A" "Available now! Frontier Defense returns along with Rise as well as brand new warpaints to buy and new a new Live Fire map. Watch it all in action here.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_08_Q" "\"The War Games\" Gameplay Trailer" + "COMMUNITYUPDATE_08_A" "Available now! The iconic War Games map returns to Titanfall 2 looking better than ever. Also check out the new execution and new live fire map, Traffic in action.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_09_Q" "\"Monarch's Reign\" Gameplay Trailer" + "COMMUNITYUPDATE_09_A" "This DLC features the addition of the 7th multiplayer Titan: Monarch, a remaster of the map, Relic, a new execution as well as purchasable Ronin and Tone Prime Titans, more camos, banners, and nose art. Watch the action here.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_10_Q" "\"A Glitch in the Frontier\" Gameplay Trailer" + "COMMUNITYUPDATE_10_A" "All is not as it appears on the Frontier - prepare to enter the newest free DLC pack for Titanfall 2: A Glitch in the Frontier - featuring the new map “Glitch”. Inspired by Captain Lastimosa’s home planet of Harmony, vertical drops and long, twisting paths dominate the environment, perfect for chaining together long wall runs to seamlessly glide across the map. A new Live Fire map also joins the fold: Deck, which features tight interior spaces, exposed courtyards, and watchful drones circling overhead. If you’re feeling overwhelmed, the ever-helpful M.R.V.N.s are now here as an all-new faction to lend a cheery robotic hand. Finally, the new Pulse Blade execution is available to unlock to use whenever you feel the need to get your point across.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_11_Q" "\"Colony Reborn\" Gameplay Trailer" + "COMMUNITYUPDATE_11_A" "Return to an iconic fan favorite multiplayer map from the original Titanfall: Colony. Mix in all of the new tacticals & Titans from Titanfall 2, and Pilots & Titans will have to keep their wits about them to survive in this tightly-packed idyllic village of back alleys, blind corners and exposed rooftops; available for free on March 30th for all players. The “Colony Reborn” DLC pack includes the return of classic weapons like the tricked out R-101 assault rifle, a new grapple execution, and new cosmetic options for purchase to look your best while you paint the town red.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_12_Q" "\"Welcome to Live Fire\" Gameplay Trailer" + "COMMUNITYUPDATE_12_A" "Introducing Live Fire: a lightning fast 6v6 Pilot only mode that brings competitive, close quarter combat to the forefront. Featuring two brand new maps designed specifically for Live Fire: Stacks and Meadow. These two free maps are tight, enclosed death boxes designed specifically for the fast-paced, intense nature of the mode.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_13_Q" "\"Welcome to Angel City\" Gameplay Trailer" + "COMMUNITYUPDATE_13_A" "Experience a remastered version of the fan favorite map from the original Titanfall, `1Angel City`0. Stand by for the first free DLC for Titanfall 2 with `1Angel City's Most Wanted`0 available on December 1st for all players. This content includes new cosmetic options to add more flair to to the Frontier. \n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_14_Q" "\"Encore\" Accolades Trailer" + "COMMUNITYUPDATE_14_A" "Welcome back.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_15_Q" "\"Become One\" Single Player Gameplay Trailer" + "COMMUNITYUPDATE_15_A" "Two legends, one legacy.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + "COMMUNITYUPDATE_16_Q" "\"Pilots\" Multiplayer Gameplay Trailer" + "COMMUNITYUPDATE_16_A" "Limitless.\n\n\nPress `2%[A_BUTTON|MOUSE1]%`0 to view." + + // faq_community_count = 17 + + // FAQ - Patch Notes + // + + "KNB_SUBJECT_00_NAME" "Game Updates" + "KNB_SUBJECT_00_DESC" "`3What's New in Titanfall?`0\n\nCheck here to see what's changed in Titanfall 2!" + + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 New community created callsign banners\n\n`2%$rui/bullet_point%`0All advocate gifts are now purchasable with credits\n\n`2%$rui/bullet_point%`0New Purchasable Store Content\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% November 28 - Harvest Time" + + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Pistol Primary Slot\n\n`2%$rui/bullet_point%`0Halloween Banners\n\n`2%$rui/bullet_point%`0Balance Changes\n\n`2%$rui/bullet_point%`0New Purchasable Store Content\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% October 31 - Tricks and Treats" + + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Frontier Defense - Support for 3 more maps - Drydock, Angel City and Exoplanet.\n\n`2%$rui/bullet_point%`0New Live Fire Map - UMA\n\n`2%$rui/bullet_point%`0New Pilot Execution - Hole In The Wall\n\n`2%$rui/bullet_point%`0New Purchasable Store Content" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% August 29 - Postcards from the Frontier" + + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Frontier Defense - A new cooperative mode where you join forces with up to three other players to defend a vital objective from increasingly intense waves of AI combatants. Communication and adaptation are key to surviving.\n\n`2%$rui/bullet_point%`0New Map - Rise\n\n`2%$rui/bullet_point%`0New Live Fire Map - Township\n\n`2%$rui/bullet_point%`0New Purchasable Store Content" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% July 25 - Operation Frontier Shield" + + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0New Map - Wargames\n\n`2%$rui/bullet_point%`0New Live Fire Map - Traffic\n\n`2%$rui/bullet_point%`0New Pilot Execution - Shadow Boxing\n\n`2%$rui/bullet_point%`03rd Weapon Slot\n\n`2%$rui/bullet_point%`0Private Match Settings" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% June 27 - The War Games" + + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0New Titan - Monarch\n\n`2%$rui/bullet_point%`0New Map - Relic\n\n`2%$rui/bullet_point%`0New Pilot Execution - Now You See Me\n\n`2%$rui/bullet_point%`0New Purchasable Store Content" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% May 30 - Monarch's Reign" + + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0New Map - Glitch\n\n`2%$rui/bullet_point%`0New Live Fire Map - Deck\n\n`2%$rui/bullet_point%`0New Faction - M.R.V.N.\n\n`2%$rui/bullet_point%`0New Pilot Execution - Get to the Point\n\n`2%$rui/bullet_point%`0Max Gen increased to 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% Apr 25 - A Glitch in the Frontier" + + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0New Map - Colony\n\n`2%$rui/bullet_point%`0New Pilot Execution - Curb Check\n\n`2%$rui/bullet_point%`0New Weapon - R-101\n\n`2%$rui/bullet_point%`0New Purchasable Store Content" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% Mar 30 - Colony Reborn" + + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Live Fire - A new Pilot vs Pilot elimination game mode! It’s a 6v6 round-based with no respawns, you will have one minute to eliminate the opposing team in order to win the round. You can also win the round if your team is holding the neutral flag when the round timer ends. The team to win 5 rounds first wins the match.\n\n`2%$rui/bullet_point%`0New Live Fire Map - Meadow\n\n`2%$rui/bullet_point%`0New Live Fire Map - Stacks\n\n`2%$rui/bullet_point%`0New Pilot Execution - Late Hit" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% Feb 23 - Live Fire" + + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0New Map - Angel City\n\n`2%$rui/bullet_point%`0New Weapon - B3 Wingman Elite\n\n`2%$rui/bullet_point%`0New Pilot Execution - Inner Pieces\n\n`2%$rui/bullet_point%`0New Titan Kits\n\n`2%$rui/bullet_point%`0New Purchasable Store Content" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% Nov 30 - Angel City's Most Wanted" + + "MP_ANGEL_CITY_FD_WAVE_1" "Chained to the Sky" + "MP_ANGEL_CITY_FD_WAVE_2" "Formlessness" + "MP_ANGEL_CITY_FD_WAVE_3" "Insurgency" + "MP_ANGEL_CITY_FD_WAVE_4" "An Obstinate Lot" + "MP_ANGEL_CITY_FD_WAVE_5" "Roll the Hard Six" + + "MP_DRYDOCK_FD_WAVE_1" "To Swim in Strange Water" + "MP_DRYDOCK_FD_WAVE_2" "They've got no bullets!" + "MP_DRYDOCK_FD_WAVE_3" "Blinded by Science" + "MP_DRYDOCK_FD_WAVE_4" "High Pressure System" + "MP_DRYDOCK_FD_WAVE_5" "Eye of the Storm" + + "MP_THAW_FD_WAVE_1" "Situational Awareness" + "MP_THAW_FD_WAVE_2" "Strength in Numbers" + "MP_THAW_FD_WAVE_3" "Henchman 21" + "MP_THAW_FD_WAVE_4" "Fun in the Fire" + "MP_THAW_FD_WAVE_5" "Serve Well the Guns" + + "GAMEMODE_TMFD" "Titan Marked for Death" + + "MP_RELIC02_FD_WAVE_1" "United We Stand" + "MP_RELIC02_FD_WAVE_2" "Seeking the Main Path" + "MP_RELIC02_FD_WAVE_3" "Cutting Another Path" + "MP_RELIC02_FD_WAVE_4" "Blind Patch" + "MP_RELIC02_FD_WAVE_5" "Divided We Ambush" + } + } + "lang" + { + "Language" "french" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Vos aventures à travers les environnements de la Frontière continuent avec le nouveau DLC de Titanfall 2 : Cartes postales de la Frontière. Personnalisez votre arsenal avec des peintures de guerre d'élite et combattez dans des lieux nouveaux ou familiers. La Frontière n'aura jamais été aussi belle !\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_00_Q" "Trailer \"Cartes postales de la Frontière\"" + "COMMUNITYUPDATE_01_A" "Consultez la liste de changements inclus au patch Cartes postales de la Frontière.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_01_Q" "Cartes postales de la Frontière : Notes " + "COMMUNITYUPDATE_02_A" "Prochainement disponible sur appareils mobiles, Titanfall: Assault est un STR captivant dans l'univers Titanfall développé en collaboration avec Particle City. Regardez la vidéo ! \n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_02_Q" "Titanfall: Assault - Trailer de lancement" + "COMMUNITYUPDATE_03_A" "Iniquity nous présente le didacticiel et les bases de Titanfall: Assault. Obtenez vite plus d'informations sur les mécaniques de ce nouveau jeu.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_03_Q" "Titanfall: Assault - \"Les bases du jeu\"" + "COMMUNITYUPDATE_04_A" "Regardez les créateurs de Défense frontalière évoquer l'histoire et la conception de ce mode de jeu manette en main ! \n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_04_Q" "Respawn Plays : Défense frontalière" + "COMMUNITYUPDATE_05_A" "Kevin Younger a créé un montage de ses meilleures actions avec sa lame à impulsion. \n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_05_Q" "Créations communautaires : impulsion fatale" + "COMMUNITYUPDATE_06_A" "ConzeyG (sur reddit) nous démontre de toute son efficacité avec le Titan Northstar dans le mode de jeu Condamnation. \n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_06_Q" "Créations : Northstar chasseur de pilotes " + "COMMUNITYUPDATE_07_A" "Disponible ! Défense frontalière revient avec la carte Expansion, de nouvelles peintures de guerre payantes et une nouvelle carte Live Fire. Regardez vite le trailer !\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0." + "COMMUNITYUPDATE_07_Q" "Trailer gameplay \"Opération Frontier Shield\"" + "COMMUNITYUPDATE_08_A" "Disponible dès maintenant ! La carte à succès Jeux de guerre fait son grand retour dans Titanfall 2. Découvrez également une exécution inédite et Trafic, une toute nouvelle carte Live Fire.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_08_Q" "Trailer gameplay \"Jeux de guerre\"" + "COMMUNITYUPDATE_09_A" "Notre nouveau DLC inclut le Monarch (7e Titan multijoueur du jeu), une version remasterisée de la carte Relique, une exécution inédite, ainsi que du contenu payant incluant les Titans Ronin Prime et Tone Prime avec des nouveaux camouflages, bannières et personnalisations de cockpit. Regardez vite le trailer !\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_09_Q" "Trailer gameplay \"Règne du Monarch\"" + "COMMUNITYUPDATE_10_A" "Les apparences sont parfois trompeuses à la Frontière ! Préparez-vous pour Glitch frontalier, le nouveau DLC gratuit de Titanfall 2 qui inclut la carte inédite \"Glitch\". Inspirée par Harmony, la planète natale du capitaine Lastimosa, cette carte regorge de voies verticales et de longs chemins tortueux qui vous permettront d'enchaîner les courses sur les murs. Découvrez également \"Pont\", une toute nouvelle carte Live Fire avec des sections intérieures étroites et des zones exposées survolées par des drones aériens. Vous ne serez pas seuls sur ces nouveaux champs de bataille : les serviables Marvins s'invitent au combat en tant que nouvelle faction pour vous prêter main forte ! Débloquez également la nouvelle exécution Impulsion fatale pour faire passer un message à tous vos ennemis.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_10_Q" "Trailer gameplay \"Glitch frontalier\"" + "COMMUNITYUPDATE_11_A" "Découvrez la nouvelle version de Colonie, l'une des cartes multijoueurs favorites des fans du premier Titanfall ! Combinez les différentes capacités tactiques et les classes de Titan de Titanfall 2 à compter du 30 mars pour éliminer vos adversaires à travers les ruelles tortueuses, les recoins dangereux et les toitures exposées de ce village idyllique. Le DLC gratuit \"Nouvelle colonie\" inclut des armes mythiques comme la nouvelle version du fusil d'assaut R-101, une exécution au grappin inédite et de nouvelles options cosmétiques payantes pour combattre avec encore plus de style !\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_11_Q" "Trailer gameplay \"Nouvelle colonie\"" + "COMMUNITYUPDATE_12_A" "Découvrez Live Fire, un tout nouveau mode de jeu pour pilotes proposant des affrontements ultra-rapides à 6c6 en combat rapproché. Combattez sur deux nouvelles cartes spécialement conçues pour Live Fire : Empilements et Prairie. Ces deux cartes comportent des zones de jeu resserrées parfaitement adaptées au caractère intense et débridé de ce nouveau mode de jeu.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_12_Q" "Trailer gameplay \"Live Fire\"" + "COMMUNITYUPDATE_13_A" "Découvrez la version remasterisée d'`1Angel City`0, la carte favorite des joueurs du premier Titanfall ! Préparez-vous pour le premier DLC gratuit de Titanfall 2, `1Liste noire d'Angel City`0, qui sera disponible le 1er décembre pour tous les joueurs. Ce nouveau contenu inclut également des optimisations cosmétiques qui vous aideront à vous démarquer sur les champs de bataille de la Frontière. \n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_13_Q" "Trailer gameplay \"Angel City\"" + "COMMUNITYUPDATE_14_A" "Bon retour parmi nous !\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_14_Q" "Trailer - \"Encore\"" + "COMMUNITYUPDATE_15_A" "Deux légendes, un héritage.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_15_Q" "Trailer Solo - \"Ne faites plus qu'un\"" + "COMMUNITYUPDATE_16_A" "Sans limite.\n\n\nAppuyez sur `2%[A_BUTTON|MOUSE1]%`0 pour voir la vidéo." + "COMMUNITYUPDATE_16_Q" "Trailer multijoueur - \"Pilotes\"" + "COMMUNITYUPDATE_DESC" "`3Titanfall - Mises à jour de la communauté`0\n\nDes infos et des liens en provenance de tout le web.\n\nPour ne rien manquer :\n`2%$rui/bullet_point%`0Suivez-nous sur Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Rendez-vous sur `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Rejoignez-nous sur `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "Communauté" + "KNB_SUBJECT_00_DESC" "`3Quoi de neuf dans Titanfall ?`0\n\nPrenez connaissance des nouvelles fonctionnalités de Titanfall 2 !" + "KNB_SUBJECT_00_NAME" "Mises à jour du jeu" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 Nouvelles bannières créées par la communauté\n\n`2%$rui/bullet_point%`0Tous les cadeaux sont désormais achetables avec des crédits\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 novembre - Récolte" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Emplacement principal pour pistolet\n\n`2%$rui/bullet_point%`0Bannières Halloween\n\n`2%$rui/bullet_point%`0Optimisations de l'équilibre\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 octobre - Bundle Halloween" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Défense frontalière - Prise en charge de 3 cartes supplémentaires : Cale sèche, Angel City et Exoplanète.\n\n`2%$rui/bullet_point%`0Nouvelle carte Live Fire - UMA\n\n`2%$rui/bullet_point%`0Nouvelle exécution de pilote - Trou dans le mur\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 août - Cartes postales de la Frontière" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Défense frontalière - Nouveau mode coopératif, qui vous propose de vous allier à un maximum de trois autres joueurs pour défendre un objectif stratégique face à des vagues de combattants IA de plus en plus intenses. Votre survie dépendra de vos facultés de communication et d'adaptation !\n\n`2%$rui/bullet_point%`0Nouvelle carte - Expansion\n\n`2%$rui/bullet_point%`0Nouvelle carte Live Fire - Cité\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25 juillet - Opération Frontier Shield" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Nouvelle carte - Jeux de guerre\n\n`2%$rui/bullet_point%`0Nouvelle carte Live Fire - Trafic\n\n`2%$rui/bullet_point%`0Nouvelle exécution de pilote - Boxe furtive\n\n`2%$rui/bullet_point%`0Troisième emplacement d'armement\n\n`2%$rui/bullet_point%`0Paramètres de partie privée" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27 juin - Jeux de guerre" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Nouveau Titan - Monarch\n\n`2%$rui/bullet_point%`0Nouvelle carte - Relique\n\n`2%$rui/bullet_point%`0Nouvelle exécution - Vision mortelle\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30 mai - Règne du Monarch" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Nouvelle carte - Glitch\n\n`2%$rui/bullet_point%`0Nouvelle carte Live Fire - Pont\n\n`2%$rui/bullet_point%`0Nouvelle faction - Marvin\n\n`2%$rui/bullet_point%`0Nouvelle exécution de pilote - Impulsion fatale\n\n`2%$rui/bullet_point%`0Niveau de génération maximal augmenté à 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25 avril - Glitch frontalier" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Nouvelle carte - Colonie\n\n`2%$rui/bullet_point%`0Nouvelle exécution de pilote - Coup du grappin\n\n`2%$rui/bullet_point%`0Nouvelle arme - R-101\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30 mars - Nouvelle colonie" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Live Fire - Un nouveau mode Pilotes contre pilotes à élimination ! Dans ce mode à 6c6 en plusieurs manches, vous disposerez d'une minute pour éliminer l'équipe adverse et remporter la manche. Vous pourrez aussi gagner la manche si votre équipe est en possession du drapeau neutre à la fin du temps imparti. La première équipe à gagner 5 manches remporte la partie.\n\n`2%$rui/bullet_point%`0Nouvelle carte Live Fire - Prairie\n\n`2%$rui/bullet_point%`0Nouvelle carte Live Fire - Empilements\n\n`2%$rui/bullet_point%`0Nouvelle exécution de pilote - Frappe spéciale" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23 février - Live Fire" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Nouvelle carte - Angel City\n\n`2%$rui/bullet_point%`0Nouvelle arme - Wingman B3 Élite\n\n`2%$rui/bullet_point%`0Nouvelle exécution de pilote - Viscéral\n\n`2%$rui/bullet_point%`0Nouveaux kits pour Titan\n\n`2%$rui/bullet_point%`0Nouveau contenu payant dans la Boutique" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30 novembre - Liste noire d'Angel City" + "MP_ANGEL_CITY_FD_WAVE_1" "Enchaînement céleste" + "MP_ANGEL_CITY_FD_WAVE_2" "Menace informe" + "MP_ANGEL_CITY_FD_WAVE_3" "Insurrection" + "MP_ANGEL_CITY_FD_WAVE_4" "Obstination" + "MP_ANGEL_CITY_FD_WAVE_5" "Tout pour le tout" + "MP_DRYDOCK_FD_WAVE_1" "En eaux troubles" + "MP_DRYDOCK_FD_WAVE_2" "En manque de munitions" + "MP_DRYDOCK_FD_WAVE_3" "Aveuglement scientifique" + "MP_DRYDOCK_FD_WAVE_4" "Haute pression" + "MP_DRYDOCK_FD_WAVE_5" "Oeil du cyclone" + "MP_THAW_FD_WAVE_1" "Connaissance situationnelle" + "MP_THAW_FD_WAVE_2" "La force par le nombre" + "MP_THAW_FD_WAVE_3" "Hommes de main" + "MP_THAW_FD_WAVE_4" "Divertissement ardent" + "MP_THAW_FD_WAVE_5" "Pour l'honneur" + "NO_PRICE" "Offre expirée" + "NO_PRICE_TWO_LINES" "Offre\nexpirée" + "PL_aegis_last_titan_standing" "DT Aegis" + "PL_aegis_last_titan_standing_abbr" "DTA" + "PL_aegis_last_titan_standing_desc" "Optimisations Aegis autorisées. Plusieurs manches à élimination. La première équipe à gagner 3 manches remporte la partie.\n^FFC83200Joueurs : 5c5 *Début en Titan\nLimite de temps : 3 min par manche *Aucune réapparition\nTaille max. du groupe : 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Combat de Titan Aegis" + "PL_aegis_titan_brawl_abbr" "CDTA" + "PL_aegis_titan_brawl_desc" "Détruisez les Titans ennemis. Optimisations Aegis autorisées.\n^FFC83200Joueurs : 5c5\nLimite de temps : 10 min\nTaille max. du groupe : 5" + "PL_aegis_titan_brawl_hint" "Détruisez les Titans ennemis.\nPas d'éjection" + "PL_aegis_titan_brawl_lobby" "Salon Combat de Titan Aegis" + "PL_aitdm" "Attrition" + "PL_aitdm_abbr" "ATT" + "PL_aitdm_desc" "Tuez tous vos ennemis.\n^FFC83200Joueurs : 6c6 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_aitdm_lobby" "Salon Attrition" + "PL_all_grapple" "Attaque sur Titanfall" + "PL_all_grapple_abbr" "ATT" + "PL_all_grapple_desc" "Règles Attrition classiques avec toutes les capacités tactiques remplacées par le grappin.\n^FFC83200Joueurs : 6c6 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_all_grapple_lobby" "Salon Attaque sur Titanfall" + "PL_all_holopilot" "Holo-bataille" + "PL_all_holopilot_abbr" "LF" + "PL_all_holopilot_desc" "Règles Live Fire classiques avec toutes les capacités tactiques remplacées par le module holo-pilote.^FFC83200\nJoueurs : 6c6 *Aucun Titan\nLimite de temps : 60 s *Aucune réapparition\nTaille max. du groupe : 6" + "PL_all_holopilot_lobby" "Salon Holo-bataille" + "PL_all_phase" "De l'autre côté" + "PL_all_phase_abbr" "ATT" + "PL_all_phase_desc" "Règles Attrition classiques avec toutes les capacités tactiques remplacées par la téléportation.\n^FFC83200Joueurs : 6c6 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_all_phase_lobby" "Salon De l'autre côté" + "PL_all_spicy" "Attritique" + "PL_all_spicy_abbr" "ATT" + "PL_all_spicy_desc" "Règles Attrition classiques avec toutes les capacités tactiques remplacées par des tiques.\n^FFC83200Joueurs : 6c6 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_all_spicy_lobby" "Salon Attritique" + "PL_amped_tacticals" "Tactiques amplifiées" + "PL_amped_tacticals_abbr" "ATT" + "PL_amped_tacticals_desc" "Règles Attrition classiques avec amplification de toutes les capacités tactiques.\n^FFC83200Joueurs : 6c6 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_amped_tacticals_lobby" "Salon Tactiques amplifiées" + "PL_ANGEL_CITY" "Angel City 24/7" + "PL_angel_city_abbr" "AC" + "PL_angel_city_desc" "Tout Angel City, tout le temps." + "PL_angel_city_lobby" "Salon Angel City 24/7" + "PL_at_coop" "Évasion (Coop)" + "PL_at_coop_desc" "Vous venez de vous évader de prison avec un pistolet pour seule arme. Survivez jusqu’à l’arrivée du vaisseau d’évacuation. Abattez des ennemis pour gagner de l’argent et acheter des armes. \n^FFC83200Joueurs : 6\n^FFC83200Taille max. du groupe : 6" + "PL_at_coop_lobby" "Salon Évasion" + "PL_attrition" "Chasse aux primes" + "PL_attrition_abbr" "CP" + "PL_attrition_desc" "Abattez vos ennemis pour gagner de l'argent. Augmentez votre score en encaissant des bonus aux emplacements désignés.\n^FFC83200Joueurs : 5c5 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 5" + "PL_attrition_lobby" "Salon Chasse aux primes" + "PL_capture_the_flag" "Capture de drapeau" + "PL_capture_the_flag_abbr" "CDD" + "PL_capture_the_flag_desc" "Emparez-vous du drapeau adverse et rapportez-le à votre base, tout en empêchant l’ennemi de prendre le vôtre.\n^FFC83200Joueurs : 5c5\nLimite de temps : 12 min\nTaille max. du groupe : 5" + "PL_capture_the_flag_lobby" "Salon CDD" + "PL_coliseum" "Colisée" + "PL_coliseum_desc" "Duels rapides en cage à 3 manches gagnantes avec cadeau. Abattez votre adversaire pour remporter la manche.^FFC83200\nJoueurs : 1c1 *Aucun Titan\nLimite de temps : 3 min *Aucune réapparition\n**^FFFFFF00REQUIERT TICKET COLISÉE ou INSCRIPTION PAYANTE" + "PL_coliseum_lobby" "Salon Colisée" + "PL_colony" "Colonie 24/7" + "PL_colony_abbr" "COL" + "PL_colony_desc" "Affrontements exclusivement sur la carte Colonie. ^CCCCCC00Vous allez chercher des parties en modes ^FFC83200Attrition^CCCCCC00, ^FFC83200Pilotes contre pilotes^CCCCCC00 et ^FFC83200Dernier Titan^CCCCCC00." + "PL_colony_lobby" "Salon Colonie 24/7" + "PL_ctf_lf" "CDD (Nitro)" + "PL_ctf_lf_abbr" "CDD-N" + "PL_ctf_lf_desc" "Affrontements rapides en Capture de drapeau sur une sélection de cartes.\n^FFC83200Joueurs : 5c5\nTaille max. du groupe : 5\n^F4D5A600Retours instantanés du drapeau" + "PL_ctf_lf_lobby" "Salon CDD Nitro" + "PL_default_description" "Description par défaut" + "PL_default_lobbytitle" "Nom salon par défaut" + "PL_default_name" "Nom par défaut" + "PL_don" "Quitte ou double" + "PL_fd" "Défense frontalière" + "PL_fd_desc" "Défendez-vous contre des vagues de forces ennemies." + "PL_fd_easy" "Défense frontalière : Facile" + "PL_fd_easy_desc" "Éliminez l'opposition !" + "PL_fd_easy_lobby" "Salon Défense frontalière : Facile" + "PL_fd_hard" "Défense frontalière : Difficile" + "PL_fd_hard_desc" "Résistez en développant des stratégies avancées." + "PL_fd_hard_lobby" "Défense frontalière : Salon difficile" + "PL_fd_insane" "Défense frontalière : Extrême" + "PL_fd_insane_desc" "Vous ne survivrez pas." + "PL_fd_insane_lobby" "Défense frontalière : Salon extrême" + "PL_fd_lobby" "Salon Défense frontalière" + "PL_fd_master" "Défense frontalière : Élite" + "PL_fd_master_desc" "Seuls les meilleurs pilotes gagneront." + "PL_fd_master_lobby" "Défense frontalière : Salon élite" + "PL_fd_normal" "Défense frontalière : Standard" + "PL_fd_normal_desc" "Recommandé aux joueurs chevronnés" + "PL_fd_normal_lobby" "Défense frontalière : salon Standard" + "PL_ffa" "Chacun pour soi" + "PL_ffa_abbr" "CPS" + "PL_ffa_desc" "Chaque pilote joue seul et doit abattre tous ses ennemis.\n^FFC83200Joueurs : 1c11\nLimite de temps : 10 min\nTaille max. du groupe : 1" + "PL_ffa_lobby" "Salon Chacun pour soi" + "PL_fra" "Agent libre" + "PL_fra_abbr" "AL" + "PL_fra_desc" "Vous jouez pour vous. Abattez vos ennemis pour gagner. Collectez 3 batteries pour appeler votre Titan.\n^FFC83200Joueurs : 1c11\nLimite de temps : 15 min\nTaille max. du groupe : 1" + "PL_fra_lobby" "Salon Agent libre" + "PL_groud_war_lobby" "Salon Mixtape 8c8" + "PL_ground_war" "Mixtape 8c8" + "PL_ground_war_abbr" "8c8" + "PL_ground_war_desc" "Inclut les modes Escarmouche et Point clé amplifié avec un nombre de joueurs élevé sur toutes les cartes.\n^FFC83200Joueurs : 8c8" + "PL_hardpoint" "Point clé amplifié" + "PL_hardpoint_abbr" "PCA" + "PL_hardpoint_desc" "Capturez et contrôlez des points clés pour gagner des points (amplifier les points clés rapporte 2X plus).\n^FFC83200Joueurs : 6c6\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_hardpoint_lobby" "Salon Point clé amplifié" + "PL_hardpoint_non_amp" "Point clé" + "PL_hardpoint_lobby_non_amp" "Salon Point clé" + "PL_hunted" "Traque" + "PL_iron_last_titan_standing" "DT d'Acier" + "PL_iron_last_titan_standing_abbr" "DTA" + "PL_iron_last_titan_standing_desc" "Titans uniquement avec plusieurs manches à élimination. La première équipe à gagner 3 manches remporte la partie.\n^FFC83200Joueurs : 5c5 *PAS DE PILOTES\nLimite de temps : 3 min par manche *Aucune réapparition\nTaille max. du groupe : 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Dernier Titan" + "PL_last_titan_standing_abbr" "DT" + "PL_last_titan_standing_desc" "Chaque joueur commence à bord d'un Titan dans plusieurs manches à élimination. La première équipe à gagner 3 manches remporte la partie.\n^FFC83200Joueurs : 5c5 *Début en Titan\nLimite de temps : 3 min par manche *Aucune réapparition\nTaille max. du groupe : 5" + "PL_last_titan_standing_lobby" "Salon DT" + "PL_limited_time_mode" "Mode à durée limitée" + "PL_live_fire" "Live Fire" + "PL_live_fire_abbr" "LF" + "PL_live_fire_desc" "Combats rapides dans une arène Live Fire. Abattez tous les pilotes ennemis ou détenez le drapeau à la fin du temps imparti pour remporter la manche.^FFC83200\nJoueurs : 6c6 *Aucun Titan\nLimite de temps : 60 s *Aucune réapparition\nTaille max. du groupe : 6" + "PL_live_fire_lobby" "Salon Live Fire" + "PL_load_a_map_on_the_command_line" "Charger carte par ligne de commande –dev uniquement" + "PL_marked_for_death" "Condamnation" + "PL_marked_for_death_abbr" "COND" + "PL_marked_for_death_desc" "Abattez ou protégez les cibles désignées.\n^FFC83200Joueurs : 6c6 \nLimite de temps : 12 min\nTaille max. du groupe : 6" + "PL_marked_for_death_lobby" "Salon Condamnation" + "PL_nitro_ffa" "CPS (Nitro)" + "PL_nitro_ffa_abbr" "CPS-N" + "PL_nitro_ffa_desc" "Affrontements rapides en Chacun pour soi sur une sélection de cartes.\n^FFC83200Joueurs : 6\n^F4D5A600Pas de Titans\nAucun Boost" + "PL_nitro_ffa_lobby" "Salon CPS Nitro" + "PL_nitro_mixtape" "Mixtape (Nitro)" + "PL_nitro_mixtape_abbr" "MXT-N" + "PL_nitro_mixtape_desc" "Affrontements rapides en CDD, COND et PcP sur une sélection de cartes.\n^FFC83200Joueurs : 5c5\nTaille max. du groupe : 5\n^F4D5A600Retours instantanés du drapeau" + "PL_nitro_mixtape_lobby" "Salon Mixtape" + "PL_pilot_hunter" "Escarmouche" + "PL_pilot_hunter_abbr" "ESC" + "PL_pilot_hunter_desc" "Éliminez les pilotes et Titans ennemis. \n^FFC83200Joueurs : 8c8\nLimite de temps : 10 min\nTaille max. du groupe : 8" + "PL_pilot_hunter_lobby" "Salon Escarmouche" + "PL_pilot_skirmish" "Pilotes contre pilotes" + "PL_pilot_skirmish_abbr" "PcP" + "PL_pilot_skirmish_desc" "Tuez les pilotes ennemis. Aucun largage de Titan n’est autorisé.\n^FFC83200Joueurs : 8c8 *Aucun Titan\nLimite de temps : 10 min\nTaille max. du groupe : 8" + "PL_pilot_skirmish_lobby" "Salon PcP" + "PL_pl_rebuild_all_paths" "Tout reconstruire" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Exécuter avec ai_ainRebuildOnMapStart 2" + "PL_private_match" "Partie privée" + "PL_private_match_desc" "Jouez une partie privée personnalisée sur le mode et la carte de votre choix.\n^FFC83200Choisissez INVITER RÉSEAU ou INVITER AMIS pour jouer.\n^FFC83200Joueurs : 1-16\nAucune progression" + "PL_private_match_lobby" "Salon Partie privée" + "PL_promo_coop" "COOP 4 joueurs" + "PL_raid" "Raid" + "PL_glitch" "Glitch 24/7" + "PL_glitch_abbr" "GLI" + "PL_glitch_desc" "Affrontements exclusivement sur la carte Glitch. ^CCCCCC00Vous allez chercher des parties en modes ^FFC83200CDD^CCCCCC00, ^FFC83200Point clé amplifié^CCCCCC00, ^FFC83200Pilotes contre pilotes^CCCCCC00, ^FFC83200Live Fire^CCCCCC00 et ^FFC83200Dernier Titan^CCCCCC00." + "PL_glitch_lobby" "Salon Glitch 24/7" + "PL_rocket_arena" "Arène à roquettes" + "PL_rocket_arena_abbr" "LF" + "PL_rocket_arena_desc" "Règles Live Fire classiques avec EPG modifiés.^FFC83200\nJoueurs : 6c6 *Aucun Titan\nLimite de temps : 90 s *Aucune réapparition\nTaille max. du groupe : 6" + "PL_rocket_arena_lobby" "Salon Arène à roquettes" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Paramètres pour le chargement utilisateur d’une carte par ligne de commande. Ne pas éditer la commande \"cmdlineMapLoad 1\" ci-dessous, elle est requise pour le chargement." + "PL_speedball" "Live Fire" + "PL_speedball_desc" "Disputez-vous la possession d'un drapeau neutre. Éliminez l'équipe ennemie ou détenez le drapeau à la fin de la manche. La première équipe à gagner 5 manches remporte la partie.\n^FFC83200Joueurs : 6c6 *Aucun Titan\nLimite de temps : 60 s par manche *Aucune réapparition\nTaille max. du groupe : 6" + "PL_speedball_lobby" "Salon Live Fire" + "PL_tactikill" "Attrition Frag tactique" + "PL_tactikill_abbr" "ATT" + "PL_tactikill_desc" "Règles Attrition classiques avec réinitialisation des capacités tactiques après un frag.\n^FFC83200Joueurs : 6c6 *IA\nLimite de temps : 10 min\nTaille max. du groupe : 6" + "PL_tactikill_lobby" "Salon Attrition Frag tactique" + "PL_titan_brawl" "Combat de Titan" + "PL_titan_brawl_abbr" "CDT" + "PL_titan_brawl_desc" "Détruisez les Titans ennemis. Les pilotes ne sont pas autorisés.\n^FFC83200Joueurs : 5c5\nLimite de temps : 10 min\nTaille max. du groupe : 5" + "PL_titan_brawl_hint" "Détruisez les Titans ennemis.\nPas d'éjection" + "PL_titan_brawl_lobby" "Salon Combat de Titan" + "PL_titan_brawl_turbo" "Combat de Titan Turbo" + "PL_titan_brawl_turbo_abbr" "CDT" + "PL_titan_brawl_turbo_desc" "Règles Combat de Titan classiques avec régénération de propulsion et génération de noyau plus rapides.\n^FFC83200Joueurs : 5c5\nLimite de temps : 10 min\nTaille max. du groupe : 5" + "PL_titan_brawl_turbo_hint" "Détruisez les Titans ennemis.\nPas d'éjection" + "PL_titan_brawl_turbo_lobby" "Salon Combat de Titan Turbo" + "PL_turbo_last_titan_standing" "DT Turbo" + "PL_turbo_last_titan_standing_abbr" "DT" + "PL_turbo_last_titan_standing_desc" "Règles DT classiques avec régénération de propulsion et génération de noyau plus rapides.\n^FFC83200Joueurs : 5c5 *Début en Titan\nLimite de temps : 3 min par manche *Aucune réapparition\nTaille max. du groupe : 5" + "PL_turbo_last_titan_standing_lobby" "Salon DT Turbo" + "PL_variety_pack" "Mixtape" + "PL_variety_pack_desc" "Jouez avec différents nombres de joueurs et cartes dans plusieurs modes de jeu :\n^FFC83200*Chasse aux primes *Attrition\n*Dernier Titan *Point clé amplifié\n*Pilotes contre pilotes *Capture de drapeau" + "PL_variety_pack_lobby" "Salon Mixtape" + "PL_wargames" "Jeux de guerre 24/7" + "PL_wargames_abbr" "JDG" + "PL_wargames_desc" "Affrontements exclusivement sur la carte Jeux de guerre. ^CCCCCC00Vous allez chercher des parties en modes ^FFC83200Attrition^CCCCCC00, ^FFC83200CDD^CCCCCC00, ^FFC83200Pilotes contre pilotes^CCCCCC00, ^FFC83200Point clé amplifié^CCCCCC00 et ^FFC83200Dernier Titan^CCCCCC00." + "PL_wargames_lobby" "Salon Jeux de guerre 24/7" + "WATCH_TUTORIAL" "VOIR DIDACTICIEL" + "GAMEMODE_TMFD" "Condamnation de titan" + "MP_RELIC02_FD_WAVE_1" "L'union fait la force" + "MP_RELIC02_FD_WAVE_2" "Déploiement frontal" + "MP_RELIC02_FD_WAVE_3" "Attaque alternative" + "MP_RELIC02_FD_WAVE_4" "À l’aveugle" + "MP_RELIC02_FD_WAVE_5" "Division et embuscade" + } + } + "lang" + { + "Language" "polish" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Kontynuuj swojÄ… przygodÄ™ na zapierajÄ…cych dech w piersi Kresach dziÄ™ki „Pocztówkom z Kresów”, najnowszemu DLC do Titanfall 2. WzbogaciliÅ›my grÄ™ o nowe obszary i szeroki wachlarz elitarnych barw wojennych broni. Kresy jeszcze nigdy nie wyglÄ…daÅ‚y tak dobrze!\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_00_Q" "Zwiastun „Pocztówek z Kresów”!" + "COMMUNITYUPDATE_01_A" "Zapoznaj siÄ™ ze wszystkimi zmianami, które wprowadziliÅ›my w aktualizacji „Pocztówki z Kresów”.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_01_Q" "„Pocztówki z Kresów”: informacje o aktualizacji" + "COMMUNITYUPDATE_02_A" "Wkrótce na urzÄ…dzeniach mobilnych dostÄ™pna bÄ™dzie gra Titanfall: Assault. To strategia czasu rzeczywistego rozgrywajÄ…ca siÄ™ w Å›wiecie Titanfall, która powstaÅ‚a we współpracy z Particle City. Zobacz jÄ… w akcji!\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_02_Q" "Titanfall: Assault – zwiastun premierowy" + "COMMUNITYUPDATE_03_A" "Iniquity pokazuje nam samouczek i udziela podstawowych porad do Titanfall: Assault. To idealny sposób na zaznajomienie siÄ™ z grÄ….\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_03_Q" "Titanfall: Assault – poznaj podstawy rozgrywki" + "COMMUNITYUPDATE_04_A" "PosÅ‚uchaj twórców „Obrony Kresów”, którzy opowiadajÄ… o kulisach powstania tego trybu i zobacz, jak rozgrywamy kilka gier! \n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_04_Q" "Respawn w akcji: Obrona Kresów" + "COMMUNITYUPDATE_05_A" "Kevin Younger przygotowaÅ‚ film prezentujÄ…cy szeroki wachlarz zagraÅ„ z użyciem ostrza pulsacyjnego. \n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_05_Q" "Prace spoÅ‚ecznoÅ›ci – Przejdźmy do rzeczy" + "COMMUNITYUPDATE_06_A" "ConzeyG prezentuje w serwisie reddit zabójczÄ… skuteczność Polaris w trybie „Na celowniku”. \n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_06_Q" "Filmy fanów – Polaris na polowaniu" + "COMMUNITYUPDATE_07_A" "Już jest! „Obrona Kresów” powraca wraz z mapÄ… „Powstanie”, a także nowymi barwami wojennymi do kupienia oraz mapÄ… do trybu „Szybki szturm”. Zobacz caÅ‚ość w akcji.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_07_Q" "Operacja „Tarcza Kresów” – zwiastun z rozgrywkÄ…" + "COMMUNITYUPDATE_08_A" "Już dostÄ™pne! SÅ‚ynna mapa „Gry wojenne” powraca do Titanfall 2 w odÅ›wieżonej postaci. Oprócz tego gracze bÄ™dÄ… mogli cieszyć siÄ™ nowÄ… egzekucjÄ… i „Ruchem ulicznym”, czyli nowÄ… mapÄ… do Szybkiego szturmu.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_08_Q" "„Gry wojenne” – zwiastun z rozgrywkÄ…" + "COMMUNITYUPDATE_09_A" "Ten dodatek obejmuje MonarchÄ™, czyli siódmego Tytana dostÄ™pnego w trybie wieloosobowym, odÅ›wieżonÄ… mapÄ™ „Relikt”, nowÄ… egzekucjÄ™, a także Tytany Prime: Ronina i Tona oraz wiÄ™cej kamuflaży, sztandarów i grafik dziobowych do kupienia. Åšledź akcjÄ™ tutaj.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_09_Q" "Zwiastun - rozgrywka w „RzÄ…dach Monarchy”" + "COMMUNITYUPDATE_10_A" "Nie wszystko jest takie, jak siÄ™ wydaje na Kresach – przygotujcie siÄ™ na „Błąd na Kresach”, najnowsze darmowe DLC do Titanfall 2, zawierajÄ…ce nowÄ… mapÄ™ „Błąd”. InspiracjÄ… dla jej stworzenia byÅ‚a ojczysta planeta kapitana Lastimosy, Harmonia. Mapa obfituje w wysokie urwiska i dÅ‚ugie, krÄ™te Å›cieżki. To idealna przestrzeÅ„ dla dÅ‚ugich sekwencji skoków po Å›cianach, które pozwolÄ… bÅ‚yskawicznie przemieszczać siÄ™ po mapie. Gra zostanie również wzbogacona o nowÄ… mapÄ™ do trybu „Szybki szturm”, „PokÅ‚ad”, peÅ‚nÄ… ciasnych pomieszczeÅ„ i otwartych dziedziÅ„ców. Nie zabraknie tam również dronów, pilnie Å›ledzÄ…cych potyczki z góry. JeÅ›li czujesz, że wróg ciÄ™ przytÅ‚acza, skorzystaj z pomocy nowej frakcji Marvinów, która chÄ™tnie wyciÄ…gnie do ciebie pomocnÄ…, mechanicznÄ… dÅ‚oÅ„. Ponadto, piloci, którzy chcÄ… przekazać wrogowi jasny komunikat, mogÄ… odblokować egzekucjÄ™ „Ostrze pulsacyjne”\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_10_Q" "Zwiastun - prezentacja „Błędu na Kresach”" + "COMMUNITYUPDATE_11_A" "Powróć na uwielbianÄ… przez fanów mapÄ™ z oryginalnego Titanfall: Kolonia. Dodajmy do niej nowe zdolnoÅ›ci taktyczne i Tytany z Titanfall 2, a piloci i Tytany bÄ™dÄ… musieli mieć oczy dookoÅ‚a gÅ‚owy, aby przeżyć w tej wiosce peÅ‚nej wÄ…skich uliczek, Å›lepych zauÅ‚ków i odkrytych dachów. Mapa bÄ™dzie dostÄ™pna za darmo dla wszystkich graczy 30 marca. Pakiet DLC „Nowa Kolonia” zawiera także klasycznÄ… broÅ„, karabin R-101, nowÄ… egzekucjÄ™ oraz opcje kosmetyczne do kupienia, dziÄ™ki którym bÄ™dziesz wyglÄ…dać bardzo stylowo podczas siania zniszczenia.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_11_Q" "Zwiastun - rozgrywka w „Nowej Kolonii”" + "COMMUNITYUPDATE_12_A" "Poznajcie „Szybki szturm” – niezwykle szybki tryb 6 na 6 dla pilotów, w którym nie zabraknie zaciÄ™tych potyczek na krótkich dystansach. Specjalnie na potrzeby tego trybu przygotowaliÅ›my dwie nowe mapy: „Stosy” i „Polana”. SÄ… to ciasne przestrzenie, na których toczyć siÄ™ bÄ™dzie dynamiczna i zażarta rywalizacja.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_12_Q" "Zwiastun – rozgrywka w tr. „Szybki szturm”" + "COMMUNITYUPDATE_13_A" "Poznaj odÅ›wieżonÄ… wersjÄ™ `1Miasta Aniołów`0, ulubionej mapy graczy z pierwszej części Titanfall. Przygotuj siÄ™ na nadejÅ›cie pierwszego darmowego pakietu DLC do Titanfall 2 – zestawu `1„Renegat z Miasta Aniołów”`0, który udostÄ™pnimy wszystkim graczom już 1 grudnia. Zestaw zawiera nowe opcje kosmetyczne, dziÄ™ki którym wyróżnisz siÄ™ podczas walk na Kresach. \n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_13_Q" "Zwiastun - rozgrywka w MieÅ›cie Aniołów" + "COMMUNITYUPDATE_14_A" "Witaj z powrotem.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_14_Q" "Zwiastun – „Bis”" + "COMMUNITYUPDATE_15_A" "Dwie legendy, jedna historia.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_15_Q" "Zwiastun – rozgrywka w trybie fabularnym" + "COMMUNITYUPDATE_16_A" "Bez ograniczeÅ„.\n\n\nWciÅ›nij `2%[A_BUTTON|MOUSE1]%`0, aby zobaczyć." + "COMMUNITYUPDATE_16_Q" "Zwiastun – rozgrywka pilotów w trybie online" + "COMMUNITYUPDATE_DESC" "`3Co nowego u spoÅ‚ecznoÅ›ci Titanfall?`0\n\nInformacje i linki z caÅ‚ego Å›wiata.\n\nAby dowiedzieć siÄ™ wiÄ™cej:\n`2%$rui/bullet_point%`0Å›ledź nas na Twitterze `1@Respawn`0\n`2%$rui/bullet_point%`0polub nasz profil na `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0dołącz do nas na stronie `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "SpoÅ‚eczność" + "KNB_SUBJECT_00_DESC" "`3Co nowego w Titanfall?`0\n\nZajrzyj tutaj, by zobaczyć zmiany w Titanfall 2!" + "KNB_SUBJECT_00_NAME" "Aktualizacje gry" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 Nowe, zaprojektowane przez spoÅ‚eczność identyfikatory.\n\n`2%$rui/bullet_point%`0Wszystkie prezenty patrona można teraz kupić za pomocÄ… kredytów.\n\n`2%$rui/bullet_point%`0Nowa zawartość do kupienia w sklepie.\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 listopada – Pora żniw" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Pistolet w głównym miejscu na broÅ„\n\n`2%$rui/bullet_point%`0Halloweenowe identyfikatory\n\n`2%$rui/bullet_point%`0Zmiany w wyważaniu\n\n`2%$rui/bullet_point%`0Nowa zawartość do kupienia w sklepie\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 października – Cukierki i psikusy" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Obrona Kresów – ObsÅ‚uga 3 dodatkowych map: Suchy Dok, Miasto Aniołów i Egzoplaneta.\n\n`2%$rui/bullet_point%`0Nowa mapa do \"Szybkiego szturmu\" - UMA\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – \"Dziura w Å›cianie\"\n\n`2%$rui/bullet_point%`0Nowa zawartość dostÄ™pna w sklepie" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 sierpnia – Pocztówki z Kresów" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Obrona Kresów – nowy tryb współpracy, w którym łączysz siÅ‚y z maksymalnie trzema innymi graczami, aby chronić ważny cel przed coraz silniejszymi falami przeciwników sterowanych przez SI. Komunikacja i przystosowanie siÄ™ do sytuacji sÄ… kluczem do przetrwania.\n\n`2%$rui/bullet_point%`0Nowa mapa – Powstanie\n\n`2%$rui/bullet_point%`0Nowa mapa do trybu „Szybki szturm” – Miasto\n\n`2%$rui/bullet_point%`0Nowa zawartość do kupienia w sklepie" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25 lipca – operacja „Tarcza Kresów”" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Nowa mapa – „Gry wojenne”\n\n`2%$rui/bullet_point%`0Nowa mapa do Szybkiego szturmu – „Ruch uliczny”\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – Walka z cieniem\n\n`2%$rui/bullet_point%`0Trzecie miejsce na broÅ„\n\n`2%$rui/bullet_point%`0Ustawienia gier prywatnych" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27 czerwca – Gry wojenne" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Nowy Tytan – Monarcha\n\n`2%$rui/bullet_point%`0Nowa mapa – Relikt\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – A kuku\n\n`2%$rui/bullet_point%`0Nowa zawartość dostÄ™pna w sklepie" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30 maja: RzÄ…dy Monarchy" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Nowa mapa – Błąd\n\n`2%$rui/bullet_point%`0Nowa mapa do szybkiego szturmu – PokÅ‚ad\n\n`2%$rui/bullet_point%`0Nowa frakcja – MARVIN\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – Na ostrzu noża\n\n`2%$rui/bullet_point%`0ZwiÄ™kszenie maksymalnej generacji do 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25 kwietnia: Błąd na Kresach" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Nowa mapa – Kolonia\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – Uziemienie\n\n`2%$rui/bullet_point%`0Nowa broÅ„ – R-101\n\n`2%$rui/bullet_point%`0Nowa zawartość dostÄ™pna w sklepie" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30 marca – Nowa Kolonia" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Szybki szturm – nowy tryb eliminacyjny, w którym zmagajÄ… siÄ™ wyłącznie piloci! To oparty na rundach tryb 6 na 6, w którym nie można siÄ™ odradzać. Gracze majÄ… minutÄ™ na wyeliminowanie drużyny przeciwnej. Możliwe jest także wygranie rundy poprzez kontrolowanie neutralnej flagi, gdy upÅ‚ynie czas. O wygranej decyduje zwyciÄ™stwo w piÄ™ciu rundach.\n\n`2%$rui/bullet_point%`0Nowa mapa do szybkiego szturmu – Polana\n\n`2%$rui/bullet_point%`0Nowa mapa do szybkiego szturmu – Stosy\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – Późne uderzenie" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23 lutego: Szybki szturm" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Nowa mapa – Miasto aniołów\n\n`2%$rui/bullet_point%`0Nowa broÅ„ – Elitarny skrzydÅ‚owy B3\n\n`2%$rui/bullet_point%`0Nowa egzekucja pilota – Rozrywacz\n\n`2%$rui/bullet_point%`0Nowe zestawy Tytana\n\n`2%$rui/bullet_point%`0Nowa zawartość dostÄ™pna w sklepie" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30 listopada: Renegat z Miasta Aniołów" + "MP_ANGEL_CITY_FD_WAVE_1" "Przykuty do nieba" + "MP_ANGEL_CITY_FD_WAVE_2" "BezksztaÅ‚tność" + "MP_ANGEL_CITY_FD_WAVE_3" "Rewolta" + "MP_ANGEL_CITY_FD_WAVE_4" "Uparta zgraja" + "MP_ANGEL_CITY_FD_WAVE_5" "Twarda szóstka" + "MP_DRYDOCK_FD_WAVE_1" "Na nieznanych wodach" + "MP_DRYDOCK_FD_WAVE_2" "Wystrzelali siÄ™!" + "MP_DRYDOCK_FD_WAVE_3" "OÅ›lepieni blaskiem nauki" + "MP_DRYDOCK_FD_WAVE_4" "System wywierania nacisku" + "MP_DRYDOCK_FD_WAVE_5" "Oko cyklonu" + "MP_THAW_FD_WAVE_1" "Åšwiadomość sytuacji" + "MP_THAW_FD_WAVE_2" "Liczy siÄ™ liczebność" + "MP_THAW_FD_WAVE_3" "Siepacz 21" + "MP_THAW_FD_WAVE_4" "Zabawa z ogniem" + "MP_THAW_FD_WAVE_5" "Obsada dziaÅ‚" + "NO_PRICE" "Oferta wygasÅ‚a" + "NO_PRICE_TWO_LINES" "Oferta\nwygasÅ‚a" + "PL_aegis_last_titan_standing" "DoT z EgidÄ…" + "PL_aegis_last_titan_standing_abbr" "DoTE" + "PL_aegis_last_titan_standing_desc" "Ulepszenia Egidy dostÄ™pne. Tryb eliminacyjny, wygrywa drużyna, która jako pierwsza wygra 3 rundy.\n^FFC83200Gracze: 5 na 5 *Rozpoczynasz grÄ™ w Tytanie\nLimit czasu: 3 min na rundÄ™ *Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Starcie Tytanów z EgidÄ…" + "PL_aegis_titan_brawl_abbr" "STE" + "PL_aegis_titan_brawl_desc" "Zniszcz wrogie Tytany. Ulepszenia Egidy dostÄ™pne.\n^FFC83200Gracze: 5 na 5\nLimit czasu: 10 min\nMaksymalny rozmiar grupy: 5" + "PL_aegis_titan_brawl_hint" "Zniszcz wrogie Tytany.\nBrak katapultowania" + "PL_aegis_titan_brawl_lobby" "Lobby: Starcie Tytanów z EgidÄ…" + "PL_aitdm" "Wyniszczenie" + "PL_aitdm_abbr" "WYN" + "PL_aitdm_desc" "Zabij wszystkich wrogów.\n^FFC83200Gracze: 6 na 6 *AI\nLimit czasowy: 10m\nMaksymalny rozmiar grupy: 6" + "PL_aitdm_lobby" "Wyniszczenie – lobby" + "PL_all_grapple" "Atak na Tytany" + "PL_all_grapple_abbr" "W" + "PL_all_grapple_desc" "Klasyczne zasady wyniszczenia, poza tym, że wszystkie zdolnoÅ›ci taktyczne zostajÄ… zastÄ…pione linÄ… z hakiem.\n^FFC83200Gracze: 6 na 6 *SI\nLimit czasowy: 10 min\nMaksymalna wielkość grupy: 6" + "PL_all_grapple_lobby" "Lobby: Atak na Tytany" + "PL_all_holopilot" "Wielka Å›ciema" + "PL_all_holopilot_abbr" "SS" + "PL_all_holopilot_desc" "Klasyczne zasady szybkiego szturmu, poza tym, że wszystkie zdolnoÅ›ci taktyczne zostajÄ… zastÄ…pione holopilotem.\n^FFC83200Gracze: 6 na 6 *Bez Tytanów\nLimit czasowy: 60 s *Bez odrodzeÅ„\nMaksymalna wielkość grupy: 6" + "PL_all_holopilot_lobby" "Lobby: Wielka Å›ciema" + "PL_all_phase" "Druga strona" + "PL_all_phase_abbr" "W" + "PL_all_phase_desc" "Klasyczne zasady wyniszczenia, poza tym, że wszystkie zdolnoÅ›ci taktyczne zostajÄ… zastÄ…pione przeskokiem fazowym.\n^FFC83200Gracze: 6 na 6 *SI\nLimit czasowy: 10 min\nMaksymalna wielkość grupy: 6" + "PL_all_phase_lobby" "Lobby: Druga strona" + "PL_all_spicy" "Pikantne wyniszczenie" + "PL_all_spicy_abbr" "W" + "PL_all_spicy_desc" "Klasyczne zasady wyniszczenia, poza tym, że wszystkie zdolnoÅ›ci taktyczne zostajÄ… zastÄ…pione kleszczami.\n^FFC83200Gracze: 6 na 6 *SI\nLimit czasowy: 10 min\nMaksymalna wielkość grupy: 6" + "PL_all_spicy_lobby" "Lobby: Pikantne wyniszczenie" + "PL_amped_tacticals" "Wzmocnione zdolnoÅ›ci taktyczne" + "PL_amped_tacticals_abbr" "W" + "PL_amped_tacticals_desc" "Klasyczne zasady wyniszczenia, poza tym, że wszystkie zdolnoÅ›ci taktyczne sÄ… potężniejsze.\n^FFC83200Gracze: 6 na 6 *SI\nLimit czasowy: 10 min\nMaksymalna wielkość grupy: 6" + "PL_amped_tacticals_lobby" "Lobby: Wzmocnione zdolnoÅ›ci taktyczne" + "PL_ANGEL_CITY" "Miasto Aniołów 24/7" + "PL_angel_city_abbr" "MA" + "PL_angel_city_desc" "NieustajÄ…ce walki w MieÅ›cie Aniołów." + "PL_angel_city_lobby" "Miasto Aniołów 24/7 – lobby" + "PL_at_coop" "Ucieczka (współpraca)" + "PL_at_coop_desc" "WÅ‚aÅ›nie uciekÅ‚eÅ› z wiÄ™zienia. Masz przy sobie jedynie pistolet. Musisz przeżyć do czasu ewakuacji. Eliminuj przeciwników, żeby zdobyć pieniÄ…dze na zakup broni. \n^FFC83200Gracze: 6\nMaksymalny rozmiar grupy: 6" + "PL_at_coop_lobby" "Lobby: Ucieczka" + "PL_attrition" "Łowy" + "PL_attrition_abbr" "ŁN" + "PL_attrition_desc" "Zabijaj wrogów, aby zdobywać punkty. Zyskaj jeszcze wiÄ™cej, deponujÄ…c punkty w wyznaczonych miejscach.\n^FFC83200Gracze: 5 na 5 *SI\nLimit czasu: 10 min.\nMaksymalny rozmiar grupy: 5" + "PL_attrition_lobby" "Lobby: Łowy" + "PL_capture_the_flag" "Walka o flagÄ™" + "PL_capture_the_flag_abbr" "WOF" + "PL_capture_the_flag_desc" "Odbierz wrogom flagÄ™ i zanieÅ› jÄ… do swojej bazy, jednoczeÅ›nie chroniÄ…c wÅ‚asnÄ… flagÄ™ przed atakami przeciwnej drużyny!\n^FFC83200Gracze: 5 na 5\nLimit czasu: 12 min.\nMaksymalny rozmiar grupy: 5" + "PL_capture_the_flag_lobby" "Lobby: Walka o flagÄ™" + "PL_coliseum" "Koloseum" + "PL_coliseum_desc" "Potyczka w klatce jeden na jednego z usprawnionymi zdolnoÅ›ciami poruszania siÄ™. Gracz, który wygra 3 z 5 rund, otrzyma w nagrodÄ™ prezent patrona.^FFC83200\nGracze: 1 na 1 *Bez Tytanów\nLimit czasu: 3 min. *Bez odrodzeÅ„\n**^FFFFFF00WYMAGA BILETU DO KOLOSEUM lub UISZCZENIA OPŁATY WPISOWEJ" + "PL_coliseum_lobby" "Lobby: Koloseum" + "PL_colony" "Kolonia 24/7" + "PL_colony_abbr" "KOL" + "PL_colony_desc" "NieustajÄ…ce walki w Kolonii. ^CCCCCC00Spowoduje wyszukiwanie gier w trybach ^FFC83200Wyniszczenia^CCCCCC00, ^FFC83200Piloci kontra piloci^CCCCCC00 i ^FFC83200Do ostatniego Tytana^CCCCCC00." + "PL_colony_lobby" "Kolonia 24/7 – lobby" + "PL_ctf_lf" "WoF (Nitro)" + "PL_ctf_lf_abbr" "WoF-N" + "PL_ctf_lf_desc" "Dynamiczna rozgrywka w trybie „Walka o flagę” na wybranych mapach.\n^FFC83200Gracze: 5 na 5\nMaksymalny rozmiar grupy: 5\n^F4D5A600Natychmiastowe odniesienie flagi" + "PL_ctf_lf_lobby" "Lobby: WoF (Nitro)" + "PL_default_description" "DomyÅ›lny opis" + "PL_default_lobbytitle" "DomyÅ›lny tytuÅ‚ lobby" + "PL_default_name" "DomyÅ›lna nazwa" + "PL_don" "Podwójne ryzyko" + "PL_fd" "Obrona Kresów" + "PL_fd_desc" "BroÅ„ siÄ™ przed falami siÅ‚ floty OcalaÅ‚ych" + "PL_fd_easy" "Obrona Kresów: niski" + "PL_fd_easy_desc" "Zmiażdż opozycjÄ™" + "PL_fd_easy_lobby" "Obrona Kresów: niski (lobby)" + "PL_fd_hard" "Obrona Kresów: wysoki" + "PL_fd_hard_desc" "W tym starciu liczÄ… siÄ™ umiejÄ™tnoÅ›ci" + "PL_fd_hard_lobby" "Obrona Kresów: wysoki (lobby)" + "PL_fd_insane" "Obrona Kresów: szalony" + "PL_fd_insane_desc" "Nie przeżyjesz" + "PL_fd_insane_lobby" "Obrona Kresów: szalony (lobby)" + "PL_fd_lobby" "Lobby: Obrona Kresów" + "PL_fd_master" "Obrona Kresów: mistrzowski" + "PL_fd_master_desc" "PrzetrwajÄ… tylko najlepsi z najlepszych" + "PL_fd_master_lobby" "Obrona Kresów: mistrzowski (lobby)" + "PL_fd_normal" "Obrona Kresów: normalny" + "PL_fd_normal_desc" "Zalecane dla doÅ›wiadczonych graczy" + "PL_fd_normal_lobby" "Obrona Kresów: normalny (lobby)" + "PL_ffa" "Każdy na każdego" + "PL_ffa_abbr" "KNK" + "PL_ffa_desc" "Każdy na każdego, musisz wyeliminować wszystkich przeciwników.\n^FFC83200Gracze: 1 na 11\nLimit czasu: 10 min.\nMaksymalny rozmiar grupy: 1" + "PL_ffa_lobby" "Lobby: Każdy na każdego" + "PL_fra" "Wolni strzelcy" + "PL_fra_abbr" "WS" + "PL_fra_desc" "Każdy pilot dziaÅ‚a sam. Eliminuj przeciwników i zbierz 3 baterie, aby wezwać Tytana.\n^FFC83200Gracze: 1 na 11\nLimit czasu: 15 min\nMaksymalny rozmiar grupy: 1" + "PL_fra_lobby" "Lobby: Wolni strzelcy" + "PL_groud_war_lobby" "8 na 8 Remix – lobby" + "PL_ground_war" "8 na 8 Remix" + "PL_ground_war_abbr" "8 na 8" + "PL_ground_war_desc" "Zawiera tryby „Starcie pilotów” i „Obrona umocnień” z dużą liczbÄ… graczy na każdej z map.\n^FFC83200Gracze: 8 na 8" + "PL_hardpoint" "Obrona umocnieÅ„" + "PL_hardpoint_abbr" "OU" + "PL_hardpoint_desc" "Przejmij i utrzymaj umocnienie, aby zdobyć punkty. Wzmocnione umocnienia sÄ… warte dwa razy wiÄ™cej punktów.\n^FFC83200Gracze: 6 na 6\nLimit czasu: 10 min.\nMaksymalny rozmiar grupy: 6" + "PL_hardpoint_lobby" "Lobby: Obrona umocnieÅ„" + "PL_hardpoint_non_amp" "Umocnienia" + "PL_hardpoint_lobby_non_amp" "Umocnienia – lobby" + "PL_hunted" "Åšcigany" + "PL_iron_last_titan_standing" "Å»elazne DoT" + "PL_iron_last_titan_standing_abbr" "Å»DoT" + "PL_iron_last_titan_standing_desc" "Tylko Tytany, tryb eliminacyjny, walka toczy siÄ™ do 3 wygranych rund.\n^FFC83200Gracze: 5 na 5 *BEZ PILOTÓW\nLimit czasu: 3 min na rundÄ™ *Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Do ostatniego Tytana" + "PL_last_titan_standing_abbr" "DOT" + "PL_last_titan_standing_desc" "Wszyscy gracze rozpoczynajÄ… eliminacje w trybie rundowym, siedzÄ…c w swoich Tytanach. Wygrywa drużyna, która jako pierwsza wygra 3 rundy.\n^FFC83200Gracze: 5 na 5 *Rozpoczynasz grÄ™ w Tytanie\nLimit czasu: 3 min na rundÄ™ *Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 5" + "PL_last_titan_standing_lobby" "Lobby: DoT" + "PL_limited_time_mode" "(Tymczasowo)" + "PL_live_fire" "Szybki szturm" + "PL_live_fire_abbr" "SS" + "PL_live_fire_desc" "Dynamiczna potyczka na arenie do trybu Szybki szturm. Aby wygrać rundÄ™, musisz wyeliminować wszystkich pilotów z przeciwnej drużyny lub być w posiadaniu flagi, gdy czas dobiegnie koÅ„ca.^FFC83200\nGracze: 6 na 6 *Bez Tytanów\nLimit czasu: 60 s *Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 6" + "PL_live_fire_lobby" "Lobby: Szybki szturm" + "PL_load_a_map_on_the_command_line" "Wczytaj mapÄ™ w wierszu poleceÅ„ – tylko dla deva." + "PL_marked_for_death" "Na celowniku" + "PL_marked_for_death_abbr" "NC" + "PL_marked_for_death_desc" "Zabijaj lub chroÅ„ oznaczone cele.\n^FFC83200Gracze: 6 na 6 \nLimit czasu: 12 min\nMaksymalny rozmiar grupy: 6" + "PL_marked_for_death_lobby" "Lobby: Na celowniku" + "PL_nitro_ffa" "KNK (Nitro)" + "PL_nitro_ffa_abbr" "KNK-N" + "PL_nitro_ffa_desc" "Dynamiczne starcia w trybie Każdy na każdego na wybranych mapach.\n^FFC83200Gracze: 6\n^F4D5A600Brak Tytanów\nBrak wzmocnieÅ„" + "PL_nitro_ffa_lobby" "Lobby: KNK Nitro " + "PL_nitro_mixtape" "Remix (Nitro)" + "PL_nitro_mixtape_abbr" "RMX-N" + "PL_nitro_mixtape_desc" "Dynamiczna rozgrywka w trybach „Walka o flagę”, „Na celowniku” i PvP na wybranych mapach.\n^FFC83200Gracze: 5 na 5\nMaksymalny rozmiar grupy: 5\n^F4D5A600Natychmiastowe odniesienie flagi" + "PL_nitro_mixtape_lobby" "Lobby: Remix" + "PL_pilot_hunter" "Starcie pilotów" + "PL_pilot_hunter_abbr" "SP" + "PL_pilot_hunter_desc" "Zabij wrogich pilotów i ich Tytany. \n^FFC83200Gracze: 8 na 8\nLimit czasu: 10 min.\nMaksymalny rozmiar grupy: 8" + "PL_pilot_hunter_lobby" "Lobby: Starcie pilotów" + "PL_pilot_skirmish" "Piloci kontra piloci" + "PL_pilot_skirmish_abbr" "PvP" + "PL_pilot_skirmish_desc" "Zabij wrogich pilotów. Zrzuty Tytanów niedozwolone.\n^FFC83200Gracze: 8 na 8 *Bez Tytanów\nLimit czasu: 10 min.\nMaksymalny rozmiar grupy: 8" + "PL_pilot_skirmish_lobby" "Lobby: PvP" + "PL_pl_rebuild_all_paths" "Odnów wszystkie Å›cieżki" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Uruchamianie z: ai_ainRebuildOnMapStart 2" + "PL_private_match" "Gra prywatna" + "PL_private_match_desc" "Rozegraj wÅ‚asnÄ… grÄ™ prywatnÄ… i samodzielnie wybierz tryb i mapÄ™.\n^FFC83200ZAPROÅš SIEĆ lub ZAPROÅš ZNAJOMYCH do gry\n^FFC83200Gracze: 1-16\nBez postÄ™pów" + "PL_private_match_lobby" "Lobby: Gra prywatna" + "PL_promo_coop" "4-OS. TRYB KOOPERACJI" + "PL_raid" "Rajd" + "PL_glitch" "Błąd 24/7" + "PL_glitch_abbr" "BŁD" + "PL_glitch_desc" "Błąd non-stop. ^CCCCCC00Wyszukiwane bÄ™dÄ… gry w trybach: ^FFC83200WOF^CCCCCC00, ^FFC83200Obrona umocnieÅ„^CCCCCC00, ^FFC83200Piloci kontra piloci^CCCCCC00, ^FFC83200Szybki szturm^CCCCCC00 i ^FFC83200Do ostatniego Tytana^CCCCCC00." + "PL_glitch_lobby" "Lobby: Błąd 24/7" + "PL_rocket_arena" "Rakietowa arena" + "PL_rocket_arena_abbr" "SS" + "PL_rocket_arena_desc" "Klasyczne zasady szybkiego szturmu ze zmodyfikowanymi EPG.^FFC83200\nGracze: 6 na 6 *Bez Tytanów\nLimit czasowy: 90s *Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 6" + "PL_rocket_arena_lobby" "Lobby: Rakietowa arena" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Ustawienia w przypadku wczytania mapy poprzez wiersz poleceÅ„. Nie edytować cmdlineMapLoad 1 – wszystko bÄ™dzie dziaÅ‚ać." + "PL_speedball" "Szybki szturm" + "PL_speedball_desc" "Walcz o przejÄ™cie neutralnej flagi. Wyeliminuj drużynÄ™ przeciwnÄ… lub bÄ…dź w posiadaniu flagi, gdy runda dobiegnie koÅ„ca. Gra toczy siÄ™ do 5 zwyciÄ™stw.\n^FFC83200Gracze: 6 na 6 *Bez Tytanów\nLimit czasu: 60 s/tura * Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 6" + "PL_speedball_lobby" "Szybki szturm – lobby" + "PL_tactikill" "Taktyczne wyniszczenie" + "PL_tactikill_abbr" "W" + "PL_tactikill_desc" "Klasyczne zasady wyniszczenia, poza tym, że wszystkie zdolnoÅ›ci taktyczne zostajÄ… zresetowane przy zabójstwie.\n^FFC83200Gracze: 6 na 6 *SI\nLimit czasowy: 10 min\nMaksymalna wielkość grupy: 6" + "PL_tactikill_lobby" "Lobby: Taktyczne wyniszczenie" + "PL_titan_brawl" "Starcie Tytanów" + "PL_titan_brawl_abbr" "ST" + "PL_titan_brawl_desc" "Zniszcz wrogie Tytany. Bez pilotów.\n^FFC83200Gracze: 5 na 5\nLimit czasu: 10 min\nMaksymalny rozmiar grupy: 5" + "PL_titan_brawl_hint" "Zniszcz wrogie Tytany.\nBrak katapultowania" + "PL_titan_brawl_lobby" "Lobby: Starcie Tytanów" + "PL_titan_brawl_turbo" "Turbo starcie Tytanów" + "PL_titan_brawl_turbo_abbr" "ST" + "PL_titan_brawl_turbo_desc" "Klasyczne zasady starcia Tytanów z szybszym odnawianiem zrywów oraz Å‚adowaniem rdzenia.\n^FFC83200Gracze: 5 na 5\nLimit czasowy: 10 min\nMaksymalny rozmiar grupy: 5" + "PL_titan_brawl_turbo_hint" "Zniszcz wrogie Tytany.\nBrak katapultowania" + "PL_titan_brawl_turbo_lobby" "Lobby: Turbo starcie Tytanów" + "PL_turbo_last_titan_standing" "Turbo DoT" + "PL_turbo_last_titan_standing_abbr" "DOT" + "PL_turbo_last_titan_standing_desc" "Klasyczne zasady DoT z szybszym odnawianiem zrywów oraz Å‚adowaniem rdzenia.\n^FFC83200Gracze: 5v5 *Rozpoczynasz grÄ™ w Tytanie\nLimit czasowy: 3 min na każdÄ… rundÄ™ *Bez odrodzeÅ„\nMaksymalny rozmiar grupy: 5" + "PL_turbo_last_titan_standing_lobby" "Lobby: Turbo DoT" + "PL_variety_pack" "Remix" + "PL_variety_pack_desc" "Zmienna liczba graczy i wybór różnych map; rozgrywka w trybach takich jak:\n^FFC83200*Łowy *Wyniszczenie\n*Do ostatniego Tytana *Obrona umocnieÅ„\n*Piloci kontra piloci *Walka o flagÄ™" + "PL_variety_pack_lobby" "Remix – lobby" + "PL_wargames" "Gry wojenne 24/7" + "PL_wargames_abbr" "GW" + "PL_wargames_desc" "Gry wojenne non-stop. ^CCCCCC00Wyszukiwanie gier w trybach^FFC83200Wyniszczenia^CCCCCC00, ^FFC83200WOF^CCCCCC00, ^FFC83200Piloci kontra piloci^CCCCCC00, ^FFC83200Obrona umocnieÅ„^CCCCCC00, i ^FFC83200Do ostatniego Tytana^CCCCCC00." + "PL_wargames_lobby" "Gry wojenne 24/7 – lobby" + "WATCH_TUTORIAL" "OBEJRZYJ SAMOUCZEK" + "GAMEMODE_TMFD" "Tytanów Na celowniku" + "MP_RELIC02_FD_WAVE_1" "W jednoÅ›ci siÅ‚a" + "MP_RELIC02_FD_WAVE_2" "W poszukiwaniu drogi" + "MP_RELIC02_FD_WAVE_3" "Torowanie drogi" + "MP_RELIC02_FD_WAVE_4" "Åšlepy zauÅ‚ek" + "MP_RELIC02_FD_WAVE_5" "W zasadzce" + } + } + "lang" + { + "Language" "mspanish" + "Tokens" + { + "COMMUNITYUPDATE_00_A" "Tu aventura por los asombrosos paisajes de la Frontera continúa con el último DLC de Titanfall 2: Postales de la Frontera. La Frontera se ve mejor que nunca con ubicaciones nuevas y conocidas, además de la nueva colección de pinturas de guerra de arma élite.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_00_Q" "Tráiler de \"Postales de la Frontera\"" + "COMMUNITYUPDATE_01_A" "Lee todos los cambios que llegan con el parche de Postales de la Frontera.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_01_Q" "Notas sobre parches de Postales de la Frontera" + "COMMUNITYUPDATE_02_A" "Próximamente disponible para celulares, Titanfall: Assault es un juego de disparos en tiempo real ambientado en el universo de Titanfall con la colaboración de Particle City. Míralo en acción aquí. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_02_Q" "Tráiler de \"lanzamiento\" de Titanfall: Assault" + "COMMUNITYUPDATE_03_A" "Iniquity nos muestra el tutorial y nos da consejos básicos para Titanfall: Assault. Esta es la forma perfecta de iniciarse en el juego.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_03_Q" "Video \"aprende lo básico\" de Titanfall: Assault" + "COMMUNITYUPDATE_04_A" "Conoce la historia y la creación del modo a través de algunas de las personas clave que se encuentran tras Defensa fronteriza y mira cómo jugamos unas rondas. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_04_Q" "Partidas de Respawn: Defensa fronteriza" + "COMMUNITYUPDATE_05_A" "Kevin Younger creó un montaje divertido en el que presume de grandes movimientos con la cuchilla de pulso. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_05_Q" "Creaciones de la comunidad: dale en el centro" + "COMMUNITYUPDATE_06_A" "ConzeyG presume a través de reddit de manejar a Northstar de forma asombrosa mientras recoge pilotos en el modo Marcado para morir. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_06_Q" "Creaciones : cacería de pilotos con Northstar" + "COMMUNITYUPDATE_07_A" "¡Ya disponible! Defensa fronteriza regresa junto con Ascenso y nuevas pinturas de guerra que podrás comprar y un nuevo mapa de Fuego vivo. Mira todo esto en acción aquí.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_07_Q" "Tráiler de juego \"Operación Escudo fronterizo\"" + "COMMUNITYUPDATE_08_A" "¡Ya disponible! El icónico mapa Juegos bélicos regresa a Titanfall 2 y se ve mejor que nunca. No te olvides de checar la nueva ejecución y el nuevo mapa Tráfico de Fuego vivo en acción.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_08_Q" "Tráiler de juego de \"Juegos bélicos\"" + "COMMUNITYUPDATE_09_A" "Este DLC incluye al séptimo titán del multijugador: Monarch, el mapa Reliquia remasterizado y una nueva ejecución. Además podrás comprar los titanes Ronin y Tone Prime, más camuflajes, banderas y decoraciones para el fuselaje. Mira la acción aquí.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_09_Q" "Tráiler de juego de \"Reino de Monarch\"" + "COMMUNITYUPDATE_10_A" "No todo es lo que parece en la Frontera. Prepárate para el nuevo pack de DLC de Titanfall 2: Un Fallo en la Frontera, que incluye el nuevo mapa “Fallo”. Está inspirado en Harmony, el planeta en el que se crió el capitán Lastimosa, repleto de caídas verticales y senderos eternos y serpenteantes, perfectos para encadenar carreras por las paredes y recorrer todo el mapa sin interrupciones. También se une al pack un nuevo mapa de Fuego vivo: Muelle, que cuenta con espacios internos estrechos, patios desprotegidos y drones de vigilancia que te observan desde las alturas. Si crees que esto te supera, los M.R.V.N. ya están aquí dispuestos a echarte una mano robótica. Por último, puedes desbloquear la ejecución cuchilla de pulso y usarla cuando más la necesites.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_10_Q" "Tráiler de juego de \"Un Fallo en la Frontera\"" + "COMMUNITYUPDATE_11_A" "Regresa el icónico mapa favorito de los aficionados del multijugador del Titanfall original: Colonia, con las nuevas tácticas y titanes de Titanfall 2, en el que los pilotos y los titanes tendrán que ingeniárselas para sobrevivir a esta ciudad idílica repleta de callejones sin salida, esquinas con poca visibilidad y azoteas expuestas. Este mapa estará disponible el 30 de marzo para todos los jugadores. El pack de DLC “Colonia Renacida” incluye armas clásicas como el rifle de asalto R-101, una nueva ejecución de arpeo y nuevas opciones estéticas que podrás comprar para verte lo mejor posible mientras bañas la ciudad de sangre enemiga.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_11_Q" "Tráiler de juego de \"Colonia Renacida\"" + "COMMUNITYUPDATE_12_A" "Presentamos Fuego vivo: un modo vertiginoso de 6vs6 exclusivo para pilotos que se centra en el combate competitivo y de corto alcance. Incluye dos mapas nuevos diseñados específicamente para Fuego vivo: Aglomeración y Pradera. Estos mapas gratuitos, diseñados específicamente para este modo intenso y frenético, son cajas letales estrechas y cerradas.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_12_Q" "Tráiler de juego \"Bienvenidos a Fuego vivo\"" + "COMMUNITYUPDATE_13_A" "Disfruta la versión remasterizada del mapa favorito de los aficionados del Titanfall original, `1Ciudad Ángel`0. Permanece atento al primer DLC gratis de Titanfall 2 con `1El más deseado de Ciudad Ángel`0 disponible el 1 de diciembre para todos los jugadores. Este contenido incluye nuevas opciones estéticas para darle más estilo a la Frontera. \n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_13_Q" "Tráiler de juego \"Bienvenidos a Ciudad Ángel\"" + "COMMUNITYUPDATE_14_A" "Bienvenido de nuevo.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_14_Q" "Tráiler de comentarios \"Encore\"" + "COMMUNITYUPDATE_15_A" "Dos leyendas, un legado.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_15_Q" "Tráiler de juego de un jugador \"Sean uno\"" + "COMMUNITYUPDATE_16_A" "Sin límites.\n\n\nPulsa `2%[A_BUTTON|MOUSE1]%`0 para verlo." + "COMMUNITYUPDATE_16_Q" "Tráiler de juego de multijugador \"Pilotos\"" + "COMMUNITYUPDATE_DESC" "`3Actualizaciones en la comunidad de Titanfall`0\n\nInformación y enlaces de la web.\n\nPara más información:\n`2%$rui/bullet_point%`0Síguenos en Twitter `1@Respawn`0\n`2%$rui/bullet_point%`0Danos me gusta en `1facebook.com/RespawnEntertainment`0\n`2%$rui/bullet_point%`0Únete a nosotros en `1www.respawn.com`0" + "COMMUNITYUPDATE_NAME" "Comunidad" + "KNB_SUBJECT_00_DESC" "`3¿Qué es nuevo en Titanfall?`0\n\n¡Chécalo aquí para ver qué ha cambiado en Titanfall 2!" + "KNB_SUBJECT_00_NAME" "Actualizaciones" + "KNB_SUBJECT_00_SUB_00_A" "`2%$rui/bullet_point%`010 nuevas banderas creadas por la comunidad\n\n`2%$rui/bullet_point%`0Todos los regalos del defensor se pueden comprar ahora con créditos\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar\n\n" + "KNB_SUBJECT_00_SUB_00_Q" "%$rui/hud/scoreboard/status_titan% 28 de noviembre: Recolector de tiempo" + "KNB_SUBJECT_00_SUB_01_A" "`2%$rui/bullet_point%`0Espacio principal de la pistola\n\n`2%$rui/bullet_point%`0Banderas de Halloween\n\n`2%$rui/bullet_point%`0Cambios de equilibrio\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar\n\n" + "KNB_SUBJECT_00_SUB_01_Q" "%$rui/hud/scoreboard/status_titan% 31 de octubre: Trucos y tratos" + "KNB_SUBJECT_00_SUB_02_A" "`2%$rui/bullet_point%`0Defensa fronteriza compatible con 3 mapas más: Dique seco, Ciudad Ángel y Exoplaneta.\n\n`2%$rui/bullet_point%`0Nuevo mapa de Fuego vivo: UMA\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Agujero en el muro\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar" + "KNB_SUBJECT_00_SUB_02_Q" "%$rui/hud/scoreboard/status_titan% 29 de agosto: Postales de la Frontera" + "KNB_SUBJECT_00_SUB_03_A" "`2%$rui/bullet_point%`0Defensa fronteriza: un nuevo modo cooperativo en el que unes tus fuerzas con hasta 3 otros jugadores para defender un objetivo vital de las oleadas de combatientes de la IA que van aumentando de intensidad. La comunicación y la adaptación son claves para la sobrevivencia.\n\n`2%$rui/bullet_point%`0Nuevo mapa: Ascenso\n\n`2%$rui/bullet_point%`0Nuevo mapa de Fuego vivo: Municipio\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar" + "KNB_SUBJECT_00_SUB_03_Q" "%$rui/hud/scoreboard/status_titan% 25 de julio: Operación Escudo fronterizo" + "KNB_SUBJECT_00_SUB_04_A" "`2%$rui/bullet_point%`0Nuevo mapa: Juegos bélicos\n\n`2%$rui/bullet_point%`0Nuevo mapa de Fuego vivo: Tráfico\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Golpe fantasma\n\n`2%$rui/bullet_point%`0Tercer espacio de arma\n\n`2%$rui/bullet_point%`0Configuración de la partida privada" + "KNB_SUBJECT_00_SUB_04_Q" "%$rui/hud/scoreboard/status_titan% 27 de junio: Juegos bélicos" + "KNB_SUBJECT_00_SUB_05_A" "`2%$rui/bullet_point%`0Nuevo titán: Monarch\n\n`2%$rui/bullet_point%`0Nuevo mapa: Reliquia\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Ahora me ves\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar" + "KNB_SUBJECT_00_SUB_05_Q" "%$rui/hud/scoreboard/status_titan% 30 de mayo: Reino de Monarch" + "KNB_SUBJECT_00_SUB_06_A" "`2%$rui/bullet_point%`0Nuevo mapa: Fallo\n\n`2%$rui/bullet_point%`0Nuevo mapa de Fuego vivo: Muelle\n\n`2%$rui/bullet_point%`0Nueva facción: M.R.V.N.\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Dale en el centro\n\n`2%$rui/bullet_point%`0Generación máxima aumentada a 100" + "KNB_SUBJECT_00_SUB_06_Q" "%$rui/hud/scoreboard/status_titan% 25 de abril: Un Fallo en la Frontera" + "KNB_SUBJECT_00_SUB_07_A" "`2%$rui/bullet_point%`0Nuevo mapa: Colonia\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Rompecráneos\n\n`2%$rui/bullet_point%`0Nueva arma: R-101\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar" + "KNB_SUBJECT_00_SUB_07_Q" "%$rui/hud/scoreboard/status_titan% 30 de marzo: Colonia Renacida" + "KNB_SUBJECT_00_SUB_08_A" "`2%$rui/bullet_point%`0Fuego vivo: un nuevo modo de eliminaciones de Batalla de pilotos. Una partida de rondas de 6vs6 sin regeneraciones en la que tendrás un minuto para eliminar al equipo contrario y ganar la ronda. También podrás ganar la ronda si tu equipo tiene la bandera neutral cuando el temporizador llegue a cero. El primer equipo que gane 5 rondas ganará la partida.\n\n`2%$rui/bullet_point%`0Nuevo mapa de Fuego vivo: Pradera\n\n`2%$rui/bullet_point%`0Nuevo mapa de Fuego vivo: Aglomeración\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Último disparo" + "KNB_SUBJECT_00_SUB_08_Q" "%$rui/hud/scoreboard/status_titan% 23 de febrero: Fuego vivo" + "KNB_SUBJECT_00_SUB_09_A" "`2%$rui/bullet_point%`0Nuevo mapa: Ciudad Ángel\n\n`2%$rui/bullet_point%`0Nueva arma: B3 Wingman Élite\n\n`2%$rui/bullet_point%`0Nueva ejecución de piloto: Piezas internas\n\n`2%$rui/bullet_point%`0Nuevs kits de titán\n\n`2%$rui/bullet_point%`0Nuevo contenido en la tienda para comprar" + "KNB_SUBJECT_00_SUB_09_Q" "%$rui/hud/scoreboard/status_titan% 30 de nov.: El más deseado de Ciudad Ángel" + "MP_ANGEL_CITY_FD_WAVE_1" "Encadenado al cielo" + "MP_ANGEL_CITY_FD_WAVE_2" "Sin forma" + "MP_ANGEL_CITY_FD_WAVE_3" "Levantamiento" + "MP_ANGEL_CITY_FD_WAVE_4" "Un grupo tenaz" + "MP_ANGEL_CITY_FD_WAVE_5" "Arriésgate" + "MP_DRYDOCK_FD_WAVE_1" "Nadando en aguas turbias" + "MP_DRYDOCK_FD_WAVE_2" "¡No tienen balas!" + "MP_DRYDOCK_FD_WAVE_3" "Cegados por la ciencia" + "MP_DRYDOCK_FD_WAVE_4" "Sistema de alta presión" + "MP_DRYDOCK_FD_WAVE_5" "Ojo de la tormenta" + "MP_THAW_FD_WAVE_1" "Atención a los alrededores" + "MP_THAW_FD_WAVE_2" "La unión nos hace más fuertes" + "MP_THAW_FD_WAVE_3" "Secuaz 21" + "MP_THAW_FD_WAVE_4" "Diversión en el fuego" + "MP_THAW_FD_WAVE_5" "Escoge las armas adecuadas" + "NO_PRICE" "Oferta caducada" + "NO_PRICE_TWO_LINES" "Oferta\ncaducada" + "PL_aegis_last_titan_standing" "UTEP Aegis" + "PL_aegis_last_titan_standing_abbr" "UTEPA" + "PL_aegis_last_titan_standing_desc" "Mejoras Aegis activadas. Eliminación por rondas. Gana el primero que gane 3 rondas.\n^FFC83200Jugadores: 5vs5 *Comienza como titán\nLímite de tiempo: 3 min. por ronda *Sin regeneraciones\nTamaño máximo del grupo: 5" + "PL_aegis_last_titan_standing_lobby" "PL_aegis_last_titan_standing_lobby" + "PL_aegis_titan_brawl" "Pelea de titanes Aegis" + "PL_aegis_titan_brawl_abbr" "PdTA" + "PL_aegis_titan_brawl_desc" "Elimina a los titanes enemigos. Mejoras Aegis activadas.\n^FFC83200Jugadores: 5vs5\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 5" + "PL_aegis_titan_brawl_hint" "Elimina a los titanes enemigos.\nSin eyección" + "PL_aegis_titan_brawl_lobby" "Lobby de Pelea de titanes Aegis" + "PL_aitdm" "Deterioro" + "PL_aitdm_abbr" "DET" + "PL_aitdm_desc" "Elimina a todos los enemigos.\n^FFC83200Jugadores: 6vs6 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_aitdm_lobby" "Lobby de Deterioro" + "PL_all_grapple" "Ataque a los titanes" + "PL_all_grapple_abbr" "DET" + "PL_all_grapple_desc" "Las reglas clásicas de Deterioro, pero todas las habilidades tácticas se reemplazan por el arpeo.\n^FFC83200Jugadores: 6vs6 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_all_grapple_lobby" "Lobby de Ataque a los titanes" + "PL_all_holopilot" "El gran engaño" + "PL_all_holopilot_abbr" "FV" + "PL_all_holopilot_desc" "Las reglas clásicas de Fuego vivo, pero todas las habilidades tácticas se reemplazan por el holopiloto.^FFC83200\nJugadores: 6vs6 *Sin titanes\nLímite de tiempo: 60 s *Sin regeneraciones\nNúmero máximo de miembros del grupo: 6" + "PL_all_holopilot_lobby" "Lobby de El gran engaño" + "PL_all_phase" "El otro lado" + "PL_all_phase_abbr" "DET" + "PL_all_phase_desc" "Las reglas clásicas de Deterioro, pero todas las habilidades tácticas se reemplazan por la fase.\n^FFC83200Jugadores: 6vs6 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_all_phase_lobby" "Lobby de El otro lado" + "PL_all_spicy" "Deterioro picante" + "PL_all_spicy_abbr" "DET" + "PL_all_spicy_desc" "Las reglas clásicas de Deterioro, pero todas las habilidades tácticas se reemplazan por garrapatas.\n^FFC83200Jugadores: 6vs6 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_all_spicy_lobby" "Lobby de Deterioro picante" + "PL_amped_tacticals" "Tácticas +" + "PL_amped_tacticals_abbr" "DET" + "PL_amped_tacticals_desc" "Las reglas clásicas de Deterioro, pero todas las habilidades tácticas son más potentes.\n^FFC83200Jugadores: 6vs6 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_amped_tacticals_lobby" "Lobby de Tácticas +" + "PL_ANGEL_CITY" "Ciudad Ángel 24/7" + "PL_angel_city_abbr" "CA" + "PL_angel_city_desc" "Toda Ciudad Ángel, todo el tiempo." + "PL_angel_city_lobby" "Lobby de Ciudad Ángel 24/7" + "PL_at_coop" "Escape (cooperativo)" + "PL_at_coop_desc" "Recién escapaste de la cárcel y solo tienes una pistola. Sobrevive hasta que puedas evacuar. Elimina enemigos para ganar dinero y comprar armas. \n^FFC83200Jugadores: 6\nNúmero máximo de miembros del grupo: 6" + "PL_at_coop_lobby" "Lobby de Escape" + "PL_attrition" "Cazarrecompensas" + "PL_attrition_abbr" "CAZ" + "PL_attrition_desc" "Elimina enemigos para ganar dinero. Obtén más depositando tus bonificaciones en el banco.\n^FFC83200Jugadores: 5vs5 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 5" + "PL_attrition_lobby" "Lobby de Cazarrecompensas" + "PL_capture_the_flag" "Captura la bandera" + "PL_capture_the_flag_abbr" "CLB" + "PL_capture_the_flag_desc" "¡Roba la bandera enemiga y regrésala a tu base mientras evitas que el equipo enemigo tome la tuya!\n^FFC83200Jugadores: 5vs5\nLímite de tiempo: 12 min.\nTamaño máximo del grupo: 5" + "PL_capture_the_flag_lobby" "Lobby de CLB" + "PL_coliseum" "Coliseo" + "PL_coliseum_desc" "Combate individual con movilidad mejorada en una jaula. Elimina a tu oponente y gana una ronda. El mejor en 3 de 5 rondas gana un regalo del defensor.^FFC83200\nJugadores: 1vs1 *Sin titanes\nLímite de tiempo: 3 min *Sin regeneraciones\n**^FFFFFF00REQUIERE BOLETO DE COLISEO o CUOTA DE ENTRADA PAGADA" + "PL_coliseum_lobby" "Lobby de Coliseo" + "PL_colony" "Colonia 24/7" + "PL_colony_abbr" "COL" + "PL_colony_desc" "Colonia, sin interrupciones. ^CCCCCC00Buscará partidas de^FFC83200Deterioro^CCCCCC00, ^FFC83200Batalla de pilotos^CCCCCC00 y ^FFC83200Último titán en pie^CCCCCC00." + "PL_colony_lobby" "Lobby de Colonia 24/7" + "PL_ctf_lf" "CLB (Nitro)" + "PL_ctf_lf_abbr" "CLB-N" + "PL_ctf_lf_desc" "El frenético Captura la bandera en mapas seleccionados.\n^FFC83200Jugadores: 5vs5\nTamaño máximo del grupo: 5\n^F4D5A600Regresos de bandera al instante" + "PL_ctf_lf_lobby" "Lobby de Nitro de CLB" + "PL_default_description" "Descripción predeterminada" + "PL_default_lobbytitle" "Título de lobby predeterminado" + "PL_default_name" "Nombre predeterminado" + "PL_don" "Doble o nada" + "PL_fd" "Defensa fronteriza" + "PL_fd_desc" "Defiéndete contra las oleadas de las fuerzas restantes de la Flota." + "PL_fd_easy" "Defensa fronteriza: Fácil" + "PL_fd_easy_desc" "Aplasta a la oposición" + "PL_fd_easy_lobby" "Defensa fronteriza: Lobby de dificultad fácil" + "PL_fd_hard" "Defensa fronteriza: Difícil" + "PL_fd_hard_desc" "Se requieren jugadas hábiles." + "PL_fd_hard_lobby" "Defensa fronteriza: Lobby de dificultad difícil" + "PL_fd_insane" "Defensa fronteriza: demencial" + "PL_fd_insane_desc" "No sobrevivirás" + "PL_fd_insane_lobby" "Lobby de Defensa fronteriza: demencial" + "PL_fd_lobby" "Lobby de Defensa fronteriza" + "PL_fd_master" "Defensa fronteriza: maestro" + "PL_fd_master_desc" "Solo los mejores saldrán con vida" + "PL_fd_master_lobby" "Lobby de Defensa fronteriza: maestro" + "PL_fd_normal" "Defensa fronteriza: normal" + "PL_fd_normal_desc" "Recomendado para jugadores con experiencia" + "PL_fd_normal_lobby" "Defensa fronteriza: Lobby de dificultad normal" + "PL_ffa" "Todos contra todos" + "PL_ffa_abbr" "TCT" + "PL_ffa_desc" "Cada piloto por su cuenta; elimina a todos los enemigos.\n^FFC83200Jugadores: 1vs11\nLímite de tiempo: 10 min.\nTamaño máximo de grupo: 1" + "PL_ffa_lobby" "Lobby de Todos contra todos" + "PL_fra" "Agentes Libres" + "PL_fra_abbr" "AGL" + "PL_fra_desc" "Estás por tu cuenta. Elimina enemigos para ganar. Recoge 3 baterías para un despliegue de titán.\n^FFC83200Jugadores: 1vs11\nLímite de tiempo: 15 min\nTamaño máximo del grupo: 1" + "PL_fra_lobby" "Lobby de Agentes Libres" + "PL_groud_war_lobby" "Lobby diverso 8vs8" + "PL_ground_war" "Diverso 8vs8" + "PL_ground_war_abbr" "8vs8" + "PL_ground_war_desc" "Incluye Escaramuza y Punto clave amplificado con gran número de jugadores en todos los mapas.\n^FFC83200Jugadores: 8vs8" + "PL_hardpoint" "Punto clave amplificado" + "PL_hardpoint_abbr" "PCA" + "PL_hardpoint_desc" "Captura y mantén un punto clave para ganar puntos. Los puntos clave amplificados dan el doble de puntos.\n^FFC83200Jugadores: 6vs6\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_hardpoint_lobby" "Lobby de Punto clave amplificado" + "PL_hardpoint_non_amp" "Punto clave" + "PL_hardpoint_lobb_non_amp" "Lobby de Punto clave" + "PL_hunted" "Cazado" + "PL_iron_last_titan_standing" "UTEP de hierro" + "PL_iron_last_titan_standing_abbr" "UTEPH" + "PL_iron_last_titan_standing_desc" "Solo para titanes, partida de rondas por eliminación. Gana el primero con 3 rondas ganadas.\n^FFC83200Jugadores: 5vs5 *SIN PILOTOS\nLímite de tiempo: 3 min por ronda *Sin regeneraciones\nNúmero máximo de miembros del grupo: 5" + "PL_iron_last_titan_standing_lobby" "PL_iron_last_titan_standing_lobby" + "PL_last_titan_standing" "Último titán en pie" + "PL_last_titan_standing_abbr" "UTEP" + "PL_last_titan_standing_desc" "Todos los jugadores inician en titanes en esta partida de rondas por eliminación. Gana el primero con 3 rondas ganadas.\n^FFC83200Jugadores: 5vs5 *Comienza como titán\nLímite de tiempo: 3 min. por ronda *Sin regeneraciones\nTamaño máximo del grupo: 5" + "PL_last_titan_standing_lobby" "Lobby de UTEP" + "PL_limited_time_mode" "Por tiempo limitado" + "PL_live_fire" "Fuego vivo" + "PL_live_fire_abbr" "FV" + "PL_live_fire_desc" "Combate frenético en un escenario de Fuego vivo. Elimina pilotos enemigos o ten la bandera cuando se acabe el tiempo para ganar la ronda.^FFC83200\nJugadores: 6vs6 *Sin titanes\nLímite de tiempo: 60 s *Sin regeneraciones\nNúmero máximo de miembros del grupo: 6" + "PL_live_fire_lobby" "Looby de Fuego vivo" + "PL_load_a_map_on_the_command_line" "Carga un mapa en la línea de comandos. Solo para desarrollo." + "PL_marked_for_death" "Marcado para morir" + "PL_marked_for_death_abbr" "MPM" + "PL_marked_for_death_desc" "Elimina o protege los objetivos marcados.\n^FFC83200Jugadores: 6vs6 \nLímite de tiempo: 12 min\nNúmero máximo de miembros del grupo: 6" + "PL_marked_for_death_lobby" "Lobby de Marcado para morir" + "PL_nitro_ffa" "TCT (Nitro)" + "PL_nitro_ffa_abbr" "TCT-N" + "PL_nitro_ffa_desc" "Todos contra todos acelerado en mapas seleccionados.\n^FFC83200Jugadores: 6\n^F4D5A600Sin titanes\nSin potenciadores" + "PL_nitro_ffa_lobby" "Lobby de TCT (Nitro)" + "PL_nitro_mixtape" "Diverso (Nitro)" + "PL_nitro_mixtape_abbr" "DVS-N" + "PL_nitro_mixtape_desc" "CLB, MPM y BDP acelerados en mapas seleccionados.\n^FFC83200Jugadores: 5vs5\nTamaño máximo del grupo: 5\n^F4D5A600Regresos de bandera al instante" + "PL_nitro_mixtape_lobby" "Lobby de Diverso" + "PL_pilot_hunter" "Escaramuza" + "PL_pilot_hunter_abbr" "ECM" + "PL_pilot_hunter_desc" "Elimina a los pilotos y titanes enemigos. \n^FFC83200Jugadores: 8vs8\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 8" + "PL_pilot_hunter_lobby" "Lobby de Escaramuza" + "PL_pilot_skirmish" "Batalla de pilotos" + "PL_pilot_skirmish_abbr" "BDP" + "PL_pilot_skirmish_desc" "Elimina a los pilotos enemigos. No se permiten despliegues de titán.\n^FFC83200Jugadores: 8vs8 *Sin titanes\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 8" + "PL_pilot_skirmish_lobby" "Lobby BDP" + "PL_pl_rebuild_all_paths" "Reconstruir todos los caminos" + "PL_pl_run_with_ai_ainrebuildonmapstart_2" "Ejecutar con ai_ainRebuildOnMapStart 2" + "PL_private_match" "Partida privada" + "PL_private_match_desc" "Juega una partida privada personalizada en el mapa y modo que quieras.\n^FFC83200INVITAR RED o INVITAR AMIGOS para jugar\n^FFC83200Jugadores: 1-16\nSin progresión" + "PL_private_match_lobby" "Lobby de la de partida privada" + "PL_promo_coop" "COOPERATIVO de 4 jugadores" + "PL_raid" "Incursión" + "PL_glitch" "Fallo 24/7" + "PL_glitch_abbr" "FAL" + "PL_glitch_desc" "Fallo, sin interrupciones. ^CCCCCC00Buscará partidas de ^FFC83200CLB^CCCCCC00, ^FFC83200Punto clave amplificado^CCCCCC00, ^FFC83200Batalla de pilotos^CCCCCC00, ^FFC83200Fuego vivo^CCCCCC00 y ^FFC83200Último titán en pie^CCCCCC00." + "PL_glitch_lobby" "Lobby de Fallo 24/7" + "PL_rocket_arena" "Zona de misiles" + "PL_rocket_arena_abbr" "FV" + "PL_rocket_arena_desc" "Las reglas clásicas de Fuego vivo con EPGs modificadas.^FFC83200\nJugadores: 6vs6 *Sin titanes\nLímite de tiempo: 90 s *Sin regeneraciones\nTamaño máximo del grupo: 6" + "PL_rocket_arena_lobby" "Lobby de Zona de misiles" + "PL_settings_for_when_someone_loads_a_map_on_the_command_line_do_not_edit_the_cmdlinemapload_1_below_-_this_makes_this_work" "Configuraciones para cuando alguien carga un mapa en la línea de comandos. No edites la cmdlineMapLoad 1 debajo porque se encarga de que esto funcione." + "PL_speedball" "Fuego vivo" + "PL_speedball_desc" "Lucha por la posesión de una bandera neutral. Elimina al equipo enemigo o ten la bandera cuando se acabe el tiempo para ganar la ronda. Gana el primero con 5 rondas ganadas.\n^FFC83200Jugadores: 6vs6 *Sin titanes\nLímite de tiempo: 60 segundos por ronda *Sin regeneraciones\nNúmero máximo de miembros del grupo: 6" + "PL_speedball_lobby" "Looby de Fuego vivo" + "PL_tactikill" "Eliminación táctica en Deterioro" + "PL_tactikill_abbr" "DET" + "PL_tactikill_desc" "Las reglas clásicas de Deterioro, pero todas las habilidades tácticas se reemplazan por completo con cada eliminación.\n^FFC83200Jugadores: 6vs6 *IA\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 6" + "PL_tactikill_lobby" "Lobby de Eliminación táctica en Deterioro" + "PL_titan_brawl" "Pelea de titanes" + "PL_titan_brawl_abbr" "PdT" + "PL_titan_brawl_desc" "Elimina a los titanes enemigos. No se permiten pilotos.\n^FFC83200Jugadores: 5vs5\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 5" + "PL_titan_brawl_hint" "Elimina a los titanes enemigos.\nSin eyección" + "PL_titan_brawl_lobby" "Lobby de Pelea de titanes" + "PL_titan_brawl_turbo" "Pelea de titanes turbo" + "PL_titan_brawl_turbo_abbr" "PdTT" + "PL_titan_brawl_turbo_desc" "Las reglas clásicas de Pelea de titanes con regeneración de impulsos y generación de núcleo más rápidas.\n^FFC83200Jugadores: 5vs5\nLímite de tiempo: 10 min.\nTamaño máximo del grupo: 5" + "PL_titan_brawl_turbo_hint" "Elimina a los titanes enemigos.\nSin eyección" + "PL_titan_brawl_turbo_lobby" "Lobby de Pelea de titanes turbo" + "PL_turbo_last_titan_standing" "UTEP turbo" + "PL_turbo_last_titan_standing_abbr" "UTEP" + "PL_turbo_last_titan_standing_desc" "Las reglas clásicas de UTEP con regeneración de impulsos y generación de núcleo más rápidas.\n^FFC83200Jugadores: 5vs5 *Comienza como titán\nLímite de tiempo: 3 min. por ronda *Sin regeneraciones\nTamaño máximo del grupo: 5" + "PL_turbo_last_titan_standing_lobby" "Lobby de UTEP turbo" + "PL_variety_pack" "Diverso" + "PL_variety_pack_desc" "Número variado de jugadores con una gran variedad de mapas en estos modos:\n^FFC83200*Cazarrecompensas *Deterioro\n*Último titán en pie *Punto clave\n*Pilotos contra pilotos *Captura la bandera" + "PL_variety_pack_lobby" "Lobby diverso" + "PL_wargames" "Juegos de guerra 24/7" + "PL_wargames_abbr" "JDG" + "PL_wargames_desc" "Juegos de guerra, sin interrupciones. ^CCCCCC00Buscará partidas de ^FFC83200Deterioro^CCCCCC00, ^FFC83200CLB^CCCCCC00, ^FFC83200Batalla de pilotos^CCCCCC00, ^FFC83200Punto clave amplificado^CCCCCC00 y ^FFC83200Último titán en pie^CCCCCC00." + "PL_wargames_lobby" "Lobby de Juegos de guerra 24/7" + "WATCH_TUTORIAL" "VER TUTORIAL" + "GAMEMODE_TMFD" "Titan Marcado para morir" + "MP_RELIC02_FD_WAVE_1" "Unidos resistimos" + "MP_RELIC02_FD_WAVE_2" "En busca del camino principal" + "MP_RELIC02_FD_WAVE_3" "Descubriendo un nuevo camino" + "MP_RELIC02_FD_WAVE_4" "Insignia a ciegas" + "MP_RELIC02_FD_WAVE_5" "Divide y embosca" + } + } + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut index 3bdb1d8a5..d0644d703 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut @@ -1,72 +1,179 @@ global function SpawnHarvester global function generateBeamFX +global function sparksBeamFX global function generateShieldFX +global function playHarvesterDestructionFX +global function GetHarvesterBeamTriLerpColor + +global const HARVESTER_ANIM_IDLE = "generator_idle" +global const HARVESTER_ANIM_ACTIVATING = "generator_rise" +global const HARVESTER_ANIM_ACTIVE = "generator_cycle_fast" +global const HARVESTER_ANIM_ACTIVE_LOWHP = "generator_cycle_slow" +global const HARVESTER_ANIM_DESTROYED = "generator_fall" + +global const HARVESTER_SND_STARTUP = "coop_generator_startup" + +global const HARVESTER_SND_HEALTHY = "coop_generator_ambient_healthy" +global const HARVESTER_SND_DAMAGED = "coop_generator_ambient_damaged" +global const HARVESTER_SND_CRITICAL = "coop_generator_ambient_critical" +global const HARVESTER_SND_DESTROYED = "coop_generator_destroyed" +global const HARVESTER_SND_UNSTABLE = "coop_generator_electrical_arcs" + +global const HARVESTER_SND_SHIELDFROMZERO = "coop_generator_shieldrecharge_start" +global const HARVESTER_SND_SHIELDFROMMID = "coop_generator_shieldrecharge_resumeclick" +global const HARVESTER_SND_SHIELDREGENLOOP = "coop_generator_shieldrecharge_resume" +global const HARVESTER_SND_SHIELDFULL = "coop_generator_shieldrecharge_end" +global const HARVESTER_SND_SHIELDBREAK = "coop_generator_shielddown" + +global const HARVESTER_SND_KLAXON = "coop_generator_underattack_alarm" + +const HARVESTER_BEAM_HEALTHY = < 80, 180, 255 > +const HARVESTER_BEAM_MEDIUM = < 255, 192, 96 > +const HARVESTER_BEAM_CRITICAL = < 255, 96, 32 > global struct HarvesterStruct { entity harvester entity particleBeam + entity particleSparks entity particleShield entity rings + array particleFXArray float lastDamage bool shieldBoost bool harvesterShieldDown float harvesterDamageTaken bool havesterWasDamaged - } HarvesterStruct function SpawnHarvester( vector origin, vector angles, int health, int shieldHealth, int team ) { - entity harvester = CreateEntity( "prop_script" ) - harvester.SetValueForModelKey( $"models/props/generator_coop/generator_coop.mdl" ) - harvester.SetOrigin( origin ) - harvester.SetAngles( angles ) - harvester.kv.solid = SOLID_VPHYSICS - - harvester.SetMaxHealth( health ) - harvester.SetHealth( health ) - harvester.SetShieldHealthMax( shieldHealth ) - harvester.SetShieldHealth( shieldHealth ) - harvester.EnableAttackableByAI( 30, 0, AI_AP_FLAG_NONE ) - SetCustomSmartAmmoTarget( harvester, true ) - SetObjectCanBeMeleed( harvester, true ) - SetVisibleEntitiesInConeQueriableEnabled( harvester, true ) - SetTeam(harvester,team) - - DispatchSpawn( harvester ) - - - entity blackbox = CreatePropDynamic( MODEL_HARVESTER_TOWER_COLLISION, origin, angles, 0 ) - blackbox.Hide() - blackbox.Solid() - // blackbox.kv.CollisionGroup = TRACE_COLLISION_GROUP_PLAYER - - entity rings = CreatePropDynamic( MODEL_HARVESTER_TOWER_RINGS, origin, angles, 6 ) - thread PlayAnim( rings, "generator_cycle_fast" ) - - - - HarvesterStruct ret - ret.harvester = harvester - ret.lastDamage = Time() - ret.rings = rings - - return ret + entity harvester = CreatePropScript( MODEL_HARVESTER_TOWER, origin, angles, SOLID_VPHYSICS ) + + harvester.SetMaxHealth( health ) + harvester.SetHealth( health ) + harvester.SetShieldHealthMax( shieldHealth ) + harvester.SetShieldHealth( shieldHealth ) + harvester.EnableAttackableByAI( 30, 0, AI_AP_FLAG_NONE ) + ToggleNPCPathsForEntity( harvester, false ) + harvester.SetAIObstacle( true ) + SetCustomSmartAmmoTarget( harvester, true ) + SetObjectCanBeMeleed( harvester, true ) + SetVisibleEntitiesInConeQueriableEnabled( harvester, true ) + SetTeam( harvester, team ) + AI_CreateDangerousArea_Static( harvester, null, 160, TEAM_INVALID, true, true, origin ) + CreateNoSpawnArea( TEAM_INVALID, TEAM_INVALID, origin, 0, 160 ) //Prevent people calling Titans inside the Harvester + + entity blackbox = CreatePropScript( MODEL_HARVESTER_TOWER_COLLISION, origin, angles, 0 ) + ToggleNPCPathsForEntity( blackbox, false ) + blackbox.Solid() + blackbox.Hide() + blackbox.SetAIObstacle( true ) + blackbox.SetTakeDamageType( DAMAGE_NO ) + blackbox.SetScriptPropFlags( SPF_BLOCKS_AI_NAVIGATION ) + blackbox.SetParent( harvester ) //Parenting so when Harvester gets destroyed, this also goes with it + + entity rings = CreatePropDynamic( MODEL_HARVESTER_TOWER_RINGS, origin, angles, 0 ) + rings.Anim_Play( HARVESTER_ANIM_IDLE ) //Start with Harvester deactivated, gamemodes should handle animations in their local scripts + + HarvesterStruct ret + ret.harvester = harvester + ret.lastDamage = Time() + ret.rings = rings + + return ret } HarvesterStruct function generateBeamFX( HarvesterStruct harvester ) { - entity Harvester_Beam = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_BEAM ), FX_PATTACH_ABSORIGIN_FOLLOW ,0 ) - EffectSetControlPointVector( Harvester_Beam, 1, GetShieldTriLerpColor( 0.0 ) ) - harvester.particleBeam = Harvester_Beam - Harvester_Beam.DisableHibernation() - return harvester + entity Harvester_Beam = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_BEAM ), FX_PATTACH_ABSORIGIN_FOLLOW ,0 ) + EffectSetControlPointVector( Harvester_Beam, 1, GetShieldTriLerpColor( 0.0 ) ) + harvester.particleBeam = Harvester_Beam + Harvester_Beam.DisableHibernation() + return harvester +} + +HarvesterStruct function sparksBeamFX( HarvesterStruct harvester ) +{ + entity Harvester_Sparks = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_HEALTH_LOW ), FX_PATTACH_ABSORIGIN_FOLLOW ,0 ) + EffectSetControlPointVector( Harvester_Sparks, 1, GetShieldTriLerpColor( 0.0 ) ) + harvester.particleSparks = Harvester_Sparks + Harvester_Sparks.DisableHibernation() + return harvester } HarvesterStruct function generateShieldFX( HarvesterStruct harvester ) { - entity Harvester_Shield = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_OVERSHIELD ), FX_PATTACH_ABSORIGIN_FOLLOW, 0 ) - EffectSetControlPointVector( Harvester_Shield, 1, GetShieldTriLerpColor( 0.0 ) ) - harvester.particleShield = Harvester_Shield - return harvester -} \ No newline at end of file + entity Harvester_Shield = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_OVERSHIELD ), FX_PATTACH_ABSORIGIN_FOLLOW, 0 ) + EffectSetControlPointVector( Harvester_Shield, 1, GetShieldTriLerpColor( 0.0 ) ) + harvester.particleShield = Harvester_Shield + Harvester_Shield.DisableHibernation() + return harvester +} + +void function playHarvesterDestructionFX( HarvesterStruct harvester ) +{ + if( IsValid( harvester.particleBeam ) ) + harvester.particleBeam.Destroy() + + if( IsValid( harvester.particleSparks ) ) + harvester.particleSparks.Destroy() + + foreach( entity pFX in harvester.particleFXArray ) + { + if( IsValid( pFX ) ) + pFX.Destroy() + } + + harvester.particleFXArray.clear() + entity harvExpFX = PlayFX( $"P_harvester_beam_end", harvester.harvester.GetOrigin() ) + harvExpFX.Destroy() + + StopSoundOnEntity( harvester.harvester, HARVESTER_SND_HEALTHY ) + StopSoundOnEntity( harvester.harvester, HARVESTER_SND_DAMAGED ) + StopSoundOnEntity( harvester.harvester, HARVESTER_SND_CRITICAL ) + StopSoundOnEntity( harvester.harvester, HARVESTER_SND_UNSTABLE ) + + EmitSoundOnEntity( harvester.harvester, HARVESTER_SND_DESTROYED ) + EmitSoundOnEntity( harvester.harvester, "ai_reaper_nukedestruct_explo_3p" ) + EmitSoundOnEntity( harvester.harvester, "bt_beacon_controlroom_dish_explosion" ) +} + +vector function GetHarvesterBeamTriLerpColor( float frac ) +{ + return GetTriLerpColor( frac, HARVESTER_BEAM_HEALTHY, HARVESTER_BEAM_MEDIUM, HARVESTER_BEAM_CRITICAL ) +} + +//Unfortunately, repeat function here because it's not global in _vortex.nut, good thing though is setting up better transition points between harvester health stages +vector function GetTriLerpColor( float fraction, vector color1, vector color2, vector color3 ) +{ + float crossover1 = 0.33 + float crossover2 = 0.66 + + float r, g, b + + // 0 = full charge, 1 = no charge remaining + if ( fraction < crossover1 ) + { + r = Graph( fraction, 0, crossover1, color1.x, color2.x ) + g = Graph( fraction, 0, crossover1, color1.y, color2.y ) + b = Graph( fraction, 0, crossover1, color1.z, color2.z ) + return + } + else if ( fraction < crossover2 ) + { + r = Graph( fraction, crossover1, crossover2, color2.x, color3.x ) + g = Graph( fraction, crossover1, crossover2, color2.y, color3.y ) + b = Graph( fraction, crossover1, crossover2, color2.z, color3.z ) + return + } + else + { + // for the last bit of overload timer, keep it max danger color + r = color3.x + g = color3.y + b = color3.z + return + } + + unreachable +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index d93ab64a0..72929fd54 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -8290,8 +8290,8 @@ void function Player_GiveDoubleXP( entity player, int count ) bool function ClientCommand_UseDoubleXP( entity player, array args ) { - if ( IsPrivateMatch() ) - return true + //if ( IsPrivateMatch() ) Northstar servers are always considered private matches + // return true if ( GetGameState() > eGameState.Prematch ) return true diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 97d8cf02f..469993d5a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -3,36 +3,30 @@ global function SvLoadoutsMP_Init global function SetLoadoutGracePeriodEnabled global function SetWeaponDropsEnabled +global function SetAllowLoadoutChangeFunc global function AddCallback_OnTryGetTitanLoadout global function GetTitanLoadoutForPlayer -global struct sTryGetTitanLoadoutCallbackReturn -{ - bool wasChanged = false - bool runMoreCallbacks = true - TitanLoadoutDef& loadout -} - typedef TryGetTitanLoadoutCallbackType sTryGetTitanLoadoutCallbackReturn functionref( entity player, TitanLoadoutDef loadout, bool wasChanged ) struct { bool loadoutGracePeriodEnabled = true - bool weaponDropsEnabled = true array< TryGetTitanLoadoutCallbackType > onTryGetTitanLoadoutCallbacks - array dirtyLoadouts + bool functionref( entity ) allowChangeLoadoutFunc = null } file void function SvLoadoutsMP_Init() { InitDefaultLoadouts() // titan loadout code relies on this, not called on server by default - + // most of these are fairly insecure right now, could break pdata if called maliciously, need fixing eventually RegisterSignal( "EndUpdateCachedLoadouts" ) RegisterSignal( "GracePeriodDone" ) // temp to get weapons\_weapon_utility.nut:2271 to behave AddCallback_OnClientConnected( LoadoutsMPInitPlayer ) + AddCallback_OnPlayerGetsNewPilotLoadout( LoadoutSwitch_Player ) AddClientCommandCallback( "RequestPilotLoadout", ClientCommandCallback_RequestPilotLoadout ) AddClientCommandCallback( "RequestTitanLoadout", ClientCommandCallback_RequestTitanLoadout ) @@ -48,7 +42,7 @@ void function SvLoadoutsMP_Init() } else { - AddClientCommandCallback( "InGameMPMenuClosed", ClientCommandCallback_InGameMPMenuClosed ) + AddClientCommandCallback( "InGameMPMenuClosed", ClientCommandCallback_LoadoutMenuClosed ) AddClientCommandCallback( "LoadoutMenuClosed", ClientCommandCallback_LoadoutMenuClosed ) } } @@ -58,6 +52,11 @@ void function SetLoadoutGracePeriodEnabled( bool enabled ) file.loadoutGracePeriodEnabled = enabled } +void function SetAllowLoadoutChangeFunc( bool functionref( entity ) func ) +{ + file.allowChangeLoadoutFunc = func +} + void function SetWeaponDropsEnabled( bool enabled ) { if( enabled ) @@ -66,6 +65,13 @@ void function SetWeaponDropsEnabled( bool enabled ) FlagClear( "WeaponDropsAllowed" ) } +void function DelayDestroyDroppedWeapon( entity weapon ) +{ + WaitEndFrame() + if ( IsValid( weapon ) ) + weapon.Destroy() +} + void function AddCallback_OnTryGetTitanLoadout( TryGetTitanLoadoutCallbackType callback ) { file.onTryGetTitanLoadoutCallbacks.append( callback ) @@ -105,10 +111,15 @@ TitanLoadoutDef function GetTitanLoadoutForPlayer( entity player ) void function LoadoutsMPInitPlayer( entity player ) { player.s.loadoutDirty <- false + player.s.noFiredWeapon <- true // 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" ) ) + + AddButtonPressedPlayerInputCallback( player, IN_ATTACK, LoadoutSwitch_CancelGracePeriod ) + AddButtonPressedPlayerInputCallback( player, IN_OFFHAND0, LoadoutSwitch_CancelGracePeriod ) + AddButtonPressedPlayerInputCallback( player, IN_OFFHAND1, LoadoutSwitch_CancelGracePeriod ) } // loadout clientcommands @@ -117,8 +128,10 @@ bool function ClientCommandCallback_RequestPilotLoadout( entity player, array= eGameState.Playing ) return false + #if DEV print( player + " SetBurnCardPersistenceSlot " + args[0] ) - + #endif + if ( IsRefValidAndOfType( args[0], eItemTypes.BURN_METER_REWARD ) ) { if ( !IsItemLocked( player, args[0] ) ) @@ -225,7 +241,9 @@ bool function ClientCommandCallback_SetBurnCardPersistenceSlot( entity player, a } else { + #if DEV print( player + " invalid ref " + args[0] ) + #endif return false } @@ -238,7 +256,9 @@ bool function ClientCommandCallback_SetCallsignIcon( entity player, array args ) { - TryGivePilotLoadoutForGracePeriod( player ) - return true -} - -bool function ClientCommandCallback_InGameMPMenuClosed( entity player, array args ) -{ - TryGivePilotLoadoutForGracePeriod( player ) + if ( !args.len() || args[0] == "1" || args.len() > 1 && args[1] == "1" ) + TryGivePilotLoadoutForGracePeriod( player ) + return true } @@ -327,28 +353,55 @@ void function SetPlayerLoadoutDirty( entity player ) void function TryGivePilotLoadoutForGracePeriod( entity player ) { - if ( !IsLobby() && IsAlive( player ) && player.s.loadoutDirty && !player.IsTitan() && !player.ContextAction_IsActive() ) - { - player.s.loadoutDirty = false + if ( IsLobby() || player.ContextAction_IsActive() ) + return + if ( IsAlive( player ) && player.s.loadoutDirty ) + { + float gracePeriodDuration = GetCurrentPlaylistVarFloat( "loadout_grace_period", 20.0 ) + if ( !file.loadoutGracePeriodEnabled ) + gracePeriodDuration = 0.0 + // 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 ) + float respawnTime = expect float( player.s.respawnTime ) + respawnTime += gracePeriodDuration - if ( ( ( Time() - respawnTimeReal <= CLASS_CHANGE_GRACE_PERIOD || GetGameState() < eGameState.Playing ) && file.loadoutGracePeriodEnabled ) || player.p.usingLoadoutCrate ) + if ( respawnTime >= Time() && player.s.noFiredWeapon || svGlobal.isInPilotGracePeriod || GetGameState() < eGameState.Playing || player.s.usedLoadoutCrate || player.p.usingLoadoutCrate || file.allowChangeLoadoutFunc != null && file.allowChangeLoadoutFunc( player ) ) { - if ( !Loadouts_CanGivePilotLoadout( player ) && player.GetParent() != null && ( HasCinematicFlag( player, CE_FLAG_INTRO ) || HasCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) || HasCinematicFlag( player, CE_FLAG_WAVE_SPAWNING ) ) ) - thread GiveLoadoutWhenIntroOver( player ) + if ( player.IsTitan() && !GetDoomedState( player ) ) + { + player.s.loadoutDirty = false + entity soul = player.GetTitanSoul() + if ( IsValid( soul ) ) + { + // Store current health and shield because loadout swapping resets both + int currentHealth = player.GetHealth() + int currentShield = soul.GetShieldHealth() + + Loadouts_TryGiveTitanLoadout( player ) + + player.SetHealth( minint( currentHealth, player.GetMaxHealth() ) ) + soul.SetShieldHealth( minint( currentShield, soul.GetShieldHealthMax() ) ) + } + } else - Loadouts_TryGivePilotLoadout( player ) + { + if ( !Loadouts_CanGivePilotLoadout( player ) && GetGameState() < eGameState.Playing ) + thread GiveLoadoutWhenIntroOver( player ) + else if ( Loadouts_TryGivePilotLoadout( player ) ) + player.s.loadoutDirty = false + } player.p.usingLoadoutCrate = false + player.s.usedLoadoutCrate = false } else - SendHudMessage( player, "#LOADOUT_CHANGE_NEXT_BOTH", -1, 0.4, 255, 255, 255, 255, 0.15, 3.0, 0.5 ) // like 90% sure this is innacurate lol + { + if ( player.IsTitan() ) + SendHudMessage( player, "#LOADOUT_CHANGE_NEXT_TITAN", -1, 0.4, 255, 255, 255, 255, 0.15, 3.0, 0.5 ) + else + SendHudMessage( player, "#LOADOUT_CHANGE_NEXT_PILOT", -1, 0.4, 255, 255, 255, 255, 0.15, 3.0, 0.5 ) + } } } @@ -357,8 +410,20 @@ void function GiveLoadoutWhenIntroOver( entity player ) player.EndSignal( "OnDestroy" ) player.EndSignal( "OnDeath" ) - while ( player.GetParent() != null && ( HasCinematicFlag( player, CE_FLAG_INTRO ) || HasCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) || HasCinematicFlag( player, CE_FLAG_WAVE_SPAWNING ) ) ) + while ( !Loadouts_CanGivePilotLoadout( player ) ) WaitFrame() Loadouts_TryGivePilotLoadout( player ) -} + player.s.loadoutDirty = false +} + +void function LoadoutSwitch_Player( entity player, PilotLoadoutDef loadout ) +{ + player.s.noFiredWeapon = true +} + +void function LoadoutSwitch_CancelGracePeriod( entity player ) +{ + if ( GamePlaying() ) + player.s.noFiredWeapon = false +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_ping.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_ping.gnut index d3946871c..153c31f09 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_ping.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_ping.gnut @@ -31,7 +31,7 @@ void function Spotting_Init() bool function ClientCommandCallbackPingSpot( entity player, array args ) { - if ( GetCurrentPlaylistVarInt( "pingspot_enabled", 0 ) ) + if ( !GetCurrentPlaylistVarInt( "pingspot_enabled", 0 ) ) return true if( !IsAlive( player ) || !GamePlaying() || IsPrivateMatchSpectator( player ) ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_powerup.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_powerup.gnut index e57533f07..00aac0049 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_powerup.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_powerup.gnut @@ -75,6 +75,11 @@ void function PowerupSpawnerThink( entity spawnpoint, PowerUp powerupDef ) bool function OnPowerupCollected( entity player, entity healthpack ) { + string powerUpRef = expect string( healthpack.s.powerupRef ) + + if ( powerUpRef == "" ) + return false + PowerUp powerup = GetPowerUpFromItemRef( expect string( healthpack.s.powerupRef ) ) if ( powerup.titanPickup == player.IsTitan() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut b/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut index 47dd9294f..c0fd0ccf1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut @@ -1601,11 +1601,11 @@ float function GetPulseFrac( rate = 1, startTime = 0 ) bool function IsPetTitan( titan ) { Assert( titan.IsTitan() ) - + if ( !titan.GetTitanSoul() ) return false - - return titan.GetTitanSoul().GetBossPlayer() != null + + return titan.GetTitanSoul().GetBossPlayer() != null } vector function StringToVector( string vecString, string delimiter = " " ) @@ -2887,21 +2887,18 @@ bool function EntHasModelSet( entity ent ) string function GenerateTitanOSAlias( entity player, string aliasSuffix ) { - //HACK: Temp fix for blocker bug. Fixing correctly next. - if ( IsSingleplayer() ) - { + entity titan + if ( player.IsTitan() ) + titan = player + else + titan = player.GetPetTitan() + Assert( IsValid( titan ) ) + string titanCharacterName = GetTitanCharacterName( titan ) + + if ( titanCharacterName == "bt" ) // BT have a special case since hes not a multiplayer Titan return "diag_gs_titanBt_" + aliasSuffix - } else { - entity titan - if ( player.IsTitan() ) - titan = player - else - titan = player.GetPetTitan() - - Assert( IsValid( titan ) ) - string titanCharacterName = GetTitanCharacterName( titan ) string primeTitanString = "" if ( IsTitanPrimeTitan( titan ) ) @@ -3268,30 +3265,17 @@ float function LimitAxisToMapExtents( float axisVal ) return axisVal } -bool function PilotSpawnOntoTitanIsEnabledInPlaylist( entity player ) -{ - if ( GetCurrentPlaylistVarInt( "titan_spawn_deploy_enabled", 0 ) != 0 ) - return true - return false -} - bool function PlayerCanSpawnIntoTitan( entity player ) { - if ( !PilotSpawnOntoTitanIsEnabledInPlaylist( player ) ) - return false - entity titan = player.GetPetTitan() - if ( !IsAlive( titan ) ) - return false - - if ( GetDoomedState( titan ) ) + if ( !IsAlive( titan ) || GetDoomedState( titan ) ) return false - if ( titan.ContextAction_IsActive() ) + if ( titan.ContextAction_IsBusy() || titan.ContextAction_IsMeleeExecution() ) return false - return false // turned off until todd figures out how to enable + return GetCurrentPlaylistVarInt( "titan_spawn_deploy_enabled", 0 ) == 1 } array< vector > function EntitiesToOrigins( array< entity > ents ) @@ -4076,7 +4060,7 @@ string function GetTitanCharacterName( entity titan ) string aiSettingsFile = titan.GetAISettingsName() setFile = expect string( Dev_GetAISettingByKeyField_Global( aiSettingsFile, "npc_titan_player_settings" ) ) } - + return GetTitanCharacterNameFromSetFile( setFile ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut index 97d993e65..d77464c16 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut @@ -39,7 +39,15 @@ void function HandleXPGainForScoreEvent( entity player, ScoreEvent event ) int titanXp = ScoreEvent_GetXPValueTitan( event ) int factionXp = ScoreEvent_GetXPValueFaction( event ) - if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 || GetCurrentPlaylistVarInt( "double_xp_enabled", 0 ) == 1 ) + if ( GetCurrentPlaylistVarInt( "double_xp_enabled", 0 ) == 1 ) + { + xpValue *= 2 + weaponXp *= 2 + titanXp *= 2 + factionXp *= 2 + } + + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 ) { xpValue *= 2 weaponXp *= 2 diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_cloak_drone.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_cloak_drone.gnut index e3addf812..21daea06b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_cloak_drone.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_cloak_drone.gnut @@ -146,7 +146,7 @@ function CloakedDroneCloakThink( cloakedDrone ) function CloakDroneShouldCloakGuy( cloakedDrone, guy ) { expect entity( guy ) - if ( !( guy.IsTitan() || IsSpectre( guy ) || IsGrunt( guy ) || IsSuperSpectre( guy ) ) ) + if ( !( IsNPCTitan( guy ) || IsMinion( guy ) || IsStalker( guy ) || IsSuperSpectre( guy ) ) ) return false if ( guy.GetTargetName() == "empTitan" ) @@ -215,7 +215,7 @@ void function CloakedDronePathThink( entity cloakedDrone ) continue //Only cloak titans, spectres, grunts, - if ( !( guy.IsTitan() || IsSpectre( guy ) || IsGrunt( guy ) || IsSuperSpectre( guy ) ) ) + if ( !( IsNPCTitan( guy ) || IsMinion( guy ) || IsStalker( guy ) || IsSuperSpectre( guy ) ) ) continue //Don't cloak arc titans diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_spectres.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_spectres.gnut index 080e2f68c..d205267ae 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_spectres.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_spectres.gnut @@ -1,7 +1,333 @@ +untyped + +global function MortarSpectreSquadThink global function MortarSpectreGetSquadFiringPositions +const float MORTAR_SPECTRE_POSITION_SEARCH_RANGE = 8192 // How far away from their spawn point a mortar spectre squad will look for positions to siege from +const float MORTAR_SPECTRE_TRACKER_SHIELD_MAX = 1000 // just using 1000 for now, doesnt really matter as long as the shieldFrac is accurate enough +const float MORTAR_SPECTRE_SIGHT_DISTANCE = 1000 // Maximum distance the Spectres can detect players rather attack the Harvester + +const array MORTAR_SPECTRE_POSITION_OFFSETS = [ < 50, 0, 0 >, < 0, 50, 0 >, < -50, 0, 0 >, < 0, -50, 0 > ] + array function MortarSpectreGetSquadFiringPositions( vector origin, vector testTarget ) { - array< vector > ret + array ret + foreach ( vector position in MORTAR_SPECTRE_POSITION_OFFSETS ) + ret.append( OriginToGround( testTarget + position + < 0, 0, 128 > ) ) //Offset 128 units up so it traces back down in sloped ground if needed return ret +} + +/* +███╗ ███╗ ██████╗ ██████╗ ████████╗ █████╗ ██████╗ ███████╗██████╗ ███████╗ ██████╗████████╗██████╗ ███████╗ ██╗ ██████╗ ██████╗ ██╗ ██████╗ +████╗ ████║██╔═══██╗██╔══██╗╚══██╔══╝██╔══██╗██╔══██╗ ██╔════╝██╔══██╗██╔════╝██╔════╝╚══██╔══╝██╔══██╗██╔════╝ ██║ ██╔═══██╗██╔════╝ ██║██╔════╝ +██╔████╔██║██║ ██║██████╔╝ ██║ ███████║██████╔╝ ███████╗██████╔╝█████╗ ██║ ██║ ██████╔╝█████╗ ██║ ██║ ██║██║ ███╗██║██║ +██║╚██╔╝██║██║ ██║██╔══██╗ ██║ ██╔══██║██╔══██╗ ╚════██║██╔═══╝ ██╔══╝ ██║ ██║ ██╔══██╗██╔══╝ ██║ ██║ ██║██║ ██║██║██║ +██║ ╚═╝ ██║╚██████╔╝██║ ██║ ██║ ██║ ██║██║ ██║ ███████║██║ ███████╗╚██████╗ ██║ ██║ ██║███████╗ ███████╗╚██████╔╝╚██████╔╝██║╚██████╗ +╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ +*/ + +void function MortarSpectreSquadThink( array< entity > spectres, entity harvester ) +{ + if ( !spectres.len() || !IsValid( harvester ) ) + return + + StationaryAIPosition ornull mortarPosition = GetClosestAvailableStationaryPosition( spectres[0].GetOrigin(), MORTAR_SPECTRE_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + while ( mortarPosition == null ) + { + // in case all stationary spectre positions are in use wait for one to become available + wait 5 + // pick first spectre on array to look for mortar spots, it wont matter much because GetSquadCentroid counts towards all alive ones in a squad + ArrayRemoveDead( spectres ) + if ( !spectres.len() ) + return + mortarPosition = GetClosestAvailableStationaryPosition( spectres[0].GetSquadCentroid(), MORTAR_SPECTRE_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + } + + expect StationaryAIPosition( mortarPosition ) + ClaimStationaryAIPosition( mortarPosition ) //Prevent other squads from using this mortar spot + + //Create icon handler for when at least one spectre arrives at the mortar spot + entity squadMarker = CreatePropScript( $"models/dev/empty_model.mdl", mortarPosition.origin + < 0, 0, 160 >, < 0, 1, 0 > ) + SetTargetName( squadMarker, "mortarPosition" ) + squadMarker.SetShieldHealthMax( MORTAR_SPECTRE_TRACKER_SHIELD_MAX ) + squadMarker.Minimap_SetAlignUpright( true ) + squadMarker.Minimap_SetClampToEdge( true ) + squadMarker.Minimap_SetHeightTracking( true ) + squadMarker.Minimap_SetZOrder( MINIMAP_Z_NPC + 5 ) + squadMarker.Minimap_SetCustomState( eMinimapObject_prop_script.FD_MORTAR_POSITION ) + squadMarker.SetScriptName( "mortarPosition" ) + squadMarker.DisableHibernation() + squadMarker.EnableRenderAlways() + squadMarker.kv.fadedist = 32768 + squadMarker.EndSignal( "OnDestroy" ) + + vector dir = harvester.GetOrigin() - mortarPosition.origin + vector shieldangle = VectorToAngles( dir ) + shieldangle.x = 0 + shieldangle.z = 0 + vector targetoffset = PositionOffsetFromOriginAngles( mortarPosition.origin, shieldangle, 150, 0, 0 ) + + thread MortarSpectreSquadDeathThink( spectres, squadMarker, mortarPosition ) //Track squad status for icon and spot states + entity mortarfaketarget = CreateInfoTarget( targetoffset + < 0, 0, 320 >, < 0, 0, 0 > ) //Proxy target where the Mortar Spectres will actually aim to + mortarfaketarget.SetParent( squadMarker, "", true ) + + int i = 0 + foreach( entity spectre in spectres ) + { + spectre.ai.mortarTarget = harvester //Register Harvester as their true target to hit instead of proxy + spectre.ai.carryBarrel = mortarfaketarget //Keep track of proxy target for the function that handles target switching and weaponry + thread MortarSpectreMoveToMortarPosition( spectre, squadMarker, mortarPosition.origin + MORTAR_SPECTRE_POSITION_OFFSETS[i] ) //Hopefull they will path to their target spot + + if ( i++ >= MORTAR_SPECTRE_POSITION_OFFSETS.len() ) //Crash protect if Spectre Squad has more than 4 + i = 0 + } + + squadMarker.WaitSignal( "BeginMortarAttack" ) //Wait until at least one spectre reached the siege spot + + if( FD_GetDifficultyLevel() != eFDDifficultyLevel.INSANE ) + { + squadMarker.SetAngles( < 0, 0, 0 > ) //Angle in the icon prop is used as a visbility toggle + squadMarker.Minimap_AlwaysShow( TEAM_MILITIA, null ) + thread MortarIconCloakCheck( squadMarker, spectres ) + } + + //Buildup Siege Icon and Place Shield + float setupEndTime = Time() + GetCurrentPlaylistVarFloat( "fd_mortar_spectre_setup_time", 5 ) + entity mortarshield + if ( FD_IsDifficultyLevelOrHigher( eFDDifficultyLevel.HARD ) && IsValid( squadMarker ) ) //From what i could observe, Mortar Spectres don't use a playlistvar, they only check difficulty + { + vector shieldoffset = PositionOffsetFromOriginAngles( mortarPosition.origin, shieldangle, 80, 0, 0 ) + mortarshield = CreateShieldWithSettings( OriginToGround( shieldoffset + < 0, 0, 128> ), shieldangle, 112, 80, 150, 9999.0, TURRET_SHIELD_WALL_HEALTH, $"P_pilot_cover_shield" ) + mortarshield.SetParent( squadMarker, "", true ) //Parent to the Mortar Icon, so when that gets destroyed, this also goes with it + mortarshield.EndSignal( "OnDestroy" ) + mortarshield.SetBlocksRadiusDamage( true ) + mortarshield.DisableVortexBlockLOS() + UpdateShieldWallColorForFrac( mortarshield.e.shieldWallFX, GetHealthFrac( mortarshield ) ) + thread MortarShieldCloakCheck( mortarshield, spectres ) + } + + ArrayRemoveDead( spectres ) //Remove dead squadmates from tracking + + while ( Time() < setupEndTime ) + { + if ( !IsValid( squadMarker ) ) + break + + if( FD_GetDifficultyLevel() != eFDDifficultyLevel.INSANE ) //Skip Icon for Insane as it hides all icons from everyone, including this + { + float timeRemainingFrac = ( setupEndTime - Time() ) / GetCurrentPlaylistVarFloat( "fd_mortar_spectre_setup_time", 5 ) + squadMarker.SetShieldHealth( ( 1 - timeRemainingFrac ) * MORTAR_SPECTRE_TRACKER_SHIELD_MAX ) + } + WaitFrame() + } + + if ( IsValid( squadMarker ) && FD_GetDifficultyLevel() != eFDDifficultyLevel.INSANE ) + squadMarker.SetShieldHealth( MORTAR_SPECTRE_TRACKER_SHIELD_MAX ) //Set to Max Shield so it does the flare effect that the Spectres are ready to siege + + ArrayRemoveDead( spectres ) //Remove again due to delay + if( IsValid( mortarfaketarget ) ) //Enable the Proxy to be targeted by the Spectres + { + SetTeam( mortarfaketarget, TEAM_UNASSIGNED ) + mortarfaketarget.EnableAttackableByAI( 0, 0, AI_AP_FLAG_NONE ) + } + + i = 0 + foreach( entity spectre in spectres ) //Trigger the function responsible for handling target switching and weapons from them + { + if( IsValid( spectre ) ) + { + spectre.SetHearingSensitivity( 0 ) + spectre.ClearAllEnemyMemory() + spectre.SetEnemy( mortarfaketarget ) + spectre.LockEnemy( mortarfaketarget ) + thread MortarSpectreHarvesterSiege( spectre ) + + spectre.SetOrigin( mortarPosition.origin + MORTAR_SPECTRE_POSITION_OFFSETS[i] ) //Teleport them if they wander around which sometimes happens + if ( i++ >= MORTAR_SPECTRE_POSITION_OFFSETS.len() ) //Crash protect if Spectre Squad has more than 4 + i = 0 + } + } +} + +void function MortarSpectreMoveToMortarPosition( entity spectre, entity signaler, vector position ) +{ + spectre.EndSignal( "OnDeath" ) + spectre.EndSignal( "OnDestroy" ) + spectre.EndSignal( "OnLeeched" ) + + spectre.AssaultPointClamped( position ) + spectre.AssaultSetGoalRadius( spectre.GetMinGoalRadius() ) + spectre.AssaultSetGoalHeight( 128 ) + spectre.AssaultSetFightRadius( 0 ) + spectre.SetLookDistOverride( MORTAR_SPECTRE_SIGHT_DISTANCE ) + spectre.EnableNPCFlag( NPC_NO_WEAPON_DROP | NPC_NEW_ENEMY_FROM_SOUND | NPC_TEAM_SPOTTED_ENEMY ) + spectre.DisableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_USE_SHOOTING_COVER | NPC_ALLOW_PATROL | NPC_ALLOW_FLEE ) + + spectre.WaitSignal( "OnFinishedAssault" ) + + //spectre.Minimap_Hide( TEAM_IMC, null ) + //spectre.Minimap_Hide( TEAM_MILITIA, null ) + signaler.Signal( "BeginMortarAttack" ) +} + +void function MortarSpectreSquadDeathThink( array spectres, entity signaler, StationaryAIPosition mortarPosition ) +{ + int numAlive = spectres.len() + while ( numAlive != 0 ) + { + WaitFrame() + numAlive = spectres.len() + foreach ( entity spectre in spectres ) + { + if ( IsValid( spectre ) && IsAlive( spectre ) && spectre.GetTeam() == TEAM_IMC ) + continue + numAlive-- + } + } + signaler.Destroy() + ReleaseStationaryAIPosition( mortarPosition ) //Free the spot if everyone died +} + +void function MortarIconCloakCheck( entity mortaricon, array spectres ) +{ + mortaricon.EndSignal( "OnDestroy" ) + + while( IsValid( mortaricon ) ) + { + bool squadCloaked = true + foreach( entity spectre in spectres ) + { + if ( IsValid( spectre ) && IsAlive( spectre ) && !IsCloaked( spectre ) && spectre.GetTeam() == TEAM_IMC ) + squadCloaked = false + } + if( squadCloaked ) + { + mortaricon.SetAngles( < 0, 1, 0> ) + mortaricon.Minimap_Hide( TEAM_MILITIA, null ) + } + else + { + mortaricon.SetAngles( < 0, 0, 0> ) + mortaricon.Minimap_AlwaysShow( TEAM_MILITIA, null ) + } + wait 0.5 + } +} + +void function MortarShieldCloakCheck( entity mortarshield, array spectres ) +{ + mortarshield.EndSignal( "OnDestroy" ) + + while( IsValid( mortarshield ) ) + { + bool squadCloaked = true + foreach( entity spectre in spectres ) + { + if ( IsValid( spectre ) && IsAlive( spectre ) && !IsCloaked( spectre ) && spectre.GetTeam() == TEAM_IMC ) + squadCloaked = false + } + + if( squadCloaked ) + EntFireByHandle( mortarshield.e.shieldWallFX, "Stop", "", 0, null, null ) + + else + EntFireByHandle( mortarshield.e.shieldWallFX, "Start", "", 0, null, null ) + + wait 0.5 + } +} + +void function MortarSpectreHarvesterSiege( entity npc ) //Swap between Archer or primary if the Harvester is the Target +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + npc.EndSignal( "OnLeeched" ) + + string originalWeaponClassName + array originalWeaponMods + array weapons = npc.GetMainWeapons() + if ( weapons.len() ) + { + entity weapon = weapons[0] + if ( IsValid( weapon ) ) + { + originalWeaponClassName = weapon.GetWeaponClassName() + originalWeaponMods = weapon.GetMods() + } + } + + OnThreadEnd( + function () : ( npc, originalWeaponClassName, originalWeaponMods ) + { + if( IsValid( npc ) && IsAlive( npc ) ) + { + array primaryWeapons = npc.GetMainWeapons() + if( primaryWeapons.len() ) + { + entity primarygun = primaryWeapons[0] + if( IsValid( primarygun ) && primarygun.GetWeaponClassName() == "mp_weapon_rocket_launcher" ) + { + npc.TakeWeapon( primarygun.GetWeaponClassName() ) + npc.GiveWeapon( originalWeaponClassName, originalWeaponMods ) + } + } + } + } + ) + + while( npc.GetTeam() == TEAM_IMC ) //Counts only for non-hacked Spectres + { + entity enemy = npc.GetEnemy() + entity closestEnemy = npc.GetClosestEnemy() + array primaryWeapons = npc.GetMainWeapons() + + if( IsValid( enemy ) && enemy != npc.ai.carryBarrel && Distance( enemy.GetOrigin(), npc.GetOrigin() ) > MORTAR_SPECTRE_SIGHT_DISTANCE ) + { + npc.ClearAllEnemyMemory() + npc.SetHearingSensitivity( 0 ) + } + + if( IsValid( closestEnemy ) && IsAlive( closestEnemy ) && npc.CanSee( closestEnemy ) && Distance( closestEnemy.GetOrigin(), npc.GetOrigin() ) < MORTAR_SPECTRE_SIGHT_DISTANCE ) + { + if( enemy == npc.ai.carryBarrel ) + { + npc.ClearEnemy() + npc.SetEnemy( closestEnemy ) + } + npc.SetHearingSensitivity( 1 ) + } + + if( enemy == null || IsValid( enemy ) && !npc.CanSee( enemy ) && enemy != npc.ai.carryBarrel ) + { + npc.SetEnemy( npc.ai.carryBarrel ) + npc.LockEnemy( npc.ai.carryBarrel ) + } + + if( primaryWeapons.len() ) + { + entity primarygun = primaryWeapons[0] + if( IsValid( primarygun ) ) + { + if( enemy == npc.ai.carryBarrel ) + { + if( primarygun.GetWeaponClassName() != "mp_weapon_rocket_launcher" ) + { + npc.TakeWeapon( primarygun.GetWeaponClassName() ) + entity mortararcher = npc.GiveWeapon( "mp_weapon_rocket_launcher", ["fd_mortar_mode"] ) + mortararcher.w.missileFiredCallback = MortarMissileFiredCallback + } + } + + else + { + if( primarygun.GetWeaponClassName() != originalWeaponClassName ) + { + npc.TakeWeapon( primarygun.GetWeaponClassName() ) + npc.GiveWeapon( originalWeaponClassName, originalWeaponMods ) + } + } + } + } + wait 0.5 + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_titans.gnut index 08598808a..f589402d7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_mortar_titans.gnut @@ -16,9 +16,9 @@ global function MortarTitanStopAttack //global function MortarAIWaitToEngage const float MORTAR_TITAN_ABORT_ATTACK_HEALTH_FRAC = 0.90 // will stop mortar attack if he's health gets below 90% of his current health. -const float MORTAR_TITAN_POSITION_SEARCH_RANGE = 1024 //3072 // How far away from his spawn point a mortar titan will look for positions to mortar from. +const float MORTAR_TITAN_POSITION_SEARCH_RANGE = 8192 // How far away from his spawn point a mortar titan will look for positions to mortar from. const float MORTAR_TITAN_ENGAGE_DELAY = 3.0 // How long before a mortar titan start to attack the generator if he's taken damage getting to his mortar position. -const float MORTAR_TITAN_REENGAGE_DELAY = 7.0 // How long before a mortar titan goes back to attacking the generator after breaking of an attack. +const float MORTAR_TITAN_REENGAGE_DELAY = 7.0 // How long before a mortar titan goes back to attacking the generator after breaking of an attack. // -------------------------------------------------------------------- // MORTAR TITAN LOGIC @@ -73,7 +73,7 @@ void function MortarMissileThink( entity missile, entity weaponOwner ) entity targetEnt = weaponOwner.ai.mortarTarget missile.DamageAliveOnly( true ) - missile.kv.lifetime = 6.0 + missile.kv.lifetime = 10.0 missile.s.mortar <- true vector startPos = missile.GetOrigin() @@ -100,14 +100,14 @@ void function MortarMissileThink( entity missile, entity weaponOwner ) { float frac = min( 1, pow( ( Time() - startTime ) / estTravelTime, 2.0 ) ) - if ( frac > 1.0 ) - break + if ( frac > 1.0 ) + break float homingSpeed = GraphCapped( frac, 0, 1, homingSpeedMin, homingSpeedMax ) - missile.SetHomingSpeeds( homingSpeed, 0 ) + missile.SetHomingSpeeds( homingSpeed, 0 ) - wait 0.25 + wait 0.25 } missile.ClearMissileTargetPosition() @@ -304,12 +304,12 @@ void function MortarTitanThink( entity titan, entity generator ) WaitTillHotDropComplete( titan ) float minEngagementDuration = 5 - StationaryAIPosition ornull mortarPosition = GetRandomStationaryPosition( titan.GetOrigin(), MORTAR_TITAN_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.MORTAR_TITAN ) + StationaryAIPosition ornull mortarPosition = GetClosestAvailableStationaryPosition( titan.GetOrigin(), MORTAR_TITAN_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.MORTAR_TITAN ) while ( mortarPosition == null ) { // incase all stationary titan positions are in use wait for one to become available wait 5 - mortarPosition = GetRandomStationaryPosition( titan.GetOrigin(), MORTAR_TITAN_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.MORTAR_TITAN ) + mortarPosition = GetClosestAvailableStationaryPosition( titan.GetOrigin(), MORTAR_TITAN_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.MORTAR_TITAN ) } expect StationaryAIPosition( mortarPosition ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_nuke_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_nuke_titans.gnut index 0d4b43c92..56aaaca55 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_nuke_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_nuke_titans.gnut @@ -9,9 +9,11 @@ const NUKE_TITAN_RANGE_CHECK_SLEEP_SECS = 1.0 void function AutoTitan_SelfDestruct( entity titan ) { + titan.Anim_Stop() if ( titan.ContextAction_IsBusy() ) titan.ContextAction_ClearBusy() + titan.SetNPCMoveSpeedScale( 0.01 ) thread TitanEjectPlayer( titan ) } @@ -33,6 +35,9 @@ void function NukeTitanSeekOutGenerator( entity titan, entity generator ) titan.EndSignal( "OnDeath" ) titan.EndSignal( "OnDestroy" ) titan.EndSignal( "Doomed" ) + // should fix crash with invalid generator? + generator.EndSignal( "OnDeath" ) + generator.EndSignal( "OnDestroy" ) WaitSignal( titan, "FD_ReachedHarvester", "OnFailedToPath" ) @@ -58,7 +63,7 @@ void function NukeTitanSeekOutGenerator( entity titan, entity generator ) { titan.SetEnemy( generator ) thread AssaultOrigin( titan, validPos[0], goalRadius ) - titan.AssaultSetFightRadius( goalRadius ) + titan.AssaultSetFightRadius( 0 ) // dont want to set a fight radius because then the nuke titan will stop and shoot wait 0.5 @@ -107,8 +112,10 @@ void function AutoTitan_NuclearPayload_PostDamageCallback( entity titan, var dam return } + #if SERVER && DEV printt( "NUKE TITAN DOOMED TRIGGER HEALTH REACHED, NUKING! Health:", titan.s.doomedStateNukeTriggerHealth ) - + #endif + thread AutoTitan_SelfDestruct( titan ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_sniper_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_sniper_titans.gnut index 37b891699..62123e0d7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_sniper_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_sniper_titans.gnut @@ -1 +1,165 @@ -//fuck \ No newline at end of file +untyped + +global function MoveToSniperPosition +global function SniperTitanThink + +const float SNIPER_TITAN_POSITION_SEARCH_RANGE = 8192 + + + +void function MoveToSniperPosition( entity titan, vector origin, entity target ) +{ + titan.EndSignal( "OnSyncedMeleeVictim" ) + titan.EndSignal( "OnDeath" ) + titan.EndSignal( "OnDestroy" ) + target.EndSignal( "OnDeath" ) + target.EndSignal( "OnDestroy" ) + + titan.SetHearingSensitivity( 0 ) + titan.EnableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + + float goalRadius = titan.GetMinGoalRadius() + + OnThreadEnd( + function() : ( titan ) + { + if ( !IsValid( titan ) ) + return + + local classname = titan.GetClassName() + titan.DisableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + } + ) + + local tries = 0 + while( true ) + { + local dist = Distance( titan.GetOrigin(), origin ) + if ( dist <= goalRadius * 2 ) + break + + printt( "Sniper titan moving toward his goal", dist, tries++ ) + titan.AssaultPoint( origin ) + titan.AssaultSetGoalRadius( goalRadius ) + titan.AssaultSetFightRadius( 0 ) + local result = WaitSignal( titan, "OnFinishedAssault", "OnEnterGoalRadius" ) + printt( "Sniper titan done moving into position") + } +} + +void function SniperTitanThink( entity titan, entity generator) +{ + titan.EndSignal( "OnSyncedMeleeVictim" ) + titan.EndSignal( "OnDeath" ) + titan.EndSignal( "OnDestroy" ) + generator.EndSignal( "OnDeath" ) + generator.EndSignal( "OnDestroy" ) + + entity soul = titan.GetTitanSoul() + soul.EndSignal( "OnDestroy" ) + + titan.SetScriptName( "sniper_titan" ) + + WaitTillHotDropComplete( titan ) + + float minEngagementDuration = 5 + StationaryAIPosition ornull sniperPosition = GetClosestAvailableStationaryPosition( titan.GetOrigin(), SNIPER_TITAN_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.SNIPER_TITAN ) + while ( sniperPosition == null ) + { + // incase all stationary titan positions are in use wait for one to become available + wait 5 + sniperPosition = GetClosestAvailableStationaryPosition( titan.GetOrigin(), SNIPER_TITAN_POSITION_SEARCH_RANGE, eStationaryAIPositionTypes.SNIPER_TITAN ) + } + + expect StationaryAIPosition( sniperPosition ) + + ClaimStationaryAIPosition( sniperPosition ) + + OnThreadEnd( + function() : ( sniperPosition ) + { + // release sniper position when dead + ReleaseStationaryAIPosition( sniperPosition ) + } + ) + + titan.SetEnemyChangeCallback( EnemyChanged ) + + while( true ) + { + WaitFrame() + vector origin = sniperPosition.origin + waitthread MoveToSniperPosition( titan, origin, generator ) + + thread SniperTitanAttack( titan, generator ) + + waitthread WaitForInterruption( titan, generator ) + } +} + +void function EnemyChanged( entity titan ) +{ + entity enemy = titan.GetEnemy() + if ( !IsValid( enemy ) ) // if you have no enemy, focus on attacking the harvester + thread SniperTitanAttack( titan, fd_harvester.harvester ) +} + +function SniperTitanAttack( entity titan, entity target ) +{ + titan.EndSignal( "OnSyncedMeleeVictim" ) + titan.EndSignal( "OnDeath" ) + titan.EndSignal( "OnDestroy" ) + + OnThreadEnd( + function() : ( titan ) + { + if ( !IsValid( titan ) ) + return + } + ) + + if( IsValid( target ) ) + titan.SetEnemy( target ) +} + +void function WaitForInterruption( entity titan ,entity generator) +{ + Assert( IsNewThread(), "Must be threaded off" ) + + titan.EndSignal( "OnSyncedMeleeVictim" ) + titan.EndSignal( "OnDeath" ) + titan.EndSignal( "OnDestroy" ) + generator.EndSignal( "OnDeath" ) + generator.EndSignal( "OnDestroy" ) + + entity soul = titan.GetTitanSoul() + soul.EndSignal( "OnDestroy" ) + + float playerProximityDistSqr = pow( 256, 2 ) + float healthBreakOff = ( titan.GetHealth() + soul.GetShieldHealth() ) * 0.9 + + while( true ) + { + if ( IsEnemyWithinDist( titan, playerProximityDistSqr ) ) + break + if ( ( titan.GetHealth() + soul.GetShieldHealth() ) < healthBreakOff ) + break + wait 1 + } + + titan.ClearEnemy() +} + +bool function IsEnemyWithinDist( entity titan, float dist ) +{ + vector origin = titan.GetOrigin() + array players = GetPlayerArrayOfEnemies_Alive( titan.GetTeam() ) + + foreach( player in players ) + { + if ( DistanceSqr( player.GetOrigin(), origin ) < dist ) + return true + } + + return false +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut index adf0e1b45..f9e01f266 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut @@ -336,7 +336,7 @@ bool function AssignNPCAppropriateWeaponFromWeapons( entity npc, array w // first try to find an appropriate weapon foreach ( weapon in weapons ) { - bool isAntiTitan = weapon.GetWeaponType() == WT_ANTITITAN + bool isAntiTitan = weapon.GetWeaponInfoFileKeyField( "holster_type" ) == "anti_titan" if ( isAntiTitan == isRocketTarget ) { // found a weapon to use @@ -373,7 +373,7 @@ void function OnEnemyChanged_TryHeavyArmorWeapon( entity npc ) return } - bool isActiveWeapon_AntiTitan = activeWeapon.GetWeaponType() == WT_ANTITITAN + bool isActiveWeapon_AntiTitan = activeWeapon.GetWeaponInfoFileKeyField( "holster_type" ) == "anti_titan" // already using an appropriate weapon? if ( isActiveWeapon_AntiTitan == isRocketTarget ) @@ -398,7 +398,7 @@ void function TrySpottedCallout( entity guy, entity enemy ) if ( enemy.IsTitan() ) { - if ( IsSpectre( guy ) ) //Spectre callouts + if ( IsSpectre( guy ) ) // Spectre callouts { #if SPECTRE_CHATTER_MP_ENABLED PlaySpectreChatterMPLine( guy, "diag_imc_spectre_gs_spotclosetitancall_01" ) @@ -410,7 +410,7 @@ void function TrySpottedCallout( entity guy, entity enemy ) #endif } - else //Grunt callouts + else if ( IsGrunt( guy ) ) // Grunt callouts { #if GRUNT_CHATTER_MP_ENABLED PlayGruntChatterMPLine( guy, "bc_enemytitanspotcall" ) @@ -419,7 +419,7 @@ void function TrySpottedCallout( entity guy, entity enemy ) } else if ( enemy.IsPlayer() ) { - if ( IsSpectre( guy ) ) //Spectre callouts + if ( IsSpectre( guy ) ) // Spectre callouts { #if SPECTRE_CHATTER_MP_ENABLED PlaySpectreChatterMPLine( guy, "diag_imc_spectre_gs_engagepilotenemy_01_1" ) @@ -430,7 +430,7 @@ void function TrySpottedCallout( entity guy, entity enemy ) PlaySpectreChatterToAll( "spectre_gs_spotenemypilot_01_1", guy ) #endif } - else //Grunt callouts + else if ( IsGrunt( guy ) ) // Grunt callouts { #if GRUNT_CHATTER_MP_ENABLED if ( isClose ) @@ -442,7 +442,7 @@ void function TrySpottedCallout( entity guy, entity enemy ) } else if ( IsSuperSpectre( enemy ) ) { - if ( !IsSpectre( guy ) ) //Spectre callouts + if ( IsGrunt( guy ) ) // Grunt callouts { #if GRUNT_CHATTER_MP_ENABLED PlayGruntChatterMPLine( guy, "bc_reactEnemyReaper" ) @@ -451,7 +451,7 @@ void function TrySpottedCallout( entity guy, entity enemy ) } else { - if ( !IsSpectre( guy ) ) //Spectre callouts + if ( IsGrunt( guy ) ) { #if GRUNT_CHATTER_MP_ENABLED PlayGruntChatterMPLine( guy, "bc_reactEnemySpotted" ) @@ -460,7 +460,6 @@ void function TrySpottedCallout( entity guy, entity enemy ) } } - ////////////////////////////////////////////////////////// string function GetPlayerSpectreSquadName( entity player ) { @@ -799,5 +798,4 @@ function SetGlobalNPCHealth( healthValue ) //Debug, for trailer team npc.SetMaxHealth( healthValue ) npc.SetHealth( healthValue ) } -} - +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_spawn.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_spawn.gnut index 7e4d2cddf..8599f4294 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_spawn.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_spawn.gnut @@ -223,7 +223,7 @@ entity function CreateOgre( int team, vector origin, vector angles, array settingsMods = [] ) { entity npc = CreateNPCTitan( "titan_stryder", team, origin, angles, settingsMods ) - SetSpawnOption_AISettings( npc, "npc_titan_arc" ) + SetSpawnOption_AISettings( npc, "npc_titan_stryder_leadwall_arc" ) return npc } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stalker.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stalker.gnut index f49560e02..5d7d221f1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stalker.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stalker.gnut @@ -1,7 +1,9 @@ +untyped global function AiStalker_Init global function GetDeathForce global function StalkerGearOverloads global function StalkerMeltingDown +global function FDStalkerThink global function IsStalkerLimbBlownOff @@ -157,6 +159,84 @@ void function StalkerOnDamaged_Internal( entity npc, var damageInfo ) npc.SetActivityModifier( ACT_MODIFIER_STAGGER, true ) } } + if( GameRules_GetGameMode() == FD ) + thread StalkerSprint( npc, damageInfo ) +} + +void function StalkerSprint( entity npc, var damageInfo ) +{ + npc.EndSignal("OnDeath") + npc.EndSignal("OnDestroy") + float damage = DamageInfo_GetDamage( damageInfo ) + + if (!IsCrawling(npc)&&( npc.GetHealth() - damage < 50 || npc.GetHealth() <= 80)) + { + StalkerSetSprintStance( npc ) + } +} + +void function FDStalkerThink( entity npc, entity generator ) +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + generator.EndSignal( "OnDeath" ) + generator.EndSignal( "OnDestroy" ) + npc.s.isSprinting <- false + thread FDStalkerGetsStunned( npc ) + + if( GetMapName().find( "mp_lf_" ) != null ) //Stalkers already sprints directly on Live Fire maps to up the challenge a bit + { + if( !IsCrawling( npc ) && !npc.s.isSprinting ) + StalkerSetSprintStance( npc ) + } + + while ( IsAlive( npc ) ) + { + WaitFrame() + + // cant sprint with 1 leg + if ( Distance2D( npc.GetOrigin(), generator.GetOrigin() ) < 1024 ) + { + if( !IsCrawling( npc ) && !npc.s.isSprinting ) + StalkerSetSprintStance( npc ) + + npc.AssaultPointClamped( generator.GetOrigin() ) + } + + // upped from 230 to more accurately mimic vanilla i think? + if ( Distance2D( npc.GetOrigin(), generator.GetOrigin() ) > 275 ) + continue + + break + } + + thread StalkerGearOverloads( npc ) +} + +void function FDStalkerGetsStunned( entity npc ) +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + npc.WaitSignal( "ArcStunned" ) + + if( IsCrawling(npc) ) + return + + StalkerSetSprintStance( npc ) +} + +void function StalkerSetSprintStance( entity npc ) +{ + entity weapon = npc.GetActiveWeapon() + if ( IsValid( weapon ) ) + npc.TakeActiveWeapon() // when stalkers fall over on harvester they will randomly shoot their guns, we don't want that. + + npc.EnableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + npc.SetCapabilityFlag( bits_CAP_MOVE_SHOOT | bits_CAP_WEAPON_RANGE_ATTACK1 | bits_CAP_AIM_GUN, false ) + npc.EnableNPCFlag( NPC_DISABLE_SENSING | NPC_IGNORE_ALL ) + npc.ClearMoveAnim() + npc.SetMoveAnim( "sp_spectre_sprint_F" ) + npc.s.isSprinting = true } bool function TryDismemberStalker( entity npc, var damageInfo, entity attacker, int hitGroup ) @@ -261,10 +341,13 @@ bool function StalkerMeltingDown( entity npc ) void function StalkerGearOverloads( entity npc, entity attacker = null ) { Assert( !StalkerMeltingDown( npc ) ) - + + if ( npc.Anim_IsActive() ) + npc.Anim_Stop() + if ( !IsCrawling( npc ) && StalkerCanCrawl( npc ) ) thread FallAndBecomeCrawlingStalker( npc ) - + int bodyGroup = npc.FindBodyGroup( "gear" ) // hide gear @@ -603,4 +686,4 @@ vector function GetDeathForce() vector angles = vector forward = AnglesToForward( angles ) return forward * RandomFloatRange( 0.25, 0.75 ) -} \ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut index 50b6cc759..0d605820d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut @@ -5,6 +5,7 @@ global function GetRandomStationaryPosition global function GetClosestAvailableStationaryPosition global function ClaimStationaryAIPosition global function ReleaseStationaryAIPosition +global function DebugDrawStationaryAiPositions global enum eStationaryAIPositionTypes { @@ -136,7 +137,7 @@ void function ValidateAndFinalizePendingStationaryPositions() } } -StationaryAIPosition function GetClosestAvailableStationaryPosition( vector origin, float maxDist, int type ) +StationaryAIPosition ornull function GetClosestAvailableStationaryPosition( vector origin, float maxDist, int type ) { array resultArray = [] @@ -167,14 +168,12 @@ StationaryAIPosition function GetClosestAvailableStationaryPosition( vector orig // if too far, throw warning and continue search beyond maxDist if ( result.distanceSqr > maxDistSqr ) - { CodeWarning( "Couldn't find a mortar position within " + maxDist + " units for type " + type + " around " + origin.tostring() + " that wasn't in use. Expanding Search. Add more AddStationaryTitanPositions to the map near this point." ) - } return position } - - unreachable + + return null //Unreachable gives a script crash, returning null allows the while loops to keep going without that } StationaryAIPosition function GetRandomStationaryPosition( vector origin, float maxDist, int type ) @@ -258,4 +257,44 @@ int function DistanceCompareClosestForStationaryAIPosition( ArrayDistanceEntryFo return -1 return 0; -} \ No newline at end of file +} + + +void function DebugDrawStationaryAiPositions( int typeMask ) +{ + thread DebugDrawStationaryAiPositions_thread( typeMask ) +} + + +void function DebugDrawStationaryAiPositions_thread( int typeMask ) +{ + while( true ) + { + for( int i = 0; i < 4; i++ ) + { + if( ( 1 << i ) & typeMask ) + foreach( StationaryAIPosition a in file.stationaryPositions[i] ) + { + switch( i ) + { + case 0: + DebugDrawSphere( a.origin, 50, 255, 255, 0,false, 0.5 ) + case 1: + DebugDrawSphere( a.origin, 50, 0, 255, 255, false, 0.5 ) + case 2: + DebugDrawSphere( a.origin, 50, 0, 0, 255, false, 0.5 ) + case 3: + DebugDrawSphere( a.origin, 50, 255, 0, 255, false, 0.5 ) + } + + if( a.inUse ) + DebugDrawSphere( a.origin, 40, 255, 0, 0, false, 0.5 ) + else + DebugDrawSphere( a.origin, 40, 0, 255, 0, false, 0.5 ) + + } + } + wait 0.4 + } + +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_suicide_spectres.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_suicide_spectres.gnut index f8e0652ce..83a57525f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_suicide_spectres.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_suicide_spectres.gnut @@ -64,6 +64,7 @@ void function SuicideSpectres_Init() ###### ######## ## ####### ## \************************************************************************************************/ + void function MakeSuicideSpectre( entity spectre ) { spectre.SetAimAssistAllowed( true ) @@ -122,6 +123,7 @@ void function FragDroneDeath_Think( entity spectre, var damageInfo ) int damageDef = GetDamageDefForFragDrone( spectre ) RadiusDamage_DamageDefSimple( damageDef, pos, attackerEnt, spectre, 0 ) + EmitSoundAtPosition( spectre.GetTeam(), pos, expSFX ) CreateShake( pos, 10, 105, 1.25, 768 ) StartParticleEffectInWorld( expFX, fxOrg, Vector( 0, 0, 0 ) ) @@ -462,7 +464,10 @@ void function SpectreOverloads( entity spectre ) } else { + spectre.SetNPCMoveSpeedScale( 0.01 ) + spectre.Anim_Stop() string anim = "sp_suicide_spectre_explode_stand" + var overrideAnim = spectre.Dev_GetAISettingByKeyField( "OverrideOverloadAnim" ) if ( overrideAnim != null ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret.gnut index 738133856..847e0794b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret.gnut @@ -2,10 +2,24 @@ global function AiTurret_Init global function GetMegaTurretLinkedToPanel global function MegaTurretUsabilityFunc global function SetUsePromptForPanel +global function IsTurretActive +global function TurretRefundThink +global function RevivableTurret_DamageCallback +global function HeavyTurret_DamageCallback +global function RepairTurret_WaveBreak +global function AddTurretRepairCallback -void function AiTurret_Init() +struct { + array turretRepairCallbacks +} file +void function AiTurret_Init() +{ + RegisterSignal( "TurretOffline" ) + PrecacheModel( $"models/robots/turret_rocket/turret_rocket.mdl" ) + + AddSpawnCallback( "npc_turret_sentry", OnTurretSpawn ) } entity function GetMegaTurretLinkedToPanel( entity panel ) @@ -21,4 +35,171 @@ string function MegaTurretUsabilityFunc( var turret, var panel ) void function SetUsePromptForPanel( var panel, var turret ) { +} + +void function OnTurretSpawn( entity turret ) +{ + turret.e.spawnTime = Time() +} + +bool function IsTurretActive( entity turret ) +{ + // ----- Turret State ----- // + // TURRET_SEARCHING , TURRET_INACTIVE , TURRET_ACTIVE , TURRET_DEPLOYING , TURRET_RETIRING , TURRET_DEAD // + + switch( turret.GetTurretState() ) + { + case TURRET_DEPLOYING: + case TURRET_SEARCHING: + case TURRET_ACTIVE: + return true + } + return false +} + +void function TurretRefundThink( entity turret ) +{ + turret.EndSignal( "OnDestroy" ) + turret.EndSignal( "OnDeath" ) + turret.EndSignal( "CancelRefund" ) + turret.EndSignal( "TurretOffline" ) + + while( turret.e.burnReward == "" || !IsTurretActive( turret ) ) + WaitFrame() + + turret.SetUsable() + turret.SetUsableByGroup( "owner pilot" ) + turret.SetUsePrompts( "#REFUND_HOLD_USE", "#REFUND_PRESS_USE" ) + + entity player = expect entity( turret.WaitSignal( "OnPlayerUse" ).player ) + + if ( turret.e.burnReward == "" ) + return + + BurnMeter_GiveRewardDirect( player, turret.e.burnReward ) + entity weapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) + + // Defensive: meaning the boost didn't make it to the inventory for some reason + if ( weapon == null ) + return + + weapon.w.savedKillCount = int( turret.kv.killCount ) + turret.DisableTurret() + turret.Signal( "StopTurretLaser" ) + weapon.e.fd_roundDeployed = turret.e.fd_roundDeployed + + EmitSoundAtPosition( TEAM_UNASSIGNED, turret.GetOrigin(), "Emplacement_Move_Dissolve" ) + turret.Signal( "BoostRefunded" ) + turret.UnsetUsable() + turret.SetInvulnerable() + turret.Dissolve( ENTITY_DISSOLVE_CORE, Vector( 0, 0, 0 ), 100 ) +} + +void function RevivableTurret_DamageCallback( entity turret, var damageInfo ) +{ + if( turret.GetHealth() <= DamageInfo_GetDamage( damageInfo ) ) + { + turret.Signal( "TurretOffline" ) + turret.SetHealth( 1 ) + turret.SetUsable() + + if ( GetCurrentPlaylistVarInt( "fd_titans_can_repair_turrets", 0 ) == 1 ) + turret.SetUsableByGroup( "friendlies" ) + else + turret.SetUsableByGroup( "friendlies pilot" ) + + turret.SetUsePrompts( "#TURRET_WAKEUP_HOLD_USE", "#TURRET_WAKEUP_PRESS_USE" ) + thread RevivableTurret_Kill( turret ) + thread RevivableTurretThink( turret ) + DamageInfo_SetDamage( damageInfo, 0.0 ) + } +} + +void function HeavyTurret_DamageCallback( entity turret, var damageInfo ) +{ + if( turret.GetHealth() <= DamageInfo_GetDamage( damageInfo ) ) + { + turret.Signal( "TurretOffline" ) + turret.SetHealth( 1 ) + DamageInfo_SetDamage( damageInfo, 0.0 ) + turret.DisableTurret() + turret.EnableNPCFlag( NPC_IGNORE_ALL ) + MakeTurretInvulnerable( turret ) + } +} + +void function RevivableTurretThink( entity turret ) +{ + entity player = expect entity( turret.WaitSignal( "OnPlayerUse" ).player ) + entity owner = turret.GetBossPlayer() + if ( !IsTurretActive( turret ) ) + { + thread RevivableTurret_Revive( turret ) + foreach ( callbackFunc in file.turretRepairCallbacks ) + { + callbackFunc( turret, player, owner ) + } + } +} + +void function RevivableTurret_Revive( entity turret ) +{ + turret.EndSignal( "OnDestroy" ) + + turret.UnsetUsable() + turret.SetHealth( turret.GetMaxHealth() ) + Highlight_ClearFriendlyHighlight( turret ) + Highlight_SetOwnedHighlight( turret, "sp_friendly_hero" ) + turret.Highlight_SetParam( 3, 0, HIGHLIGHT_COLOR_INTERACT ) + turret.EnableTurret() + turret.Anim_Play( "deploy" ) + turret.DisableNPCFlag( NPC_IGNORE_ALL ) + MakeTurretVulnerable( turret ) + turret.SetNoTargetSmartAmmo( true ) + + wait 0.3 + + thread TurretRefundThink( turret ) +} + +void function RevivableTurret_Kill( entity turret ) +{ + turret.EndSignal( "OnDestroy" ) + + entity turretOwner = turret.GetBossPlayer() + if( IsValidPlayer( turretOwner ) ) + PlayFactionDialogueToPlayer( "fd_turretOffline", turretOwner ) + + turret.EnableNPCFlag( NPC_IGNORE_ALL ) + MakeTurretInvulnerable( turret ) + Highlight_SetFriendlyHighlight( turret, "sp_objective_entity" ) + Highlight_SetOwnedHighlight( turret, "sp_objective_entity" ) + turret.Highlight_SetParam( 1, 0, HIGHLIGHT_COLOR_OBJECTIVE ) + turret.Highlight_SetParam( 3, 0, HIGHLIGHT_COLOR_OBJECTIVE ) + turret.DisableTurret() +} + +void function RepairTurret_WaveBreak( entity turret ) +{ + if ( turret.GetHealth() == 1 ) + { + turret.UnsetUsable() + turret.EnableTurret() + turret.Anim_Play("deploy") + turret.DisableNPCFlag( NPC_IGNORE_ALL ) + Highlight_ClearFriendlyHighlight( turret ) + Highlight_SetOwnedHighlight( turret, "sp_friendly_hero" ) + turret.Highlight_SetParam( 3, 0, HIGHLIGHT_COLOR_INTERACT ) + MakeTurretVulnerable( turret ) + turret.SetNoTargetSmartAmmo( true ) + thread TurretRefundThink( turret ) + } + + turret.SetHealth( turret.GetMaxHealth() ) +} + +void function AddTurretRepairCallback( void functionref(entity,entity,entity) callbackFunc ) +{ + Assert (!( file.turretRepairCallbacks.contains( callbackFunc ) )) + file.turretRepairCallbacks.append( callbackFunc ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret_sentry.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret_sentry.gnut index e34b30826..5d0cff0a2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret_sentry.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_turret_sentry.gnut @@ -8,13 +8,14 @@ const SENTRY_TURRET_AIM_FX_BLUE = $"P_wpn_lasercannon_aim_short_blue" void function AiTurretSentry_Init() { PrecacheParticleSystem( DEAD_SENTRY_TURRET_FX ) - //PrecacheParticleSystem( SENTRY_TURRET_AIM_FX_RED ) - //PrecacheParticleSystem( SENTRY_TURRET_AIM_FX_BLUE ) + PrecacheParticleSystem( SENTRY_TURRET_AIM_FX_RED ) + PrecacheParticleSystem( SENTRY_TURRET_AIM_FX_BLUE ) //PrecacheParticleSystem( SENTRY_TURRET_AIM_FX2 ) AddSpawnCallback( "npc_turret_sentry", LightTurretSpawnFunction ) AddDeathCallback( "npc_turret_sentry", LightTurretDeathFX ) + RegisterSignal( "StopTurretLaser" ) //RegisterSignal( "TurretDisabled" ) //RegisterSignal( "HandleTargetDeath" ) //RegisterSignal( "OnPlayerDisconnectResetTurret" ) @@ -55,6 +56,7 @@ void function LightTurretSpawnFunction( entity turret ) void function SentryTurretAimLaser( entity turret ) { + EndSignal( turret, "StopTurretLaser" ) entity fx1 = PlayLoopFXOnEntity( SENTRY_TURRET_AIM_FX_RED, turret, "camera_glow", null, null, ENTITY_VISIBLE_TO_ENEMY ) entity fx2 = PlayLoopFXOnEntity( SENTRY_TURRET_AIM_FX_BLUE, turret, "camera_glow", null, null, ENTITY_VISIBLE_TO_FRIENDLY ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 56750352f..42678c67c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -67,6 +67,7 @@ void function BurnMeter_Init() AddCallback_OnClientConnected( InitBurncardsForLateJoiner ) AddCallback_OnPlayerRespawned( StartPhaseRewindLifetime ) + AddCallback_OnPlayerRespawned( InitialisePermenantAmpedWeaponsForPlayer ) AddCallback_OnTitanBecomesPilot( RemoveAmpedWeaponsForTitanPilot ) // necessary signals @@ -163,10 +164,14 @@ string function GetSelectedBurncardRefFromWeaponOrPlayer( entity weapon, entity case "mp_ability_turretweapon": // turret has 2 burncards, antititan and antipilot - if( weapon.HasMod( "burnmeter_at_turret_weapon" ) || weapon.HasMod( "burnmeter_at_turret_weapon_inf" ) ) + if( weapon.HasMod( "burnmeter_at_turret_weapon" ) ) return "burnmeter_at_turret_weapon" - else + else if( weapon.HasMod( "burnmeter_at_turret_weapon_inf" ) ) + return "burnmeter_at_turret_weapon_infinite" + else if( weapon.HasMod( "burnmeter_ap_turret_weapon" ) ) return "burnmeter_ap_turret_weapon" + else if( weapon.HasMod( "burnmeter_ap_turret_weapon_inf" ) ) + return "burnmeter_ap_turret_weapon_infinite" // note: cloak and stim both have burn_card_weapon_mod mods, but they aren't used and don't call burncard code at all, likely for tf1 infinite stim/cloak burncards? @@ -248,6 +253,10 @@ void function RunBurnCardUseFunc( entity player, string itemRef ) print( itemRef ) void functionref( entity ) ornull func = BurnReward_GetByRef( itemRef ).rewardAvailableCallback + #if BATTLECHATTER_ENABLED + if( itemRef == "burnmeter_amped_weapons_permanent" || itemRef == "burnmeter_amped_weapons" ) + PlayBattleChatterLine( player, "bc_pAmp" ) + #endif if ( func != null ) ( expect void functionref( entity ) ( func ) )( player ) else @@ -302,10 +311,10 @@ void function PlayerUsesAmpedWeaponsBurncard( entity player ) void function PlayerUsesAmpedWeaponsBurncardThreaded( entity player ) { player.Signal( "StopAmpedWeapons" ) - player.EndSignal("StopAmpedWeapons") + player.EndSignal( "StopAmpedWeapons" ) array weapons = player.GetMainWeapons() - //weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here + weapons.extend( player.GetOffhandWeapons() ) foreach ( entity weapon in weapons ) { if( weapon.GetWeaponPrimaryClipCountMax() > 0 ) @@ -347,22 +356,32 @@ void function PlayerUsesAmpedWeaponsBurncardThreaded( entity player ) void function RemoveAmpedWeaponsForTitanPilot( entity player, entity titan ) { - foreach ( entity weapon in player.GetMainWeapons() ) - foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) ) - weapon.RemoveMod( mod ) + if ( !( "hasPermenantAmpedWeapons" in player.s ) || !player.s.hasPermenantAmpedWeapons ) + foreach ( entity weapon in player.GetMainWeapons() ) + foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) ) + weapon.RemoveMod( mod ) } void function PlayerUsesSmartPistolBurncard( entity player ) { - // take secondary weapon - array sidearms = player.GetMainWeapons() - if ( sidearms.len() > 1 ) - player.TakeWeaponNow( sidearms[ 1 ].GetWeaponClassName() ) // take secondary weapon - - player.GiveWeapon( "mp_weapon_smart_pistol" ) + array weapons = player.GetMainWeapons() + bool gaveSmartPistol = false + foreach ( entity weaponEnt in weapons ) + { + if ( weaponEnt.GetWeaponInfoFileKeyField( "menu_category" ) != "pistol" ) + continue + + player.TakeWeaponNow( weaponEnt.GetWeaponClassName() ) + player.GiveWeapon( "mp_weapon_smart_pistol" ) + gaveSmartPistol = true + } + if ( !gaveSmartPistol ) // Failsafe in case player previously replaced their sidearm with any primary or AT + { + if ( weapons.len() > 1 ) + player.TakeWeaponNow( weapons[1].GetWeaponClassName() ) + player.GiveWeapon( "mp_weapon_smart_pistol" ) + } player.SetActiveWeaponByName( "mp_weapon_smart_pistol" ) - - // do we need to track the player losing smart pistol, then give their old weapon back? idk not implementing for now, check later } void function PlayerUsesRadarJammerBurncard( entity player ) @@ -537,7 +556,6 @@ void function PutPhaseRewindedPlayerInSafeSpot( entity player, int severity ) return return PutPhaseRewindedPlayerInSafeSpot( player, severity + 5 ) - } void function PlayerUsesNukeTitanBurncard( entity player ) @@ -570,10 +588,17 @@ void function PlayerUsesNukeBurncardThreaded( entity player ) thread TitanEjectPlayer( titan, true ) } +void function InitialisePermenantAmpedWeaponsForPlayer( entity player ) +{ + player.s.hasPermenantAmpedWeapons <- false +} + void function PlayerUsesPermanentAmpedWeaponsBurncard( entity player ) { + player.s.hasPermenantAmpedWeapons = true + array weapons = player.GetMainWeapons() - //weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here + weapons.extend( player.GetOffhandWeapons() ) foreach ( entity weapon in weapons ) { weapon.RemoveMod( "silencer" ) // both this and the burnmod will override firing fx, if a second one overrides this we crash diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut new file mode 100644 index 000000000..f06725748 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/sh_boost_store.gnut @@ -0,0 +1,782 @@ +global function ShInitBoostStore +global function ShInitBoostStoreForMode +global function GetAvailableBoosts +global function BoostStoreEnabled +global function CanPurchaseBoost +global function CanAffordBoost +global function GetPlaylistBoostCost + +#if CLIENT || SERVER +global function BoostStoreOpen +#endif + +#if SERVER +global function SetBoostPurchaseCallback +global function SetBoostRefundCallback +global function SetTeamReserveInteractCallback +global function AddMoneyToPlayer +global function SetMoneyForPlayer +global function CreateBoostStoreLocation +global function OpenBoostStores +global function CloseBoostStores +global function GetBoostStores +global function BurnRewardRefundThink +global function SetJoinInProgressBonus +#endif + +#if CLIENT +global function ServerCallback_EnableDropshipBoostStore +global function ServerCallback_DisableDropshipBoostStore +global function ServerCallback_BoostStoreTitanHint +#endif + +#if UI +global function UpdatePlayerMoney +global function ServerCallback_UpdateTurretCount +global function ServerCallback_UpdatePlayerHasBattery +global function ServerCallback_UpdateAmpedWeaponState +#endif + +global function GetPlayerMoney +global function GetTeamReserve +global function UpdateTeamReserve + +const int MAX_MONEY = 5000 +const float BOOST_STORE_TRIGGER_RADIUS = 300 +const int BOOST_STORE_DEFAULT_EXCHANGE = 100 + +global struct BoostStoreData +{ + string itemRef + string modesAllowed + string additionalDesc + int cost + bool autoActivate + asset storeIcon + asset lockedStoreIcon + string additionalDescFail +} + +struct +{ + array allBoosts + array availableBoosts + table playerBonusData + int joinInProgressBonus = 0 + array joinInProgressGivenToPlayers + + int teamReserveAmount = 0 + + var boostStoreHintRui + + #if UI + int playerMoney = 0 + int turretCount = 0 + int maxTurretCount = 5 + bool playerHasBattery = false + bool playerHasAmpedWeapons = false + #endif + + array storeLocations + table boostPurchaseExtraChecks + void functionref(entity,BoostStoreData) boostPurchaseCallback + void functionref( entity, string ) boostRefundCallback + void functionref( entity, string, int ) teamReserveDepositOrWithdrawCallback +} file + +void function ShInitBoostStore() +{ + var dataTable = GetDataTable( $"datatable/burn_meter_store.rpak" ) + int len = GetDatatableRowCount( dataTable ) + for ( int i=0; i tokens = split( data.modesAllowed, " " ) + if ( tokens.contains( boostStoreMode ) ) + { + file.availableBoosts.append( data ) + } + } + file.availableBoosts.sort( SortCompareBoostCost ) + //printt( file.availableBoosts.len() ) +} + +int function SortCompareBoostCost( BoostStoreData a, BoostStoreData b ) +{ + int acost = GetPlaylistBoostCost( a.itemRef, a.cost ) + int bcost = GetPlaylistBoostCost( b.itemRef, b.cost ) + + if ( acost > bcost ) + return 1 + + if ( bcost > acost ) + return -1 + + return 0 +} + +array function GetAvailableBoosts() +{ + return file.availableBoosts +} + +bool function CanAffordBoost( entity player, BoostStoreData data ) +{ + int money = GetPlayerMoney( player ) + return money >= GetPlaylistBoostCost( data.itemRef, data.cost ) +} + +bool function CanPurchaseBoost( entity player, BoostStoreData data, bool checkMoney = true ) +{ + bool canBuy = true + + if ( checkMoney ) + canBuy = canBuy && CanAffordBoost( player, data ) + + if ( data.itemRef in file.boostPurchaseExtraChecks ) + { + canBuy = canBuy && file.boostPurchaseExtraChecks[ data.itemRef ]( player ) + } + + return canBuy +} + +#if SERVER +bool function ClientCommand_PurchaseBoost( entity player, array args ) +{ + // bob note: readded this check, why the fuck is it not a check in vanilla + if ( !BoostStoreOpen() ) + return true + + if ( !IsAlive( player ) ) + return true + + if ( player.IsTitan() ) + return true + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return true + + array availableBoosts = GetAvailableBoosts() + + if ( args.len() == 0 ) + return true + + foreach ( data in availableBoosts ) + { + if ( data.itemRef == args[0] ) + { + if ( IsItemLocked( player, data.itemRef ) ) + break + + if ( CanPurchaseBoost( player, data ) ) + { + if ( file.boostPurchaseCallback != null ) + file.boostPurchaseCallback( player, data ) + + AddMoneyToPlayer( player, -1*GetPlaylistBoostCost( data.itemRef, data.cost ) ) + BurnReward burnReward = BurnReward_GetByRef( data.itemRef ) + if ( !data.autoActivate ) + { + BurnMeter_GiveRewardDirect( player, data.itemRef ) + } + else + { + RunBurnCardUseFunc( player, data.itemRef ) + Remote_CallFunction_NonReplay( player, "ServerCallback_RewardUsed", burnReward.id ) + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_Boost_Card_Earned_1P" ) + } + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_InGame_FD_ArmoryPurchase" ) + MessageToTeam( player.GetTeam(), eEventNotifications.FD_BoughtItem, null, player, burnReward.id ) + break + } + } + } + + return true +} + +bool function ClientCommand_Deposit( entity player, array args ) +{ + if ( !BoostStoreOpen() ) + return true + + if ( !IsAlive( player ) ) + return true + + if ( player.IsTitan() ) + return true + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return true + + int depositAmount = minint( file.playerBonusData[ player ], BOOST_STORE_DEFAULT_EXCHANGE ) + file.teamReserveAmount += depositAmount + AddMoneyToPlayer( player, -1*depositAmount ) + + if ( IsValid( file.teamReserveDepositOrWithdrawCallback ) ) + file.teamReserveDepositOrWithdrawCallback( player, "deposit", depositAmount ) + + foreach ( player in GetPlayerArray() ) + { + Remote_CallFunction_UI( player, "ServerCallback_UpdateTeamReserve", file.teamReserveAmount ) + } + + return true +} + + +bool function ClientCommand_Withdraw( entity player, array args ) +{ + if ( !BoostStoreOpen() ) + return true + + if ( !BoostStoreOpen() ) + return true + + if ( !IsAlive( player ) ) + return true + + if ( player.IsTitan() ) + return true + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return true + + if ( GetPlayerMoney( player ) >= MAX_MONEY ) + return true + + int withdrawAmount = minint( file.teamReserveAmount, BOOST_STORE_DEFAULT_EXCHANGE ) + file.teamReserveAmount -= withdrawAmount + AddMoneyToPlayer( player, withdrawAmount ) + + if ( IsValid( file.teamReserveDepositOrWithdrawCallback ) ) + file.teamReserveDepositOrWithdrawCallback( player, "withdraw", withdrawAmount ) + + foreach ( player in GetPlayerArray() ) + { + Remote_CallFunction_UI( player, "ServerCallback_UpdateTeamReserve", file.teamReserveAmount ) + } + + return true +} + +void function AddMoneyToPlayer( entity player, int points ) +{ + SetMoneyForPlayer( player, file.playerBonusData[ player ] + points ) +} + +void function SetMoneyForPlayer( entity player, int points ) +{ + file.playerBonusData[ player ] = int( Clamp( float( points ), 0, MAX_MONEY ) ) + + int bonusPoints = file.playerBonusData[ player ] + int bonusPointStack = int( max( ( bonusPoints - ( bonusPoints % 256 ) ) / 256, 0 ) ) + int bonusPointRemainder = ( bonusPoints % 256 ) + + player.SetPlayerNetInt( "FD_money", bonusPointRemainder ) + player.SetPlayerNetInt( "FD_money256", bonusPointStack ) + player.SetTitle( "$" + bonusPoints ) + + Remote_CallFunction_UI( player, "ServerCallback_UpdateMoney", file.playerBonusData[ player ] ) +} + +void function CreateBoostStoreLocation( int team, vector origin, vector angles, bool showOnMinimap = true ) +{ + if ( !BoostStoreEnabled() ) + return + + entity crate = CreatePropDynamic( MODEL_ATTRITION_BANK, origin, angles, 6 ) + + entity invisibleCrate = CreatePropScript( MODEL_ATTRITION_BANK, origin, angles, 6 ) + SetTargetName( invisibleCrate, "boostStore" ) + SetTeam( invisibleCrate, team ) + invisibleCrate.Hide() + invisibleCrate.NotSolid() + + // just to create an association + crate.SetParent( invisibleCrate ) + + thread PlayAnim( crate, "mh_inactive_idle", crate.GetParent() ) + if ( BoostStoreOpen() ) + thread EnableBoostStoreCrate( crate ) + + crate.SetUsePrompts( "#BOOST_STORE_HOLD_USE", "#BOOST_STORE_PRESS_USE" ) + crate.SetForceVisibleInPhaseShift( true ) + + file.storeLocations.append( crate ) + + if ( showOnMinimap ) + { + invisibleCrate.Minimap_SetObjectScale( MINIMAP_LOADOUT_CRATE_SCALE ) + invisibleCrate.Minimap_SetAlignUpright( true ) + invisibleCrate.Minimap_AlwaysShow( TEAM_IMC, null ) + invisibleCrate.Minimap_AlwaysShow( TEAM_MILITIA, null ) + invisibleCrate.Minimap_SetHeightTracking( true ) + invisibleCrate.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + invisibleCrate.Minimap_SetCustomState( eMinimapObject_prop_script.BOOST_STORE ) + } + if ( !GetGlobalNetBool("boostStoreOpen") ) + { + invisibleCrate.Minimap_Hide( TEAM_IMC, null ) + invisibleCrate.Minimap_Hide( TEAM_MILITIA, null ) + } + + thread CreateBoostStoreHintTrigger( crate ) + thread BoostStoreThink( crate ) +} + +void function EnableBoostStoreCrate( entity crate ) +{ + crate.EndSignal( "OnDestroy" ) + crate.SetUsable() + + entity parentCrate = crate.GetParent() + int team = parentCrate.GetTeam() + if ( team == TEAM_MILITIA || team == TEAM_IMC ) + crate.SetUsableByGroup( "friendlies pilot" ) + else + crate.SetUsableByGroup( "pilot" ) + + SetTeam( crate, team ) + + waitthread PlayAnim( crate, "mh_inactive_2_active", crate.GetParent() ) + thread PlayAnim( crate, "mh_active_idle", crate.GetParent() ) + EmitSoundOnEntity( crate, "Mobile_Hardpoint_Idle" ) +} + +void function DisableBoostStoreCrate( entity crate ) +{ + crate.EndSignal( "OnDestroy" ) + crate.UnsetUsable() + SetTeam( crate, TEAM_UNASSIGNED ) + FadeOutSoundOnEntity( crate, "Mobile_Hardpoint_Idle", 1.0 ) + waitthread PlayAnim( crate, "mh_active_2_inactive", crate.GetParent() ) + thread PlayAnim( crate, "mh_inactive_idle", crate.GetParent() ) +} + +void function CreateBoostStoreHintTrigger( entity crate ) +{ + entity trig = CreateEntity( "trigger_cylinder" ) + trig.SetRadius( BOOST_STORE_TRIGGER_RADIUS ) + trig.SetAboveHeight( 200 ) + trig.SetBelowHeight( 0 ) + trig.SetOrigin( crate.GetOrigin() ) + trig.kv.triggerFilterNpc = "none" + trig.kv.triggerFilterPlayer = "all" + DispatchSpawn( trig ) + + trig.EndSignal( "OnDestroy" ) + crate.EndSignal( "OnDestroy" ) + + OnThreadEnd( + function() : ( trig ) + { + if ( IsValid( trig ) ) + trig.Destroy() + } + ) + + trig.SetEnterCallback( BoostHintTrigEnter ) + + WaitForever() +} + +void function BoostHintTrigEnter( entity trigger, entity ent ) +{ + if ( !ent.IsPlayer() ) + return + if ( !ent.IsTitan() ) + return + if ( !GetGlobalNetBool( "boostStoreOpen" ) ) + return + vector org = trigger.GetOrigin() + Remote_CallFunction_NonReplay( ent, "ServerCallback_BoostStoreTitanHint", org.x, org.y, org.z ) +} + +void function CloseBoostStores() +{ + foreach ( crate in file.storeLocations ) + thread DisableBoostStoreCrate( crate ) + SetGlobalNetBool( "boostStoreOpen", false ) +} + +void function OpenBoostStores() +{ + foreach ( crate in file.storeLocations ) + thread EnableBoostStoreCrate( crate ) + SetGlobalNetBool( "boostStoreOpen", true ) +} + +array function GetBoostStores() +{ + return file.storeLocations +} + +void function BurnRewardRefundThink( entity useEnt, entity ent ) +{ + useEnt.EndSignal( "OnDestroy" ) + ent.EndSignal( "OnDestroy" ) + ent.EndSignal( "OnDeath" ) + ent.EndSignal( "CancelRefund" ) + useEnt.SetUsable() + useEnt.SetUsableByGroup( "owner pilot" ) + useEnt.SetUsePrompts( "#REFUND_HOLD_USE", "#REFUND_PRESS_USE" ) + + entity player = expect entity( useEnt.WaitSignal( "OnPlayerUse" ).player ) + { + if ( ent.e.burnReward == "" ) + return + + BurnMeter_GiveRewardDirect( player, ent.e.burnReward ) + entity weapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) + + // Defensive: meaning the boost didn't make it to the inventory for some reason + if ( weapon == null ) + return + + if ( IsTurret( ent ) ) + { + weapon.w.savedKillCount = int( ent.kv.killCount ) + ent.DisableTurret() + ent.Signal( "StopTurretLaser" ) + } + weapon.e.fd_roundDeployed = ent.e.fd_roundDeployed + + EmitSoundAtPosition( TEAM_UNASSIGNED, ent.GetOrigin(), "Emplacement_Move_Dissolve" ) + ent.Signal( "BoostRefunded" ) + ent.UnsetUsable() + ent.SetInvulnerable() + ent.Dissolve( ENTITY_DISSOLVE_CORE, Vector( 0, 0, 0 ), 100 ) + + if ( file.boostRefundCallback != null ) + file.boostRefundCallback( player, ent.e.burnReward ) + } +} + +void function BoostStoreThink( entity crate ) +{ + while( IsValid( crate ) ) + { + entity player = expect entity( crate.WaitSignal( "OnPlayerUse" ).player ) + if ( IsValid( player ) && Distance( player.GetOrigin(), crate.GetOrigin() ) < BOOST_STORE_TRIGGER_RADIUS ) + OpenBoostStoreMenu( player ) + } +} + +void function OpenBoostStoreMenu( entity player ) +{ + if ( !BoostStoreEnabled() ) + return + + if ( !IsPlayerNearbyAnyBoostStore( player ) ) + return + + CalculatePlayerTurretCount( player ) + Remote_CallFunction_UI( player, "ServerCallback_UpdateMoney", file.playerBonusData[ player ] ) + Remote_CallFunction_UI( player, "ServerCallback_UpdateTeamReserve", file.teamReserveAmount ) + Remote_CallFunction_UI( player, "ServerCallback_UpdatePlayerHasBattery", PlayerHasBattery( player ) ) + Remote_CallFunction_UI( player, "ServerCallback_UpdateAmpedWeaponState", PlayerHasAmpedWeapons( player ) ) + Remote_CallFunction_UI( player, "ServerCallback_OpenBoostStore" ) +} + +bool function IsPlayerNearbyAnyBoostStore( entity player ) +{ + bool playerNearStore = false + foreach ( entity crate in GetBoostStores() ) + { + if ( Distance( player.GetOrigin(), crate.GetOrigin() ) < BOOST_STORE_TRIGGER_RADIUS ) + playerNearStore = true + } + + return playerNearStore +} +#endif + +#if CLIENT +void function ServerCallback_BoostStoreTitanHint( float x, float y, float z ) +{ + vector org = + thread ServerCallback_BoostStoreTitanHint_Internal( org ) +} + +void function ServerCallback_BoostStoreTitanHint_Internal( vector org ) +{ + entity player = GetLocalViewPlayer() + + player.EndSignal( "OnDeath" ) + + float titanHullCompensate = 75.0 + float maxDist = ((BOOST_STORE_TRIGGER_RADIUS+titanHullCompensate) * (BOOST_STORE_TRIGGER_RADIUS+titanHullCompensate)) + float minDot = 0.8 + float fadeTime = 0.25 + float hintTime = 3.5 + float showHintTime = -999.0 + bool hintShowing = false + + OnThreadEnd( + function() : ( ) + { + HidePlayerHint( "#BOOST_STORE_NEED_PILOT_HINT" ) + } + ) + + while ( player.IsTitan() ) + { + float dist = DistanceSqr( org, player.GetOrigin() ) + + bool showHint = false + + if ( dist <= maxDist ) + { + if ( PlayerCanSeePos( player, org, false, 35.0 ) ) + { + if ( Time() - showHintTime + fadeTime >= hintTime ) + { + AddPlayerHint( hintTime, fadeTime, $"", "#BOOST_STORE_NEED_PILOT_HINT" ) + showHintTime = Time() + } + showHint = true + } + } + else + { + return + } + + if ( !showHint && Time() - showHintTime + fadeTime < hintTime ) + { + showHintTime = -999.0 + HidePlayerHint( "#BOOST_STORE_NEED_PILOT_HINT" ) + } + + WaitFrame() + } +} + + +void function OpenBoostStoreMenu( entity player ) +{ + if ( !BoostStoreEnabled() ) + return + + RunUIScript( "OpenBoostStore" ) +} + +void function ServerCallback_EnableDropshipBoostStore() +{ + if ( !BoostStoreEnabled() ) + return + + RegisterButtonPressedCallback( BUTTON_A, OpenBoostStoreMenu ) + RegisterButtonPressedCallback( KEY_SPACE, OpenBoostStoreMenu ) + if ( file.boostStoreHintRui != null ) + RuiDestroyIfAlive( file.boostStoreHintRui ) + file.boostStoreHintRui = CreatePermanentCockpitRui( $"ui/hint_display.rpak" ) + RuiSetString( file.boostStoreHintRui, "hintText", Localize( "#BOOST_STORE_DROPSHIP_PRESS_USE" ) ) +} + +void function ServerCallback_DisableDropshipBoostStore() +{ + if ( !BoostStoreEnabled() ) + return + + if ( file.boostStoreHintRui != null ) + { + RuiDestroyIfAlive( file.boostStoreHintRui ) + DeregisterButtonPressedCallback( BUTTON_A, OpenBoostStoreMenu ) + DeregisterButtonPressedCallback( KEY_SPACE, OpenBoostStoreMenu ) + file.boostStoreHintRui = null + } +} +#endif + +bool function BoostStoreEnabled() +{ + return ( GetCurrentPlaylistVarString( "boost_store_mode", "off" ) != "off" ) +} + +#if CLIENT || SERVER +bool function BoostStoreOpen() +{ + return GetGlobalNetBool("boostStoreOpen" ) +} +#endif + +int function GetTeamReserve() +{ + return file.teamReserveAmount +} + +void function UpdateTeamReserve( int reserveMoney ) +{ + file.teamReserveAmount = reserveMoney +} + + +int function GetPlayerMoney( entity player ) +{ + #if SERVER + return file.playerBonusData[ player ] + #endif + + #if CLIENT + int money = player.GetPlayerNetInt( "FD_money" ) + int money256 = player.GetPlayerNetInt( "FD_money256" ) + return ( money256 * 256 ) + money + #endif + + #if UI + return file.playerMoney + #endif +} + +bool function CheckTooManyTurrets( entity player ) +{ + #if SERVER || CLIENT + return player.GetPlayerNetInt( "burn_numTurrets" ) < GetGlobalNetInt( "burn_turretLimit" ) + #elseif UI + return file.turretCount < file.maxTurretCount + #endif +} + +bool function CheckHasNoBattery( entity player ) +{ + #if SERVER || CLIENT + return !PlayerHasBattery( player ) + #elseif UI + return !file.playerHasBattery + #endif +} + +bool function CheckHasNoAmpedWeapons( entity player ) +{ + #if SERVER || CLIENT + return !PlayerHasAmpedWeapons( player ) + #elseif UI + return !file.playerHasAmpedWeapons + #endif +} + +#if UI +void function ServerCallback_UpdatePlayerHasBattery( bool hasBattery ) +{ + file.playerHasBattery = hasBattery +} + +void function ServerCallback_UpdateAmpedWeaponState( bool hasAmpedWeapons ) +{ + file.playerHasAmpedWeapons = hasAmpedWeapons +} + +void function ServerCallback_UpdateTurretCount( int count, int max ) +{ + file.turretCount = count + file.maxTurretCount = max +} + +void function UpdatePlayerMoney( int money ) +{ + file.playerMoney = money +} +#endif + +int function GetPlaylistBoostCost( string ref, int originalCost ) +{ + int cost = GetCurrentPlaylistVarInt( "override_boost_cost_" + ref, -1 ) + + if ( cost > 0 ) + return cost + + return originalCost +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_conversation_schedule.gnut b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_conversation_schedule.gnut index 089d4b711..579360fee 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_conversation_schedule.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_conversation_schedule.gnut @@ -207,6 +207,9 @@ void function CodeDialogue_GrenadeOut( entity guy ) void function CodeDialogue_DangerousAreaDisplace( entity guy ) { #if GRUNT_CHATTER_MP_ENABLED + if( !IsGrunt( guy ) ) //Titans were playing this dialogue when it doesnt make sense + return + //MP ONly string dangerousAreaWeaponName = guy.GetDangerousAreaWeapon() //printt( "CodeDialogue_DangerousAreaDisplace, Dangerous weapon name: " + dangerousAreaWeaponName ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_faction_dialogue.gnut b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_faction_dialogue.gnut index ccb5cd6eb..199b2d581 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_faction_dialogue.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_faction_dialogue.gnut @@ -14,7 +14,7 @@ void function InitFactionDialoguePersistence( entity player ) // doesn't seem to be used? required to compile tho } -void function PlayFactionDialogueToPlayer( string conversationType, entity player ) +void function PlayFactionDialogueToPlayer( string conversationType, entity player, bool forced = false ) { #if !FACTION_DIALOGUE_ENABLED return @@ -24,20 +24,23 @@ void function PlayFactionDialogueToPlayer( string conversationType, entity playe return int conversationIndex = GetConversationIndex( conversationType ) - Remote_CallFunction_NonReplay( player, "ServerCallback_PlayFactionDialogue", conversationIndex ) + if( forced ) + Remote_CallFunction_NonReplay( player, "ServerCallback_ForcePlayFactionDialogue", conversationIndex ) + else + Remote_CallFunction_NonReplay( player, "ServerCallback_PlayFactionDialogue", conversationIndex ) } -void function PlayFactionDialogueToTeam( string conversationType, int team ) +void function PlayFactionDialogueToTeam( string conversationType, int team, bool forced = false ) { foreach ( entity player in GetPlayerArrayOfTeam( team ) ) - PlayFactionDialogueToPlayer( conversationType, player ) + PlayFactionDialogueToPlayer( conversationType, player, forced ) } -void function PlayFactionDialogueToTeamExceptPlayer( string conversationType, int team, entity except ) +void function PlayFactionDialogueToTeamExceptPlayer( string conversationType, int team, entity except, bool forced = false ) { foreach ( entity player in GetPlayerArrayOfTeam( team ) ) if ( player != except ) - PlayFactionDialogueToPlayer( conversationType, player ) + PlayFactionDialogueToPlayer( conversationType, player, forced ) } void function AssignEnemyFactionToPlayer( entity player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut index 4eb423fdb..d2c72e676 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut @@ -44,7 +44,7 @@ void function GruntChatter_OnPlayerOrNPCKilled( entity deadGuy, entity attacker, if ( !IsValid( deadGuy ) || !IsValid( attacker ) ) return - if( IsGrunt( attacker ) && IsPilot( deadGuy ) ) + if ( IsGrunt( attacker ) && IsPilot( deadGuy ) ) PlayGruntChatterMPLine( attacker, "bc_killenemypilot" ) else GruntChatter_TryEnemyTitanDown( deadGuy ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/drop_battery_command.nut b/Northstar.CustomServers/mod/scripts/vscripts/drop_battery_command.nut new file mode 100644 index 000000000..8f4f8cdcb --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/drop_battery_command.nut @@ -0,0 +1,20 @@ +global function DropBatteryCommand_Init + +void function DropBatteryCommand_Init() +{ + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_RIFF", "drop_battery_command", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) + + #if SERVER + AddClientCommandCallback( "dropbattery", ClientCommandCallbackDropBattery ) + #endif +} + +#if SERVER + bool function ClientCommandCallbackDropBattery( entity player, array args ) + { + if ( GetCurrentPlaylistVarInt( "drop_battery_command", 0 ) && !player.IsTitan() && PlayerHasBattery( player ) ) + Rodeo_PilotThrowsBattery( player ) + + return true + } +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index dcf76de27..2ec2fea38 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -6,6 +6,10 @@ global function IsEvacDropship global function EvacEpilogueSetup global function Evac +global function EvacEpiloguePlayerCanBoard +global function EvacEpilogueShouldLeaveEarly +global function EvacEpilogueCompleted +global function SetRespawnAndWait const float EVAC_INITIAL_WAIT = 5.0 const float EVAC_ARRIVAL_TIME = 40.0 @@ -68,7 +72,7 @@ struct { entity evacDropship entity evacIcon - table shouldholsterweapons + table< entity, bool > shouldholsterweapons } file struct EvacShipSetting @@ -148,16 +152,16 @@ void function EvacSpectatorFunc( entity player ) player.SetObserverModeStaticAngles( cam.GetAngles() ) player.StartObserverMode( OBS_MODE_STATIC ) - file.evacDropship.WaitSignal( "EvacOver" ) + svGlobal.levelEnt.WaitSignal( "EvacOver" ) } void function SetRespawnAndWait( bool mode ) { wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY - SetRespawnsEnabled( mode ) + Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) // clear any respawn availablity, or players are able to save there respawn for whenever they want - foreach( entity player in GetPlayerArray() ) + foreach ( entity player in GetPlayerArray() ) ClearRespawnAvailable( player ) } @@ -194,7 +198,7 @@ void function EvacEpilogueCompleted( entity dropship ) ScreenFadeToBlackForever( player, 2.0 ) wait 2.0 - if( GetGameState() != eGameState.Postmatch ) + if ( GetGameState() != eGameState.Postmatch ) SetGameState( eGameState.Postmatch ) } @@ -248,7 +252,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa 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 + 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 @@ -257,21 +261,23 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa entity dropship = CreateDropship( evacTeam, evacNode.GetOrigin(), evacNode.GetAngles() ) 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.SetShieldHealthMax( EVAC_SHIP_SHIELDS ) dropship.SetShieldHealth( EVAC_SHIP_SHIELDS ) SetTargetName( dropship, "#NPC_EVAC_DROPSHIP" ) DispatchSpawn( dropship ) + dropship.SetModel( evacShip.shipModel ) + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_CreateDropShipIntLighting", dropship.GetEncodedEHandle(), dropship.GetTeam() ) // reduce nuclear core's damage AddEntityCallback_OnDamaged( dropship, EvacDropshipDamaged ) AddEntityCallback_OnKilled( dropship, EvacDropshipKilled ) - - file.shouldholsterweapons[ dropship ] <- false + dropship.s.evacSlots <- [ null, null, null, null, null, null, null, null ] file.evacDropship = dropship @@ -280,25 +286,26 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa { if ( "evacTrigger" in dropship.s ) dropship.s.evacTrigger.Destroy() - + // this should be for both teams - if( !IsValid( dropship ) ) + if ( !IsAlive( dropship ) ) { SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" ) - SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" ) - - foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) + SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractDropshipDestroyed" ) + + foreach ( entity player in GetPlayerArrayOfTeam( evacTeam ) ) SetPlayerChallengeEvacState( player, 0 ) + + foreach ( entity player in dropship.s.evacSlots ) + { + if ( IsValid( player ) && IsAlive( player ) ) + { + player.ClearParent() + player.Die( null, null, { damageSourceId = eDamageSourceId.evac_dropship_explosion, scriptType = DF_GIB } ) + } + } } - - foreach ( entity player in dropship.s.evacSlots ) - { - if ( !IsValid( player ) ) - continue - - player.ClearInvulnerable() - } - + // this is called whether dropship is destroyed or evac finishes, callback can handle this itself thread completionCallback( dropship ) }) @@ -330,14 +337,14 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa PlayFactionDialogueToTeam( "mp_evacStop", GetOtherTeam( evacTeam ) ) // stop evac beam - if( IsValid( effectFriendly ) ) + if ( IsValid( effectFriendly ) ) EffectStop( effectFriendly ) // setup evac trigger entity trigger = CreateEntity( "trigger_cylinder" ) - trigger.SetRadius( 150 ) - trigger.SetAboveHeight( 100 ) - trigger.SetBelowHeight( 100 ) + trigger.SetRadius( 200 ) + trigger.SetAboveHeight( 200 ) + trigger.SetBelowHeight( 200 ) trigger.SetOrigin( dropship.GetOrigin() ) trigger.SetParent( dropship, "ORIGIN" ) DispatchSpawn( trigger ) @@ -367,9 +374,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa // holster all weapons file.shouldholsterweapons[ dropship ] <- true + foreach ( entity player in dropship.s.evacSlots ) if ( IsValid( player ) ) - player.HolsterWeapon() + HolsterViewModelAndDisableWeapons( player ) // fly away dropship.Signal( "EvacShipLeaves" ) @@ -390,7 +398,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa dropship.kv.VisibilityFlags = 0 // prevent jetpack trails being like "dive" into ground WaitFrame() // better wait because we are server - if( !IsValid( dropship ) ) + if ( !IsValid( dropship ) ) return thread __WarpOutEffectShared( dropship ) @@ -403,10 +411,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa dropship.SetOrigin( file.spaceNode.GetOrigin() ) dropship.SetAngles( file.spaceNode.GetAngles() ) dropship.SetInvulnerable() - dropship.Signal( "EvacOver" ) + svGlobal.levelEnt.Signal( "EvacOver" ) thread PlayAnim( dropship, "ds_space_flyby_dropshipA", file.spaceNode ) - foreach( entity player in GetPlayerArray() ) + foreach ( entity player in GetPlayerArray() ) { // evac-ed players only beyond this point if ( !PlayerInDropship( player, dropship ) ) @@ -420,7 +428,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa continue } - SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" ) + if ( player.GetTeam() == evacTeam ) + SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" ) + else + SetPlayerActiveObjective( player, "EG_StopExtractDropshipSuccessfulEscape" ) // let evacing team able to see the ship again dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY @@ -452,7 +463,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa bool allEvac = evacCount == evacingPlayers.len() - foreach(entity player in evacingPlayers) + foreach (entity player in evacingPlayers) { if ( !PlayerInDropship( player, dropship ) ) continue @@ -499,9 +510,10 @@ void function AddPlayerToEvacDropship( entity dropship, entity player ) player.SetInvulnerable() player.UnforceCrouch() player.ForceStand() - + Remote_CallFunction_NonReplay( player, "ServerCallback_CreateDropShipIntLighting", dropship.GetEncodedEHandle(), dropship.GetTeam() ) + if ( dropship in file.shouldholsterweapons && file.shouldholsterweapons[ dropship ] ) // don't let people have their weapons in the dropship after it leaves - player.HolsterWeapon() + HolsterViewModelAndDisableWeapons( player ) FirstPersonSequenceStruct fp //fp.firstPersonAnim = EVAC_EMBARK_ANIMS_1P[ slot ] @@ -513,6 +525,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 ) + FirstPersonSequence( fp, player, dropship ) FirstPersonSequenceStruct idleFp @@ -521,8 +534,8 @@ void function AddPlayerToEvacDropship( entity dropship, entity player ) idleFp.attachment = "RESCUE" idleFp.teleport = true idleFp.hideProxy = true - idleFp.viewConeFunction = ViewConeWide - + idleFp.viewConeFunction = ViewConeWide + thread FirstPersonSequence( idleFp, player, dropship ) ViewConeWide( player ) // gotta do this after for some reason, adding it to idleFp does not work for some reason } @@ -541,7 +554,7 @@ void function EvacDropshipKilled( entity dropship, var damageInfo ) { foreach ( entity player in dropship.s.evacSlots ) { - if ( IsValid( player ) ) + if ( IsAlive( player ) ) { player.ClearParent() player.Die( DamageInfo_GetAttacker( damageInfo ), DamageInfo_GetWeapon( damageInfo ), { damageSourceId = eDamageSourceId.evac_dropship_explosion, scriptType = DF_GIB } ) @@ -552,32 +565,33 @@ 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 ) { + svGlobal.levelEnt.EndSignal( "EvacOver" ) wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY - float startTime = Time() OnThreadEnd( function() : ( evacTeam ) { + if( IsAlive( file.evacDropship ) ) + return + 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 + if ( !GetPlayerArrayOfTeam( evacTeam ).len() ) + return - AddPlayerScore( player, "TeamBonusKilledAll") - } + // score for killing the entire evacing team + foreach ( entity player in GetPlayerArrayOfTeam( GetOtherTeam( evacTeam ) ) ) + AddPlayerScore( player, "TeamBonusKilledAll" ) } ) - while( true ) + + while( GetPlayerArrayOfTeam_Alive( evacTeam ).len() ) { - if( GetPlayerArrayOfTeam_Alive( evacTeam ).len() == 0 ) - break - if( GetGameState() == eGameState.Postmatch ) + if ( GetGameState() == eGameState.Postmatch ) return + WaitFrame() } } @@ -587,7 +601,7 @@ 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 ) ) + if ( IsValid( dropship ) ) { dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE ShowName( dropship ) @@ -602,7 +616,7 @@ EvacShipSetting function GetEvacShipSettingByTeam( int team ) tempSetting.hoverSound = "Goblin_IMC_Evac_Hover" tempSetting.flyoutSound = "Goblin_IMC_Evac_FlyOut" - if( team == TEAM_MILITIA ) + if ( team == TEAM_MILITIA ) { tempSetting.shipModel = $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" tempSetting.flyinSound = "Crow_MCOR_Evac_Flyin" @@ -615,7 +629,7 @@ EvacShipSetting function GetEvacShipSettingByTeam( int team ) void function EvacDropshipDamaged( entity evacShip, var damageInfo ) { int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) - if( damageSourceID == damagedef_nuclear_core ) + if ( damageSourceID == damagedef_nuclear_core ) DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) * EVAC_SHIP_DAMAGE_MULTIPLIER_AGAINST_NUCLEAR_CORE ) } @@ -641,4 +655,4 @@ void function WarpInEffectEvacShip( entity dropship ) EmitSoundAtPosition( TEAM_UNASSIGNED, origin, sfx ) wait totalTime - sfxWait -} +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut index 5aee11044..6a0c4a837 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut @@ -17,6 +17,9 @@ void function AddFactionXP( entity player, int amount ) player.SetPersistentVar( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]", FactionXPMatch + 1 ) if( ProgressionEnabledForPlayer( player ) ) + { + PlayFactionDialogueToPlayer( "scoring_gotMailAlert", player ) AwardRandomItemsForFactionLevels( player, faction, oldLevel, FactionGetLevel( player, faction ) ) + } } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut index 4ed7ee4a0..f9a24f793 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut @@ -32,9 +32,12 @@ void function AiGameModes_SetNPCWeapons( string npcClass, array weapons //------------------------------------------------------ -void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int count, void functionref( array guys ) squadHandler = null ) +void function AiGameModes_SpawnDropShip( entity node, int team, int count, void functionref( array guys ) squadHandler = null ) { + ToggleSpawnNodeInUse( node, true ) string squadName = MakeSquadName( team, UniqueString( "" ) ) + vector pos = node.GetOrigin() + vector rot = node.GetAngles() CallinData drop drop.origin = pos @@ -42,7 +45,7 @@ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int c drop.dist = 768 drop.team = team drop.squadname = squadName - SetDropTableSpawnFuncs( drop, CreateSoldier, count ) + SetDropTableSpawnFuncs( drop, CreateDropshipSoldier, count ) SetCallinStyle( drop, eDropStyle.ZIPLINE_NPC ) thread RunDropshipDropoff( drop ) @@ -53,49 +56,81 @@ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int c foreach ( guy in guys ) { - SetUpNPCWeapons( guy ) - guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) + foreach ( entity weapon in guy.GetMainWeapons() ) + { + if ( weapon.GetWeaponClassName() == "mp_weapon_rocket_launcher" && GetCurrentPlaylistVarInt( "aitdm_archer_grunts", 0 ) == 0 ) + guy.TakeWeapon( weapon.GetWeaponClassName() ) + } + guy.SetBehaviorSelector( "behavior_sp_soldier" ) + //guy.GiveWeapon( "mp_weapon_defender", ["longNPCCharge"] ) + guy.AssaultSetFightRadius( 800 ) + guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE | NPC_NEW_ENEMY_FROM_SOUND | NPC_STAY_CLOSE_TO_SQUAD ) } - + if ( squadHandler != null ) thread squadHandler( guys ) + + ToggleSpawnNodeInUse( node, false ) } -void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null, int flags = 0 ) +void function AiGameModes_SpawnDropPod( entity node, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null, int flags = 0 ) { + ToggleSpawnNodeInUse( node, true ) + vector pos = node.GetOrigin() + vector rot = node.GetAngles() + 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> ) + SetSpawnOption_Alert( npc ) + SetUpNPCWeapons( npc ) 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 ) + if( content == "npc_soldier" || content == "npc_spectre" ) + { + npc.SetBehaviorSelector( "behavior_sp_soldier" ) + //npc.GiveWeapon( "mp_weapon_defender", ["longNPCCharge"] ) + } + + foreach ( entity weapon in npc.GetMainWeapons() ) + { + if ( weapon.GetWeaponClassName() == "mp_weapon_rocket_launcher" && GetCurrentPlaylistVarInt( "aitdm_archer_grunts", 0 ) == 0 ) + npc.TakeWeapon( weapon.GetWeaponClassName() ) + } + + npc.MakeInvisible() + npc.AssaultSetFightRadius( 800 ) + npc.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE | NPC_NEW_ENEMY_FROM_SOUND | NPC_STAY_CLOSE_TO_SQUAD ) guys.append( npc ) } + waitthread LaunchAnimDropPod( pod, "pod_testpath", pos, rot ) + ActivateFireteamDropPod( pod, guys ) - // start searching for enemies if ( squadHandler != null ) thread squadHandler( guys ) + + ToggleSpawnNodeInUse( node, false ) } 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 ) +void function AiGameModes_SpawnReaper( entity node, int team, string aiSettings = "", void functionref( entity reaper ) reaperHandler = null ) { + ToggleSpawnNodeInUse( node, true ) + vector pos = node.GetOrigin() + vector rot = node.GetAngles() + float reaperLandTime = REAPER_WARPFALL_DELAY + 1.2 // reaper takes ~1.2s to warpfall thread HotDrop_Spawnpoint( pos, team, reaperLandTime, false, damagedef_reaper_fall ) @@ -119,9 +154,12 @@ void function AiGameModes_SpawnReaper( vector pos, vector rot, int team, string reaper.WaitSignal( "WarpfallComplete" ) ShowName( reaper ) // show name again after drop + reaper.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_NEW_ENEMY_FROM_SOUND | NPCMF_WALK_NONCOMBAT ) if ( reaperHandler != null ) thread reaperHandler( reaper ) + + ToggleSpawnNodeInUse( node, false ) } // copied from cl_replacement_titan_hud.gnut @@ -172,8 +210,12 @@ void function HotDrop_Spawnpoint( vector origin, int team, float impactTime, boo // 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 ) +void function AiGameModes_SpawnTitan( entity node, int team, string setFile, string aiSettings = "", void functionref( entity titan ) titanHandler = null ) { + ToggleSpawnNodeInUse( node, true ) + vector pos = node.GetOrigin() + vector rot = node.GetAngles() + entity titan = CreateNPCTitan( setFile, TEAM_BOTH, pos, rot ) SetSpawnOption_Titanfall( titan ) SetSpawnOption_Warpfall( titan ) @@ -185,9 +227,18 @@ void function AiGameModes_SpawnTitan( vector pos, vector rot, int team, string s SetSpawnOption_AISettings( titan, aiSettings ) DispatchSpawn( titan ) - + WaitTillHotDropComplete( titan ) if ( titanHandler != null ) thread titanHandler( titan ) + + ToggleSpawnNodeInUse( node, false ) +} + +entity function CreateDropshipSoldier( int team, vector origin, vector angles ) +{ + entity gruntToSpawn = CreateNPC( "npc_soldier", team, origin, angles ) + SetUpNPCWeapons( gruntToSpawn ) + return gruntToSpawn } void function SetUpNPCWeapons( entity guy ) @@ -198,18 +249,13 @@ void function SetUpNPCWeapons( entity guy ) if ( className in file.npcWeaponsTable ) mainWeapons = file.npcWeaponsTable[ className ] - if ( mainWeapons.len() == 0 ) // no valid weapons + if ( !mainWeapons.len() ) // 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 ) + SetSpawnOption_Weapon( guy, weaponName ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index cacb54cf1..c96bf3599 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -34,7 +34,7 @@ struct void function GamemodeAITdm_Init() { - SetSpawnpointGamemodeOverride( ATTRITION ) // use bounty hunt spawns as vanilla game has no spawns explicitly defined for aitdm + SetSpawnpointGamemodeOverride( TEAM_DEATHMATCH ) AddCallback_GameStateEnter( eGameState.Prematch, OnPrematchStart ) AddCallback_GameStateEnter( eGameState.Playing, OnPlaying ) @@ -48,9 +48,9 @@ void function GamemodeAITdm_Init() if ( GetCurrentPlaylistVarInt( "aitdm_archer_grunts", 0 ) == 0 ) { - AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) - AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) - AiGameModes_SetNPCWeapons( "npc_stalker", [ "mp_weapon_hemlok_smg", "mp_weapon_lstar", "mp_weapon_mastiff" ] ) + AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_vinson", "mp_weapon_hemlok_smg", "mp_weapon_mastiff", "mp_weapon_shotgun_pistol" ] ) + AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_g2", "mp_weapon_doubletake", "mp_weapon_hemlok", "mp_weapon_rspn101_og", "mp_weapon_r97", "mp_weapon_shotgun_doublebarrel" ] ) + AiGameModes_SetNPCWeapons( "npc_stalker", [ "mp_weapon_esaw", "mp_weapon_lstar", "mp_weapon_shotgun", "mp_weapon_lmg", "mp_weapon_smr", "mp_weapon_epg" ] ) } else { @@ -61,6 +61,9 @@ void function GamemodeAITdm_Init() ScoreEvent_SetupEarnMeterValuesForMixedModes() SetupGenericTDMChallenge() + SetAILethality( eAILethality.High ) + + level.endOfRoundPlayerState = ENDROUND_FREE } // add settings @@ -110,6 +113,7 @@ void function OnPlaying() void function OnPlayerConnected( entity player ) { Remote_CallFunction_NonReplay( player, "ServerCallback_AITDM_OnPlayerConnected" ) + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 0 ) } // Used to handle both player and ai events @@ -165,13 +169,13 @@ void function HandleScoreEvent( entity victim, entity attacker, var damageInfo ) teamScore = playerScore // Check score so we dont go over max - if ( GameRules_GetTeamScore(attacker.GetTeam()) + teamScore > GetScoreLimit_FromPlaylist() ) - teamScore = GetScoreLimit_FromPlaylist() - GameRules_GetTeamScore(attacker.GetTeam()) + if ( GameRules_GetTeamScore( attacker.GetTeam()) + teamScore > GetScoreLimit_FromPlaylist() ) + teamScore = GetScoreLimit_FromPlaylist() - GameRules_GetTeamScore( attacker.GetTeam() ) // Add score + update network int to trigger the "Score +n" popup AddTeamScore( attacker.GetTeam(), teamScore ) attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, playerScore ) - attacker.SetPlayerNetInt("AT_bonusPoints", attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) ) + attacker.SetPlayerNetInt( "AT_bonusPoints", attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) ) } // When attrition starts both teams spawn ai on preset nodes, after that @@ -245,9 +249,10 @@ void function SpawnIntroBatch_Threaded( int team ) index = RandomInt( podNodes.len() ) node = podNodes[ index ] - thread AiGameModes_SpawnDropPod( node.GetOrigin(), node.GetAngles(), team, "npc_soldier", SquadHandler ) + thread AiGameModes_SpawnDropPod( node, team, "npc_soldier", SquadHandler ) pods-- + wait 0.5 } else { @@ -255,9 +260,10 @@ void function SpawnIntroBatch_Threaded( int team ) startIndex = i // save where we started node = shipNodes[ i - startIndex ] - thread AiGameModes_SpawnDropShip( node.GetOrigin(), node.GetAngles(), team, 4, SquadHandler ) + thread AiGameModes_SpawnDropShip( node, team, 4, SquadHandler ) ships-- + wait 2.5 } // Vanilla has a delay after first spawn @@ -288,6 +294,16 @@ void function Spawner_Threaded( int team ) // TODO: this should possibly not count scripted npc spawns, probably only the ones spawned by this script array npcs = GetNPCArrayOfTeam( team ) + + ArrayRemoveDead( npcs ) + foreach ( entity npc in npcs ) + { + if( IsMinion( npc ) || IsStalker( npc ) ) + continue + + npcs.removebyvalue( npc ) //Remove Titans, Dropships, Turrets and Ticks from the equation, Reapers are picked separately + } + int count = npcs.len() int reaperCount = GetNPCArrayEx( "npc_super_spectre", team, -1, <0,0,0>, -1 ).len() @@ -298,42 +314,34 @@ void function Spawner_Threaded( int team ) if ( reaperCount < file.reapersPerTeam ) { entity node = points[ GetSpawnPointIndex( points, team ) ] - waitthread AiGameModes_SpawnReaper( node.GetOrigin(), node.GetAngles(), team, "npc_super_spectre_aitdm", ReaperHandler ) + waitthread AiGameModes_SpawnReaper( node, team, "npc_super_spectre_aitdm", ReaperHandler ) } } // NORMAL SPAWNS - if ( count < file.squadsPerTeam * 4 - 2 ) + if ( count <= file.squadsPerTeam * 3 ) // x3 so means if theres one squad missing, try to spawn it back to keep 16 AI active per team { - string ent = file.podEntities[ index ][ RandomInt( file.podEntities[ index ].len() ) ] + string ent = file.podEntities[ index ].getrandom() array< entity > points = GetZiplineDropshipSpawns() - // Prefer dropship when spawning grunts - if ( ent == "npc_soldier" && points.len() != 0 ) + if ( ent == "npc_soldier" && points.len() && RandomInt( 100 ) >= 66 ) //Prefer using Dropship 1/3rd of the times { - if ( RandomInt( points.len() ) ) - { - entity node = points[ GetSpawnPointIndex( points, team ) ] - waitthread Aitdm_SpawnDropShip( node, team ) - continue - } + entity node = points[ GetSpawnPointIndex( points, team ) ] + thread AiGameModes_SpawnDropShip( node, team, 4, SquadHandler ) + wait 3.0 //Wait 3 seconds because Dropships does not exist until they warp in, which takes about 3.7 seconds to happen because of the effect + } + else + { + points = SpawnPoints_GetDropPod() + entity node = points[ GetSpawnPointIndex( points, team ) ] + thread AiGameModes_SpawnDropPod( node, team, ent, SquadHandler ) } - - points = SpawnPoints_GetDropPod() - entity node = points[ GetSpawnPointIndex( points, team ) ] - waitthread AiGameModes_SpawnDropPod( node.GetOrigin(), node.GetAngles(), team, ent, SquadHandler ) } - WaitFrame() + wait 1.0 //Not really needed to check this every frame, also stacks with Dropship wait to Warp In } } -void function Aitdm_SpawnDropShip( entity node, int team ) -{ - thread AiGameModes_SpawnDropShip( node.GetOrigin(), node.GetAngles(), team, 4, SquadHandler ) - wait 20 -} - // Based on points tries to balance match void function Escalate( int team ) { @@ -412,7 +420,7 @@ void function SquadHandler( array guys ) // Not all maps have assaultpoints / have weird assault points ( looking at you ac ) // So we use enemies with a large radius - while ( GetNPCArrayOfEnemies( team ).len() == 0 ) // if we can't find any enemy npcs, keep waiting + while ( !GetNPCArrayOfEnemies( team ).len() ) // if we can't find any enemy npcs, keep waiting WaitFrame() // our waiting is end, check if any soldiers left @@ -429,18 +437,14 @@ void function SquadHandler( array guys ) array points = GetNPCArrayOfEnemies( team ) - vector point - point = points[ RandomInt( points.len() ) ].GetOrigin() + vector point = points.getrandom().GetOrigin() // Setup AI, first assault point foreach ( guy in guys ) { - if ( IsAlive( guy ) ) - { - guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) - guy.AssaultPoint( point ) - guy.AssaultSetGoalRadius( 1600 ) // 1600 is minimum for npc_stalker, works fine for others - } + guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) + guy.AssaultPoint( point ) + guy.AssaultSetGoalRadius( 1600 ) // 1600 is minimum for npc_stalker, works fine for others //thread AITdm_CleanupBoredNPCThread( guy ) } @@ -448,36 +452,19 @@ void function SquadHandler( array guys ) // Every 5 - 15 secs change AssaultPoint while ( true ) { - foreach ( guy in guys ) - { - // Check if alive - if ( !IsAlive( guy ) ) - { - guys.removebyvalue( guy ) - continue - } - // Stop func if our squad has been killed off - if ( guys.len() == 0 ) - return - } + ArrayRemoveDead( guys ) + if ( !guys.len() ) + return // Get point and send our whole squad to it points = GetNPCArrayOfEnemies( team ) - if ( points.len() == 0 ) // can't find any points here + while ( !points.len() ) { - // Have to wait some amount of time before continuing - // because if we don't the server will continue checking this - // forever, aren't loops fun? - // This definitely didn't waste ~8 hours of my time reverting various - // launcher PRs before finding this mods PR that caused servers to - // freeze forever before having their process killed by the dedi watchdog - // without any logging. If anyone reads this, PLEASE add logging to your scripts - // for when weird edge cases happen, it can literally only help debugging. -Spoon WaitFrame() - continue + points = GetNPCArrayOfEnemies( team ) } - - point = points[ RandomInt( points.len() ) ].GetOrigin() + + point = points.getrandom().GetOrigin() foreach ( guy in guys ) { @@ -485,7 +472,7 @@ void function SquadHandler( array guys ) guy.AssaultPoint( point ) } - wait RandomFloatRange(5.0,15.0) + wait RandomFloatRange( 5.0, 15.0 ) } } @@ -507,7 +494,7 @@ void function ReaperHandler( entity reaper ) foreach ( player in players ) reaper.Minimap_AlwaysShow( 0, player ) - reaper.AssaultSetGoalRadius( 500 ) + reaper.AssaultSetGoalRadius( 1200 ) // Every 10 - 20 secs get a player and go to him // Definetly not annoying or anything :) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index 9cf0021d7..fa47a169c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -1463,9 +1463,8 @@ void function AT_SpawnDroppodSquad( AT_WaveOrigin campData, int spawnId, string // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnDropPod( - spawnpoint.GetOrigin(), - spawnpoint.GetAngles(), + AiGameModes_SpawnDropPod( + spawnpoint, AT_AI_TEAM, aiType, // squad handler @@ -1565,8 +1564,7 @@ void function AT_SpawnReaper( AT_WaveOrigin campData, int spawnId, int scriptMan wait RandomFloat( 1.0 ) AiGameModes_SpawnReaper( - spawnpoint.GetOrigin(), - spawnpoint.GetAngles(), + spawnpoint, AT_AI_TEAM, "npc_super_spectre_aitdm", // reaper handler @@ -1638,8 +1636,7 @@ void function AT_SpawnBountyTitan( AT_WaveOrigin campData, int spawnId, int scri string titanClass = expect string( Dev_GetAISettingByKeyField_Global( aisettings, "npc_titan_player_settings" ) ) AiGameModes_SpawnTitan( - spawnpoint.GetOrigin(), - spawnpoint.GetAngles(), + spawnpoint, AT_AI_TEAM, titanClass, aisettings, diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut index fb0270ccb..fb237ffc0 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_coliseum.nut @@ -25,7 +25,6 @@ void function GamemodeColiseum_Init() { // gamemode settings SetRoundBased( true ) - SetRespawnsEnabled( false ) SetShouldUseRoundWinningKillReplay( true ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) @@ -128,7 +127,7 @@ void function GivePlayerColiseumLoadout( entity player ) string function GetColiseumItem( string name ) { - return expect string ( GetCurrentPlaylistVar( "coliseum_" + name ) ) + return expect string ( GetCurrentPlaylistVar( "pilot_loadout_" + name ) ) } void function SetupColiseumEpilogue() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 85b80d744..99449ec2a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -3,6 +3,10 @@ untyped global function CaptureTheFlag_Init global function RateSpawnpoints_CTF +#if DEV +global function ShowCTFInfluenceSphere +#endif + const array SWAP_FLAG_MAPS = [ "mp_forwardbase_kodai", "mp_lf_meadow" @@ -46,7 +50,6 @@ void function CaptureTheFlag_Init() CaptureTheFlagShared_Init() SetSwitchSidesBased( true ) - SetSuddenDeathBased( true ) SetShouldUseRoundWinningKillReplay( true ) SetRoundWinningKillReplayKillClasses( false, false ) @@ -62,18 +65,23 @@ void function CaptureTheFlag_Init() AddCallback_OnPlayerKilled( OnPlayerKilled ) AddCallback_OnPilotBecomesTitan( DropFlagForBecomingTitan ) + AddCallback_OnTitanBecomesPilot( TransferFlagFromTitan ) + + AddSpawnCallback( "npc_titan", PlayerTitanSpawning ) AddSpawnpointValidationRule( VerifyCTFSpawnpoint ) - RegisterSignal( "ResetDropTimeout" ) + RegisterSignal( "CTF_GrabbedFlag" ) level.teamFlags <- {} ScoreEvent_SetEarnMeterValues( "KillPilot", 0.05, 0.20 ) + ScoreEvent_SetEarnMeterValues( "PilotAssist", 0.05, 0.10 ) ScoreEvent_SetEarnMeterValues( "Headshot", 0.0, 0.02 ) ScoreEvent_SetEarnMeterValues( "FirstStrike", 0.0, 0.05 ) ScoreEvent_SetEarnMeterValues( "KillTitan", 0.0, 0.25 ) ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.35 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryApplied", 0.0, 0.35 ) ScoreEvent_SetEarnMeterValues( "FlagCarrierKill", 0.0, 0.20 ) ScoreEvent_SetEarnMeterValues( "FlagTaken", 0.0, 0.10 ) @@ -141,6 +149,7 @@ void function CreateFlags() flag.SetModel( CTF_FLAG_MODEL ) flag.SetOrigin( spawn.GetOrigin() + < 0, 0, base.GetBoundingMaxs().z * 2 > ) flag.SetVelocity( < 0, 0, 1 > ) + flag.kv.gravity = 0.8 flag.s.canTake <- true @@ -168,6 +177,12 @@ void function CreateFlags() SetFlagStateForTeam( TEAM_MILITIA, eFlagState.None ) SetFlagStateForTeam( TEAM_IMC, eFlagState.None ) + + if ( GetCurrentPlaylistVarInt( "ctf_friendly_hightlights", 0 ) != 0 ) + { + foreach ( entity player in GetPlayerArray() ) + Highlight_ClearFriendlyHighlight( player ) + } } void function RemoveFlags() @@ -194,6 +209,8 @@ void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, in { vector allyFlagSpot vector enemyFlagSpot + vector flagsMedianPosition + foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) { if( spawn.GetTeam() == team ) @@ -201,28 +218,27 @@ void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, in else enemyFlagSpot = spawn.GetOrigin() } - + + flagsMedianPosition = ( allyFlagSpot + enemyFlagSpot ) * 0.5 + foreach ( entity spawn in spawnpoints ) { - float rating = 0.0 + entity teamFlag = GetFlagForTeam( team ) + float allyFlagDistance = Distance2D( spawn.GetOrigin(), allyFlagSpot ) float enemyFlagDistance = Distance2D( spawn.GetOrigin(), enemyFlagSpot ) + float friendliesScore = spawn.NearbyAllyScore( team, "ai" ) + spawn.NearbyAllyScore( team, "titan" ) + spawn.NearbyAllyScore( team, "pilot" ) + float enemiesRating = spawn.NearbyEnemyScore( team, "ai" ) + spawn.NearbyEnemyScore( team, "titan" ) + spawn.NearbyEnemyScore( team, "pilot" ) + float rating = 1.0 - ( Distance2D( spawn.GetOrigin(), allyFlagSpot ) / MAP_EXTENTS ) - if( enemyFlagDistance > allyFlagDistance ) - { - rating += spawn.NearbyAllyScore( team, "ai" ) - rating += spawn.NearbyAllyScore( team, "titan" ) - rating += spawn.NearbyAllyScore( team, "pilot" ) - - rating += spawn.NearbyEnemyScore( team, "ai" ) - rating += spawn.NearbyEnemyScore( team, "titan" ) - rating += spawn.NearbyEnemyScore( team, "pilot" ) + rating += friendliesScore * 0.5 + rating += enemiesRating - rating = rating / allyFlagDistance - } - if ( spawn == player.p.lastSpawnPoint ) rating += GetConVarFloat( "spawnpoint_last_spawn_rating" ) + + if( allyFlagDistance > enemyFlagDistance ) // Prevent ratings from crossing past midpoint between flags + rating = 0.0 spawn.CalculateRating( checkClass, team, rating, rating * 0.25 ) } @@ -232,20 +248,41 @@ bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) { vector allyFlagSpot vector enemyFlagSpot - foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) + foreach ( entity flagBase in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) { - if( spawn.GetTeam() == team ) - allyFlagSpot = spawn.GetOrigin() + if( flagBase.GetTeam() == team ) + allyFlagSpot = flagBase.GetOrigin() else - enemyFlagSpot = spawn.GetOrigin() + enemyFlagSpot = flagBase.GetOrigin() } - if( Distance2D( spawnpoint.GetOrigin(), allyFlagSpot ) > Distance2D( spawnpoint.GetOrigin(), enemyFlagSpot ) ) + float allyFlagDistance = Distance2D( spawnpoint.GetOrigin(), allyFlagSpot ) + float enemyFlagDistance = Distance2D( spawnpoint.GetOrigin(), enemyFlagSpot ) + + if( allyFlagDistance > enemyFlagDistance ) return false return true } +void function PlayerTitanSpawning( entity ent ) +{ + if ( GetCurrentPlaylistVarInt( "ctf_friendly_hightlights", 0 ) != 0 ) + thread OnFriendlyNPCTitanSpawnThreaded( ent ) +} + +void function OnFriendlyNPCTitanSpawnThreaded( entity npc ) +{ + npc.EndSignal( "OnDestroy" ) + + WaitFrame() + + WaitTillHotDropComplete( npc ) + + Highlight_SetFriendlyHighlight( npc, "sp_friendly_hero" ) + npc.Highlight_SetParam( 1, 0, HIGHLIGHT_COLOR_FRIENDLY ) +} + @@ -270,7 +307,10 @@ void function OnPlaying() void function CTFInitPlayer( entity player ) { - if ( !GamePlaying() ) + if ( GetGameState() >= eGameState.Playing && GetCurrentPlaylistVarInt( "ctf_friendly_hightlights", 0 ) != 0 ) + Highlight_SetFriendlyHighlight( player, "sp_friendly_hero" ) + + if( !GamePlaying() ) return if ( IsValid( file.imcFlagSpawn ) ) @@ -304,10 +344,26 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) if ( PlayerHasEnemyFlag( victim ) ) { if ( victim != attacker && attacker.IsPlayer() ) - AddPlayerScore( attacker, "FlagCarrierKill", victim ) + AddPlayerScore( attacker, "FlagCarrierKill" ) DropFlag( victim ) + + AddPlayerToAssistList( attacker ) + } + + entity flagCarrier + foreach ( teamMate in GetPlayerArrayOfTeam( attacker.GetTeam() ) ) + { + if( PlayerHasEnemyFlag( teamMate ) ) + { + flagCarrier = teamMate + break + } } + + // Killing players that damaged the flag carrier counts an assist for protecting the carrier + if( IsValidPlayer( flagCarrier ) && WasRecentlyHitByEntity( flagCarrier, victim, 5.0 ) ) + AddPlayerToAssistList( attacker ) } @@ -330,7 +386,8 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) bool function OnFlagCollected( entity player, entity flag ) { - if ( !IsAlive( player ) || flag.GetParent() != null || player.IsTitan() || player.IsPhaseShifted() ) + if ( !IsAlive( player ) || flag.GetParent() != null || FlagIngoresPlayerTitans( player ) || + player.IsPhaseShifted() || player.p.isEmbarking || player.p.isDisembarking || player.p.pilotEjecting ) return false if ( player.GetTeam() != flag.GetTeam() && flag.s.canTake ) @@ -344,10 +401,10 @@ bool function OnFlagCollected( entity player, entity flag ) void function GiveFlag( entity player, entity flag ) { print( player + " picked up the flag!" ) - flag.Signal( "ResetDropTimeout" ) + thread FlagSignalGrab_Threaded( flag ) // Delay this signal so it prevents race conditions when flag drops and gets picked up in the same frame flag.SetParent( player, "FLAG" ) - if ( GetCurrentPlaylistVarInt( "phase_shift_drop_flag", 0 ) == 1 ) + if( GetCurrentPlaylistVarInt( "phase_shift_drop_flag", 0 ) == 1 ) thread DropFlagIfPhased( player, flag ) // do notifications @@ -366,10 +423,17 @@ void function GiveFlag( entity player, entity flag ) SetFlagStateForTeam( flag.GetTeam(), eFlagState.Away ) // used for held } +void function FlagSignalGrab_Threaded( entity flag ) +{ + flag.EndSignal( "OnDestroy" ) + WaitFrame() + flag.Signal( "CTF_GrabbedFlag" ) +} + void function CaptureFlag( entity player, entity flag ) { // can only capture flags during normal play or sudden death - if ( GetGameState() != eGameState.Playing && GetGameState() != eGameState.SuddenDeath ) + if ( !GamePlaying() && GetGameState() != eGameState.SuddenDeath ) { printt( player + " tried to capture the flag, but the game state was " + GetGameState() + " not " + eGameState.Playing + " or " + eGameState.SuddenDeath) return @@ -387,7 +451,7 @@ void function CaptureFlag( entity player, entity flag ) SetRoundWinningKillReplayAttacker( player ) // set attacker for last cap replay array assistList - if ( player.GetTeam() == TEAM_IMC ) + if ( team == TEAM_IMC ) assistList = file.imcCaptureAssistList else assistList = file.militiaCaptureAssistList @@ -405,22 +469,23 @@ void function CaptureFlag( entity player, entity flag ) } } } - - assistList.clear() - - // notifs - MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) - EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) + ClearAssistListOfOpposingTeam( TEAM_BOTH ) + if( !HasPlayerCompletedMeritScore( player ) ) SetPlayerChallengeMeritScore( player ) - MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) - - MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScores", flag.GetTeam() ) + if ( GamePlaying() ) // Messages should appears only for non-final caps, otherwise it mess with gamestate hud messages + { + MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) + MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) + MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player ) + } + if ( GameRules_GetTeamScore( team ) == GetScoreLimit_FromPlaylist() - 1 ) { PlayFactionDialogueToTeam( "ctf_notifyWin1more", team ) @@ -436,29 +501,39 @@ void function DropFlag( entity player, bool realDrop = true ) if( !IsValid( flag ) || flag.GetParent() != player ) return - + print( player + " dropped the flag!" ) flag.ClearParent() + flag.SetOrigin( player.GetOrigin() + < 0, 0, 8 > ) // Offset a bit from the ground so it doesn't clip below flag.SetAngles( < 0, 0, 0 > ) flag.SetVelocity( < 0, 0, 0 > ) if ( realDrop ) { - if ( player.GetTeam() == TEAM_IMC && !file.imcCaptureAssistList.contains( player ) ) - file.imcCaptureAssistList.append( player ) - - else if( !file.militiaCaptureAssistList.contains( player ) ) - file.militiaCaptureAssistList.append( player ) + vector vec = RandomVec( 50 ) + vec.z = 100 + + flag.SetVelocity( vec ) + + AddPlayerToAssistList( player ) - MessageToPlayer( player, eEventNotifications.YouDroppedTheEnemyFlag ) + if( IsAlive( player ) ) + MessageToPlayer( player, eEventNotifications.YouDroppedTheEnemyFlag ) + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_FlagDrop" ) MessageToTeam( player.GetTeam(), eEventNotifications.PlayerDroppedEnemyFlag, player, player ) MessageToTeam( GetOtherTeam( player.GetTeam() ), eEventNotifications.PlayerDroppedFriendlyFlag, player, player ) } - thread TrackFlagDropTimeout( flag ) + if ( IsFlagHome( flag ) ) + { + ResetFlag( flag ) + return + } + else + thread TrackFlagDropTimeout( flag ) SetFlagStateForTeam( flag.GetTeam(), eFlagState.Home ) } @@ -476,33 +551,49 @@ void function ResetFlag( entity flag ) flagBase = file.militiaFlagSpawn flag.SetOrigin( flagBase.GetOrigin() + < 0, 0, flagBase.GetBoundingMaxs().z + 1 > ) + flag.SetVelocity( < 0, 0, 0 > ) flag.s.canTake = true SetFlagStateForTeam( flag.GetTeam(), eFlagState.None ) + + ClearAssistListOfOpposingTeam( flag.GetTeam() ) - flag.Signal( "ResetDropTimeout" ) + flag.Signal( "CTF_ReturnedFlag" ) } -//----------------------------------------------------------------------------- -// Purpose: Check proximity for flag returns -// Input : flag - The flag entity -//----------------------------------------------------------------------------- void function FlagProximityTracker( entity flag ) { flag.EndSignal( "OnDestroy" ) - array < entity > playerInsidePerimeter + array< entity > playerInsidePerimeter while( true ) { if( !playerInsidePerimeter.len() ) ArrayRemoveDead( playerInsidePerimeter ) + if ( GetCurrentPlaylistVarInt( "ctf_flag_instant_return_in_triggers", 0 ) == 1 ) + { + array< entity > instantReturnTriggers = GetEntArrayByClass_Expensive( "trigger_out_of_bounds" ) + instantReturnTriggers.extend( GetEntArrayByClass_Expensive( "trigger_hurt" ) ) + foreach( trigger in instantReturnTriggers ) + { + if( trigger.ContainsPoint( flag.GetOrigin() + < 0, 0, 8 > ) && !IsAlive( flag.GetParent() ) ) + ResetFlag( flag ) + } + } + foreach ( player in GetPlayerArrayOfTeam_Alive( flag.GetTeam() ) ) { if ( Distance( player.GetOrigin(), flag.GetOrigin() ) < CTF_GetFlagReturnRadius() ) { - if ( player.IsTitan() || player.GetTeam() != flag.GetTeam() || IsFlagHome( flag ) || flag.GetParent() != null ) + if ( FlagIngoresPlayerTitans( player ) || player.GetTeam() != flag.GetTeam() ) + continue + + if ( IsFlagHome( flag ) || flag.GetParent() != null || player.IsPhaseShifted() ) + continue + + if ( player.p.isEmbarking || player.p.isDisembarking || player.p.pilotEjecting ) continue if( playerInsidePerimeter.contains( player ) ) @@ -513,7 +604,7 @@ void function FlagProximityTracker( entity flag ) } else { - if( playerInsidePerimeter.contains( player ) ) + if( playerInsidePerimeter.contains( player ) || playerInsidePerimeter.contains( player ) && player.IsPhaseShifted() ) { player.Signal( "CTF_LeftReturnTriggerArea" ) // Cut the progress if outside range playerInsidePerimeter.removebyvalue( player ) @@ -540,19 +631,19 @@ void function TryReturnFlag( entity player, entity flag ) }) flag.EndSignal( "CTF_ReturnedFlag" ) + flag.EndSignal( "CTF_GrabbedFlag" ) flag.EndSignal( "OnDestroy" ) player.EndSignal( "CTF_LeftReturnTriggerArea" ) player.EndSignal( "OnDeath" ) player.EndSignal( "OnDestroy" ) + player.EndSignal( "StartPhaseShift" ) wait CTF_GetFlagReturnTime() - ResetFlag( flag ) - MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerReturnedFriendlyFlag, null, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_TeamReturnsFlag", flag.GetTeam() ) - PlayFactionDialogueToTeam( "ctf_flagReturnedFriendly", flag.GetTeam() ) + PlayFactionDialogueToPlayer( "ctf_flagReturnedFriendly", player ) MessageToPlayer( player, eEventNotifications.YouReturnedFriendlyFlag ) AddPlayerScore( player, "FlagReturn", player ) @@ -568,7 +659,9 @@ void function TryReturnFlag( entity player, entity flag ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyReturnsFlag", GetOtherTeam( flag.GetTeam() ) ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_ReturnsFlag" ) PlayFactionDialogueToTeam( "ctf_flagReturnedEnemy", GetOtherTeam( flag.GetTeam() ) ) - + AddPlayerToAssistList( player ) + + ResetFlag( flag ) flag.Signal( "CTF_ReturnedFlag" ) } @@ -592,7 +685,7 @@ void function DropFlagIfPhased( entity player, entity flag ) { if ( IsValidPlayer( player ) ) { - if ( GetGameState() == eGameState.Playing || GetGameState() == eGameState.SuddenDeath ) + if ( GamePlayingOrSuddenDeath() ) DropFlag( player, true ) } }) @@ -603,16 +696,149 @@ void function DropFlagIfPhased( entity player, entity flag ) void function DropFlagForBecomingTitan( entity pilot, entity titan ) { - DropFlag( pilot, true ) + if( GetCurrentPlaylistVarInt( "ctf_titan_flag_interaction", 0 ) == 1 ) + { + entity flagCarried = GetFlagForTeam( GetOtherTeam( pilot.GetTeam() ) ) + if ( !IsValid( flagCarried ) ) + return + + if( flagCarried.GetParent() == pilot ) // Reattach so it goes to the proper position + { + flagCarried.ClearParent() + flagCarried.SetParent( pilot, "FLAG" ) + } + } + else + DropFlag( pilot, true ) +} + +void function TransferFlagFromTitan( entity pilot, entity titan ) +{ + entity flagCarried = GetFlagForTeam( GetOtherTeam( pilot.GetTeam() ) ) + if ( !IsValid( flagCarried ) ) + return + + if( flagCarried.GetParent() == titan ) + { + flagCarried.ClearParent() + flagCarried.SetParent( pilot, "FLAG" ) + } } void function TrackFlagDropTimeout( entity flag ) { flag.EndSignal( "CTF_ReturnedFlag" ) - flag.EndSignal( "ResetDropTimeout" ) + flag.EndSignal( "CTF_GrabbedFlag" ) flag.EndSignal( "OnDestroy" ) wait CTF_GetDropTimeout() - ResetFlag( flag ) + if( !IsValidPlayer( flag.GetParent() ) ) // The drop timeout sometimes triggers when players are holding it, this ensures it will stay with players if so + ResetFlag( flag ) +} + +bool function FlagIngoresPlayerTitans( entity player ) +{ + return GetCurrentPlaylistVarInt( "ctf_titan_flag_interaction", 0 ) == 0 && player.IsTitan() +} + + + + + + + + + + +/* + █████ ███████ ███████ ██ ███████ ████████ ███████ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ███████ ███████ ██ ███████ ██ ███████ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ███████ ███████ ██ ███████ ██ ███████ ███████ ██████ ██████ ██ ██████ +*/ + +void function AddPlayerToAssistList( entity player ) +{ + if ( player.GetTeam() == TEAM_IMC && !file.imcCaptureAssistList.contains( player ) ) + file.imcCaptureAssistList.append( player ) + else if( !file.militiaCaptureAssistList.contains( player ) ) + file.militiaCaptureAssistList.append( player ) +} + +void function ClearAssistListOfOpposingTeam( int team ) +{ + switch ( team ) + { + case TEAM_IMC: + file.militiaCaptureAssistList.clear() + break + + case TEAM_MILITIA: + file.imcCaptureAssistList.clear() + break + + case TEAM_BOTH: + file.militiaCaptureAssistList.clear() + file.imcCaptureAssistList.clear() + break + } +} + + + + + + + + + + + +/* +██████ ███████ ██████ ██ ██ ██████ ██████ ██ ███ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██ ██ █████ ██████ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ███████ ██████ ██████ ██████ ██████ ██ ██ ████ ██████ +*/ + +#if DEV +void function ShowCTFInfluenceSphere() +{ + vector allyFlagSpot + vector enemyFlagSpot + float allyFlagDistance + float enemyFlagDistance + foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) + { + if( spawn.GetTeam() == TEAM_MILITIA ) + allyFlagSpot = spawn.GetOrigin() + else + enemyFlagSpot = spawn.GetOrigin() + } + + array< entity > spawnPoints = SpawnPoints_GetTitan() + foreach ( sPoint in spawnPoints ) + { + allyFlagDistance = Distance2D( sPoint.GetOrigin(), allyFlagSpot ) + enemyFlagDistance = Distance2D( sPoint.GetOrigin(), enemyFlagSpot ) + if( enemyFlagDistance > allyFlagDistance ) + DebugDrawSpawnpoint( sPoint, 255, 0, 0, false, 600 ) + else + DebugDrawSpawnpoint( sPoint, 0, 0, 255, false, 600 ) + } + + spawnPoints = SpawnPoints_GetPilot() + foreach ( sPoint in spawnPoints ) + { + allyFlagDistance = Distance2D( sPoint.GetOrigin(), allyFlagSpot ) + enemyFlagDistance = Distance2D( sPoint.GetOrigin(), enemyFlagSpot ) + if( enemyFlagDistance > allyFlagDistance ) + DebugDrawSpawnpoint( sPoint, 255, 0, 0, false, 600 ) + else + DebugDrawSpawnpoint( sPoint, 0, 0, 255, false, 600 ) + } } +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut index 8a6b8bf0b..e0971bbdb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fd.nut @@ -1,12 +1,3992 @@ +untyped + global function GamemodeFD_Init global function RateSpawnpoints_FD +global function IsHarvesterAlive +global function GetTargetNameForID + +global function FD_DropshipSetAnimationOverride +global function AddCallback_RegisterCustomFDContent +global function AddFDCustomProp +global function AddFDCustomShipStart +global function AddFDCustomTitanStart +global function SetFDGroundSpawn +global function SetFDDropshipSpawn +global function PlaceFDShop +global function OverrideFDHarvesterLocation +global function AddWaveAnnouncement + +enum eDropshipState{ + Idle, + InProgress, + Returning +} + +struct player_struct_fd{ + bool diedThisRound = false + int assaultScoreThisRound = 0 + int defenseScoreThisRound = 0 + int moneyThisRound = 0 + int wavesCompleted = 0 + float lastRespawnLifespan = 0.0 + float lastTitanDrop = 0.0 + bool pilotPerfectWin = true + bool titanPerfectWin = true +} + +struct player_struct_score{ + int savedCombatScore + int savedSupportScore +} + +global HarvesterStruct& fd_harvester +global table< string, array > routes +global array routeNodes +global array spawnedNPCs +global int difficultyLevel +global bool useCustomFDLoad + +const float FD_HARVESTER_PERIMETER_DIST = 1200.0 + +struct { + table< string, array > smokePoints + array titanSpawnPoints + array harvesterDamageSource + bool harvesterWasDamaged + bool harvesterShieldDown + bool harvesterHalfHealth + float harvesterDamageTaken + float lastHarvesterLowHPAnnouncedTime + array waveAnnouncement = [] + vector shopPosition + vector shopAngles = < 0, 0, 0 > + vector dropshipSpawnPosition = < 0, 0, 0 > + vector dropshipSpawnAngles = < 0, 0, 0 > + vector groundSpawnPosition + vector groundSpawnAngles = < 0, 0, 0 > + vector harvesterLocation = < 0, 0, 0 > + vector harvesterLocationOverride = < 0, 0, 0 > + vector harvesterAngles = < 0, 0, 0 > + vector harvesterAngleOverride = < 0, 0, 0 > + + table players + table > playerAwardStats + table playerHasTitanSelectionLocked + table playerSavedScore + + bool waveRestart = false + bool harvesterPerfectWin = true + bool isLiveFireMap = false + int moneyInBank = 0 + + string animationOverride = "" + int dropshipState + int playersInShip + entity dropship + array playersInDropship + + array CustomFDContent +}file + +const array DROPSHIP_IDLE_ANIMS_POV = [ + "ptpov_ds_coop_side_intro_gen_idle_B", + "ptpov_ds_coop_side_intro_gen_idle_A", + "ptpov_ds_coop_side_intro_gen_idle_C", + "ptpov_ds_coop_side_intro_gen_idle_D" +] + +const array DROPSHIP_IDLE_ANIMS = [ + "pt_ds_coop_side_intro_gen_idle_B", + "pt_ds_coop_side_intro_gen_idle_A", + "pt_ds_coop_side_intro_gen_idle_C", + "pt_ds_coop_side_intro_gen_idle_D" +] + +const array DROPSHIP_EXIT_ANIMS_POV = [ + "ptpov_ds_coop_side_intro_gen_exit_B", + "ptpov_ds_coop_side_intro_gen_exit_A", + "ptpov_ds_coop_side_intro_gen_exit_C", + "ptpov_ds_coop_side_intro_gen_exit_D" +] + +const array DROPSHIP_EXIT_ANIMS = [ + "pt_ds_coop_side_intro_gen_exit_B", + "pt_ds_coop_side_intro_gen_exit_A", + "pt_ds_coop_side_intro_gen_exit_C", + "pt_ds_coop_side_intro_gen_exit_D" +] void function GamemodeFD_Init() { PrecacheModel( MODEL_ATTRITION_BANK ) + PrecacheParticleSystem( $"P_smokescreen_FD" ) + + RegisterSignal( "FD_ReachedHarvester" ) + + SetRoundBased( true ) + SetSwitchSidesBased( false ) //Just to make sure in case of any future problem regarding teamside switch + FlagSet( "DisableTimeLimit" ) //Disable loss by timer because the wait feature will truly idle servers until people joins + SetShouldUseRoundWinningKillReplay( false ) + SetServerVar( "replayDisabled", true ) //Only disabling Killcams because it's PvE, also seems to reduce server network load a little bit + Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) + PlayerEarnMeter_SetEnabled( false ) + SetAllowLoadoutChangeFunc( FD_ShouldAllowChangeLoadout ) + SetGetDifficultyFunc( FD_GetDifficultyLevel ) + SetShouldUsePickLoadoutScreen( true ) + SetShouldSpectateInPickLoadoutScreen( true ) + TeamTitanSelectMenu_Init() + + //General Callbacks + AddCallback_EntitiesDidLoad( LoadEntities ) + AddCallback_GameStateEnter( eGameState.PickLoadout, FD_PickLoadout ) + AddCallback_GameStateEnter( eGameState.Prematch, FD_createHarvester ) + AddCallback_GameStateEnter( eGameState.Playing, StartFDMatch ) + AddCallback_OnRoundEndCleanup( FD_WaveCleanup ) + AddCallback_OnClientConnected( GamemodeFD_InitPlayer ) + AddCallback_OnClientDisconnected( OnPlayerDisconnectedOrDestroyed ) + AddCallback_OnPlayerGetsNewPilotLoadout( FD_OnPlayerGetsNewPilotLoadout ) + AddCallback_OnPilotBecomesTitan( FD_PilotEmbark ) + AddCallback_OnTitanBecomesPilot( FD_PilotDisembark ) + ClassicMP_SetEpilogue( FD_SetupEpilogue ) + AddOnRodeoStartedCallback( FD_PilotStartRodeo ) + + //Damage Callbacks + AddDamageByCallback( "player", FD_DamageByPlayerCallback ) + AddDamageFinalCallback( "player", DamageScaleByDifficulty ) + AddDamageFinalCallback( "npc_titan", DamageScaleByDifficulty ) + AddDamageFinalCallback( "npc_turret_sentry", DamageScaleByDifficulty ) + AddDamageFinalCallback( "npc_turret_sentry", RevivableTurret_DamageCallback ) + AddDamageFinalCallback( "npc_turret_mega", HeavyTurret_DamageCallback ) + AddDamageFinalCallback( "npc_titan", FD_DamageToMoney ) + AddDamageFinalCallback( "player", FD_DamageToMoney ) //PvP case, player Titans will give money + + //Spawn Callbacks + AddSpawnCallback( "npc_titan", HealthScaleByDifficulty ) + AddSpawnCallback( "npc_super_spectre", HealthScaleByDifficulty ) + AddSpawnCallback( "npc_frag_drone", OnTickSpawn ) + AddCallback_OnPlayerRespawned( FD_PlayerRespawnCallback ) + AddSpawnCallback( "npc_turret_sentry", AddTurretSentry ) + AddTurretRepairCallback( IncrementPlayerstat_TurretRevives ) + + //Death Callbacks + AddCallback_OnNPCKilled( FD_OnNPCDeath ) + AddCallback_NPCLeeched( FD_OnNPCLeeched ) + AddCallback_OnPlayerKilled( GamemodeFD_OnPlayerKilled ) + + //Wave Checker Death Callbacks + /* This is split from the AddCallback_OnNPCKilled function because that callback only runs if the attacker is valid, which disconnected players + does not count towards, and causes softlocks due to that */ + AddDeathCallback( "npc_frag_drone", OnTickDeath ) + + foreach ( string npcClass in [ "npc_frag_drone", "npc_soldier", "npc_spectre", "npc_stalker", "npc_super_spectre", "npc_drone", "npc_titan" ] ) + { + AddSpawnCallback( npcClass, FD_GenericNPCDeathChecker ) + } + + //Command Callbacks + AddClientCommandCallback( "FD_ToggleReady", ClientCommandCallbackToggleReady ) + AddClientCommandCallback( "FD_UseHarvesterShieldBoost", ClientCommandCallbackUseShieldBoost ) + AddClientCommandCallback( "FD_SetTutorialBit", ClientCommand_FDSetTutorialBit ) + + //Shop Callback + SetBoostPurchaseCallback( FD_BoostPurchaseCallback ) + SetTeamReserveInteractCallback( FD_TeamReserveDepositOrWithdrawCallback ) + + //Data Collection + AddStunLaserHealCallback( FD_StunLaserHealTeammate ) + SetApplyBatteryCallback( FD_BatteryHealTeammate ) + AddSmokeHealCallback( FD_SmokeHealTeammate ) + SetUsedCoreCallback( FD_UsedCoreCallback ) + + //Score Event + AddArcTrapTriggeredCallback( FD_OnArcTrapTriggered ) + AddArcWaveDamageCallback( FD_OnArcWaveDamage ) + AddOnTetherCallback( FD_OnTetherTrapTriggered ) + AddSonarStartCallback( FD_OnSonarStart ) + ScoreEvent_SetupScoreValuesForFrontierDefense() + + difficultyLevel = FD_GetDifficultyLevel() //Refresh this only on map load, to avoid midgame commands messing up with difficulties (i.e setting mp_gamemode fd_hard midgame in a regular match through console on local host would immediately make Stalkers spawns with EPG) + + #if SERVER + AILoadout_SetupNPCWeapons( "npc_soldier", ["mp_weapon_rspn101","mp_weapon_car","mp_weapon_alternator_smg","mp_weapon_hemlok_smg","mp_weapon_r97"] ) + AILoadout_SetupNPCWeapons( "npc_spectre", ["mp_weapon_hemlok","mp_weapon_vinson","mp_weapon_g2","mp_weapon_mastiff","mp_weapon_shotgun","mp_weapon_doubletake","mp_weapon_dmr"] ) + AILoadout_SetupNPCAntiTitanWeapons( "npc_soldier", [ "mp_weapon_defender" ] ) + AILoadout_SetupNPCAntiTitanWeapons( "npc_spectre", [ "mp_weapon_defender" ] ) + level.endOfRoundPlayerState = ENDROUND_FREE + #endif + + for ( int i = 0; i < 20; i++ ) //Setup NPC array for Harvester Damage tracking + file.harvesterDamageSource.append( 0.0 ) + + switch ( difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + SetAILethality( eAILethality.VeryLow ) + break + case eFDDifficultyLevel.NORMAL: + SetAILethality( eAILethality.Low ) + break + case eFDDifficultyLevel.HARD: + SetAILethality( eAILethality.Medium ) + break + case eFDDifficultyLevel.MASTER: + case eFDDifficultyLevel.INSANE: + SetAILethality( eAILethality.High ) + break + } +} + +void function ScoreEvent_SetupScoreValuesForFrontierDefense() +{ + ScoreEvent_SetDisplayType( GetScoreEvent( "FDAirDroneKilled" ), eEventDisplayType.MEDAL | eEventDisplayType.CENTER ) + ScoreEvent_SetDisplayType( GetScoreEvent( "FDGruntKilled" ), eEventDisplayType.MEDAL | eEventDisplayType.CENTER ) + ScoreEvent_SetDisplayType( GetScoreEvent( "FDSpectreKilled" ), eEventDisplayType.MEDAL | eEventDisplayType.CENTER ) + ScoreEvent_SetDisplayType( GetScoreEvent( "FDStalkerKilled" ), eEventDisplayType.MEDAL | eEventDisplayType.CENTER ) + ScoreEvent_SetDisplayType( GetScoreEvent( "FDSuperSpectreKilled" ), eEventDisplayType.MEDAL | eEventDisplayType.CENTER ) + ScoreEvent_SetDisplayType( GetScoreEvent( "Execution" ), eEventDisplayType.MEDAL_FORCED | eEventDisplayType.CENTER ) + ScoreEvent_SetDisplayType( GetScoreEvent( "FDTeamHeal" ), eEventDisplayType.MEDAL_FORCED | eEventDisplayType.GAMEMODE | eEventDisplayType.SHOW_SCORE ) + ScoreEvent_SetDisplayType( GetScoreEvent( "KillDropship" ), eEventDisplayType.CENTER ) + + ScoreEvent_SetXPValueWeapon( GetScoreEvent( "FDTitanKilled" ), 1 ) + ScoreEvent_SetXPValueWeapon( GetScoreEvent( "KillDropship" ), 1 ) + ScoreEvent_SetXPValueWeapon( GetScoreEvent( "TitanAssist" ), 1 ) + ScoreEvent_SetXPValueTitan( GetScoreEvent( "FDTitanKilled" ), 1 ) + ScoreEvent_SetXPValueTitan( GetScoreEvent( "KillDropship" ), 1 ) + ScoreEvent_SetXPValueFaction( GetScoreEvent( "ChallengeFD" ), 1 ) + + ScoreEvent_Disable( GetScoreEvent( "KillGrunt" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillDrone" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillProwler" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillSpectre" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillStalker" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillSuperSpectre" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillTitan" ) ) + ScoreEvent_Disable( GetScoreEvent( "KillPilot" ) ) + ScoreEvent_Disable( GetScoreEvent( "TitanKillTitan" ) ) +} + +void function UpdateEarnMeter_ByPlayersInMatch() +{ + WaitFrame() //Waitframe because the disconnecting player still exist in the current frame of the disconnection callbacks + array numplayers = GetPlayerArrayOfTeam( TEAM_MILITIA ) + + switch ( numplayers.len() ) + { + case 1: + ScoreEvent_SetEarnMeterValues( "FDAirDroneKilled", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "FDGruntKilled", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "FDSpectreKilled", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "FDStalkerKilled", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "LeechSpectre", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "FDSuperSpectreKilled", 0.0, 0.4 ) + ScoreEvent_SetEarnMeterValues( "Execution", 0.0, 0.5 ) + ScoreEvent_SetEarnMeterValues( "KillDropship", 0.0, 0.5 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryApplied", 0.0, 1.0 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 1.0 ) + SetTitanMeterGainScale( 0.0004 ) + break + case 2: + ScoreEvent_SetEarnMeterValues( "FDAirDroneKilled", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "FDGruntKilled", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "FDSpectreKilled", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "FDStalkerKilled", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "LeechSpectre", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "FDSuperSpectreKilled", 0.0, 0.35 ) + ScoreEvent_SetEarnMeterValues( "Execution", 0.0, 0.35 ) + ScoreEvent_SetEarnMeterValues( "KillDropship", 0.0, 0.35 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryApplied", 0.0, 0.8 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.8 ) + SetTitanMeterGainScale( 0.0003 ) + break + case 3: + ScoreEvent_SetEarnMeterValues( "FDAirDroneKilled", 0.0, 0.073 ) + ScoreEvent_SetEarnMeterValues( "FDGruntKilled", 0.0, 0.073 ) + ScoreEvent_SetEarnMeterValues( "FDSpectreKilled", 0.0, 0.073 ) + ScoreEvent_SetEarnMeterValues( "FDStalkerKilled", 0.0, 0.073 ) + ScoreEvent_SetEarnMeterValues( "LeechSpectre", 0.0, 0.073 ) + ScoreEvent_SetEarnMeterValues( "FDSuperSpectreKilled", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "Execution", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "KillDropship", 0.0, 0.2 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryApplied", 0.0, 0.5 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.5 ) + SetTitanMeterGainScale( 0.0002 ) + break + default: + ScoreEvent_SetEarnMeterValues( "FDAirDroneKilled", 0.0, 0.036 ) + ScoreEvent_SetEarnMeterValues( "FDGruntKilled", 0.0, 0.036 ) + ScoreEvent_SetEarnMeterValues( "FDSpectreKilled", 0.0, 0.036 ) + ScoreEvent_SetEarnMeterValues( "FDStalkerKilled", 0.0, 0.036 ) + ScoreEvent_SetEarnMeterValues( "LeechSpectre", 0.0, 0.036 ) + ScoreEvent_SetEarnMeterValues( "FDSuperSpectreKilled", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "Execution", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "KillDropship", 0.0, 0.1 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryApplied", 0.0, 0.35 ) + ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.35 ) + SetTitanMeterGainScale( 0.0001 ) + } +} + +void function AddCallback_RegisterCustomFDContent( void functionref() callback ) +{ + file.CustomFDContent.append( callback ) +} + +void function AddFDCustomProp( asset modelasset, vector origin, vector angles ) +{ + entity prop = CreateEntity( "prop_script" ) + prop.SetValueForModelKey( modelasset ) + prop.SetOrigin( origin ) + prop.SetAngles( angles ) + prop.kv.fadedist = -1 + prop.kv.renderamt = 255 + prop.kv.rendercolor = "255 255 255" + prop.kv.solid = 6 + prop.SetAIObstacle( true ) + prop.SetTakeDamageType( DAMAGE_NO ) + prop.SetScriptPropFlags( SPF_CUSTOM_SCRIPT_3 ) + prop.AllowMantle() + DispatchSpawn( prop ) + ToggleNPCPathsForEntity( prop, false ) +} + +void function AddFDCustomShipStart( vector origin, vector angles, int team ) +{ + entity shipSpawn = CreateEntity( "info_spawnpoint_dropship_start" ) + shipSpawn.SetOrigin( origin ) + shipSpawn.SetAngles( angles ) + SetTeam( shipSpawn, team ) + DispatchSpawn( shipSpawn ) +} + +void function AddFDCustomTitanStart( vector origin, vector angles ) +{ + entity titanSpawn = CreateEntity( "info_spawnpoint_titan_start" ) //info_replacement_titan_spawn + titanSpawn.SetOrigin( origin ) + titanSpawn.SetAngles( angles ) + SetTeam( titanSpawn, TEAM_MILITIA ) + DispatchSpawn( titanSpawn ) + titanSpawn.s.lastUsedTime <- -999 + file.titanSpawnPoints.append( titanSpawn ) +} + +void function SetFDGroundSpawn( vector origin, vector angles = < 0, 0, 0 > ) +{ + file.groundSpawnPosition = origin + file.groundSpawnAngles = angles +} + +void function SetFDDropshipSpawn( vector origin, vector angles = < 0, 0, 0 > ) +{ + file.dropshipSpawnPosition = origin + file.dropshipSpawnAngles = angles +} + +void function PlaceFDShop( vector origin, vector angles = < 0, 0, 0 > ) +{ + file.shopPosition = origin + file.shopAngles = angles +} + +void function OverrideFDHarvesterLocation( vector origin, vector angles = < 0, 0, 0 > ) +{ + file.harvesterLocationOverride = origin + file.harvesterAngleOverride = angles +} + +void function AddWaveAnnouncement( string waveAnnouncementAlias ) +{ + file.waveAnnouncement.append( waveAnnouncementAlias ) +} + +void function LoadEntities() +{ + CreateBoostStoreLocation( TEAM_MILITIA, file.shopPosition, file.shopAngles ) + + foreach ( callback in file.CustomFDContent ) + callback() + + foreach ( entity info_target in GetEntArrayByClass_Expensive( "info_target" ) ) + { + if ( GameModeRemove( info_target ) ) + continue + + if ( info_target.HasKey( "editorclass" ) ) + { + switch ( info_target.kv.editorclass ) + { + case "info_fd_harvester": + file.harvesterLocation = info_target.GetOrigin() + file.harvesterAngles = info_target.GetAngles() + info_target.Destroy() + break + case "info_fd_mode_model": + AddFDCustomProp( info_target.GetModelName(), info_target.GetOrigin(), info_target.GetAngles() ) + info_target.Destroy() + break + case "info_fd_ai_position": + AddStationaryAIPosition( info_target.GetOrigin(), int( info_target.kv.aiType ) ) + info_target.Destroy() + break + case "info_fd_route_node": + routeNodes.append( info_target ) + break + case "info_fd_smoke_screen": + string smokePointName = string( info_target.kv.locationName ) + + if ( !( smokePointName in file.smokePoints ) ) + file.smokePoints[ smokePointName ] <- [] + + file.smokePoints[ smokePointName ].append( info_target.GetOrigin() ) + info_target.Destroy() + break + } + } + } + + if ( file.harvesterLocationOverride != < 0, 0, 0 > ) + file.harvesterLocation = file.harvesterLocationOverride + + if ( file.harvesterAngleOverride != < 0, 0, 0 > ) + file.harvesterAngles = file.harvesterAngleOverride + + ValidateAndFinalizePendingStationaryPositions() + SetTeam( GetTeamEnt( TEAM_IMC ), TEAM_IMC ) + + SetGlobalNetInt( "FD_totalWaves", WaveSpawnEvents.len() ) + SetGlobalNetInt( "burn_turretLimit", 2 ) + + SetGlobalNetInt( "FD_currentWave", 0 ) + EarnMeterMP_SetPassiveMeterGainEnabled( false ) // Initially don't give passive earnmeter otherwise waiting players can get it + + int maxRestarts = GetCurrentPlaylistVarInt( "roundscorelimit", 3 ) - 1 // Minus one because current round already counts + FD_SetMaxAllowedRestarts( maxRestarts ) + FD_SetNumAllowedRestarts( maxRestarts ) +} + + + + + + + + + + + +/* Main Gamemode Flow +███ ███ █████ ██ ███ ██ ██████ █████ ███ ███ ███████ ███ ███ ██████ ██████ ███████ ███████ ██ ██████ ██ ██ +████ ████ ██ ██ ██ ████ ██ ██ ██ ██ ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ████ ██ ███████ ██ ██ ██ ██ ██ ███ ███████ ██ ████ ██ █████ ██ ████ ██ ██ ██ ██ ██ █████ █████ ██ ██ ██ ██ █ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ +██ ██ ██ ██ ██ ██ ████ ██████ ██ ██ ██ ██ ███████ ██ ██ ██████ ██████ ███████ ██ ███████ ██████ ███ ███ +*/ + +void function FD_PickLoadout() +{ + EnableTitanSelection() +} + +void function FD_createHarvester() +{ + fd_harvester = SpawnHarvester( file.harvesterLocation, file.harvesterAngles, GetCurrentPlaylistVarInt( "fd_harvester_health", 25000 ), GetCurrentPlaylistVarInt( "fd_harvester_shield", 6000 ), TEAM_MILITIA ) + SetGlobalNetEnt( "FD_activeHarvester", fd_harvester.harvester ) + + fd_harvester.harvester.Minimap_SetAlignUpright( true ) + fd_harvester.harvester.Minimap_AlwaysShow( TEAM_IMC, null ) + fd_harvester.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null ) + fd_harvester.harvester.Minimap_SetHeightTracking( true ) + fd_harvester.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + fd_harvester.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) + fd_harvester.harvester.SetTakeDamageType( DAMAGE_EVENTS_ONLY ) + fd_harvester.harvester.SetArmorType( ARMOR_TYPE_HEAVY ) + fd_harvester.harvester.SetAIObstacle( true ) + fd_harvester.harvester.SetScriptPropFlags( SPF_DISABLE_CAN_BE_MELEED ) + fd_harvester.harvester.SetNoTarget( true ) + + ToggleNPCPathsForEntity( fd_harvester.harvester, false ) + AddEntityCallback_OnPostShieldDamage( fd_harvester.harvester, HarvesterShieldInvulnCheck ) + AddEntityCallback_OnFinalDamaged( fd_harvester.harvester, OnHarvesterDamaged ) + thread MonitorHarvesterProximity( fd_harvester.harvester ) + SetGlobalNetInt( "FD_waveState", WAVE_STATE_NONE ) + + SetPlayerDeathsHidden( false ) + if ( !file.waveRestart ) + EnableTitanSelection() + else + SetGlobalNetInt( "FD_waveState", WAVE_STATE_BREAK ) + + //Some maps have sky battles happening on them + switch ( GetMapName() ) + { + case "mp_angel_city": + case "mp_homestead": + case "mp_colony02": + case "mp_thaw": + case "mp_relic02": + case "mp_crashsite3": + case "mp_forwardbase_kodai": + case "mp_black_water_canal": + thread StratonHornetDogfights() + } + + UpdateTeamReserve( file.moneyInBank ) + WaveRestart_ResetPlayersInventory() //Call it in here to not misinform players about items they had in previous wave restarts +} + +void function StartFDMatch() +{ + // only start the highlight when we start playing, not during dropship + foreach ( entity player in GetPlayerArray() ) + Highlight_SetFriendlyHighlight( player, "sp_friendly_hero" ) + + thread mainGameLoop() +} + +void function mainGameLoop() +{ + startHarvester() + int currentWave = GetGlobalNetInt( "FD_currentWave" ) + + if ( !file.waveRestart ) + { + if ( currentWave == 0 && GetCurrentPlaylistVarFloat( "riff_minimap_state", 0 ) == 0 ) + { + wait 14 + PlayFactionDialogueToTeam( "fd_minimapTip" , TEAM_MILITIA ) + wait 14 + } + else //Still wait 14 seconds to let them to speak about the Harvester being up and running on first wave + wait 14 + } + + thread FD_AlivePlayersMonitor() + bool showShop = false + for ( currentWave = GetGlobalNetInt( "FD_currentWave" ); currentWave < WaveSpawnEvents.len(); currentWave++ ) + { + if ( file.waveRestart ) + { + if ( currentWave > 0 ) + { + showShop = true + SetGlobalNetTime( "FD_nextWaveStartTime", Time() + GetCurrentPlaylistVarFloat( "fd_wave_buy_time", 60 ) ) + } + + WaveRestart_ResetDropshipState() + + wait 1 + + if ( currentWave > 0 ) + { + PlayerEarnMeter_SetEnabled( true ) + foreach ( entity player in GetPlayerArray() ) + GiveTitanToPlayer( player ) + } + } + + if ( !runWave( currentWave, showShop ) ) + break + + showShop = true + } +} + +void function executeWave() +{ + int currentWave = GetGlobalNetInt( "FD_currentWave" ) + 1 + int enemyCount + print( "WAVE START: " + currentWave ) + thread eventIterator_FrontierDefense() + + //Wait for all events to execute + while( IsHarvesterAlive( fd_harvester.harvester ) && !allEventsExecuted( GetGlobalNetInt( "FD_currentWave" ) ) ) + WaitFrame() + print( "All Events executed, waiting on players to finish the wave" ) + + //Do a secondary wait for alive enemies after all events executed + while( IsHarvesterAlive( fd_harvester.harvester ) && GetGlobalNetInt( "FD_AICount_Current" ) > 0 ) + { + if ( enemyCount != GetGlobalNetInt( "FD_AICount_Current" ) ) + { + enemyCount = GetGlobalNetInt( "FD_AICount_Current" ) + switch ( enemyCount ) + { + case 10: + PlayFactionDialogueToTeam( "fd_waveCleanup" , TEAM_MILITIA ) + break + + case 5: + PlayFactionDialogueToTeam( "fd_waveCleanup5" , TEAM_MILITIA ) + break + + case 4: + PlayFactionDialogueToTeam( "fd_waveCleanup4" , TEAM_MILITIA ) + break + + case 3: + PlayFactionDialogueToTeam( "fd_waveCleanup3" , TEAM_MILITIA ) + break + + case 2: + PlayFactionDialogueToTeam( "fd_waveCleanup2" , TEAM_MILITIA ) + break + + case 1: + PlayFactionDialogueToTeam( "fd_waveCleanup1" , TEAM_MILITIA ) + break + } + } + + WaitFrame() + } + + wait 0.5 + print( "All enemies from wave eliminated" ) + if ( GetGlobalNetInt( "FD_AICount_Drone_Cloak" ) > 0 ) //Kill Cloak Drones when a wave ends to avoid them just wandering off their original wave + { + foreach ( entity cloakedDrone in GetNPCCloakedDrones() ) + { + if ( IsAlive( cloakedDrone ) ) + { + cloakedDrone.Show() + cloakedDrone.Solid() + cloakedDrone.Die() + } + } + } + foreach ( entity tick in GetEntArrayByClass_Expensive( "npc_frag_drone" ) ) + { + if ( IsAlive( tick ) ) + tick.Destroy() + } +} + +bool function runWave( int waveIndex, bool shouldDoBuyTime ) +{ + SetGlobalNetInt( "FD_currentWave", waveIndex ) + file.harvesterWasDamaged = false + int highestScore + entity highestScore_player + SetEnemyAmountNetVars( waveIndex ) + file.moneyInBank = GetTeamReserve() + + for ( int i = 0; i < 20; i++ )//Number of npc type ids + file.harvesterDamageSource[i] = 0 + + foreach ( entity player in GetPlayerArray() ) + { + file.players[player].diedThisRound = false + file.players[player].assaultScoreThisRound = 0 + file.players[player].defenseScoreThisRound = 0 + file.players[player].moneyThisRound = GetPlayerMoney( player ) + } + array enemys = getHighestEnemyAmountsForWave( waveIndex ) + + if ( waveIndex > 0 ) + { + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_AnnouncePreParty", enemys[0], enemys[1], enemys[2], enemys[3], enemys[4], enemys[5], enemys[6], enemys[7], enemys[8] ) + } + + if ( waveIndex < file.waveAnnouncement.len() && file.waveAnnouncement[waveIndex] != "" && !file.waveRestart ) + { + PlayFactionDialogueToTeam( file.waveAnnouncement[waveIndex], TEAM_MILITIA ) + if ( waveIndex == 0 ) + wait 8 + } + if ( file.waveRestart ) + { + file.waveRestart = false + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_WaveRestart ) + } + + if ( shouldDoBuyTime ) + { + print( "Opening Shop" ) + SetGlobalNetInt( "FD_waveState", WAVE_STATE_BREAK ) + OpenBoostStores() + entity parentCrate = GetBoostStores()[0].GetParent() + parentCrate.Minimap_AlwaysShow( TEAM_MILITIA, null ) + Minimap_PingForTeam( TEAM_MILITIA, file.shopPosition, 150, 5, TEAM_COLOR_YOU / 255.0, 5 ) + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_NotifyStoreOpen" ) + player.s.extracashnag = Time() + 30 + } + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_IMC ) ) + player.SetPlayerNetBool( "FD_readyForNextWave", true ) + + while( Time() < GetGlobalNetTime( "FD_nextWaveStartTime" ) ) + { + if ( FD_CheckPlayersReady() ) + SetGlobalNetTime( "FD_nextWaveStartTime", Time() ) + WaitFrame() + } + wait 0.6 + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_StoreClosing ) + print( "Closing Shop" ) + wait 4 + parentCrate.Minimap_Hide( TEAM_MILITIA, null ) + CloseBoostStores() + } + else if ( waveIndex > 0 ) + { + SetGlobalNetInt( "FD_waveState", WAVE_STATE_BREAK ) + SetGlobalNetTime( "FD_nextWaveStartTime", Time() + 15.0 ) + wait 15 + } + + print( "STARTING WAVE" ) + SetGlobalNetInt( "FD_waveState", WAVE_STATE_INCOMING ) + EarnMeterMP_SetPassiveMeterGainEnabled( true ) + foreach ( entity player in GetPlayerArray() ) + { + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_ClearPreParty" ) + player.SetPlayerNetBool( "FD_readyForNextWave", false ) + } + SetGlobalNetBool( "FD_waveActive", true ) + FD_UpdateTitanBehavior() + + //Droz & Dravis should be mentioning when waves are starting + if ( waveIndex == 0 ) + { + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_AnnouncePreParty", enemys[0], enemys[1], enemys[2], enemys[3], enemys[4], enemys[5], enemys[6], enemys[7], enemys[8] ) + + PlayFactionDialogueToTeam( "fd_firstWaveStartPrefix", TEAM_MILITIA ) + } + else if ( isFinalWave() ) + PlayFactionDialogueToTeam( "fd_finalWaveStartPrefix", TEAM_MILITIA ) + else + PlayFactionDialogueToTeam( "fd_newWaveStartPrefix", TEAM_MILITIA ) + + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_AnnounceWaveStart ) + + wait 10 + + if ( waveIndex == 0 ) + { + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_ClearPreParty" ) + } + + SetGlobalNetInt( "FD_waveState", WAVE_STATE_IN_PROGRESS ) + executeWave() + + SetGlobalNetInt( "FD_waveState", WAVE_STATE_COMPLETE ) + EarnMeterMP_SetPassiveMeterGainEnabled( false ) + foreach ( entity player in GetPlayerArray() ) + { + player.s.didthepvpglitch = false //Clear the pvp flag after wave completion + player.s.isbeingmonitored = false + } + + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + { + print( "Stopping Wave, Harvester Died" ) + SetGlobalNetBool( "FD_waveActive", false ) + float totalDamage = 0.0 + array highestDamage = [ 0.0, 0.0, 0.0 ] + array highestDamageSource = [ -1, -1, -1 ] + foreach ( index, float damage in file.harvesterDamageSource ) + { + totalDamage += damage + if ( highestDamage[0] < damage ) + { + highestDamage[2] = highestDamage[1] + highestDamageSource[2] = highestDamageSource[1] + highestDamage[1] = highestDamage[0] + highestDamageSource[1] = highestDamageSource[0] + highestDamageSource[0] = index + highestDamage[0] = damage + } + else if ( highestDamage[1] < damage ) + { + highestDamage[2] = highestDamage[1] + highestDamageSource[2] = highestDamageSource[1] + highestDamage[1] = damage + highestDamageSource[1] = index + } + else if ( highestDamage[2] < damage ) + { + highestDamage[2] = damage + highestDamageSource[2] = index + } + } + + file.waveRestart = true + spawnedNPCs.clear() + resetWaveEvents() + SetPlayerDeathsHidden( true ) + + if ( FD_PlayersHaveRestartsLeft() ) + { + SetWinner( TEAM_IMC ) + PlayFactionDialogueToTeam( "fd_baseDeath", TEAM_MILITIA, true ) + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_DisplayHarvesterKiller", FD_GetNumRestartsLeft(), getHintForTypeId( highestDamageSource[0] ), highestDamageSource[0], highestDamage[0] / totalDamage, highestDamageSource[1], highestDamage[1] / totalDamage , highestDamageSource[2], highestDamage[2] / totalDamage ) + player.SetNoTarget( true ) + player.SetInvulnerable() + } + } + else + { + SetRoundBased( false ) + AddTeamRoundScoreNoStateChange( TEAM_IMC ) + SetWinner( TEAM_IMC, "#FD_TOTAL_DEFEAT_HINT", "#FD_TOTAL_DEFEAT_HINT" ) + print( "Finishing match, no more retries left" ) + PlayFactionDialogueToTeam( "fd_matchDefeat", TEAM_MILITIA, true ) + } + + wait 8 + + if ( FD_PlayersHaveRestartsLeft() ) + { + FD_DecrementRestarts() //Decrement restarts in here to avoid issues + foreach ( entity player in GetPlayerArray() ) + Highlight_ClearFriendlyHighlight( player ) //Clear Highlight for dropship animation + } + else + RegisterPostSummaryScreenForMatch( false ) //Do it here to override the settings established in _challenges.gnut + + return false + } + + wait 1 + + WaveBreak_RegisterAttackOrSupportScore( 0 ) + + wait 1 + + WaveBreak_RegisterAttackOrSupportScore( 1 ) + + wait 1 + //wave end + + SetGlobalNetBool( "FD_waveActive", false ) + FD_UpdateTitanBehavior() + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + file.players[player].wavesCompleted++ + + if ( isFinalWave() ) + { + //Game won code + print( "No more pending Waves, match won" ) + + if ( GetPlayerArrayOfTeam( TEAM_MILITIA ).len() ) + { + highestScore = 0 + highestScore_player = GetPlayerArrayOfTeam( TEAM_MILITIA )[0] + } + else + { + SetRoundBased( false ) + AddTeamRoundScoreNoStateChange( TEAM_MILITIA ) + SetWinner( TEAM_MILITIA, "#FD_TOTAL_VICTORY_HINT", "#FD_TOTAL_VICTORY_HINT" ) + return true + } + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( !file.players[player].diedThisRound ) + AddPlayerScore( player, "FDDidntDie" ) + if ( player in file.players && player in file.playerAwardStats ) + { + if ( file.players[player].lastRespawnLifespan > file.playerAwardStats[player]["longestLife"] ) + file.playerAwardStats[player]["longestLife"] = file.players[player].lastRespawnLifespan + } + } + + SetRoundBased( false ) + AddTeamRoundScoreNoStateChange( TEAM_MILITIA ) + SetWinner( TEAM_MILITIA, "#FD_TOTAL_VICTORY_HINT", "#FD_TOTAL_VICTORY_HINT" ) + PlayFactionDialogueToTeam( "fd_matchVictory", TEAM_MILITIA, true ) + + wait 2 + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + AddPlayerScore( player, "FDTeamWave" ) + + wait 1 + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( highestScore < ( file.players[player].assaultScoreThisRound + file.players[player].defenseScoreThisRound ) ) + { + highestScore = file.players[player].assaultScoreThisRound + file.players[player].defenseScoreThisRound + highestScore_player = player + } + } + if ( highestScore_player in file.playerAwardStats ) + file.playerAwardStats[highestScore_player]["mvp"] += 1.0 + AddPlayerScore( highestScore_player, "FDWaveMVP" ) + + wait 1 + + if ( !file.harvesterWasDamaged ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + AddPlayerScore( player, "FDTeamFlawlessWave" ) + } + + wait 1 + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + AddPlayerScore( player, "FDTeamFinalWave" ) + + wait 1 + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) //Repeat this one here because the block below is never reached due to return, and late joiners might not get the reward + { + UpdatePlayerStat( player, "fd_stats", "wavesComplete" ) + if ( file.players[player].wavesCompleted == 3 ) + { + AddPlayerScore( player, "ChallengeFD" ) + SetPlayerChallengeMeritScore( player ) + } + } + + RegisterPostSummaryScreenForMatch( true ) + + return false //False so it breaks the loop in the main function that handles the waves + } + + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_AnnounceWaveEnd ) + + wait 2 + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + UpdatePlayerStat( player, "fd_stats", "wavesComplete" ) + if ( file.players[player].wavesCompleted == 3 ) + { + AddPlayerScore( player, "ChallengeFD" ) + SetPlayerChallengeMeritScore( player ) + } + } + + WaveBreak_AnnounceHarvesterDamaged() + + wait 5 + + print( "Repairing turrets in wave break" ) + thread FD_AttemptToRepairTurrets() + + if ( waveIndex == 0 ) + { + wait 5 + WaveBreak_GiveAndLockTitanSelection() + wait 5 + } + + //Player scoring + WaveBreak_ShowPlayerBonus() + + print( "Waiting buy time" ) + if ( waveIndex < WaveSpawnEvents.len() ) + SetGlobalNetTime( "FD_nextWaveStartTime", Time() + GetCurrentPlaylistVarFloat( "fd_wave_buy_time", 60 ) + 15.0 ) //Vanilla has built-in extra 15s + + return true +} + +void function WaveBreak_RegisterAttackOrSupportScore( int scoretype ) +{ + if ( scoretype == 0 ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( file.players[player].assaultScoreThisRound > 0 ) + { + AddPlayerScore( player, "FDDamageBonus", null, "", file.players[player].assaultScoreThisRound ) + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, file.players[player].assaultScoreThisRound ) + UpdatePlayerScoreboard( player ) + } + } + } + + else if ( scoretype == 1 ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( file.players[player].defenseScoreThisRound > 0 ) + { + AddPlayerScore( player, "FDSupportBonus", null, "", file.players[player].defenseScoreThisRound ) + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, file.players[player].defenseScoreThisRound ) + UpdatePlayerScoreboard( player ) + } + } + } +} + +void function WaveBreak_AnnounceHarvesterDamaged() +{ + if ( !file.harvesterWasDamaged ) + PlayFactionDialogueToTeam( "fd_waveRecapPerfect", TEAM_MILITIA, true ) + else + { + float damagepercent = ( ( file.harvesterDamageTaken / fd_harvester.harvester.GetMaxHealth().tofloat() ) * 100 ) + float healthpercent = ( ( fd_harvester.harvester.GetHealth().tofloat() / fd_harvester.harvester.GetMaxHealth() ) * 100 ) + if ( damagepercent < 5 ) // if less than 5% damage taken + PlayFactionDialogueToTeam( "fd_waveRecapNearPerfect", TEAM_MILITIA, true ) + else if ( healthpercent < 15 ) // if less than 15% health remains and more than 5% damage taken + PlayFactionDialogueToTeam( "fd_waveRecapLowHealth", TEAM_MILITIA, true ) + else + PlayFactionDialogueToTeam( "fd_waveVictory", TEAM_MILITIA, true ) + } +} + +void function WaveBreak_GiveAndLockTitanSelection() +{ + PlayerEarnMeter_SetEnabled( true ) + foreach ( entity player in GetPlayerArray() ) + { + GiveTitanToPlayer( player ) + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_InGame_FD_TitanSelected" ) + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_InGame_FD_TitanSelected" ) + } + + DisableTitanSelection() + PlayFactionDialogueToTeam( "fd_titanReadyNag", TEAM_MILITIA ) +} + +void function WaveBreak_ShowPlayerBonus() +{ + int highestScore + entity highestScore_player + + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_NotifyWaveBonusIncoming ) + wait 3 + + print( "Showing Player Stats: Wave Complete" ) + SetJoinInProgressBonus( GetCurrentPlaylistVarInt( "fd_money_per_round", FD_MONEY_PER_ROUND ) ) + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( isSecondWave() ) + PlayFactionDialogueToPlayer( "fd_wavePayoutFirst", player, true ) + else + PlayFactionDialogueToPlayer( "fd_wavePayoutAddtnl", player, true ) + + AddPlayerScore( player, "FDTeamWave" ) + AddMoneyToPlayer( player, GetCurrentPlaylistVarInt( "fd_money_per_round", FD_MONEY_PER_ROUND ) ) + UpdatePlayerScoreboard( player ) + FD_EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P" ) + FD_EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_1P" ) + } + wait 2 + print( "Showing Player Stats: No Deaths This Wave" ) + SetJoinInProgressBonus( 100 ) + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( !file.players[player].diedThisRound ) + { + AddPlayerScore( player, "FDDidntDie" ) + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, FD_SCORE_DIDNT_DIE ) + UpdatePlayerScoreboard( player ) + AddMoneyToPlayer( player, 100 ) + FD_EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P" ) + } + } + wait 2 + print( "Showing Player Stats: Wave MVP" ) + SetJoinInProgressBonus( 100 ) + if ( GetPlayerArrayOfTeam( TEAM_MILITIA ).len() ) + { + highestScore = 0 + highestScore_player = GetPlayerArrayOfTeam( TEAM_MILITIA )[0] + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( highestScore < ( file.players[player].assaultScoreThisRound + file.players[player].defenseScoreThisRound ) ) + { + highestScore = file.players[player].assaultScoreThisRound + file.players[player].defenseScoreThisRound + highestScore_player = player + } + } + + if ( highestScore_player in file.playerAwardStats ) + file.playerAwardStats[highestScore_player]["mvp"] += 1.0 + AddPlayerScore( highestScore_player, "FDWaveMVP" ) + AddMoneyToPlayer( highestScore_player, 100 ) + highestScore_player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, FD_SCORE_MVP ) + UpdatePlayerScoreboard( highestScore_player ) + FD_EmitSoundOnEntityOnlyToPlayer( highestScore_player, highestScore_player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P" ) + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( player == highestScore_player ) + continue + + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_NotifyMVP", highestScore_player.GetEncodedEHandle() ) + } + } + + wait 2 + print( "Showing Player Stats: Flawless Defense" ) + SetJoinInProgressBonus( 100 ) + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( !file.harvesterWasDamaged ) + { + AddPlayerScore( player, "FDTeamFlawlessWave" ) + AddMoneyToPlayer( player, 100 ) + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, FD_SCORE_TEAM_FLAWLESS_WAVE ) + FD_EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P" ) + } + UpdatePlayerScoreboard( player ) + } + + wait 2 + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + FD_EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Successful_1P" ) + StopSoundOnEntity( player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_1P" ) + } + + wait 2 +} + +void function FD_AlivePlayersMonitor() +{ + svGlobal.levelEnt.EndSignal( "RoundEnd" ) + + while( true ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( IsAlive( player ) && player in file.playerAwardStats ) + { + file.playerAwardStats[player]["longestLife"] += 1.0 + if ( IsValid( GetSoulFromPlayer( player ) ) ) + file.playerAwardStats[player]["longestTitanLife"] += 1.0 + } + } + + wait 1.0 + } +} + + + + + + + + + + + +/* Player Setup +██████ ██ █████ ██ ██ ███████ ██████ ███████ ███████ ████████ ██ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ███████ ████ █████ ██████ ███████ █████ ██ ██ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███████ ██ ██ ██ ███████ ██ ██ ███████ ███████ ██ ██████ ██ +*/ + +void function GamemodeFD_InitPlayer( entity player ) +{ + player_struct_fd data + file.players[player] <- data + + table awardStats + foreach ( string statRef in GetFDStatRefs() ) + awardStats[statRef] <- 0.0 + + file.playerAwardStats[player] <- awardStats + + player.s.extracashnag <- Time() + player.s.didthepvpglitch <- false + player.s.isbeingmonitored <- false + player.s.scoredamage <- 0.0 + thread SetTurretSettings_threaded( player ) + + // only start the highlight when we start playing, not during dropship + if ( GetGameState() >= eGameState.Playing ) + Highlight_SetFriendlyHighlight( player, "sp_friendly_hero" ) + + //Store current Aegis unlocks + foreach ( string FDTitan in shTitanXP.titanClasses ) + player.SetPersistentVar( "previousFDUnlockPoints[" + FDTitan + "]", player.GetPersistentVarAsInt( "titanFDUnlockPoints[" + FDTitan + "]" ) ) + + string playerUID = player.GetUID() + if ( playerUID in file.playerSavedScore ) + { + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, file.playerSavedScore[ playerUID ].savedCombatScore ) + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, file.playerSavedScore[ playerUID ].savedSupportScore ) + UpdatePlayerScoreboard( player ) + } + + thread TryDisableTitanSelectionForPlayerAfterDelay( player ) + + if ( playerUID in file.playerHasTitanSelectionLocked ) + { + player.SetPersistentVar( "activeTitanLoadoutIndex", file.playerHasTitanSelectionLocked[ playerUID ] + 1 ) + SetActiveTitanLoadoutIndex( player, file.playerHasTitanSelectionLocked[ playerUID ] ) + SetActiveTitanLoadout( player ) + DisableTitanSelectionForPlayer( player ) + } + else + EnableTitanSelectionForPlayer( player ) //This is actually used in here to sort which Titans such player can use in the difficulty being played + thread TrackDeployedArcTrapThisRound( player ) + + thread UpdateEarnMeter_ByPlayersInMatch() + + if ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_BREAK && Time() + 30.0 > GetGlobalNetTime( "FD_nextWaveStartTime" ) && GetGlobalNetTime( "FD_nextWaveStartTime" ) > Time() ) + SetGlobalNetTime( "FD_nextWaveStartTime", Time() + 40.0 ) + + //Reset victory summary panel in here because dude just joined and prolly match havent finished + player.SetPersistentVar( "fd_match[" + eFDXPType.WAVES_COMPLETED + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WAVES_COMPLETED + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.RETRIES_REMAINING + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.RETRIES_REMAINING + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WAVES_ATTEMPTED + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.WAVES_ATTEMPTED + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.PERFECT_COMPOSITION + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.PERFECT_COMPOSITION + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.DIFFICULTY_BONUS + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.DIFFICULTY_BONUS + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.WARPAINT_BONUS + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WARPAINT_BONUS + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.EASY_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.EASY_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.NORMAL_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.NORMAL_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.HARD_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.HARD_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.MASTER_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.MASTER_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_match[" + eFDXPType.INSANE_VICTORY + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.INSANE_VICTORY + "]", 0 ) + player.SetPersistentVar( "isPostGameScoreboardValid", true ) + player.SetPersistentVar( "isFDPostGameScoreboardValid", false ) + if ( difficultyLevel >= eFDDifficultyLevel.INSANE ) + { + player.SetPersistentVar( "fd_match[" + eFDXPType.RETRIES_REMAINING + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.RETRIES_REMAINING + "]", 0 ) + } + + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.HARVESTER, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.ARC_TRAP, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.SENTRY_TURRET, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.CORE_OVERLOAD, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.WAVE_BREAK, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.FRONTIER_DEFENSE, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.HARD_DIFFICULTY, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.MASTER_DIFFICULTY, 0 ) + SetPersistenceBitfield( player, "fdTutorialBits", eFDTutorials.INSANE_DIFFICULTY, 0 ) +} + +void function OnPlayerDisconnectedOrDestroyed( entity player ) +{ + if ( file.playersInDropship.contains( player ) ) + { + file.playersInDropship.removebyvalue( player ) + file.playersInShip-- + } + + if ( player in file.playerAwardStats ) //Clear out disconnecting players so the postcards don't show less than 4 when server has more than 4 slots + delete file.playerAwardStats[player] + + string playerUID = player.GetUID() + if ( playerUID in file.playerSavedScore ) + { + file.playerSavedScore[ playerUID ].savedCombatScore = player.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + file.playerSavedScore[ playerUID ].savedSupportScore = player.GetPlayerGameStat( PGS_DEFENSE_SCORE ) + } + else + { + player_struct_score playerBackupScore + playerBackupScore.savedCombatScore = player.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + playerBackupScore.savedSupportScore = player.GetPlayerGameStat( PGS_DEFENSE_SCORE ) + + file.playerSavedScore[ playerUID ] <- playerBackupScore + } + + foreach ( entity npc in GetNPCArray() ) + { + entity BossPlayer = npc.GetBossPlayer() + if ( IsValidPlayer( BossPlayer ) && IsAlive( npc ) && BossPlayer == player && npc.GetTeam() == TEAM_MILITIA && ( IsMinion( npc ) || IsFragDrone( npc ) ) ) + npc.Die() + } +} + +bool function FD_ShouldAllowChangeLoadout( entity player ) +{ + return ( !GetGlobalNetBool( "FD_waveActive" ) || player.GetTeam() == TEAM_IMC ) +} + +void function FD_OnPlayerGetsNewPilotLoadout( entity player, PilotLoadoutDef loadout ) +{ + if ( GetCurrentPlaylistVarInt( "fd_at_unlimited_ammo", 1 ) ) + FD_GivePlayerInfiniteAntiTitanAmmo( player ) + + //If player has bought the Amped Weapons before, keep it for the new weapons + if ( "hasPermenantAmpedWeapons" in player.s && player.s.hasPermenantAmpedWeapons ) + { + array weapons = player.GetMainWeapons() + weapons.extend( player.GetOffhandWeapons() ) + foreach ( entity weapon in weapons ) + { + weapon.RemoveMod( "silencer" ) + foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) ) + { + try + { + weapon.AddMod( mod ) + } + catch( ex ) + { + weapons.removebyvalue( weapon ) + } + } + weapon.SetScriptFlags0( weapon.GetScriptFlags0() | WEAPONFLAG_AMPED ) + } + } +} + +void function FD_GivePlayerInfiniteAntiTitanAmmo( entity player ) +{ + foreach ( entity weaponEnt in player.GetMainWeapons() ) + { + if ( weaponEnt.GetWeaponInfoFileKeyField( "menu_category" ) != "at" ) + continue + + if ( !weaponEnt.HasMod( "at_unlimited_ammo" ) ) + weaponEnt.AddMod( "at_unlimited_ammo" ) + } +} + +void function FD_BoostPurchaseCallback( entity player, BoostStoreData data ) +{ + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["moneySpent"] += float( data.cost ) +} + +void function FD_TeamReserveDepositOrWithdrawCallback( entity player, string action, int amount ) +{ + if ( !( player in file.playerAwardStats ) ) + return + + switch ( action ) + { + case "deposit": + file.playerAwardStats[player]["moneyShared"] += float( amount ) + break + case "withdraw": + file.playerAwardStats[player]["moneyShared"] -= float( amount ) + break + } +} + +bool function FD_CheckPlayersReady() +{ + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( !player.GetPlayerNetBool( "FD_readyForNextWave" ) ) + return false + } + return true +} + +bool function ClientCommandCallbackToggleReady( entity player, array args ) +{ + if ( !args.len() || GetGlobalNetInt( "FD_waveState" ) != WAVE_STATE_BREAK || player.GetTeam() == TEAM_IMC ) + return true + + if ( args[0] == "true" && !player.GetPlayerNetBool( "FD_readyForNextWave" ) ) + { + player.SetPlayerNetBool( "FD_readyForNextWave", true ) + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_PlayerReady, null, player ) + } + else if ( args[0] == "false" && player.GetPlayerNetBool( "FD_readyForNextWave" ) ) + player.SetPlayerNetBool( "FD_readyForNextWave", false ) + + return true +} + +bool function ClientCommand_FDSetTutorialBit( entity player, array args ) +{ + if ( !args.len() ) + return true + + int fdbits = args[0].tointeger() + SetPersistenceBitfield( player, "fdTutorialBits", fdbits, -1 ) + return true +} + +bool function ClientCommandCallbackUseShieldBoost( entity player, array args ) +{ + if ( ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_BREAK || GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_NONE ) && player.GetPlayerNetInt( "numHarvesterShieldBoost" ) > 0 ) + return false + + if ( GetGlobalNetTime( "FD_harvesterInvulTime" ) < Time() && player.GetPlayerNetInt( "numHarvesterShieldBoost" ) > 0 ) + { + fd_harvester.harvester.SetShieldHealth( fd_harvester.harvester.GetShieldHealthMax() ) + + //If shield is down and someone uses Shield Boost, Harvester Shield Particle FX wasn't spawning (Vanilla bug) + if ( !IsValid( fd_harvester.particleShield ) ) + { + generateShieldFX( fd_harvester ) + EmitSoundOnEntity( fd_harvester.harvester, "shieldwall_deploy" ) + file.harvesterShieldDown = false //Assume this was set to true since shields went down + } + + int boostcount = player.GetPlayerNetInt( "numHarvesterShieldBoost" ) + boostcount-- + + fd_harvester.lastDamage = Time() - GENERATOR_SHIELD_REGEN_DELAY + SetGlobalNetTime( "FD_harvesterInvulTime", Time() + 5 ) + AddPlayerScore( player, "FDShieldHarvester" ) + MessageToTeam( TEAM_MILITIA,eEventNotifications.FD_PlayerBoostedHarvesterShield, player, player ) + player.SetPlayerNetInt( "numHarvesterShieldBoost", boostcount ) + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["harvesterHeals"] += 1.0 + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, FD_SCORE_SHIELD_HARVESTER ) + UpdatePlayerScoreboard( player ) + UpdatePlayerStat( player, "fd_stats", "harvesterBoosts" ) + } + return true +} + +void function TrackDeployedArcTrapThisRound( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + OnThreadEnd( + function() : ( player ) + { + thread UpdateEarnMeter_ByPlayersInMatch() + ClearInvalidFDEntities() + } + ) + + while( IsValidPlayer( player ) ) + { + entity ArcTrap = expect entity( player.WaitSignal( "DeployArcTrap" ).projectile ) + UpdatePlayerStat( player, "fd_stats", "arcMinesPlaced" ) + if ( player.GetTeam() == TEAM_IMC ) //Remove the ability of IMC players deploying Arc Traps for the defending players + ArcTrap.Destroy() + + if ( ArcTrap.e.fd_roundDeployed == -1 ) + ArcTrap.e.fd_roundDeployed = GetGlobalNetInt( "FD_currentWave" ) + } +} + +void function TryDisableTitanSelectionForPlayerAfterDelay( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + OnThreadEnd( + function() : ( player ) + { + if ( IsValidPlayer( player ) && GamePlaying() ) + { + int waveNumber = GetGlobalNetInt( "FD_currentWave" ) + + UnMuteAll( player ) //I've got reports of people having problems with muted audio when joining midgame + + if ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_BREAK ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_NotifyStoreOpen" ) + else if ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_IN_PROGRESS || GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_INCOMING ) //Announces which wave players are in right after they leave the Titan Selection Menu, this is to prevent the whole wave not having music for them + { + array enemys = getHighestEnemyAmountsForWave( waveNumber ) + + MessageToPlayer( player, eEventNotifications.FD_AnnounceWaveStart ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_UpdateWaveInfo", enemys[0], enemys[1], enemys[2], enemys[3], enemys[4], enemys[5], enemys[6], enemys[7], enemys[8] ) //Avoid joining players having blank scoreboard menu + + if ( player.GetParent() ) //Dropship check, because TTS Menu applies and removes player Invulnerability in its own way + player.SetInvulnerable() + } + + if ( PlayerEarnMeter_Enabled() ) + { + DisableTitanSelectionForPlayer( player ) + if ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_BREAK ) //On wave break, let joiners have their Titan instantly + GiveTitanToPlayer( player ) + } + } + } + ) + + player.WaitSignal( "StopSendingTTSMenuCommand" ) + wait 0.2 //Ensure to setup stuff after the TTS menu thingies +} + +void function SetTurretSettings_threaded( entity player ) +{ + WaitFrame() + DeployableTurret_SetAISettingsForPlayer_AP( player, "npc_turret_sentry_burn_card_ap_fd" ) + DeployableTurret_SetAISettingsForPlayer_AT( player, "npc_turret_sentry_burn_card_at_fd" ) + file.players[player].moneyThisRound = GetPlayerMoney( player ) //Save money in case bro joined midwave and that wave is about to restart +} + +void function DisableTitanSelection() +{ + foreach ( entity player in GetPlayerArray() ) + DisableTitanSelectionForPlayer( player ) +} + +void function EnableTitanSelection() +{ + foreach ( entity player in GetPlayerArray() ) + EnableTitanSelectionForPlayer( player ) +} + +void function EnableTitanSelectionForPlayer( entity player ) +{ + int enumCount = PersistenceGetEnumCount( "titanClasses" ) + + if ( !IsValidPlayer( player ) ) + return + + for ( int i = 0; i < enumCount; i++ ) + { + string enumName = PersistenceGetEnumItemNameForIndex( "titanClasses", i ) + if ( enumName != "" && ProgressionEnabledForPlayer( player ) ) + { + int AegisLevel = FD_TitanGetLevelForXP( enumName, FD_TitanGetXP( player, enumName ) ) + switch ( difficultyLevel ) + { + case eFDDifficultyLevel.HARD: + if ( GetItemUnlockType( "fd_hard" ) == eUnlockType.STAT && AegisLevel <= int( GetStatUnlockStatVal( "fd_hard" ) ) ) + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_LEVELRECOMMENDED ) + break + case eFDDifficultyLevel.MASTER: + if ( GetItemUnlockType( "fd_master" ) == eUnlockType.STAT && AegisLevel <= int( GetStatUnlockStatVal( "fd_master" ) ) ) + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_LEVELREQUIRED ) + break + case eFDDifficultyLevel.INSANE: + if ( GetItemUnlockType( "fd_insane" ) == eUnlockType.STAT && AegisLevel <= int( GetStatUnlockStatVal( "fd_insane" ) ) ) + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_LEVELREQUIRED ) + break + default: + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_AVAILABLE ) + } + } + else //Progression disabled, unlock everything regardless + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_AVAILABLE ) + } + + if ( !GetAvailableTitanRefs( player ).len() ) + { + for ( int i = 0; i < enumCount; i++ ) + { + string enumName = PersistenceGetEnumItemNameForIndex( "titanClasses", i ) + if ( enumName != "" ) + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_LEVELRECOMMENDED ) + } + } } -void function RateSpawnpoints_FD(int _0, array _1, int _2, entity _3) +void function DisableTitanSelectionForPlayer( entity player ) { + int enumCount = PersistenceGetEnumCount( "titanClasses" ) + if ( !IsValidPlayer( player ) ) + return + + int suitIndex = GetPersistentSpawnLoadoutIndex( player, "titan" ) + if ( suitIndex > enumCount ) + { + print( "Not locking Titans for " + player + " because selected titan is outside vanilla range, server is using custom Titans" ) + return + } + + string playerUID = player.GetUID() + if ( playerUID in file.playerHasTitanSelectionLocked ) //Override if player is rejoining with a different titan selected from lobby to bypass lock + suitIndex = file.playerHasTitanSelectionLocked[ playerUID ] + + string selectedEnumName = GetItemRefOfTypeByIndex( eItemTypes.TITAN, suitIndex ) + + for ( int i = 0; i < enumCount; i++ ) + { + string enumName = PersistenceGetEnumItemNameForIndex( "titanClasses", i ) + if ( enumName != "" && enumName != selectedEnumName ) + player.SetPersistentVar( "titanClassLockState[" + enumName + "]", TITAN_CLASS_LOCK_STATE_LOCKED ) + } + + player.SetPersistentVar( "titanClassLockState[" + selectedEnumName + "]", TITAN_CLASS_LOCK_STATE_AVAILABLE ) //Ensure selected one stays avaliable + if ( !( playerUID in file.playerHasTitanSelectionLocked ) ) + file.playerHasTitanSelectionLocked[ playerUID ] <- suitIndex +} + +void function WaveRestart_ResetPlayersInventory() +{ + foreach ( entity player in GetPlayerArray() ) + { + SetMoneyForPlayer( player, file.players[player].moneyThisRound ) + player.SetPlayerNetInt( "numHarvesterShieldBoost", 0 ) + player.SetPlayerNetInt( "numSuperRodeoGrenades", 0 ) + PlayerInventory_TakeAllInventoryItems( player ) + PlayerEarnMeter_Reset( player ) + } +} + +void function FD_PilotStartRodeo( entity pilot, entity titan ) +{ + if ( titan.GetTeam() == TEAM_IMC ) + UpdatePlayerStat( pilot, "fd_stats", "rodeos" ) +} + + + + + + + + + + + +/* Player Respawn Logic +██████ ██ █████ ██ ██ ███████ ██████ ██████ ███████ ███████ ██████ █████ ██ ██ ███ ██ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ███████ ████ █████ ██████ ██████ █████ ███████ ██████ ███████ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███████ ██ ██ ██ ███████ ██ ██ ██ ██ ███████ ███████ ██ ██ ██ ███ ███ ██ ████ ███████ ██████ ██████ ██ ██████ +*/ + +void function RateSpawnpoints_FD( int checkClass, array spawnpoints, int team, entity player ) +{ + foreach ( entity spawnpoint in spawnpoints ) + { + float rating = 0.0 + float enemiesRating = spawnpoint.NearbyEnemyScore( team, "ai" ) + spawnpoint.NearbyEnemyScore( team, "titan" ) + spawnpoint.NearbyEnemyScore( team, "pilot" ) + float distance = Distance2D( spawnpoint.GetOrigin(), file.harvesterLocation ) + if ( team == TEAM_MILITIA && distance < Distance2D( < 0, 0, 0 >, file.harvesterLocation ) ) + rating = 4.0 * ( 1 - ( distance / 3000.0 ) ) + else + rating = Distance2D( spawnpoint.GetOrigin(), file.harvesterLocation ) / MAP_EXTENTS + + rating += enemiesRating + spawnpoint.CalculateRating( checkClass, team, rating, rating * 0.25 ) + } +} + +void function FD_PlayerRespawnCallback( entity player ) +{ + if ( IsValidPlayer( player ) ) + { + if ( !GetGlobalNetInt( "FD_currentWave" ) ) + PlayerEarnMeter_SetMode( player, eEarnMeterMode.DISABLED ) + + if ( player.GetTeam() == TEAM_IMC ) + { + player.Minimap_AlwaysShow( TEAM_MILITIA, null ) + + array spawnpoints = SpawnPoints_GetPilotStart( TEAM_IMC ) + + if ( spawnpoints.len() && !player.IsTitan() ) + { + entity imcspawn = spawnpoints.getrandom() + + player.SetOrigin( imcspawn.GetOrigin() ) + player.SetAngles( imcspawn.GetAngles() ) + } + } + else if ( player.GetTeam() == TEAM_MILITIA && player.s.didthepvpglitch ) + { + SetTeam( player, TEAM_IMC ) + + player.Minimap_AlwaysShow( TEAM_MILITIA, null ) + + array spawnpoints = SpawnPoints_GetPilotStart( TEAM_IMC ) + + if ( spawnpoints.len() && !player.IsTitan() ) + { + entity imcspawn = spawnpoints.getrandom() + + player.SetOrigin( imcspawn.GetOrigin() ) + player.SetAngles( imcspawn.GetAngles() ) + } + } + } + else + return + + //Players spawn directly on ground if Dropship already passed the point where players drops from it + //If the wave is on break joiners can buy stuff with the time remaining + //Also more than 4 players, additionals will spawn directly on ground + //Respawning as Titan just will apply the Protection time + + if ( + !FD_ShouldUseRespawnDropship() && !player.IsTitan() && !GamePlaying() && + player.GetTeam() != TEAM_IMC && !player.s.didthepvpglitch + ) + { + //Teleport player to a more reliable location if they spawn on ground, some maps picks too far away spawns from the Harvester and Shop (i.e Colony, Homestead, Drydock) + player.SetOrigin( file.groundSpawnPosition ) + player.SetAngles( file.groundSpawnAngles ) + } + + if ( !IsHarvesterAlive( fd_harvester.harvester ) || player.GetTeam() == TEAM_IMC || GetGameState() == eGameState.Prematch ) + return + + if ( !player.IsTitan() ) + { + player.Highlight_SetParam( 1, 0, < 0, 0, 0 > ) + player.SetInvulnerable() + player.SetNoTarget( true ) + + ScreenFadeFromBlack( player, 1.5, 0.5 ) + } + else + { + player.Highlight_SetParam( 1, 0, HIGHLIGHT_COLOR_FRIENDLY ) + return + } + + if ( !FD_ShouldUseRespawnDropship() ) + { + if ( !player.IsTitan() ) + thread FD_PlayerRespawnProtection( player ) + return + } + + if ( file.dropshipState == eDropshipState.Idle ) + thread FD_DropshipSpawnDropship() + + if ( IsValid( file.dropship ) ) + { + //Attach player + FirstPersonSequenceStruct idleSequence + idleSequence.firstPersonAnim = DROPSHIP_IDLE_ANIMS_POV[ file.playersInShip ] + idleSequence.thirdPersonAnim = DROPSHIP_IDLE_ANIMS[ file.playersInShip ] + idleSequence.attachment = "ORIGIN" + idleSequence.teleport = true + idleSequence.viewConeFunction = ViewConeNarrow + idleSequence.hideProxy = true + + thread FirstPersonSequence( idleSequence, player, file.dropship ) + + file.playersInDropship.append( player ) + file.playersInShip++ + } +} + +bool function FD_ShouldUseRespawnDropship() +{ + return file.dropshipState != eDropshipState.Returning + && file.playersInShip < 4 + && GetGameState() == eGameState.Playing + && GetGlobalNetBool( "FD_waveActive" ) + && GetCurrentPlaylistVarInt( "fd_respawn_dropship", 1 ) != 0 + && file.dropshipSpawnPosition != < 0, 0, 0 > +} + + + + + + + + + + + +/* Damage Logic +██████ █████ ███ ███ █████ ██████ ███████ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ███████ ██ ████ ██ ███████ ██ ███ █████ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ██ ██ ██ ██ ██ ██████ ███████ ███████ ██████ ██████ ██ ██████ +*/ + +void function FD_DamageByPlayerCallback( entity victim, var damageInfo ) +{ + entity player = DamageInfo_GetAttacker( damageInfo ) + + if ( !( player in file.players ) || victim.IsTitan() ) + return + + float damageDone = min( victim.GetHealth(), DamageInfo_GetDamage( damageInfo ) ) + + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["damageDealt"] += damageDone + + player.s.scoredamage += damageDone + while( player.s.scoredamage >= 100 ) + { + player.s.scoredamage -= 100 + file.players[player].assaultScoreThisRound++ + } +} + +void function FD_DamageToMoney( entity victim, var damageInfo ) +{ + entity attacker = DamageInfo_GetAttacker( damageInfo ) + float damage = min( victim.GetHealth(), DamageInfo_GetDamage( damageInfo ) ) + float moneybuffer = ceil( victim.GetMaxHealth() / 50.0 ) + + if ( attacker.GetTeam() == TEAM_MILITIA && attacker.IsPlayer() && victim.IsTitan() && victim.GetTeam() == TEAM_IMC ) + { + if ( !HeavyArmorCriticalHitRequired( damageInfo ) || DamageInfo_GetCustomDamageType( damageInfo ) & DF_CRITICAL ) + { + if ( !( "moneydamage" in victim.s ) ) + victim.s.moneydamage <- 0.0 + + entity soul = victim.GetTitanSoul() + if ( !GetDoomedState( victim ) && soul.GetShieldHealth() <= 0 ) + { + victim.s.moneydamage += damage + while( victim.s.moneydamage >= moneybuffer ) + { + victim.s.moneydamage -= moneybuffer + AddMoneyToPlayer( attacker, 1 ) + } + } + + if ( soul.GetShieldHealth() <= 0 ) + { + attacker.s.scoredamage += damage + while( attacker.s.scoredamage >= 100 ) + { + attacker.s.scoredamage -= 100 + file.players[attacker].assaultScoreThisRound++ + } + } + + if ( attacker in file.playerAwardStats ) + file.playerAwardStats[attacker]["damageDealt"] += damage + } + } +} + +void function DamageScaleByDifficulty( entity ent, var damageInfo ) +{ + entity attacker = DamageInfo_GetAttacker( damageInfo ) + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + + if ( !attacker || !damageSourceID ) + return + + if ( ent.GetTeam() != TEAM_MILITIA ) + return + + //IMC Players being a distraction will do less damage, countermeasure to smoothen the stress put onto the Defending players + //Also Wave Breaks WILL be respected + if ( attacker.GetTeam() == TEAM_IMC ) + { + if ( attacker.IsPlayer() && !GetGlobalNetBool( "FD_waveActive" ) ) + { + SendHudMessage( attacker, "Do NOT Attack Defending players during Wave Breaks!", -1, 0.4, 255, 0, 0, 255, 0.15, 3.0, 0.5 ) + if ( IsAlive( attacker ) ) + attacker.Die( svGlobal.worldspawn, svGlobal.worldspawn, { damageSourceId = eDamageSourceId.damagedef_suicide } ) + if ( IsAlive( inflictor ) && inflictor.GetBossPlayer() == attacker ) + inflictor.Die( svGlobal.worldspawn, svGlobal.worldspawn, { damageSourceId = eDamageSourceId.damagedef_suicide } ) + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + else if ( attacker.IsPlayer() ) + { + switch ( damageSourceID ) + { + case eDamageSourceId.mp_weapon_sniper: + case eDamageSourceId.mp_weapon_mastiff: + case eDamageSourceId.mp_weapon_shotgun: + case eDamageSourceId.mp_weapon_defender: + case eDamageSourceId.mp_weapon_epg: + case eDamageSourceId.mp_weapon_softball: + case eDamageSourceId.mp_weapon_satchel: + case eDamageSourceId.mp_weapon_frag_grenade: + case eDamageSourceId.mp_weapon_thermite_grenade: + case eDamageSourceId.mp_weapon_pulse_lmg: + case eDamageSourceId.damagedef_titan_fall: + case eDamageSourceId.damagedef_titan_hotdrop: + DamageInfo_ScaleDamage( damageInfo, 0.1 ) + break + + case eDamageSourceId.melee_titan_punch_ion: + case eDamageSourceId.melee_titan_punch_tone: + case eDamageSourceId.melee_titan_punch_legion: + case eDamageSourceId.melee_titan_punch_scorch: + case eDamageSourceId.melee_titan_punch_northstar: + case eDamageSourceId.melee_titan_punch_vanguard: + case eDamageSourceId.melee_titan_sword: + if ( !ent.IsTitan() ) + DamageInfo_ScaleDamage( damageInfo, 0.1 ) + break + + case eDamageSourceId.mp_weapon_lstar: + case eDamageSourceId.mp_weapon_smr: + DamageInfo_ScaleDamage( damageInfo, 0.2 ) + break + + default: + DamageInfo_ScaleDamage( damageInfo, 0.4 ) + } + return + } + } + + if ( damageSourceID == eDamageSourceId.damagedef_stalker_powersupply_explosion_large_at && ent.IsPlayer() && ent.IsTitan() ) //Warn Titan players about Stalkers + PlayFactionDialogueToPlayer( "fd_stalkerExploNag", ent ) + + if ( difficultyLevel < eFDDifficultyLevel.MASTER && ( IsMinion( attacker ) || IsStalker( attacker ) || IsFragDrone( attacker ) ) ) //On Vanilla, Light Infantry does not scale damage to players for Hard or below + return + + DamageInfo_ScaleDamage( damageInfo, GetCurrentPlaylistVarFloat( "fd_player_damage_scalar", 1.0 ) ) +} + +void function HarvesterShieldInvulnCheck( entity harvester, var damageInfo, float actualShieldDamage ) +{ + if ( !IsValid( harvester ) || !GetGlobalNetBool( "FD_waveActive" ) ) + { + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + if ( fd_harvester.harvester != harvester ) + { + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + if ( GetGlobalNetTime( "FD_harvesterInvulTime" ) > Time() ) + { + harvester.SetShieldHealth( harvester.GetShieldHealthMax() ) + DamageInfo_SetDamage( damageInfo, 0.0 ) + } +} + +void function OnHarvesterDamaged( entity harvester, var damageInfo ) +{ + entity attacker = DamageInfo_GetAttacker( damageInfo ) + + /*On vanilla, because of the glitch of swapping teams, IMC players could attack the Harvester, i am removing this possibility from them because FD is a + PvE gamemode after all and such should behave accordingly, so what IMC players should do now is actually distract or kill the defending players, assisting + the AI in actually reach the Harvester for them to do the damage */ + if ( attacker.IsPlayer() && attacker.GetTeam() == TEAM_IMC ) + { + SendHudMessage( attacker, "You cannot attack the Harvester, only the AI!", -1, 0.4, 255, 255, 255, 255, 0.15, 3.0, 0.5 ) + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + if ( !IsValid( harvester ) || !GetGlobalNetBool( "FD_waveActive" ) ) //Harvester can only be damaged while waves are active, prevention of AI spawned outside waves or some other shenaningans modders might do + { + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + if ( fd_harvester.harvester != harvester ) + { + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + entity weapon = DamageInfo_GetWeapon( damageInfo ) + int attackerTypeID = FD_GetAITypeID_ByString( attacker.GetTargetName() ) + float damageAmount = DamageInfo_GetDamage( damageInfo ) + + //Titan smokes triggers damage calls on Harvester somehow + if ( attacker.GetTeam() == TEAM_MILITIA ) + { + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + if ( IsValid( weapon ) && HeavyArmorCriticalHitRequired( damageInfo ) && IsValid( attacker ) && !attacker.IsTitan() ) //Small change since Grunts will do 0 damage with normal guns because Harvester uses heavy armor + damageAmount = float( weapon.GetWeaponSettingInt( eWeaponVar.damage_near_value ) ) + + int PlayersInMatch = minint( 4, GetPlayerArrayOfTeam( TEAM_MILITIA ).len() + 1 ) //Additional players should not be considered + float MultiplierPerPlayer = 0.25 + + if ( !damageSourceID || !damageAmount || !IsValid( attacker ) ) + { + DamageInfo_ScaleDamage( damageInfo, 0.0 ) + return + } + + fd_harvester.lastDamage = Time() + + if ( difficultyLevel == eFDDifficultyLevel.EASY ) //Not sure if its a check vanilla does, but stuff does a bit less damage on Easy + damageAmount *= 0.8 + + /* Looks like Respawn stepped back with damage multipliers affecting the Harvester because a Charge Rifle grunt takes 15% of Harvester's health on Master + with the 2.5x multiplier, but doesn't do the same on vanilla. + damageAmount *= GetCurrentPlaylistVarFloat( "fd_player_damage_scalar", 1.0 ) + */ + + damageAmount *= MultiplierPerPlayer * PlayersInMatch + + //All of this multiplies after difficulty damage scalar + //These are not 1:1 to vanilla yet just for gameplay sanity, since on vanilla there are atrocious things that can happen which will be restored later + switch ( damageSourceID ) + { + //One of the atrocious things from vanilla is that AI can earn core on Hard or higher and remove the Harvester from existence + case eDamageSourceId.mp_titancore_laser_cannon: + case eDamageSourceId.mp_titancore_salvo_core: + case eDamageSourceId.mp_titanweapon_flightcore_rockets: + damageAmount *= 0.1 + break + + //Apparently Scorches does less damage because their thermite really just chomps the harvester really quick when damage is unchanged + case eDamageSourceId.mp_titanweapon_meteor: + case eDamageSourceId.mp_titanweapon_meteor_thermite: + case eDamageSourceId.mp_titanweapon_meteor_thermite_charged: + case eDamageSourceId.mp_titancore_flame_wave_secondary: + case eDamageSourceId.mp_titanweapon_heat_shield: + case eDamageSourceId.mp_titanweapon_flame_wall: + case eDamageSourceId.mp_titanweapon_flame_ring: + case eDamageSourceId.mp_titancore_flame_wave: + damageAmount *= 0.03 + break + + //Taken from consts, 1:1 to vanilla formula + case eDamageSourceId.damagedef_nuclear_core: + damageAmount *= GENERATOR_DAMAGE_NUKE_CORE_MULTIPLIER + break + + //Taken from consts, 1:1 to vanilla formula + case eDamageSourceId.mp_weapon_rocket_launcher: + case eDamageSourceId.mp_titanweapon_rocketeer_rocketstream: + damageAmount *= GENERATOR_DAMAGE_MORTAR_ROCKET_MULTIPLIER + break + + case eDamageSourceId.mp_weapon_smr: //SMR spectres doing 150 per missile is bad, so back to the 25 that they do to normal armor + damageAmount = 25 + break + } + + float shieldPercent = ( ( harvester.GetShieldHealth().tofloat() / harvester.GetShieldHealthMax() ) * 100 ) + if ( shieldPercent < 100 && !file.harvesterShieldDown ) + { + switch ( attackerTypeID ) + { + case eFD_AITypeIDs.TITAN_ARC: + PlayFactionDialogueToTeam( "fd_nagTitanArcAtBase", TEAM_MILITIA ) + break + + case eFD_AITypeIDs.STALKER: + PlayFactionDialogueToTeam( "fd_nagKillStalkers", TEAM_MILITIA ) + break + + case eFD_AITypeIDs.GRUNT: + case eFD_AITypeIDs.SPECTRE: + PlayFactionDialogueToTeam( "fd_nagKillInfantry", TEAM_MILITIA ) + break + + case eFD_AITypeIDs.TITAN_MORTAR: + PlayFactionDialogueToTeam( "fd_nagKillTitansMortar", TEAM_MILITIA ) + break + + case eFD_AITypeIDs.SPECTRE_MORTAR: + PlayFactionDialogueToTeam( "fd_nagKillMortarSpectres", TEAM_MILITIA ) + break + + case eFD_AITypeIDs.TITAN_NUKE: + if ( Distance2D( attacker.GetOrigin(), harvester.GetOrigin() ) < 2000 ) //Do this because bullets from Nuke Titans may trigger the speech from too far + PlayFactionDialogueToTeam( "fd_nukeTitanNearBase", TEAM_MILITIA ) + else + PlayFactionDialogueToTeam( "fd_baseShieldTakingDmg", TEAM_MILITIA ) + break + + default: + PlayFactionDialogueToTeam( "fd_baseShieldTakingDmg", TEAM_MILITIA ) + break + } + } + + if ( shieldPercent < 35 && !file.harvesterShieldDown ) // idk i made this up + PlayFactionDialogueToTeam( "fd_baseShieldLow", TEAM_MILITIA ) + + if ( harvester.GetShieldHealth() == 0 ) + { + file.harvesterDamageTaken += damageAmount // track damage for wave recaps + + if ( attackerTypeID in file.harvesterDamageSource ) //Only track damage from existing ids + file.harvesterDamageSource[attackerTypeID] += damageAmount + + float newHealth = harvester.GetHealth() - damageAmount + float oldhealthpercent = ( ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth() ) * 100 ) + float healthpercent = ( ( newHealth / harvester.GetMaxHealth() ) * 100 ) + + if ( healthpercent <= 75 && oldhealthpercent > 75 ) + PlayFactionDialogueToTeam( "fd_baseHealth75", TEAM_MILITIA ) + + if ( healthpercent <= 50 && oldhealthpercent > 50 ) + { + if ( !file.harvesterHalfHealth ) + { + sparksBeamFX( fd_harvester ) + StopSoundOnEntity( harvester, HARVESTER_SND_HEALTHY ) + EmitSoundOnEntity( harvester, HARVESTER_SND_DAMAGED ) + EmitSoundOnEntity( harvester, HARVESTER_SND_UNSTABLE ) + fd_harvester.rings.Anim_Play( HARVESTER_ANIM_ACTIVE_LOWHP ) + file.harvesterHalfHealth = true + } + if ( RandomInt( 100 ) >= 50 ) + PlayFactionDialogueToTeam( "fd_baseHealth50", TEAM_MILITIA ) + else + PlayFactionDialogueToTeam( "fd_baseHealth50nag", TEAM_MILITIA ) + } + + if ( healthpercent <= 25 && oldhealthpercent > 25 ) + { + StopSoundOnEntity( harvester, HARVESTER_SND_DAMAGED ) + EmitSoundOnEntity( harvester, HARVESTER_SND_CRITICAL ) + EmitSoundOnEntity( harvester, HARVESTER_SND_UNSTABLE ) + + if ( RandomInt( 100 ) >= 50 ) + PlayFactionDialogueToTeam( "fd_baseHealth25", TEAM_MILITIA ) + else + PlayFactionDialogueToTeam( "fd_baseHealth25nag", TEAM_MILITIA ) + } + + if ( healthpercent <= 15 ) + { + if ( fd_harvester.lastDamage > file.lastHarvesterLowHPAnnouncedTime ) + { + if ( RandomInt( 100 ) >= 50 ) + PlayFactionDialogueToTeam( "fd_baseLowHealth", TEAM_MILITIA ) + else + PlayFactionDialogueToTeam( "fd_baseShieldLowHolding", TEAM_MILITIA ) + + file.lastHarvesterLowHPAnnouncedTime = Time() + 5.0 + } + } + + if ( newHealth <= 0 ) + { + newHealth = 1 + harvester.SetInvulnerable() + DamageInfo_SetDamage( damageInfo, 0.0 ) + fd_harvester.rings.Anim_Play( HARVESTER_ANIM_DESTROYED ) + playHarvesterDestructionFX( fd_harvester ) + } + + if ( IsValid( fd_harvester.particleSparks ) ) + { + vector sparkColor = GetHarvesterBeamTriLerpColor( 1.0 - ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth().tofloat() ) ) + EffectSetControlPointVector( fd_harvester.particleSparks, 1, sparkColor ) + } + + harvester.SetHealth( newHealth ) + file.harvesterWasDamaged = true + file.harvesterPerfectWin = false //Remove perfect win + } + + DamageInfo_SetDamage( damageInfo, damageAmount ) +} + + + + + + + + + + + +/* Spawn Logic +███████ ██████ █████ ██ ██ ███ ██ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ +███████ ██████ ███████ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ + ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██ ██ ██ ███ ███ ██ ████ ███████ ██████ ██████ ██ ██████ +*/ + +void function HealthScaleByDifficulty( entity ent ) +{ + if ( ent.GetTeam() == TEAM_MILITIA ) + { + thread OnFriendlyNPCTitanSpawnThreaded( ent ) + return + } + + if ( ent.IsTitan() && IsValid( GetPetTitanOwner( ent ) ) ) // in case we ever want pvp in FD + { + thread OnEnemyNPCPlayerTitanSpawnThreaded( ent ) + return + } + + if ( ent.IsTitan() ) + ent.SetMaxHealth( ent.GetMaxHealth() + GetCurrentPlaylistVarInt( "fd_titan_health_adjust", 0 ) ) + else if ( IsSuperSpectre( ent ) ) + ent.SetMaxHealth( ent.GetMaxHealth() + GetCurrentPlaylistVarInt( "fd_reaper_health_adjust", 0 ) ) +} + +void function OnFriendlyNPCTitanSpawnThreaded( entity npc ) +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + FD_UpdateTitanBehavior() + WaitFrame() + WaitTillHotDropComplete( npc ) + Highlight_SetFriendlyHighlight( npc, "sp_friendly_hero" ) + npc.Highlight_SetParam( 1, 0, HIGHLIGHT_COLOR_FRIENDLY ) +} + +void function OnEnemyNPCPlayerTitanSpawnThreaded( entity npc ) +{ + npc.Minimap_SetAlignUpright( true ) + npc.Minimap_AlwaysShow( TEAM_MILITIA, null ) + npc.Minimap_SetCustomState( eMinimapObject_npc_titan.AT_BOUNTY_BOSS ) + + int aiTypeID = eFD_AITypeIDs.TITAN + switch ( GetTitanCharacterName( npc ) ) + { + case "ion": + aiTypeID = eFD_AITypeIDs.ION + break + case "tone": + aiTypeID = eFD_AITypeIDs.TITAN_SNIPER + break + case "legion": + aiTypeID = eFD_AITypeIDs.LEGION + break + case "scorch": + aiTypeID = eFD_AITypeIDs.SCORCH + break + case "ronin": + aiTypeID = eFD_AITypeIDs.RONIN + break + case "northstar": + aiTypeID = eFD_AITypeIDs.NORTHSTAR + break + case "vanguard": + aiTypeID = eFD_AITypeIDs.MONARCH + break + } + + WaitTillHotDropComplete( npc ) + WaitFrame() + SetTargetName( npc, GetTargetNameForID( aiTypeID ) ) + + if ( !IsAlive( npc ) ) + return + + GiveShieldByDifficulty( npc, true ) + entity soul = npc.GetTitanSoul() + if ( IsValid( soul ) ) + soul.SetTitanSoulNetBool( "showOverheadIcon", true ) +} + +void function OnTickSpawn( entity tick ) +{ + thread TickSpawnThreaded( tick ) +} + +void function TickSpawnThreaded( entity tick ) +{ + WaitFrame() + if ( IsValid( tick.GetParent() ) ) //Parented Ticks are Drop Pod ones, and those are handled by the function there itself + return + + else if ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_IN_PROGRESS && IsHarvesterAlive( fd_harvester.harvester ) ) + { + tick.kv.alwaysalert = 1 + tick.Minimap_SetAlignUpright( true ) + tick.Minimap_AlwaysShow( TEAM_IMC, null ) + tick.Minimap_AlwaysShow( TEAM_MILITIA, null ) + tick.Minimap_SetHeightTracking( true ) + tick.Minimap_SetZOrder( MINIMAP_Z_NPC ) + tick.Minimap_SetCustomState( eMinimapObject_npc.AI_TDM_AI ) + tick.EnableNPCFlag( NPC_ALLOW_INVESTIGATE ) + if ( tick.GetTeam() == TEAM_IMC ) + thread NPCNav_FD( tick, "" ) + } + else + { + if ( IsAlive( tick ) && tick.GetTeam() == TEAM_IMC ) //In case you wonder, this is to immediately kill Ticks spawned by Reapers AFTER wave completion + tick.Destroy() + } +} + +void function AddTurretSentry( entity turret ) +{ + entity player = turret.GetBossPlayer() + if ( player != null && player.GetTeam() == TEAM_MILITIA ) + { + UpdatePlayerStat( player, "fd_stats", "turretsPlaced" ) + + turret.Minimap_AlwaysShow( TEAM_MILITIA, null ) + turret.Minimap_SetHeightTracking( true ) + turret.Minimap_SetZOrder( MINIMAP_Z_NPC ) + turret.Minimap_SetCustomState( eMinimapObject_npc.FD_TURRET ) + turret.SetMaxHealth( DEPLOYABLE_TURRET_HEALTH ) + turret.SetHealth( DEPLOYABLE_TURRET_HEALTH ) + turret.kv.AccuracyMultiplier = DEPLOYABLE_TURRET_ACCURACY_MULTIPLIER + turret.ai.buddhaMode = true + turret.EnableNPCFlag( NPC_NO_PAIN | NPC_NO_GESTURE_PAIN | NPC_IGNORE_FRIENDLY_SOUND | NPC_NEW_ENEMY_FROM_SOUND | NPC_TEAM_SPOTTED_ENEMY ) + SetPreventSmartAmmoLock( turret, true ) //Prevents enemy Legion Smart Core to target them automatically + Highlight_SetOwnedHighlight( turret , "sp_friendly_hero" ) + turret.Highlight_SetParam( 3, 0, HIGHLIGHT_COLOR_INTERACT ) + + if ( turret.e.fd_roundDeployed == -1 ) + turret.e.fd_roundDeployed = GetGlobalNetInt( "FD_currentWave" ) + + thread TurretRefundThink( turret ) + + if ( turret.GetMainWeapons()[0].GetWeaponClassName() == "mp_weapon_yh803_bullet" ) + turret.GetMainWeapons()[0].AddMod( "fd" ) + } + else if ( player != null && player.GetTeam() == TEAM_IMC ) + turret.Destroy() //IMC Players shall not deploy turrets +} + + + + + + + + + + + +/* Death Logic +██████ ███████ █████ ████████ ██ ██ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ █████ ███████ ██ ███████ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ███████ ██ ██ ██ ██ ██ ███████ ██████ ██████ ██ ██████ +*/ + +void function GamemodeFD_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( file.playersInDropship.contains( victim ) ) + { + file.playersInDropship.removebyvalue( victim ) + file.playersInShip-- + } + + if ( !IsHarvesterAlive( fd_harvester.harvester ) || GetGameState() != eGameState.Playing ) + return + + victim.s.currentKillstreak = 0 + victim.s.lastKillTime = 0.0 + victim.s.currentTimedKillstreak = 0 + victim.s.hasPermenantAmpedWeapons = false + + if ( victim.GetTeam() == TEAM_IMC && attacker.IsPlayer() && attacker.GetTeam() == TEAM_MILITIA && GetGlobalNetBool( "FD_waveActive" ) ) //Give money to Militia players killing IMC players + { + PlayerEarnMeter_AddEarnedFrac( attacker, 0.15 ) + AddMoneyToPlayer( attacker, 25 ) + victim.s.didthepvpglitch = true //Flag the player to force it to stay on IMC side for the whole wave as punishment + if ( !victim.s.isbeingmonitored ) + thread PvPGlitchMonitor( victim ) + return + } + + if ( FD_PlayerInDropship( victim ) ) + { + victim.ClearParent() + ClearPlayerAnimViewEntity( victim ) + victim.ClearInvulnerable() + } + //set longest Time alive for end awards + if ( victim in file.players && victim in file.playerAwardStats ) + { + if ( file.players[victim].lastRespawnLifespan < file.playerAwardStats[victim]["longestLife"] ) + file.players[victim].lastRespawnLifespan = file.playerAwardStats[victim]["longestLife"] + + file.playerAwardStats[victim]["longestLife"] = 0.0 //Reset to count again + } + + file.players[victim].pilotPerfectWin = false //Remove perfect win for this player + + if ( GetGlobalNetInt( "FD_waveState") != WAVE_STATE_BREAK ) + file.players[victim].diedThisRound = true + + //play voicelines for amount of players alive + array militiaplayers = GetPlayerArrayOfTeam( TEAM_MILITIA ) + int deaths = 0 + foreach ( entity player in militiaplayers ) + if ( !IsAlive( player ) || IsAlive( player.GetParent() ) && player.GetParent().GetClassName() == "npc_dropship" ) + deaths++ + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( player == victim ) + continue + + if ( player.GetParent() && player.GetParent().GetClassName() == "npc_dropship" ) + continue + + if ( deaths == 1 ) // only one pilot died + PlayFactionDialogueToPlayer( "fd_singlePilotDown", player ) + else if ( deaths > 1 && deaths < militiaplayers.len() - 1 ) // multiple pilots died but at least one alive + PlayFactionDialogueToPlayer( "fd_multiPilotDown", player ) + else if ( deaths == militiaplayers.len() - 1 ) // ur shit out of luck ur the only survivor + PlayFactionDialogueToPlayer( "fd_onlyPlayerIsAlive", player ) + } +} + +void function FD_OnNPCDeath( entity victim, entity attacker, var damageInfo ) +{ + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + int scriptDamageType = DamageInfo_GetCustomDamageType( damageInfo ) + int damageSourceId = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + + if ( attacker.IsPlayer() && attacker.GetTeam() == TEAM_IMC ) //Give nothing for IMC players + return + + //Killing unwanted NPCs instantly causes a crash + switch ( victim.GetClassName() ) + { + case "npc_gunship": + case "npc_dropship": + case "npc_marvin": + case "npc_prowler": + case "npc_pilot_elite": + case "npc_turret_sentry": + return + } + + if ( victim.IsTitan() && victim.GetTeam() == TEAM_MILITIA && IsValid( victim.GetBossPlayer() ) ) + file.players[victim.GetBossPlayer()].titanPerfectWin = false //Remove perfect win for the owner of the Titan + + int victimTypeID = FD_GetAITypeID_ByString( victim.GetTargetName() ) + + if ( IsPlayerControlledTurret( inflictor ) && inflictor.GetBossPlayer() == attacker && attacker in file.players ) + { + if ( attacker in file.playerAwardStats ) + file.playerAwardStats[attacker]["turretKills"] += 1.0 + if ( "totalScore" in inflictor.s ) + inflictor.s.totalScore += 2 + + file.players[attacker].defenseScoreThisRound += 5 + UpdatePlayerStat( attacker, "fd_stats", "turretKills" ) + } + + if ( victim.IsTitan() && attacker in file.playerAwardStats ) + file.playerAwardStats[attacker]["titanKills"] += 1.0 + + if ( victimTypeID == eFD_AITypeIDs.TITAN_MORTAR || victimTypeID == eFD_AITypeIDs.SPECTRE_MORTAR ) + if ( attacker in file.playerAwardStats ) + file.playerAwardStats[attacker]["mortarUnitsKilled"] += 1.0 + + if ( victim.GetOwner() == attacker || !attacker.IsPlayer() || attacker == victim || victim.GetBossPlayer() == attacker || !IsValid( attacker ) ) + return + + int money = 0 + if ( victim.IsNPC() ) + { + //Play the subtle kill sound and immediately sets NPCs as nonsolid to prevent them bodyblocking further shots from hitting alive allies behind + victim.NotSolid() + victim.Minimap_Hide( TEAM_IMC, null ) + victim.Minimap_Hide( TEAM_MILITIA, null ) + + if ( victim.IsTitan() ) + victim.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", false ) + + switch ( victim.GetClassName() ) + { + case "npc_soldier": + AddPlayerScore( attacker, "FDGruntKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_GRUNT + money = GetCurrentPlaylistVarInt( "fd_killcredit_grunt", 5 ) + break + case "npc_drone": + if ( !IsAttackDrone( victim ) ) //ignore worker drones + break + AddPlayerScore( attacker, "FDAirDroneKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_AIR_DRONE + money = GetCurrentPlaylistVarInt( "fd_killcredit_drone", 10 ) + break + case "npc_spectre": + AddPlayerScore( attacker, "FDSpectreKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_SPECTRE + money = GetCurrentPlaylistVarInt( "fd_killcredit_spectre", 10 ) + break + case "npc_stalker": + AddPlayerScore( attacker, "FDStalkerKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_STALKER + money = GetCurrentPlaylistVarInt( "fd_killcredit_stalker", 15 ) + break + case "npc_super_spectre": + AddPlayerScore( attacker, "FDSuperSpectreKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_SUPER_SPECTRE + money = GetCurrentPlaylistVarInt( "fd_killcredit_reaper", 20 ) + break + case "npc_titan": + AddPlayerScore( attacker, "FDTitanKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_TITAN + break + default: + money = 0 + } + if ( damageSourceId == eDamageSourceId.rodeo_forced_titan_eject || damageSourceId == eDamageSourceId.core_overload ) + UpdatePlayerStat( attacker, "fd_stats", "rodeoNukes" ) + } + + if ( money != 0 ) + { + if ( victim.GetClassName() != "npc_drone" && GetCurrentPlaylistVarInt( "fd_money_flyouts", 0 ) == 1 ) //Drones returns null because they stop existing right on death frame + Remote_CallFunction_NonReplay( attacker, "ServerCallback_FD_MoneyFly", victim.GetEncodedEHandle(), money ) + AddMoneyToPlayer( attacker , money ) + } + + if ( IsValid( inflictor ) ) + { + if ( !inflictor.IsNPC() && attacker.IsPlayer() ) //Turret and Auto-Titan kills should not give xp awards + { + entity weapon = attacker.GetActiveWeapon() + bool canWeaponEarnXp = IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) ? true : false + + attacker.s.currentKillstreak++ + if ( attacker.s.currentKillstreak >= 5 && canWeaponEarnXp ) + { + AddWeaponXP( attacker, 1 ) + attacker.s.currentKillstreak = 0 + } + + if ( Time() - attacker.s.lastKillTime > CASCADINGKILL_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak = 0 + attacker.s.currentKillstreak = 0 + attacker.s.lastKillTime = Time() + } + } + } + + attacker.s.lastKillTime = Time() + + if ( IsValid( inflictor ) ) + { + if ( !inflictor.IsNPC() && !attacker.IsTitan() && victim.IsTitan() ) + { + if ( Time() - attacker.s.lastKillTime <= CASCADINGKILL_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak++ + + if ( attacker.s.currentTimedKillstreak == DOUBLEKILL_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "DoubleKill" ) + else if ( attacker.s.currentTimedKillstreak == TRIPLEKILL_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "TripleKill" ) + else if ( attacker.s.currentTimedKillstreak == MEGAKILL_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "MegaKill" ) + } + } + } +} + +void function FD_OnNPCLeeched( entity victim, entity attacker ) +{ + int findIndex = spawnedNPCs.find( victim ) + if ( findIndex != -1 ) + { + spawnedNPCs.remove( findIndex ) + string netIndex = GetAiNetIdFromTargetName( victim.GetTargetName() ) + if ( netIndex != "" ) + SetGlobalNetInt( netIndex, GetGlobalNetInt( netIndex ) - 1 ) + + SetGlobalNetInt( "FD_AICount_Current", GetGlobalNetInt( "FD_AICount_Current" ) - 1 ) + } + + if ( victim.IsNPC() && victim.GetClassName() == "npc_spectre" ) + { + file.players[attacker].assaultScoreThisRound += FD_SCORE_SPECTRE + AddMoneyToPlayer( attacker, 10 ) + victim.kv.AccuracyMultiplier = 1.0 + victim.kv.WeaponProficiency = eWeaponProficiency.AVERAGE + victim.SetBehaviorSelector( "behavior_spectre" ) + victim.Minimap_AlwaysShow( TEAM_MILITIA, null ) + victim.ai.preventOwnerDamage = true + } +} + +void function OnTickDeath( entity victim, var damageInfo ) +{ + entity attacker = DamageInfo_GetAttacker( damageInfo ) + + int findIndex = spawnedNPCs.find( victim ) + if ( findIndex != -1 ) + { + victim.Minimap_Hide( TEAM_IMC, null ) + victim.Minimap_Hide( TEAM_MILITIA, null ) + + if ( IsValid( attacker ) && attacker.IsPlayer() ) + { + EmitSoundOnEntityOnlyToPlayer( attacker, attacker, "HUD_Grunt_Killed_Indicator" ) + AddPlayerScore( attacker, "FDGruntKilled" ) + file.players[attacker].assaultScoreThisRound += FD_SCORE_GRUNT + AddMoneyToPlayer( attacker , 5 ) + } + } +} + +void function FD_GenericNPCDeathChecker( entity npc ) +{ + if ( !IsNewThread() ) + { + thread FD_GenericNPCDeathChecker( npc ) + return + } + + npc.EndSignal( "OnDestroy" ) + npc.EndSignal( "OnDeath" ) + + OnThreadEnd + ( + function() : ( npc ) + { + if ( IsValid( svGlobal.levelEnt ) ) + { + int findIndex = spawnedNPCs.find( npc ) + if ( findIndex != -1 ) + { + spawnedNPCs.remove( findIndex ) + string netIndex = GetAiNetIdFromTargetName( npc.GetTargetName() ) + if ( netIndex != "" ) + SetGlobalNetInt( netIndex, GetGlobalNetInt( netIndex ) - 1 ) + + if ( IsAirDrone( npc ) && GetDroneType( npc ) == "drone_type_cloaked" ) + return + + SetGlobalNetInt( "FD_AICount_Current", GetGlobalNetInt( "FD_AICount_Current" ) - 1 ) + + if ( IsTick( npc ) ) + SetGlobalNetInt( "FD_AICount_Ticks", GetGlobalNetInt( "FD_AICount_Ticks" ) - 1 ) + } + } + } + ) + + WaitForever() +} + +void function ClearInvalidFDEntities() +{ + foreach ( projectile in GetProjectileArray() ) + { + if ( projectile instanceof CProjectile || projectile instanceof CBaseGrenade ) + { + if ( !IsValidPlayer( projectile.GetOwner() ) ) + projectile.Destroy() + } + } + foreach ( entity turret in GetNPCArrayByClass( "npc_turret_sentry" ) ) + { + if ( !IsValidPlayer( turret.GetBossPlayer() ) && IsValid( turret ) && turret.GetAISettingsName() == "npc_turret_sentry_burn_card_ap_fd" ) + turret.Destroy() + } +} + + + + + + + + + + + +/* Harvester Logic +██ ██ █████ ██████ ██ ██ ███████ ███████ ████████ ███████ ██████ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ███████ ██████ ██ ██ █████ ███████ ██ █████ ██████ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ██ ██ ██ ████ ███████ ███████ ██ ███████ ██ ██ ███████ ██████ ██████ ██ ██████ +*/ + +void function startHarvester() +{ + thread HarvesterThink() + thread HarvesterAlarm() +} + +void function HarvesterAlarm() +{ + while( IsHarvesterAlive( fd_harvester.harvester ) ) + { + if ( fd_harvester.harvester.GetShieldHealth() == 0 ) + wait EmitSoundOnEntity( fd_harvester.harvester, HARVESTER_SND_KLAXON ) + else + WaitFrame() + } +} + +void function HarvesterThink() +{ + entity harvester = fd_harvester.harvester + float lastTime = Time() + wait 2 + EmitSoundOnEntity( harvester, HARVESTER_SND_STARTUP ) + fd_harvester.rings.Anim_Play( HARVESTER_ANIM_ACTIVATING ) + entity mainBeamStart = PlayLoopFXOnEntity( $"P_harvester_beam", harvester ) + mainBeamStart.DisableHibernation() + fd_harvester.particleFXArray.append( mainBeamStart ) + wait 4 + harvester.SetNoTarget( false ) + fd_harvester.rings.Anim_Play( HARVESTER_ANIM_ACTIVE ) + int lastShieldHealth = harvester.GetShieldHealth() + generateBeamFX( fd_harvester ) + generateShieldFX( fd_harvester ) + EmitSoundOnEntity( harvester, HARVESTER_SND_HEALTHY ) + + bool isRegening = false // stops the regenning sound to keep stacking on top of each other + int shieldregenpercent + float harvesterShieldRegenDelay = GetCurrentPlaylistVarFloat( "fd_harvester_regen_delay", 10.0 ) + float harvesterShieldRegenTime = GetCurrentPlaylistVarFloat( "fd_harvester_regen_time", 10.0 ) + + while ( IsHarvesterAlive( harvester ) ) + { + float currentTime = Time() + float deltaTime = currentTime - lastTime + + if ( IsValid( fd_harvester.particleShield ) ) + { + vector shieldColor = GetShieldTriLerpColor( 1.0 - ( harvester.GetShieldHealth().tofloat() / harvester.GetShieldHealthMax().tofloat() ) ) + if ( GetGlobalNetTime( "FD_harvesterInvulTime" ) > Time() ) + EffectSetControlPointVector( fd_harvester.particleShield, 1, < 255, 192, 96 > ) + else + EffectSetControlPointVector( fd_harvester.particleShield, 1, shieldColor ) + } + + if ( IsValid( fd_harvester.particleBeam ) ) + { + vector beamColor = GetHarvesterBeamTriLerpColor( 1.0 - ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth().tofloat() ) ) + if ( harvester.GetHealth() > 1 ) + EffectSetControlPointVector( fd_harvester.particleBeam, 1, beamColor ) + } + + if ( fd_harvester.harvester.GetShieldHealth() == 0 ) + if ( IsValid( fd_harvester.particleShield ) ) + fd_harvester.particleShield.Destroy() + + if ( ( ( currentTime - fd_harvester.lastDamage ) >= harvesterShieldRegenDelay ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) + { + if ( !IsValid( fd_harvester.particleShield ) ) + generateShieldFX( fd_harvester ) + + //printt((currentTime-fd_harvester.lastDamage)) + + if ( file.harvesterShieldDown ) + EmitSoundOnEntity( harvester, HARVESTER_SND_SHIELDFROMZERO ) + + if (!isRegening) + { + if ( !file.harvesterShieldDown ) + { + EmitSoundOnEntity( harvester, HARVESTER_SND_SHIELDFROMMID ) + EmitSoundOnEntity( harvester, HARVESTER_SND_SHIELDREGENLOOP ) + } + file.harvesterShieldDown = false + if ( GetGlobalNetBool( "FD_waveActive" ) && harvester.GetShieldHealth() < harvester.GetShieldHealthMax() / 2 ) + { + if ( RandomInt( 100 ) >= 50 ) + PlayFactionDialogueToTeam( "fd_baseShieldRecharging", TEAM_MILITIA, true ) + else + PlayFactionDialogueToTeam( "fd_baseShieldRechargingShort", TEAM_MILITIA, true ) + } + shieldregenpercent = harvester.GetShieldHealth() + isRegening = true + } + + float newShieldHealth = ( harvester.GetShieldHealthMax() / harvesterShieldRegenTime * deltaTime ) + harvester.GetShieldHealth() + + if ( newShieldHealth >= harvester.GetShieldHealthMax() ) + { + StopSoundOnEntity( harvester, HARVESTER_SND_SHIELDREGENLOOP ) + harvester.SetShieldHealth( harvester.GetShieldHealthMax() ) + EmitSoundOnEntity( harvester, HARVESTER_SND_SHIELDFULL ) + if ( GetGlobalNetBool( "FD_waveActive" ) && shieldregenpercent <= ( harvester.GetShieldHealthMax() * 0.8 ) ) //Only talk about Harvester shield back up if shield drops below 80% and during waves, prevents too much dialogue cutting just for this + PlayFactionDialogueToTeam( "fd_baseShieldUp", TEAM_MILITIA, true ) + isRegening = false + } + + else + harvester.SetShieldHealth( newShieldHealth ) + } + + else if ( ( ( currentTime-fd_harvester.lastDamage ) < harvesterShieldRegenDelay ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) + isRegening = false + + if ( lastShieldHealth > 0 && harvester.GetShieldHealth() == 0 ) + { + EmitSoundOnEntity( harvester, HARVESTER_SND_SHIELDBREAK ) + PlayFactionDialogueToTeam( "fd_baseShieldDown", TEAM_MILITIA, true ) + file.harvesterShieldDown = true + } + + lastShieldHealth = harvester.GetShieldHealth() + lastTime = currentTime + WaitFrame() + } +} + +bool function IsHarvesterAlive( entity harvester ) +{ + if ( harvester == null ) + return false + if ( !harvester.IsValidInternal() ) + return false + if ( !harvester.IsEntAlive() ) + return false + + return harvester.GetHealth() > 1 +} + +void function MonitorHarvesterProximity( entity harvester ) +{ + harvester.EndSignal( "OnDestroy" ) + + while( IsHarvesterAlive( harvester ) ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( IsAlive( player ) && Distance( player.GetOrigin(), harvester.GetOrigin() ) <= FD_HARVESTER_PERIMETER_DIST ) + { + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["timeNearHarvester"] += 1.0 + } + } + + wait 1 + } +} + + + + + + + + + + + +/* Dropship Functions +██████ ██████ ██████ ██████ ███████ ██ ██ ██ ██████ ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██ ██ ██████ ██ ██ ██████ ███████ ███████ ██ ██████ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ██ ██████ ██ ███████ ██ ██ ██ ██ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ +*/ + +bool function FD_PlayerInDropship( entity player ) +{ + if ( !IsValid( file.dropship ) ) + return false + + if ( !IsValidPlayer( player ) ) + return false + + foreach ( entity dropshipPlayer in file.playersInDropship ) + if ( dropshipPlayer == player ) + return true + + return false +} + +void function FD_DropshipSpawnDropship() +{ + svGlobal.levelEnt.EndSignal( "RoundEnd" ) + + OnThreadEnd( function() : () + { + file.playersInDropship.clear() + file.playersInShip = 0 //Do it again in here to avoid dropship not appearing anymore after a while if theres too many players in a match + file.dropshipState = eDropshipState.Idle + }) + + asset model = GetFlightPathModel( "fp_crow_model" ) + + Point start = GetWarpinPosition( model, FD_DropshipGetAnimation(), file.dropshipSpawnPosition, file.dropshipSpawnAngles ) + entity fx = PlayFX( FX_GUNSHIP_CRASH_EXPLOSION_ENTRANCE, start.origin, start.angles ) + fx.FXEnableRenderAlways() + fx.DisableHibernation() + + file.playersInShip = 0 + file.dropshipState = eDropshipState.InProgress + file.dropship = CreateDropship( TEAM_MILITIA, file.dropshipSpawnPosition, file.dropshipSpawnAngles ) + file.dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + + file.dropship.Hide() + DispatchSpawn( file.dropship ) + file.dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + file.dropship.SetInvulnerable() + file.dropship.NotSolid() + NPC_NoTarget( file.dropship ) + + thread PlayAnim( file.dropship, FD_DropshipGetAnimation() ) + file.dropship.Show() + + file.dropship.Anim_ScriptedAddGestureSequence( "dropship_coop_respawn", true ) + file.dropship.WaitSignal( "deploy" ) + file.dropshipState = eDropshipState.Returning + + foreach ( int i, entity player in file.playersInDropship ) + { + if ( IsValid( player ) ) + thread FD_DropshipDropPlayer( player, i ) + } + + if ( file.playersInDropship.len() > 0 && GamePlaying() ) //Only one player in dropship is needed to warn about them respawning + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( file.playersInDropship.contains( player ) ) + continue + + PlayFactionDialogueToPlayer( "fd_pilotRespawn", player ) + } + } + + wait 8 +} + +void function FD_DropshipDropPlayer( entity player, int playerDropshipIndex ) +{ + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) + //check the player + if ( IsValid( player ) && !player.IsTitan() ) + { + if( player.s.loadoutDirty ) + Loadouts_OnUsedLoadoutCrate( player ) + + EnableOffhandWeapons( player ) + + FirstPersonSequenceStruct jumpSequence + jumpSequence.firstPersonAnim = DROPSHIP_EXIT_ANIMS_POV[ playerDropshipIndex ] + jumpSequence.thirdPersonAnim = DROPSHIP_EXIT_ANIMS[ playerDropshipIndex ] + jumpSequence.attachment = "ORIGIN" + jumpSequence.blendTime = 0.0 + jumpSequence.hideProxy = true + jumpSequence.viewConeFunction = ViewConeNarrow + + #if BATTLECHATTER_ENABLED + if ( playerDropshipIndex == 0 ) + PlayBattleChatterLine( player, "bc_pIntroChat" ) + #endif + + waitthread FirstPersonSequence( jumpSequence, player, file.dropship ) + if ( IsValidPlayer( player ) ) //Check again because the delay + { + player.ClearParent() + ClearPlayerAnimViewEntity( player ) + thread FD_PlayerRespawnProtection( player ) + } + } +} + +void function FD_PlayerRespawnProtection( entity player ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + + OnThreadEnd( function() : ( player ) + { + if ( IsValidPlayer( player ) ) + { + player.Highlight_SetParam( 1, 0, HIGHLIGHT_COLOR_FRIENDLY ) + player.ClearInvulnerable() + player.SetNoTarget( false ) + } + }) + + wait 0.1 + if ( !player.IsTitan() ) + player.ConsumeDoubleJump() //Dropship case scenario + wait 5.0 +} + +void function WaveRestart_ResetDropshipState() +{ + file.dropshipState = eDropshipState.Idle + file.playersInShip = 0 + file.playersInDropship.clear() + file.harvesterHalfHealth = false + file.harvesterShieldDown = false +} + +void function FD_DropshipSetAnimationOverride(string animation) +{ + file.animationOverride = animation +} + +string function FD_DropshipGetAnimation() +{ + if ( file.animationOverride != "" ) + return file.animationOverride + + switch ( GetMapName() ) + { + case "mp_homestead": //Homestead flight path has a very very jank coordinate where the drop point actually is + return "dropship_coop_respawn_homestead" + + case "mp_colony02": //Could use the default animation, but this one works nicely for Colony + case "mp_relic02": //Also works for Relic so it goes above IMS Odyssey if rotated + return "dropship_coop_respawn_lagoon" + + case "mp_grave": //Boomtown has low ceiling and this one matches perfectly for it (default clips alot into ceiling geo) + return "dropship_coop_respawn_outpost" + + case "mp_thaw": //Titanfall 1 flight path, but used in vanilla since the ship also circles around the radio tower of the main building + return "dropship_coop_respawn_overlook" + + /* Those here doesn't even fit any map, theyre just legacy assets from Titanfall 1 since those map names are from there + case "mp_wargames": Despite this one literally saying wargames, the flight path it does clips into the buildings + return "dropship_coop_respawn_wargames" + case "mp_digsite": + return "dropship_coop_respawn_digsite" */ + } + return "dropship_coop_respawn" +} + + + + + + + + + + + +/* Score System +███████ ██████ ██████ ██████ ███████ ███████ ██ ██ ███████ ████████ ███████ ███ ███ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ +███████ ██ ██ ██ ██████ █████ ███████ ████ ███████ ██ █████ ██ ████ ██ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██████ ██████ ██ ██ ███████ ███████ ██ ███████ ██ ███████ ██ ██ +*/ + +void function UpdatePlayerScoreboard( entity player ) +{ + player.SetPlayerGameStat( PGS_DETONATION_SCORE, player.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + player.GetPlayerGameStat( PGS_DEFENSE_SCORE ) ) +} + +void function FD_UsedCoreCallback( entity titan, entity weapon ) +{ + if ( !( titan in file.players ) ) + return + + if ( titan in file.playerAwardStats ) + file.playerAwardStats[titan]["coresUsed"] += 1.0 +} + +void function FD_StunLaserHealTeammate( entity player, entity target, int shieldRestoreAmount ) +{ + if ( IsValidPlayer( player ) && player in file.players ) + { + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["heals"] += float( shieldRestoreAmount ) + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, shieldRestoreAmount / 100 ) + UpdatePlayerScoreboard( player ) + } +} + +void function FD_SmokeHealTeammate( entity player, entity target, int shieldRestoreAmount ) +{ + if ( IsValidPlayer( player ) && player in file.players ) + { + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["heals"] += float( shieldRestoreAmount ) + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, shieldRestoreAmount / 100 ) + UpdatePlayerScoreboard( player ) + } +} + +void function FD_BatteryHealTeammate( entity rider, entity titan, entity battery ) +{ + entity soul = titan.GetTitanSoul() + + if ( IsAmpedBattery( battery ) ) + AddCreditToTitanCoreBuilder( titan, GetCurrentPlaylistVarFloat( "battery_core_frac", 0.2 ) ) + + thread FD_BatteryHealTeammate_Threaded( rider, titan, titan.GetHealth(), soul.GetShieldHealth() ) +} + +void function FD_BatteryHealTeammate_Threaded( entity rider, entity titan, int ogHealth, int ogShield ) +{ + WaitFrame() //Do this way because it's ironically more accurate to track the health change when healing teammates with batteries + + if ( !IsAlive( titan ) ) + return + + entity soul = titan.GetTitanSoul() + + if ( !IsValid( soul ) ) + return + + int healAmount = titan.GetHealth() - ogHealth + int shieldAmount = soul.GetShieldHealth() - ogShield + int totalHealing = healAmount + shieldAmount + int HealScore = totalHealing / 100 + + if ( IsValidPlayer( rider ) ) + { + AddPlayerScore( rider, "FDTeamHeal", null, "", HealScore ) + if ( rider in file.playerAwardStats ) + file.playerAwardStats[rider]["heals"] += float( totalHealing ) + rider.AddToPlayerGameStat( PGS_DEFENSE_SCORE, HealScore ) + UpdatePlayerScoreboard( rider ) + } +} + +void function FD_OnArcTrapTriggered( entity victim, var damageInfo ) +{ + entity owner = DamageInfo_GetAttacker( damageInfo ) + + if ( !IsValidPlayer( owner ) ) + return + + AddPlayerScore( owner, "FDArcTrapTriggered" ) //Triggers for every enemy shocked + file.players[owner].defenseScoreThisRound += 4 + UpdatePlayerStat( owner, "fd_stats", "arcMineZaps" ) +} + +void function FD_OnArcWaveDamage( entity ent, var damageInfo ) +{ + entity attacker = DamageInfo_GetAttacker( damageInfo ) + + if ( !IsValidPlayer( attacker ) ) + return + + AddPlayerScore( attacker, "FDArcWave" ) + file.players[attacker].defenseScoreThisRound += 2 +} + +void function FD_OnTetherTrapTriggered( entity owner, entity endEnt ) +{ + if ( !IsValidPlayer( owner ) ) + return + + AddPlayerScore( owner, "FDTetherTriggered" ) + file.players[owner].defenseScoreThisRound += 2 +} + +void function FD_OnSonarStart( entity ent, vector position, int sonarTeam, entity sonarOwner ) +{ + if ( !IsValidPlayer( sonarOwner ) ) + return + + AddPlayerScore( sonarOwner, "FDSonarPulse" ) //Triggers for every enemy revealed + file.players[sonarOwner].defenseScoreThisRound++ +} + +void function IncrementPlayerstat_TurretRevives( entity turret, entity player, entity owner ) +{ + if ( IsValidPlayer( owner ) ) + { + if ( player in file.playerAwardStats ) + file.playerAwardStats[player]["turretsRepaired"]++ + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_InGame_FD_RepairTurret" ) + AddPlayerScore( player, "FDRepairTurret" ) + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, FD_SCORE_REPAIR_TURRET ) + UpdatePlayerScoreboard( player ) + + if ( player != owner ) + MessageToTeam( TEAM_MILITIA, eEventNotifications.FD_TurretRepair, null, player, owner.GetEncodedEHandle() ) + } +} + + + + + + + + + + +/* Tool functions +████████ ██████ ██████ ██ ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ + ██ ██ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██ ██████ ██████ ███████ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ +*/ + +void function FD_SetupEpilogue() +{ + AddCallback_GameStateEnter( eGameState.Epilogue, FD_Epilogue ) +} + +void function FD_Epilogue() +{ + thread FD_Epilogue_threaded() +} + +void function FD_Epilogue_threaded() +{ + table awardOwners + table awardValues + wait 5 + foreach (entity player in GetPlayerArray() ) + { + ScreenFadeToBlackForever( player, 6.0 ) + AddCinematicFlag( player, CE_FLAG_HIDE_MAIN_HUD ) + } + wait 5 + foreach (entity player in GetPlayerArray() ) + EmitSoundOnEntityOnlyToPlayer( player, player, "FrontierDefense_MatchEndFadeout" ) + wait 2 + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + MuteHalfTime( player ) + player.FreezeControlsOnServer() + foreach ( string ref in GetFDStatRefs() ) + { + if ( !( ref in awardOwners ) ) + { + awardOwners[ref] <- player + awardValues[ref] <- file.playerAwardStats[player][ref] + } + else if ( awardValues[ref] < file.playerAwardStats[player][ref] ) + { + awardOwners[ref] = player + awardValues[ref] = file.playerAwardStats[player][ref] + } + } + } + table awardResults + table awardResultValues + + foreach ( string ref, entity player in awardOwners ) + { + if ( awardValues[ref] > GetFDStatData( ref ).validityCheckValue ) //might be >= + { + awardResults[player] <- ref + awardResultValues[player] <- awardValues[ref] + } + } + + int gameMode = PersistenceGetEnumIndexForItemName( "gamemodes", GAMETYPE ) + int map = PersistenceGetEnumIndexForItemName( "maps", GetMapName() ) + int myIndex + int numPlayers = minint( 4, GetPlayerArray().len() ) //Cap cuz it crashes summary menu + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( !( player in awardResults ) ) + { + awardResults[player] <- "damageDealt" + awardResultValues[player] <- file.playerAwardStats[player]["damageDealt"] + } + } + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + if ( !IsValidPlayer( player ) ) + continue + + int i = 0 + myIndex = player.GetPlayerIndex() + + player.SetPersistentVar( "postGameDataFD.gameMode", gameMode ) + player.SetPersistentVar( "postGameDataFD.map", map ) + player.SetPersistentVar( "postGameDataFD.myIndex", myIndex ) + player.SetPersistentVar( "postGameDataFD.numPlayers", numPlayers ) + + bool shouldSkipAward = false + foreach ( entity medalPlayer, string ref in awardResults ) + { + if ( !IsValidPlayer( medalPlayer ) ) + continue + + if ( i == 4 ) + break + + int targetIndex = medalPlayer.GetPlayerIndex() + + string name = medalPlayer.GetPlayerName() + string xuid = medalPlayer.GetUID() + int awardId = GetFDStatData( ref ).index + float awardValue = awardResultValues[medalPlayer] + int suitIndex = GetPersistentSpawnLoadoutIndex( medalPlayer, "titan" ) + int playerEHandle = medalPlayer.GetEncodedEHandle() + + player.SetPersistentVar( "postGameDataFD.players[" + i + "].name", name ) + player.SetPersistentVar( "postGameDataFD.players[" + i + "].xuid", xuid ) + player.SetPersistentVar( "postGameDataFD.players[" + i + "].awardId", awardId ) + player.SetPersistentVar( "postGameDataFD.players[" + i + "].awardValue", awardValue ) + player.SetPersistentVar( "postGameDataFD.players[" + i + "].suitIndex", suitIndex ) + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateGameStats", playerEHandle, awardId, awardValue, suitIndex ) + i++ + } + Remote_CallFunction_NonReplay( player, "ServerCallback_ShowGameStats", Time() + 19 ) + } + + wait 20 + SetGameState( eGameState.Postmatch ) +} + +bool function isFinalWave() +{ + return ( ( GetGlobalNetInt( "FD_currentWave" ) + 1 ) == GetGlobalNetInt( "FD_totalWaves" ) ) +} + +bool function isSecondWave() +{ + return ( ( GetGlobalNetInt( "FD_currentWave" ) + 1 ) == 1 ) +} + +//Idk the precise behavior of the summary panel in vanilla, but this is the closest i got so far +//IMC players gains nothing because PvP on FD is an exploit and should actually reward nothing for these "clever" people +void function RegisterPostSummaryScreenForMatch( bool matchwon ) +{ + //50% of enemies defeated in a wave counts a Milestone for the current wave + int WaveMilestone = GetGlobalNetInt( "FD_AICount_Current" ) + if ( WaveMilestone <= GetGlobalNetInt( "FD_AICount_Total" ) / 2 ) + WaveMilestone = 1 + else + WaveMilestone = 0 + + int Composition = 1 + bool doubleXP = GetCurrentPlaylistVarInt( "double_xp_enabled", 0 ) ? true : false + + if ( GetPlayerArrayOfTeam( TEAM_MILITIA ).len() >= 1 ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + int suitIndex1 = GetPersistentSpawnLoadoutIndex( player, "titan" ) + foreach ( entity otherPlayer in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + int suitIndex2 = GetPersistentSpawnLoadoutIndex( otherPlayer, "titan" ) + if ( player == otherPlayer ) + continue + + if ( suitIndex2 == suitIndex1 ) + Composition = 0 + } + } + } + + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + { + int fdXPamount = 0 + int suitIndex = GetPersistentSpawnLoadoutIndex( player, "titan" ) + string titanRef = GetItemRefOfTypeByIndex( eItemTypes.TITAN, suitIndex ) + + UpdatePlayerStat( player, "titan_stats", "matchesByDifficulty", 1, titanRef ) + UpdatePlayerStat( player, "game_stats", "games_completed_fd" ) + + player.SetPersistentVar( "isPostGameScoreboardValid", false ) + player.SetPersistentVar( "isFDPostGameScoreboardValid", true ) + player.SetPersistentVar( "lastFDDifficulty", difficultyLevel ) + player.SetPersistentVar( "lastFDTitanRef", titanRef ) + + player.SetPersistentVar( "fd_match[" + eFDXPType.WAVES_COMPLETED + "]", file.players[player].wavesCompleted ) + player.SetPersistentVar( "fd_match[" + eFDXPType.WAVES_ATTEMPTED + "]", GetGlobalNetInt( "FD_currentWave" ) + WaveMilestone ) + player.SetPersistentVar( "fd_match[" + eFDXPType.PERFECT_COMPOSITION + "]", Composition ) + player.SetPersistentVar( "fd_match[" + eFDXPType.RETRIES_REMAINING + "]", GetGlobalNetInt( "FD_restartsRemaining" ) ) + + player.SetPersistentVar( "fd_count[" + eFDXPType.WAVES_COMPLETED + "]", GetGlobalNetInt( "FD_totalWaves" ) ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WAVES_ATTEMPTED + "]", GetGlobalNetInt( "FD_totalWaves" ) ) + player.SetPersistentVar( "fd_count[" + eFDXPType.PERFECT_COMPOSITION + "]", Composition ) + player.SetPersistentVar( "fd_count[" + eFDXPType.RETRIES_REMAINING + "]", 2 ) + + fdXPamount += GetGlobalNetInt( "FD_restartsRemaining" ) + fdXPamount += file.players[player].wavesCompleted + Composition + fdXPamount += GetGlobalNetInt( "FD_currentWave" ) + WaveMilestone + + if ( matchwon ) + { + UpdatePlayerStat( player, "game_stats", "games_won_fd" ) + + if ( file.players[player].pilotPerfectWin && file.players[player].titanPerfectWin && file.harvesterPerfectWin ) + { + UpdatePlayerStat( player, "game_stats", "perfectMatches" ) + UpdatePlayerStat( player, "titan_stats", "perfectMatchesByDifficulty", 1, titanRef ) + } + + int diffbonus = 5 + switch ( difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + UpdatePlayerStat( player, "fd_stats", "easyWins" ) + player.SetPersistentVar( "fd_match[" + eFDXPType.EASY_VICTORY + "]", FD_XP_EASY_WIN ) + player.SetPersistentVar( "fd_count[" + eFDXPType.EASY_VICTORY + "]", FD_XP_EASY_WIN ) + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 && doubleXP ) + diffbonus *= 2 + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 || doubleXP ) + { + player.SetPersistentVar( "fd_match[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_count[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + fdXPamount += diffbonus + } + //player.SetPersistentVar( "fd_match[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_EASY_WAVE_BONUS ) + //player.SetPersistentVar( "fd_count[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_EASY_WAVE_BONUS ) + fdXPamount += FD_XP_EASY_WIN + break + case eFDDifficultyLevel.NORMAL: + UpdatePlayerStat( player, "fd_stats", "normalWins" ) + player.SetPersistentVar( "fd_match[" + eFDXPType.NORMAL_VICTORY + "]", FD_XP_NORMAL_WIN ) + player.SetPersistentVar( "fd_count[" + eFDXPType.NORMAL_VICTORY + "]", FD_XP_NORMAL_WIN ) + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 || doubleXP ) + { + player.SetPersistentVar( "fd_match[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_count[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + fdXPamount += diffbonus + } + //player.SetPersistentVar( "fd_match[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_NORMAL_WAVE_BONUS ) + //player.SetPersistentVar( "fd_count[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_NORMAL_WAVE_BONUS ) + fdXPamount += FD_XP_NORMAL_WIN + break + case eFDDifficultyLevel.HARD: + if ( doubleXP ) + diffbonus *= 2 + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 ) + diffbonus *= 2 + UpdatePlayerStat( player, "fd_stats", "hardWins" ) + player.SetPersistentVar( "fd_match[" + eFDXPType.HARD_VICTORY + "]", FD_XP_HARD_WIN ) + player.SetPersistentVar( "fd_count[" + eFDXPType.HARD_VICTORY + "]", FD_XP_HARD_WIN ) + player.SetPersistentVar( "fd_match[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_count[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_match[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_HARD_WAVE_BONUS ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_HARD_WAVE_BONUS ) + fdXPamount += FD_XP_HARD_WIN + FD_XP_HARD_WAVE_BONUS + diffbonus + break + case eFDDifficultyLevel.MASTER: + diffbonus = 10 + if ( doubleXP ) + diffbonus *= 2 + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 ) + diffbonus *= 2 + UpdatePlayerStat( player, "fd_stats", "masterWins" ) + player.SetPersistentVar( "fd_match[" + eFDXPType.MASTER_VICTORY + "]", FD_XP_MASTER_WIN ) + player.SetPersistentVar( "fd_count[" + eFDXPType.MASTER_VICTORY + "]", FD_XP_MASTER_WIN ) + player.SetPersistentVar( "fd_match[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_count[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_match[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_MASTER_WAVE_BONUS ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_MASTER_WAVE_BONUS ) + fdXPamount += FD_XP_MASTER_WIN + FD_XP_MASTER_WAVE_BONUS + diffbonus + break + case eFDDifficultyLevel.INSANE: + diffbonus = 15 + if ( doubleXP ) + diffbonus *= 2 + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 ) + diffbonus *= 2 + UpdatePlayerStat( player, "fd_stats", "insaneWins" ) + player.SetPersistentVar( "fd_match[" + eFDXPType.INSANE_VICTORY + "]", FD_XP_INSANE_WIN ) + player.SetPersistentVar( "fd_count[" + eFDXPType.INSANE_VICTORY + "]", FD_XP_INSANE_WIN ) + player.SetPersistentVar( "fd_match[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_count[" + eFDXPType.DIFFICULTY_BONUS + "]", diffbonus ) + player.SetPersistentVar( "fd_match[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_INSANE_WAVE_BONUS ) + player.SetPersistentVar( "fd_count[" + eFDXPType.WARPAINT_BONUS + "]", FD_XP_INSANE_WAVE_BONUS ) + player.SetPersistentVar( "fd_match[" + eFDXPType.RETRIES_REMAINING + "]", 0 ) + player.SetPersistentVar( "fd_count[" + eFDXPType.RETRIES_REMAINING + "]", 0 ) + fdXPamount += FD_XP_INSANE_WIN + FD_XP_INSANE_WAVE_BONUS + diffbonus + break + } + } + + AddFDTitanXP( player, fdXPamount ) + RecalculateHighestTitanFDLevel( player ) + } + SetUIVar( level, "showGameSummary", true ) +} + +array function getHighestEnemyAmountsForWave( int waveIndex ) +{ + table npcs + npcs[eFD_AITypeIDs.TITAN_NUKE] <- 0 + npcs[eFD_AITypeIDs.TITAN_ARC] <- 0 + npcs[eFD_AITypeIDs.TITAN_MORTAR] <- 0 + npcs[eFD_AITypeIDs.TITAN] <- 0 + npcs[eFD_AITypeIDs.TICK] <- 0 + npcs[eFD_AITypeIDs.REAPER] <- 0 + npcs[eFD_AITypeIDs.SPECTRE_MORTAR] <- 0 + npcs[eFD_AITypeIDs.DRONE_CLOAK] <- 0 + npcs[eFD_AITypeIDs.SPECTRE] <- 0 + npcs[eFD_AITypeIDs.STALKER] <- 0 + npcs[eFD_AITypeIDs.DRONE] <- 0 + npcs[eFD_AITypeIDs.GRUNT] <- 0 + // npcs[eFD_AITypeIDs.RONIN] <- 0 + // npcs[eFD_AITypeIDs.NORTHSTAR] <- 0 + // npcs[eFD_AITypeIDs.SCORCH] <- 0 + // npcs[eFD_AITypeIDs.LEGION] <- 0 + // npcs[eFD_AITypeIDs.TONE] <- 0 + // npcs[eFD_AITypeIDs.ION] <- 0 + // npcs[eFD_AITypeIDs.MONARCH] <- 0 + // npcs[eFD_AITypeIDs.TITAN_SNIPER] <- 0 + + + foreach ( WaveSpawnEvent e in WaveSpawnEvents[waveIndex] ) + { + if ( e.spawnAmount == 0 || ShouldSkipEventForDifficulty( e ) ) + continue + + switch ( e.spawnType ) + { + case( eFD_AITypeIDs.TITAN ): + case( eFD_AITypeIDs.RONIN ): + case( eFD_AITypeIDs.NORTHSTAR ): + case( eFD_AITypeIDs.SCORCH ): + case( eFD_AITypeIDs.TONE ): + case( eFD_AITypeIDs.ION ): + case( eFD_AITypeIDs.MONARCH ): + case( eFD_AITypeIDs.LEGION ): + case( eFD_AITypeIDs.TITAN_SNIPER ): + npcs[eFD_AITypeIDs.TITAN] += e.spawnAmount + break + + default: + npcs[e.spawnType] += e.spawnAmount + } + } + + array ret = [] + + if ( npcs[eFD_AITypeIDs.TITAN_NUKE] > 0 ) + ret.append( eFD_AITypeIDs.TITAN_NUKE ) + + if ( npcs[eFD_AITypeIDs.TITAN_ARC] > 0 ) + ret.append( eFD_AITypeIDs.TITAN_ARC ) + + if ( npcs[eFD_AITypeIDs.TITAN_MORTAR] > 0 ) + ret.append( eFD_AITypeIDs.TITAN_MORTAR ) + + if ( npcs[eFD_AITypeIDs.TITAN] > 0 ) + ret.append( eFD_AITypeIDs.TITAN ) + + if ( npcs[eFD_AITypeIDs.TICK] > 0 ) + ret.append( eFD_AITypeIDs.TICK ) + + if ( npcs[eFD_AITypeIDs.REAPER] > 0 ) + ret.append( eFD_AITypeIDs.REAPER ) + + if ( npcs[eFD_AITypeIDs.SPECTRE_MORTAR] > 0 ) + ret.append( eFD_AITypeIDs.SPECTRE_MORTAR ) + + if ( npcs[eFD_AITypeIDs.DRONE_CLOAK] > 0 ) + ret.append( eFD_AITypeIDs.DRONE_CLOAK ) + + if ( npcs[eFD_AITypeIDs.DRONE] > 0 ) + ret.append( eFD_AITypeIDs.DRONE ) + + if ( npcs[eFD_AITypeIDs.SPECTRE] > 0 ) + ret.append( eFD_AITypeIDs.SPECTRE ) + + if ( npcs[eFD_AITypeIDs.STALKER] > 0 ) + ret.append( eFD_AITypeIDs.STALKER ) + + if ( npcs[eFD_AITypeIDs.GRUNT] > 0 ) + ret.append( eFD_AITypeIDs.GRUNT ) + + while( ret.len() < 9 ) //Fill empty slots for return + ret.append( -1 ) + + return ret +} + +void function SetEnemyAmountNetVars( int waveIndex ) +{ + int total = 0 + bool skipevent = false + table npcs + npcs[eFD_AITypeIDs.TITAN_NUKE] <- 0 + npcs[eFD_AITypeIDs.TITAN_ARC] <- 0 + npcs[eFD_AITypeIDs.TITAN_MORTAR] <- 0 + npcs[eFD_AITypeIDs.TITAN] <- 0 + npcs[eFD_AITypeIDs.TICK] <- 0 + npcs[eFD_AITypeIDs.REAPER] <- 0 + npcs[eFD_AITypeIDs.SPECTRE_MORTAR] <- 0 + npcs[eFD_AITypeIDs.DRONE_CLOAK] <- 0 + npcs[eFD_AITypeIDs.SPECTRE] <- 0 + npcs[eFD_AITypeIDs.STALKER] <- 0 + npcs[eFD_AITypeIDs.DRONE] <- 0 + npcs[eFD_AITypeIDs.GRUNT] <- 0 + // npcs[eFD_AITypeIDs.RONIN] <- 0 + // npcs[eFD_AITypeIDs.NORTHSTAR] <- 0 + // npcs[eFD_AITypeIDs.SCORCH] <- 0 + // npcs[eFD_AITypeIDs.LEGION] <- 0 + // npcs[eFD_AITypeIDs.TONE] <- 0 + // npcs[eFD_AITypeIDs.ION] <- 0 + // npcs[eFD_AITypeIDs.MONARCH] <- 0 + // npcs[eFD_AITypeIDs.TITAN_SNIPER] <- 0 + + + foreach ( WaveSpawnEvent e in WaveSpawnEvents[waveIndex] ) + { + if ( e.spawnAmount == 0 || ShouldSkipEventForDifficulty( e ) ) + continue + + switch ( e.spawnType ) + { + case( eFD_AITypeIDs.TITAN ): + case( eFD_AITypeIDs.RONIN ): + case( eFD_AITypeIDs.NORTHSTAR ): + case( eFD_AITypeIDs.SCORCH ): + case( eFD_AITypeIDs.TONE ): + case( eFD_AITypeIDs.ION ): + case( eFD_AITypeIDs.MONARCH ): + case( eFD_AITypeIDs.LEGION ): + case( eFD_AITypeIDs.TITAN_SNIPER ): + if ( npcs[eFD_AITypeIDs.TITAN] > 511 ) + { + npcs[eFD_AITypeIDs.TITAN] = 511 + CodeWarning( "Titan Spawn Pool limit of 511 reached! Skipping further additions to prevent crash, re-adjust wave to have less enemies of this type" ) + } + else + npcs[eFD_AITypeIDs.TITAN] += e.spawnAmount + break + + default: + if ( npcs[e.spawnType] > 511 ) + { + npcs[e.spawnType] = 511 + CodeWarning( FD_GetAINameFromTypeID( e.spawnType ) + " Spawn Pool limit of 511 reached! Skipping further additions to prevent crash, re-adjust wave to have less enemies of this type" ) + } + else + npcs[e.spawnType] += e.spawnAmount + + } + if ( total > 511 ) + { + total = 511 + CodeWarning( "Total Enemy Spawn Pool limit of 511 reached! Skipping further additions to prevent crash, re-adjust wave to have overall less enemies" ) + } + else if ( e.spawnType != eFD_AITypeIDs.DRONE_CLOAK ) //Cloak Drones doesn't count for the total pool in vanilla + total += e.spawnAmount + } + SetGlobalNetInt( "FD_AICount_Titan_Nuke", npcs[eFD_AITypeIDs.TITAN_NUKE] ) + SetGlobalNetInt( "FD_AICount_Titan_Arc", npcs[eFD_AITypeIDs.TITAN_ARC] ) + SetGlobalNetInt( "FD_AICount_Titan_Mortar", npcs[eFD_AITypeIDs.TITAN_MORTAR] ) + SetGlobalNetInt( "FD_AICount_Titan", npcs[eFD_AITypeIDs.TITAN] ) + SetGlobalNetInt( "FD_AICount_Ticks", npcs[eFD_AITypeIDs.TICK] ) + SetGlobalNetInt( "FD_AICount_Reaper", npcs[eFD_AITypeIDs.REAPER] ) + SetGlobalNetInt( "FD_AICount_Spectre_Mortar", npcs[eFD_AITypeIDs.SPECTRE_MORTAR] ) + SetGlobalNetInt( "FD_AICount_Drone_Cloak", npcs[eFD_AITypeIDs.DRONE_CLOAK] ) + SetGlobalNetInt( "FD_AICount_Spectre", npcs[eFD_AITypeIDs.SPECTRE] ) + SetGlobalNetInt( "FD_AICount_Stalker", npcs[eFD_AITypeIDs.STALKER] ) + SetGlobalNetInt( "FD_AICount_Drone", npcs[eFD_AITypeIDs.DRONE] ) + SetGlobalNetInt( "FD_AICount_Grunt", npcs[eFD_AITypeIDs.GRUNT] ) + SetGlobalNetInt( "FD_AICount_Current", total ) + SetGlobalNetInt( "FD_AICount_Total", total ) + + print( "ENEMIES ON THIS WAVE:" ) + if ( GetGlobalNetInt( "FD_AICount_Titan_Nuke" ) > 0 ) + printt( "Nuke Titans:", GetGlobalNetInt( "FD_AICount_Titan_Nuke" ) ) + if ( GetGlobalNetInt( "FD_AICount_Titan_Arc" ) > 0 ) + printt( "Arc Titans:", GetGlobalNetInt( "FD_AICount_Titan_Arc" ) ) + if ( GetGlobalNetInt( "FD_AICount_Titan_Mortar" ) > 0 ) + printt( "Mortar Titans:", GetGlobalNetInt( "FD_AICount_Titan_Mortar" ) ) + if ( GetGlobalNetInt( "FD_AICount_Titan" ) > 0 ) + printt( "Titans:", GetGlobalNetInt( "FD_AICount_Titan" ) ) + if ( GetGlobalNetInt( "FD_AICount_Ticks" ) > 0 ) + printt( "Ticks:", GetGlobalNetInt( "FD_AICount_Ticks" ) ) + if ( GetGlobalNetInt( "FD_AICount_Reaper" ) > 0 ) + printt( "Reapers:", GetGlobalNetInt( "FD_AICount_Reaper" ) ) + if ( GetGlobalNetInt( "FD_AICount_Spectre_Mortar" ) > 0 ) + printt( "Mortar Spectres:", GetGlobalNetInt( "FD_AICount_Spectre_Mortar" ) ) + if ( GetGlobalNetInt( "FD_AICount_Drone_Cloak" ) > 0 ) + printt( "Cloak Drones:", GetGlobalNetInt( "FD_AICount_Drone_Cloak" ) ) + if ( GetGlobalNetInt( "FD_AICount_Drone" ) > 0 ) + printt( "Drones:", GetGlobalNetInt( "FD_AICount_Drone" ) ) + if ( GetGlobalNetInt( "FD_AICount_Spectre" ) > 0 ) + printt( "Spectres:", GetGlobalNetInt( "FD_AICount_Spectre" ) ) + if ( GetGlobalNetInt( "FD_AICount_Stalker" ) > 0 ) + printt( "Stalkers:", GetGlobalNetInt( "FD_AICount_Stalker" ) ) + if ( GetGlobalNetInt( "FD_AICount_Grunt" ) > 0 ) + printt( "Grunts:", GetGlobalNetInt( "FD_AICount_Grunt" ) ) +} + +void function FD_WaveCleanup() +{ + foreach ( projectile in GetProjectileArray() ) //Arc Trap Handling + { + if ( projectile instanceof CProjectile || projectile instanceof CBaseGrenade ) + { + if ( projectile.e.fd_roundDeployed == GetGlobalNetInt( "FD_currentWave" ) ) + projectile.Destroy() + } + } + + foreach ( entity npc in GetNPCArray() ) //Turret Handling + { + if ( IsValidPlayer( npc.GetBossPlayer() ) && npc.e.fd_roundDeployed != GetGlobalNetInt( "FD_currentWave" ) || npc.GetClassName() == "npc_turret_mega" ) + continue + + if ( IsValid( npc ) ) + npc.Destroy() + } + + if ( IsValid( fd_harvester.harvester ) ) + fd_harvester.harvester.Destroy() //Destroy harvester after match over + + thread FD_AttemptToRepairTurrets() //Repair turrets during black screen that remained from previous waves +} + +int function getHintForTypeId( int typeId ) +{ + //this is maybe a bit of an naive aproch + switch ( typeId ) + { + case eFD_AITypeIDs.TITAN_NUKE: + return ( 348 + RandomIntRangeInclusive( 0, 1 ) ) + case eFD_AITypeIDs.TITAN_ARC: + return ( 350 + RandomIntRangeInclusive( 0, 1 ) ) + case eFD_AITypeIDs.TITAN_MORTAR: + return ( 352 + RandomIntRangeInclusive( 0, 1 ) ) + case eFD_AITypeIDs.GRUNT: + return 354 + case eFD_AITypeIDs.SPECTRE: + return 355 + case eFD_AITypeIDs.SPECTRE_MORTAR: + return ( 356 + RandomIntRangeInclusive( 0, 1 ) ) + case eFD_AITypeIDs.STALKER: + if ( RandomIntRangeInclusive( 0, 1 ) == 0 ) + return 358 + else + return 361 + case eFD_AITypeIDs.REAPER: + return ( 359 + RandomIntRangeInclusive( 0, 1 ) ) + case eFD_AITypeIDs.DRONE: + return 362 + case eFD_AITypeIDs.TITAN_SNIPER: + return ( 371 + RandomIntRangeInclusive( 0, 2 ) ) + default: + return ( 363 + RandomIntRangeInclusive( 0, 7 ) ) + } + unreachable +} + +string function GetTargetNameForID( int typeId ) +{ + switch ( typeId ) + { + case eFD_AITypeIDs.TITAN_NUKE: + return "npc_titan_nuke" + case eFD_AITypeIDs.LEGION: + return "npc_titan_ogre_minigun" + case eFD_AITypeIDs.TITAN_ARC: + return "empTitan" + case eFD_AITypeIDs.RONIN: + return "npc_titan_stryder_leadwall" + case eFD_AITypeIDs.TITAN_MORTAR: + return "npc_titan_mortar" + case eFD_AITypeIDs.TONE: + return "npc_titan_atlas_tracker" + case eFD_AITypeIDs.TITAN_SNIPER: + return "npc_titan_sniper" + case eFD_AITypeIDs.NORTHSTAR: + return "npc_titan_stryder_sniper" + case eFD_AITypeIDs.ION: + return "npc_titan_atlas_stickybomb" + case eFD_AITypeIDs.SCORCH: + return "npc_titan_ogre_meteor" + case eFD_AITypeIDs.MONARCH: + return "npc_titan_atlas_vanguard" + case eFD_AITypeIDs.GRUNT: + return "grunt" + case eFD_AITypeIDs.SPECTRE: + return "spectre" + case eFD_AITypeIDs.SPECTRE_MORTAR: + return "mortar_spectre" + case eFD_AITypeIDs.STALKER: + return "stalker" + case eFD_AITypeIDs.REAPER: + return "reaper" + case eFD_AITypeIDs.TICK: + return "tick" + case eFD_AITypeIDs.DRONE: + return "drone" + case eFD_AITypeIDs.DRONE_CLOAK: + return "Cloak Drone" // have to be like this for some reason in cl_gamemode_fd + default: + return "titan" + } + unreachable +} + +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": + case "Cloak Drone": + return "FD_AICount_Drone_Cloak" + case "tick": + return "FD_AICount_Ticks" + } + printt( "unknown target name ", targetName ) + return "" +} + +void function FD_EmitSoundOnEntityOnlyToPlayer( entity targetEntity, entity player, string alias ) +{ + if ( !IsValid( targetEntity ) ) + return + + if ( !IsValidPlayer( player ) ) + return + + EmitSoundOnEntityOnlyToPlayer( targetEntity, player, alias ) +} + +function FD_AttemptToRepairTurrets() +{ + //Repair turret on here rather than in the executeWave(), softlocking reasons + foreach (entity turret in GetEntArrayByClass_Expensive( "npc_turret_sentry" ) ) + RepairTurret_WaveBreak( turret ) +} + +void function PvPGlitchMonitor( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + player.s.isbeingmonitored = true + while( IsValidPlayer( player ) && player.s.didthepvpglitch && player.s.isbeingmonitored && GetGlobalNetBool( "FD_waveActive" ) ) + { + if ( IsAlive( player ) ) + { + if ( player.GetTeam() == TEAM_MILITIA ) //Ensure this player who tried to be "funny" and went into the IMC side stays there for the whole wave + SetTeam( player, TEAM_IMC ) + + PlayerEarnMeter_AddOwnedFrac( player, 0.02 ) //At least make them buildup titan meter faster since they gain nothing for killing the defending players + } + + wait 1 + } +} + +function FD_UpdateTitanBehavior() +{ + if ( !GetGlobalNetBool( "FD_waveActive" ) ) + { + foreach (entity titan in GetEntArrayByClass_Expensive( "npc_titan" ) ) + { + if ( titan.GetTeam() == TEAM_MILITIA ) + titan.EnableNPCMoveFlag( NPCMF_WALK_NONCOMBAT | NPCMF_IGNORE_CLUSTER_DANGER_TIME | NPCMF_DISABLE_DANGEROUS_AREA_DISPLACEMENT ) + } + } + else + { + foreach (entity titan in GetEntArrayByClass_Expensive( "npc_titan" ) ) + { + if ( titan.GetTeam() == TEAM_MILITIA ) + titan.DisableNPCMoveFlag( NPCMF_WALK_NONCOMBAT | NPCMF_IGNORE_CLUSTER_DANGER_TIME | NPCMF_DISABLE_DANGEROUS_AREA_DISPLACEMENT ) + } + } +} + + + + + + + + + + + +/* NS Extra Content +███ ██ ███████ ███████ ██ ██ ████████ ██████ █████ ██████ ██████ ███ ██ ████████ ███████ ███ ██ ████████ +████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ████ ██ ██ +██ ██ ██ ███████ █████ ███ ██ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ █████ ██ ██ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ████ ███████ ███████ ██ ██ ██ ██ ██ ██ ██ ██████ ██████ ██ ████ ██ ███████ ██ ████ ██ +*/ + +void function FD_PilotEmbark( entity player, entity titan ) +{ + int aiTypeID = eFD_AITypeIDs.TITAN + switch ( GetTitanCharacterName( player ) ) + { + case "ion": + aiTypeID = eFD_AITypeIDs.ION + break + case "tone": + aiTypeID = eFD_AITypeIDs.TITAN_SNIPER + break + case "legion": + aiTypeID = eFD_AITypeIDs.LEGION + break + case "scorch": + aiTypeID = eFD_AITypeIDs.SCORCH + break + case "ronin": + aiTypeID = eFD_AITypeIDs.RONIN + break + case "northstar": + aiTypeID = eFD_AITypeIDs.NORTHSTAR + break + case "vanguard": + aiTypeID = eFD_AITypeIDs.MONARCH + break + } + + SetTargetName( player, GetTargetNameForID( aiTypeID ) ) + player.Minimap_SetCustomState( eMinimapObject_npc_titan.AT_BOUNTY_BOSS ) + player.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) +} + +void function FD_PilotDisembark( entity player, entity titan ) +{ + int aiTypeID = eFD_AITypeIDs.TITAN + switch ( GetTitanCharacterName( titan ) ) + { + case "ion": + aiTypeID = eFD_AITypeIDs.ION + break + case "tone": + aiTypeID = eFD_AITypeIDs.TITAN_SNIPER + break + case "legion": + aiTypeID = eFD_AITypeIDs.LEGION + break + case "scorch": + aiTypeID = eFD_AITypeIDs.SCORCH + break + case "ronin": + aiTypeID = eFD_AITypeIDs.RONIN + break + case "northstar": + aiTypeID = eFD_AITypeIDs.NORTHSTAR + break + case "vanguard": + aiTypeID = eFD_AITypeIDs.MONARCH + break + } + + SetTargetName( titan, GetTargetNameForID( aiTypeID ) ) + SetTargetName( player, "player" + player.entindex() ) + player.Minimap_SetCustomState( eMinimapObject_npc.AI_TDM_AI ) + titan.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut index 8999231d3..4129e74c5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut @@ -18,7 +18,6 @@ void function GamemodeLts_Init() SetShouldUsePickLoadoutScreen( true ) SetSwitchSidesBased( true ) SetRoundBased( true ) - SetRespawnsEnabled( false ) Riff_ForceSetEliminationMode( eEliminationMode.PilotsTitans ) Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) SetShouldUseRoundWinningKillReplay( true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut index 768bbde11..8a6e40e65 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut @@ -18,7 +18,6 @@ void function GamemodeMfd_Init() if ( GAMETYPE == MARKED_FOR_DEATH_PRO ) { file.isMfdPro = true - SetRespawnsEnabled( true ) SetRoundBased( true ) SetShouldUseRoundWinningKillReplay( true ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut index fb84cc82b..ef2aef093 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut @@ -15,7 +15,7 @@ struct { void function GamemodePs_Init() { Riff_ForceTitanAvailability( eTitanAvailability.Never ) - + AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut index 4617476eb..50bd9f141 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut @@ -13,7 +13,7 @@ void function GamemodeSpeedball_Init() // gamemode settings SetRoundBased( true ) - SetRespawnsEnabled( false ) + SetSwitchSidesBased( true ) SetShouldUseRoundWinningKillReplay( true ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) @@ -24,7 +24,6 @@ void function GamemodeSpeedball_Init() AddCallback_GameStateEnter( eGameState.Prematch, CreateFlagIfNoFlagSpawnpoint ) AddCallback_GameStateEnter( eGameState.Playing, ResetFlag ) - AddCallback_GameStateEnter( eGameState.WinnerDetermined,GamemodeSpeedball_OnWinnerDetermined) AddCallback_OnTouchHealthKit( "item_flag", OnFlagCollected ) AddCallback_OnPlayerKilled( OnPlayerKilled ) SetTimeoutWinnerDecisionFunc( TimeoutCheckFlagHolder ) @@ -32,6 +31,8 @@ void function GamemodeSpeedball_Init() ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) ClassicMP_ForceDisableEpilogue( true ) + + level.endOfRoundPlayerState = ENDROUND_MOVEONLY } void function CreateFlag( entity flagSpawn ) @@ -67,11 +68,15 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { if ( file.flagCarrier == victim ) DropFlag() - + if ( victim.IsPlayer() && GetGameState() == eGameState.Playing ) + { if ( GetPlayerArrayOfTeam_Alive( victim.GetTeam() ).len() == 1 ) + { foreach ( entity player in GetPlayerArray() ) Remote_CallFunction_NonReplay( player, "ServerCallback_SPEEDBALL_LastPlayer", player.GetTeam() != victim.GetTeam() ) + } + } } void function GiveFlag( entity player ) @@ -151,16 +156,14 @@ void function ResetFlag() int function TimeoutCheckFlagHolder() { - if ( file.flagCarrier == null ) - return TEAM_UNASSIGNED - - return file.flagCarrier.GetTeam() -} - -void function GamemodeSpeedball_OnWinnerDetermined() -{ - if(IsValid(file.flagCarrier)) + if( IsValidPlayer( file.flagCarrier ) ) + { + AddTeamRoundScoreNoStateChange( file.flagCarrier.GetTeam() ) file.flagCarrier.AddToPlayerGameStat( PGS_ASSAULT_SCORE, 1 ) + return file.flagCarrier.GetTeam() + } + + return TEAM_UNASSIGNED } string function GetHardpointGroup(entity hardpoint) //Hardpoint Entity B on Homestead is missing the Hardpoint Group KeyValue diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut index 3ba843945..e0ea8eed1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut @@ -88,7 +88,7 @@ void function PlayerWatchesTTDMIntroIntermissionCam( entity player ) wait TTDMIntroLength - RespawnAsTitan( player, false ) + RespawnAsTitan( player ) TryGameModeAnnouncement( player ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_hardpoints.gnut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_hardpoints.gnut index 40815ff07..b729d3889 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_hardpoints.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_hardpoints.gnut @@ -117,6 +117,7 @@ void function OnHardpointEnter( entity trigger, entity player ) // it's just too hard to handle emarking and disemarking with the count stuff HardpointState hpState = GetHardpointState( hp ) + ArrayRemoveInvalid( hpState.capPlayers ) if ( hpState.capPlayers.find( player ) == -1 ) hpState.capPlayers.append( player ) @@ -136,6 +137,7 @@ void function OnHardpointLeave( entity trigger, entity player ) // it's just too hard to handle emarking and disemarking with the count stuff HardpointState hpState = GetHardpointState( hp ) + ArrayRemoveInvalid( hpState.capPlayers ) int index = hpState.capPlayers.find( player ); if ( index != -1 ) hpState.capPlayers.fastremove( index ) @@ -162,6 +164,7 @@ void function Hardpoint_Think( HardpointState hardpoint ) hardpoint.ent.SetHardpointPlayerTitanCount( TEAM_MILITIA, 0 ) // update counts based on capPlayers + ArrayRemoveInvalid( hardpoint.capPlayers ) foreach( entity player in hardpoint.capPlayers ) { if ( player.IsTitan() ) @@ -403,6 +406,7 @@ void function SetCaptureHardpoint( entity hardpoint, int team ) if ( !hardpoint.s.wasJustCapping ) return + ArrayRemoveInvalid( hpState.capPlayers ) foreach( entity player in hpState.capPlayers ) { @@ -435,6 +439,7 @@ void function SetAmpedHardpoint( entity hardpoint, int team ) if ( CapturePoint_GetState( hardpoint ) & CAPTURE_POINT_FLAGS_AMPED ) return + ArrayRemoveInvalid( hpState.capPlayers ) foreach( entity player in hpState.capPlayers ) { // the team check is just for race conditions diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_riff_floor_is_lava.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/sh_riff_floor_is_lava.nut similarity index 100% rename from Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_riff_floor_is_lava.nut rename to Northstar.CustomServers/mod/scripts/vscripts/gamemodes/sh_riff_floor_is_lava.nut diff --git a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut index 3814126ba..4e0d65d41 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut @@ -112,6 +112,10 @@ void function PlayerInventory_GiveInventoryItem( entity player, InventoryItem in player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() ) player.GiveOffhandWeapon( inventoryItem.weaponRef, OFFHAND_INVENTORY, mods ) + if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) { + entity weapon = player.GetOffhandWeapon(OFFHAND_INVENTORY) + weapon.e.burnReward = inventoryItem.burnReward.ref + } } void function PlayerInventory_PushInventoryItem( entity player, InventoryItem inventoryItem ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut index e6da14379..d92c50e17 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut @@ -5,7 +5,8 @@ global function PrivateLobby_Init struct { int startState string map = "mp_forwardbase_kodai" - string mode = "aitdm" + array maplist + string mode = "tdm" } file void function PrivateLobby_Init() @@ -15,6 +16,13 @@ void function PrivateLobby_Init() file.map = GetConVarString( "ns_private_match_last_map" ) file.mode = GetConVarString( "ns_private_match_last_mode" ) + string cvar_maprotation = GetConVarString( "ns_private_match_map_rotation" ) + + if ( !cvar_maprotation.len() ) + file.maplist = GetPrivateMatchMapsForMode( file.mode ) + else + file.maplist = split( cvar_maprotation, "," ) + thread SetupPrivateMatchUIVarsWhenReady() AddClientCommandCallback( "PrivateMatchLaunch", ClientCommandCallback_PrivateMatchLaunch ) @@ -31,8 +39,35 @@ void function SetupPrivateMatchUIVarsWhenReady() { // have to wait until end of first frame for SetUIVar to work WaitEndFrame() + if ( GetConVarBool( "ns_private_match_auto_rotation_start" ) ) + { + int i = 0 + foreach ( map in file.maplist ) + { + if ( map == file.map ) + break + i++ + } + + i += 1 + + if( i >= file.maplist.len() ) + file.map = file.maplist[0] + else + file.map = file.maplist[i] + } SetUIVar( level, "privatematch_map", GetPrivateMatchMapIndex( file.map ) ) SetUIVar( level, "privatematch_mode", GetPrivateMatchModeIndex( file.mode ) ) + + if ( GetConVarInt( "ns_maxplayers_override" ) > 0 ) + SetPlaylistVarOverride( "max_players", GetConVarString( "ns_maxplayers_override" ) ) + + if ( GetConVarBool( "ns_private_match_auto_rotation_start" ) ) + { + wait 1 + file.startState = ePrivateMatchStartState.STARTING + thread StartMatch( true ) + } } bool function ClientCommandCallback_PrivateMatchLaunch( entity player, array args ) @@ -87,6 +122,16 @@ bool function ClientCommandCallback_PrivateMatchSetMode( entity player, array args ) { - if ( file.startState == ePrivateMatchStartState.STARTING ) - return true - if ( args.len() != 1 ) return true @@ -107,7 +149,7 @@ bool function ClientCommandCallback_SetCustomMap( entity player, array a if ( !NSIsPlayerLocalPlayer( player ) ) return true - if ( GetPrivateMatchMapsForMode( file.mode ).contains( args[0] ) ) + if ( PrivateMatch_IsValidMapModeCombo( args[0], file.mode ) ) { LogPrivateMatchChange( player , " changed the map to " , args ) } @@ -128,7 +170,7 @@ bool function ClientCommandCallback_SetCustomMap( entity player, array a bool function ClientCommandCallback_PrivateMatchSwitchTeams( entity player, array args ) { - if ( file.startState == ePrivateMatchStartState.STARTING || GetGamemodeVarOrUseValue( file.mode, "max_teams", "2" ).tointeger() != 2 ) + if ( GetGamemodeVarOrUseValue( file.mode, "max_teams", "2" ).tointeger() != 2 ) return true // currently only support 2 teams in private matches @@ -138,36 +180,37 @@ bool function ClientCommandCallback_PrivateMatchSwitchTeams( entity player, arra bool function ClientCommandCallback_PrivateMatchToggleSpectate( entity player, array args ) { - if ( file.startState == ePrivateMatchStartState.STARTING || !GetConVarBool( "ns_allow_spectators" ) ) + if ( !GetConVarBool( "ns_allow_spectators" ) ) return true player.SetPersistentVar( "privateMatchState", player.GetPersistentVarAsInt( "privateMatchState" ) == 0 ? 1 : 0 ) return true } -void function StartMatch() +void function StartMatch( bool isAutostart = false ) { // set starting uivar SetUIVar( level, "privatematch_starting", ePrivateMatchStartState.STARTING ) // start countdown - SetUIVar( level, "gameStartTime", Time() + GetConVarFloat( "ns_private_match_countdown_length" ) ) float countdownEndTime = Time() + GetConVarFloat( "ns_private_match_countdown_length" ) + if( isAutostart ) + countdownEndTime = Time() + 30.0 + SetUIVar( level, "gameStartTime", countdownEndTime ) // can't use start here because we need to check stuff while ( Time() < countdownEndTime ) { // stop if the countdown's been cancelled if ( file.startState != ePrivateMatchStartState.STARTING ) return - + WaitFrame() } - - // do this before setting playlist - if ( GetConVarBool( "ns_private_match_override_maxplayers" ) ) - SetPlaylistVarOverride( "max_players", GetCurrentPlaylistVarString( "max_players", "16" ) ) - + + if ( GetConVarInt( "ns_maxplayers_override" ) > 0 ) + SetPlaylistVarOverride( "max_players", GetConVarString( "ns_maxplayers_override" ) ) + try { // todo: not every gamemode uses the same playlist as their name! need some code to resolve these manually @@ -183,7 +226,7 @@ void function StartMatch() print( "couldn't find playlist for gamemode " + file.mode ) } - RefreshPlayerTeams() + RefreshPlayerTeams( isAutostart ) SetConVarString( "ns_private_match_last_map", file.map ) SetConVarString( "ns_private_match_last_mode", file.mode ) @@ -196,7 +239,7 @@ void function StartMatch() GameRules_ChangeMap( file.map, mode ) } -void function RefreshPlayerTeams() +void function RefreshPlayerTeams( bool rerandomize = false ) { int maxTeams = GetGamemodeVarOrUseValue( file.mode, "max_teams", "2" ).tointeger() int maxPlayers = GetGamemodeVarOrUseValue( file.mode, "max_players", "12" ).tointeger() @@ -208,22 +251,27 @@ void function RefreshPlayerTeams() for ( int i = 0; i < players.len(); i++ ) SetTeam( players[ i ], i + 7 ) // 7 is the lowest ffa team } - else + else if( maxTeams > 1 ) { bool lastSetMilitia = false foreach ( entity player in GetPlayerArray() ) { - if ( player.GetTeam() == TEAM_MILITIA || player.GetTeam() == TEAM_IMC ) + if ( !rerandomize && ( player.GetTeam() == TEAM_MILITIA || player.GetTeam() == TEAM_IMC ) ) continue if ( lastSetMilitia ) // ensure roughly evenish distribution SetTeam( player, TEAM_IMC ) else SetTeam( player, TEAM_MILITIA ) - + lastSetMilitia = !lastSetMilitia } } + else + { + foreach ( entity player in GetPlayerArray() ) + SetTeam( player, TEAM_MILITIA ) + } } bool function ClientCommandCallback_PrivateMatchSetPlaylistVarOverride( entity player, array args ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut index d2be2ab41..4afced91f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut @@ -4,18 +4,19 @@ void function PrivateMatchModesInit() { // match settings // super temp: do localisation strings later - AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "classic_mp", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "run_intro", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "run_epilogue", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "scorelimit", "5" ) //, "Score Limit" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "roundscorelimit", "0" ) //, "Score Limit (round-based modes)" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "timelimit", "12" ) //, "Time Limit" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "roundtimelimit", "0" ) //, "Time Limit (round-based modes)" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "respawnprotection", "0.0" ) //, "Player Respawn Protection Time" ) + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "pick_loadout_every_round", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "pilot_health_multiplier", "1.0" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "respawn_delay", "0.0" ) - AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "boosts_enabled", [ "#SETTING_DEFAULT", "#SETTING_DISABLED" ], "1" ) - AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_overdrive", [ "#SETTING_DISABLED", "#SETTING_ENABLED", "Only" ], "1" ) + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "boosts_enabled", [ "#PILOT_BOOSTS_DEFAULT", "#PILOT_BOOSTS_DISABLED" ], "1" ) + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_overdrive", [ "#PILOT_OVERDRIVE_OFF", "#PILOT_OVERDRIVE_ON", "#PILOT_OVERDRIVE_ONLY" ], "1" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_multiplier", "1.0" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "player_force_respawn", "5" ) @@ -34,13 +35,38 @@ void function PrivateMatchModesInit() AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_RIFF", "featured_mode_rocket_arena", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_RIFF", "featured_mode_shotguns_snipers", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_RIFF", "iron_rules", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) - + AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_RIFF", "riff_titan_queue", "0" ) + AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_RIFF", "classic_executions", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) + // gamemode settings AddPrivateMatchModeSettingEnum( "#GAMEMODE_cp", "cp_amped_capture_points", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) // would've been nice to use amped_capture_points, but this var is already used ingame and its value is default 0 - AddPrivateMatchModeSettingEnum( "#GAMEMODE_coliseum", "coliseum_loadouts_#SETTING_ENABLED", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) + AddPrivateMatchModeSettingEnum( "#GAMEMODE_coliseum", "coliseum_loadouts_enabled", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "1" ) - AddPrivateMatchModeSettingEnum( "#PL_aitdm", "aitdm_archer_grunts", [ "Disabled", "Enabled" ], "0" ) + AddPrivateMatchModeSettingEnum( "#PL_aitdm", "aitdm_archer_grunts", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) + + foreach ( string difficulty in [ "#PL_fd_easy", "#PL_fd_normal", "#PL_fd_hard", "#PL_fd_master", "#PL_fd_insane" ] ) + { + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_harvester_health", "25000" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_harvester_shield", "6000" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_wave_buy_time", "60.0" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_titan_health_adjust", "-2500" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_reaper_health_adjust", "-1000" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_mortar_spectre_setup_time", "10" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_grunt_at_weapon_users", "0" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_player_damage_scalar", "1" ) + AddPrivateMatchModeSettingEnum( difficulty, "fd_at_unlimited_ammo", [ "#SETTING_OFF", "#SETTING_ON" ], "1" ) + AddPrivateMatchModeSettingEnum( difficulty, "fd_pro_titan_shields", [ "#SETTING_OFF", "#SETTING_ON" ], "0" ) + AddPrivateMatchModeSettingEnum( difficulty, "fd_respawn_dropship", [ "#SETTING_OFF", "#SETTING_ON" ], "0" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_money_per_round", FD_MONEY_PER_ROUND.tostring() ) + AddPrivateMatchModeSettingEnum( difficulty, "fd_money_flyouts", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) + AddPrivateMatchModeSettingEnum( difficulty, "riff_minimap_state", [ "#SETTING_OFF", "#SETTING_ON" ], "0" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_killcredit_grunt", "5" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_killcredit_drone", "10" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_killcredit_spectre", "10" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_killcredit_stalker", "15" ) + AddPrivateMatchModeSettingArbitrary( difficulty, "fd_killcredit_reaper", "20" ) + } // modes AddPrivateMatchMode( "ffa" ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_human.gnut b/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_human.gnut index 15a8aa3e3..47789c0bf 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_human.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_human.gnut @@ -23,6 +23,19 @@ bool function MeleeThread_PilotVsEnemyInternal( SyncedMelee action, entity attac bool isAttackerRef = IsAttackerRef( action, target ) + if ( GetCurrentPlaylistVarInt( "classic_executions", 0 ) ) + { + action = clone action + action.attackerAnimation1p = "" + action.attackerAnimation3p = "pt_rspn101_melee_necksnap_rear" + action.targetAnimation1p = "" + action.targetAnimation3p = "pt_melee_necksnap_rear_attacked" + action.isAttackerRef = false + action.minDot = 0.2 + + isAttackerRef = false + } + vector attackerOrigin = attacker.GetOrigin() vector targetOrigin = target.GetOrigin() @@ -50,7 +63,7 @@ bool function MeleeThread_PilotVsEnemyInternal( SyncedMelee action, entity attac target.ClearParent() - if ( IsValid( attacker ) ) + if ( IsValid( attacker ) && attacker.IsPlayer() ) { attacker.PlayerMelee_SetState( PLAYER_MELEE_STATE_NONE ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_titan.gnut index 5c6285a9d..ce3819ad9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_titan.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/melee/_melee_synced_titan.gnut @@ -242,7 +242,7 @@ bool function MeleeThread_TitanVsTitan_Internal( SyncedMelee action, entity atta void functionref( SyncedMelee action, entity attacker, entity target ) function GetTitanSyncedMeleeFunc( entity attacker, entity target ) { - if ( GetCurrentPlaylistVarInt( "titan_executions_always_short", 0 ) != 0 ) + if ( GetCurrentPlaylistVarInt( "titan_executions_always_short", 0 ) ) return MeleeThread_AtlasVsTitanShort entity soul = attacker.GetTitanSoul() @@ -255,14 +255,17 @@ void functionref( SyncedMelee action, entity attacker, entity target ) function if ( SoulHasPassive( soul, ePassives.PAS_VANGUARD_COREMETER ) ) executionRef = "execution_vanguard_kit" - if ( executionRef in file.executionData_3p ) + if ( executionRef in file.executionData_3p && !GetCurrentPlaylistVarInt( "classic_executions", 0 ) ) return TitanVsTitan_3p if ( target.IsNPC() ) { - entity bossPlayer = target.GetBossPlayer() - if ( IsValid( bossPlayer ) || !IsVDUTitan( target ) ) + #if HAS_BOSS_AI + if ( !IsBossTitan( target ) ) + return MeleeThread_AtlasVsTitanShort + #else return MeleeThread_AtlasVsTitanShort + #endif } string attackerType = GetSoulTitanSubClass( soul ) @@ -270,7 +273,7 @@ void functionref( SyncedMelee action, entity attacker, entity target ) function switch ( attackerType ) { case "stryder": - return MeleeThread_StyderVsTitan + return MeleeThread_StryderVsTitan case "ogre": return MeleeThread_OgreVsTitan @@ -313,7 +316,9 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker attackerSequence.thirdPersonAnim = attackerAnimation3p // attackerSequence.thirdPersonAnimIdle = "at_melee_sync_frontkill_end_idle" - attackerSequence.firstPersonAnim = attackerAnimation1p + if ( attacker.IsPlayer() ) + attackerSequence.firstPersonAnim = attackerAnimation1p + targetSequence.thirdPersonAnim = targetAnimation3p targetSequence.blendTime = 0.25 @@ -324,10 +329,10 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker //HACK! This function was originally for NPCs only, but now that it is being used for players, we need to holster their weapon if ( target.IsPlayer() ) - HolsterAndDisableWeapons( target ) + HolsterViewModelAndDisableWeapons( target ) - if ( ShouldHolsterWeaponForSyncedMelee( attacker ) ) - HolsterAndDisableWeapons( attacker ) + if ( attacker.IsPlayer() ) + HolsterViewModelAndDisableWeapons( attacker ) local attackerViewBody @@ -339,8 +344,6 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker AddAnimEvent( target, "rider_rodeo_over", ForceTitanRodeoToEnd ) - target.SetInvulnerable() //Setting target of execution as invulnerable to prevent them dying mid-way - OnThreadEnd( function() : ( ref, attacker, target, e ) { @@ -359,31 +362,45 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker if ( IsValid( attacker ) ) { //attacker.ClearInvulnerable() - attacker.UnforceStand() + if ( attacker.IsPlayer() ) + attacker.UnforceStand() + attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - DeployAndEnableWeapons( attacker ) - attacker.PlayerMelee_ExecutionEndAttacker() + + if ( attacker.IsPlayer() ) + { + ClearPlayerAnimViewEntity( attacker ) + DeployViewModelAndEnableWeapons( attacker ) + attacker.PlayerMelee_ExecutionEndAttacker() + } if ( IsAlive( attacker ) ) { // if we got into solid, teleport back to safe place if ( !PutEntityInSafeSpot( attacker, null, null, expect vector( e.attackerStartOrg ), attacker.GetOrigin() ) ) - { + { printt( "PutEntityInSafeSpot failed, putting him back at the start origin" ) attacker.SetOrigin( expect vector( e.attackerStartOrg ) ) - } + } } + + vector noRollAngle = attacker.GetAngles() + + noRollAngle.x = 0 + + attacker.SetAngles( noRollAngle ) } if ( IsValid( target ) ) { + target.ClearInvulnerable() + if ( !target.IsNPC() ) { target.PlayerMelee_ExecutionEndTarget() ClearPlayerAnimViewEntity( target ) - DeployAndEnableWeapons( target ) + DeployViewModelAndEnableWeapons( target ) } @@ -404,6 +421,12 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker } ) + attacker.EndSignal( "OnDeath" ) + attacker.EndSignal( "OnDestroy" ) + + target.EndSignal( "OnRespawnPlayer" ) + target.EndSignal( "OnDestroy" ) + thread FirstPersonSequence( targetSequence, target, ref ) waitthread FirstPersonSequence( attackerSequence, attacker, ref ) @@ -411,7 +434,7 @@ void function MeleeThread_AtlasVsTitanShort( SyncedMelee action, entity attacker } -void function MeleeThread_StyderVsTitan( SyncedMelee action, entity attacker, entity target ) +void function MeleeThread_StryderVsTitan( SyncedMelee action, entity attacker, entity target ) { table e e.gib <- true @@ -460,7 +483,9 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke attackerSequence.thirdPersonAnim = expect string ( e.attackerAnimation3p ) // attackerSequence.thirdPersonAnimIdle = "at_melee_sync_frontkill_end_idle" - attackerSequence.firstPersonAnim = expect string( e.attackerAnimation1p ) + if ( attacker.IsPlayer() ) + attackerSequence.firstPersonAnim = expect string( e.attackerAnimation1p ) + targetSequence.thirdPersonAnim = expect string ( e.targetAnimation3p ) targetSequence.blendTime = 0.25 @@ -468,11 +493,11 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke // attacker.SetInvulnerable() target.SetInvulnerable() //HACK: Have to SetInvulnerable first before attacker holsters weapon, because if the attacker is vortexing, holster will release bullets caught and kill off the victim if low enough health - if ( ShouldHolsterWeaponForSyncedMelee( attacker ) ) - HolsterAndDisableWeapons( attacker ) + if ( attacker.IsPlayer() ) + HolsterViewModelAndDisableWeapons( attacker ) if ( !target.IsNPC() ) - HolsterAndDisableWeapons( target ) + HolsterViewModelAndDisableWeapons( target ) EmitDifferentSoundsOnEntityForPlayerAndWorld( expect string ( e.TitanSpecific1pSyncMeleeSound ), expect string ( e.TitanSpecific3pSyncMeleeSound ), attacker, attacker ) @@ -504,12 +529,26 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke targetBodySequence.attachment = "ref" targetBodySequence.blendTime = 0.25 targetBodySequence.thirdPersonAnim = expect string ( e.targetPilotAnimationForObserver ) - targetBodySequence.firstPersonAnim = expect string ( e.targetPilotAnimationForObserver1st ) + + if ( targetIsPlayer ) + targetBodySequence.firstPersonAnim = expect string ( e.targetPilotAnimationForObserver1st ) entity targetSoul = target.GetTitanSoul() targetSoul.SetInvalidHealthBarEnt( true ) + vector refAngles = GetRefAnglesBetweenEnts( attacker, target ) + + if ( !attacker.IsOnGround() ) + refAngles = < 0, refAngles.y, 0 > + + vector fwd = AnglesToForward( refAngles ) * -1 + vector targetAngles = VectorToAngles( fwd ) + + targetAngles.x = 0 + + target.SetAngles( targetAngles ) + entity targetTitan if ( targetIsPlayer ) { @@ -529,9 +568,7 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke { targetTitan = target - // target is now a random dude - target = CreateSoldier( target.GetTeam(), Vector(0,0,0), Vector(0,0,0) ) - DispatchSpawn( target ) + target = CreateNpcTitanPilotModel( target, true ) e.target <- target } @@ -539,7 +576,8 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke AddAnimEvent( targetTitan, "rider_rodeo_over", ForceTitanRodeoToEnd ) AddAnimEvent( targetTitan, "melee_killed_ragdoll", MeleeKilledRagdoll, attacker ) - targetTitan.SetInvulnerable() //Setting target of execution as invulnerable to prevent them dying mid-way + targetTitan.SetInvulnerable() + target.SetInvulnerable() target.SetOwner( attacker ) target.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) //owner cant see @@ -553,41 +591,34 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke { if ( IsValid( ref ) ) { - if ( IsValid( attacker ) ) - { - attacker.ClearParent() - } - else - { - TryClearParent( attacker ) - } - - if ( IsValid( target ) ) - { - target.ClearParent() - } - else - { - TryClearParent( target ) - } + ClearChildren( ref ) - AssertNoPlayerChildren( ref ) ref.Kill_Deprecated_UseDestroyInstead() } if ( IsValid( attacker ) ) { - attacker.UnforceStand() + attacker.ClearInvulnerable() attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - DeployAndEnableWeapons( attacker ) - attacker.PlayerMelee_ExecutionEndAttacker() + if( attacker.IsPlayer() ) + { + attacker.UnforceStand() + ClearPlayerAnimViewEntity( attacker ) + attacker.PlayerMelee_ExecutionEndAttacker() + DeployViewModelAndEnableWeapons( attacker ) + } if ( IsAlive( attacker ) ) { - // if we got into solid, teleport back to safe place PutEntityInSafeSpot( attacker, null, null, expect vector( e.attackerStartOrg ), attacker.GetOrigin() ) + attacker.SetActiveWeaponBySlot( 0 ) } + + vector noRollAngle = attacker.GetAngles() + + noRollAngle.x = 0 + + attacker.SetAngles( noRollAngle ) } if ( IsValid( target ) ) @@ -596,7 +627,7 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke { target.PlayerMelee_ExecutionEndTarget() ClearPlayerAnimViewEntity( target ) - DeployAndEnableWeapons( target ) + DeployViewModelAndEnableWeapons( target ) } if ( HasAnimEvent( target, "pink_mist" ) ) @@ -627,15 +658,38 @@ function MeleeThread_TitanRipsPilot( table e, SyncedMelee action, entity attacke } ) + attacker.EndSignal( "OnDeath" ) + attacker.EndSignal( "OnDestroy" ) + target.EndSignal( "OnRespawnPlayer" ) + target.EndSignal( "OnDestroy" ) waitthread TitanSyncedMeleeAnimationsPlay( attackerBodySequence, attackerViewBody, ref, targetBodySequence, target, attackerSequence, attacker, targetSequence, targetTitan, e ) } -entity function CreateNpcTitanPilotModel( entity titan ) +entity function CreateNpcTitanPilotModel( entity titan, bool createEntity = false ) { asset modelName = GetNpcTitanPilotModel( titan ) - return CreatePropDynamic( modelName ) + + if ( modelName == $"" ) + modelName = TEAM_IMC_GRUNT_MODEL + + if ( createEntity ) + { + entity pilot = CreateElitePilot( titan.GetTeam(), titan.GetOrigin(), titan.GetAngles() ) + + DispatchSpawn( pilot ) + + pilot.SetModel( modelName ) + + return pilot + } + + entity model = CreatePropDynamic( modelName ) + + SetTeam( model, titan.GetTeam() ) + + return model } @@ -662,14 +716,20 @@ function TitanSyncedMeleeAnimationsPlay( FirstPersonSequenceStruct attackerBodyS { // insure visibility if ( IsValid( targetTitan ) ) - targetTitan.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + { + targetTitan.ClearInvulnerable() + + if ( IsAlive( targetTitan ) ) + targetTitan.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) + } if ( !IsAlive( attacker ) ) { attacker.Anim_Stop() - if ( !e.thrown && IsAlive( target ) ) + if ( !e.thrown && IsAlive( target ) && target.IsPlayer() ) { + target.ClearInvulnerable() target.Anim_Stop() target.SetOwner( null ) target.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE @@ -679,8 +739,9 @@ function TitanSyncedMeleeAnimationsPlay( FirstPersonSequenceStruct attackerBodyS target.GetFirstPersonProxy().Anim_Stop() target.SetPlayerSettings( e.oldPlayerSettings ) } - } + else if ( IsAlive( target ) ) + target.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) } } ) @@ -895,7 +956,9 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti FirstPersonSequenceStruct targetSequence = clone attackerSequence attackerSequence.thirdPersonAnim = attackerAnimation3p - attackerSequence.firstPersonAnim = attackerAnimation1p + + if ( attacker.IsPlayer() ) + attackerSequence.firstPersonAnim = attackerAnimation1p if ( target.IsPlayer() ) targetSequence.firstPersonAnim = targetAnimation1p @@ -904,8 +967,12 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti targetSequence.blendTime = 0.25 target.e.syncedMeleeAttacker = attacker - DisableWeapons( attacker, [] ) - DisableWeapons( target, [] ) + + if ( attacker.IsPlayer() ) + HolsterViewModelAndDisableWeapons( attacker ) + + if ( target.IsPlayer() ) + HolsterViewModelAndDisableWeapons( target ) // attacker.SetInvulnerable() target.SetInvulnerable() @@ -918,23 +985,29 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti { if ( IsValid( ref ) ) { - if ( IsValid( attacker ) ) - attacker.ClearParent() - - if ( IsValid( target ) ) - target.ClearParent() + ClearChildren( ref ) - AssertNoPlayerChildren( ref ) ref.Kill_Deprecated_UseDestroyInstead() } if ( IsValid( attacker ) ) { - attacker.UnforceStand() + if ( attacker.IsPlayer() ) + attacker.UnforceStand() + + attacker.ClearInvulnerable() attacker.ClearParent() - ClearPlayerAnimViewEntity( attacker ) - EnableWeapons( attacker, [] ) - attacker.PlayerMelee_ExecutionEndAttacker() + + if ( attacker.IsPlayer() ) + { + ClearPlayerAnimViewEntity( attacker ) + DeployViewModelAndEnableWeapons( attacker ) + } + + attacker.SetActiveWeaponBySlot( 0 ) + + if ( attacker.IsPlayer() ) + attacker.PlayerMelee_ExecutionEndAttacker() if ( IsAlive( attacker ) ) { @@ -956,7 +1029,8 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti ClearPlayerAnimViewEntity( target ) } - EnableWeapons( target, [] ) + if ( target.IsPlayer() ) + DeployViewModelAndEnableWeapons( target ) if ( !target.IsNPC() ) target.PlayerMelee_ExecutionEndTarget() @@ -975,11 +1049,26 @@ void function MeleeThread_OgreVsTitan( SyncedMelee action, entity attacker, enti ) attacker.EndSignal( "OnDeath" ) + attacker.EndSignal( "OnDestroy" ) + + target.EndSignal( "OnRespawnPlayer" ) + target.EndSignal( "OnDestroy" ) EmitDifferentSoundsOnEntityForPlayerAndWorld( "Ogre_1p_Sync_Melee", "Ogre_3p_Sync_Melee", attacker, attacker ) AddAnimEvent( target, "lost_arm", TitanLostArm, e ) + vector refAngles = GetRefAnglesBetweenEnts( attacker, target ) + + if ( !attacker.IsOnGround() ) + refAngles = < 0, refAngles.y, 0 > + + vector fwd = AnglesToForward( refAngles ) * -1 + vector targetAngles = VectorToAngles( fwd ) + + targetAngles.x = 0 + + target.SetAngles( targetAngles ) thread FirstPersonSequence( targetSequence, target, ref ) waitthread FirstPersonSequence( attackerSequence, attacker, ref ) @@ -1197,6 +1286,12 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe { attacker.Anim_Stop() // if you are fighting an NPC, then they can get destroyed early the moment they explode. But sometimes, your animation isn't done playing yet so you can't move } + + vector noRollAngle = attacker.GetAngles() + + noRollAngle.x = 0 + + attacker.SetAngles( noRollAngle ) } } @@ -1307,18 +1402,12 @@ void function TitanVsTitan_3p( SyncedMelee action, entity attacker, entity targe vector refAngles = GetRefAnglesBetweenEnts( attacker, target ) if ( !attacker.IsOnGround() ) - { - refAngles = <0,refAngles.y,0> - } + refAngles = < 0, refAngles.y, 0 > - vector fwd = AnglesToForward( refAngles ) - fwd *= -1 + vector fwd = AnglesToForward( refAngles ) * -1 vector targetAngles = VectorToAngles( fwd ) - if ( !target.IsNPC() ) - { - targetAngles.x = 0 - target.SetAngles( targetAngles ) - } + + targetAngles.x = 0 target.SetAngles( targetAngles ) @@ -1479,7 +1568,10 @@ void function MeleeKilledRagdoll( entity titan ) if ( !IsValid( attacker ) ) return - titan.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) + + if ( IsAlive( titan ) ) + titan.Die( attacker, attacker, { scriptType = DF_MELEE, damageSourceId = eDamageSourceId.titan_execution } ) + titan.SetContinueAnimatingAfterRagdoll( true ) titan.BecomeRagdoll( < 0, 0, 0 >, false ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/melee/sh_melee_human.gnut b/Northstar.CustomServers/mod/scripts/vscripts/melee/sh_melee_human.gnut new file mode 100644 index 000000000..aa6f5eb13 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/melee/sh_melee_human.gnut @@ -0,0 +1,538 @@ +untyped + +global function MeleeHumanShared_Init + +global function HumanUnsyncedMelee +global function HumanMeleeAttack + +function MeleeHumanShared_Init() +{ + PrecacheParticleSystem( $"P_melee_player" ) + RegisterSignal( "StopSlowMoMelee" ) + RegisterSignal( "StopHighlightValidMeleeEnemy" ) +} + +function HumanUnsyncedMelee( entity player, bool movestunBlocked ) +{ + entity activeWeapon = player.GetActiveWeapon() + if ( !IsValid( activeWeapon ) ) + { +#if SERVER && DEV + print( "SERVER: " + player + " has no valid active weapon\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " has no valid active weapon\n" ) +#endif + return + } + + entity meleeWeapon = player.GetMeleeWeapon() + if ( !IsValid( meleeWeapon ) ) + { +#if SERVER && DEV + print( "SERVER: " + player + " has no valid melee weapon\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " has no valid melee weapon\n" ) +#endif + return + } + + local meleeAttackType = PLAYER_MELEE_STATE_HUMAN_KICK_ATTACK + if ( activeWeapon.GetWeaponClassName() == "mp_weapon_dash_melee" ) + meleeAttackType = PLAYER_MELEE_STATE_HUMAN_EVISCERATE_ATTACK + + player.PlayerMelee_StartAttack( meleeAttackType ) + + if ( player.PlayerMelee_GetState() == PLAYER_MELEE_STATE_HUMAN_EVISCERATE_ATTACK ) + { + vector lungeTargetPos = (player.GetOrigin() + (player.GetViewVector() * 300)) + player.Lunge_SetTargetPosition( lungeTargetPos ) + player.Lunge_EnableFlying() + } + else + { + entity lungeTarget = GetLungeTargetForPlayer( player ) + if ( IsAlive( lungeTarget ) ) + { + if ( !movestunBlocked ) + { +#if SERVER && DEV + print( "SERVER: " + player + " is calling Lunge_SetTargetEntity() from HumanUnsyncedMelee()\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " is calling Lunge_SetTargetEntity() from HumanUnsyncedMelee()\n" ) +#endif + if ( player.Lunge_SetTargetEntity( lungeTarget, true ) ) + { + if ( lungeTarget.IsTitan() ) + { + player.Lunge_EnableFlying() + vector oldOffset = player.Lunge_GetEndPositionOffset() + player.Lunge_SetEndPositionOffset( oldOffset + <0, 0, 128> ) + } + else + { + if ( player.IsOnGround() ) + player.Lunge_LockPitch( true ) + } + } + } + } +#if SERVER + // if we don't lunge at anything stop slowmo + else if ( IsSingleplayer() && PROTO_IsSlowMoWeapon( meleeWeapon ) ) + { + player.Signal( "StopSlowMoMelee" ) + } +#endif // #if SERVER + } + +#if SERVER + meleeWeapon.EmitWeaponNpcSound_DontUpdateLastFiredTime( 200, 0.2 ) +#endif // #if SERVER + + //player.Weapon_StartCustomActivity( meleeActivity1p, false ) + player.SetSelectedOffhandToMelee() +} + +function DoReactionForTitanHit( entity player, entity titan ) +{ +#if SERVER && DEV + print( "SERVER: " + player + " is calling Lunge_SetTargetEntity() from DoReactionForTitanHit()\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " is calling Lunge_SetTargetEntity() from DoReactionForTitanHit()\n" ) +#endif + player.Lunge_SetTargetEntity( titan, true ) + if ( player.Lunge_IsLungingToEntity() ) + player.Lunge_EnableFlying() + + vector titanCenter = titan.EyePosition() + vector delta = (player.EyePosition() - titanCenter) + vector dir = Normalize( delta ) + player.Lunge_SetEndPositionOffset( dir * 350 ) +} + +function HumanMeleeAttack( entity player ) +{ + if ( player.IsPhaseShifted() ) + return + if ( player.PlayerMelee_GetAttackHitEntity() ) + return + if ( IsInExecutionMeleeState( player ) ) + return + + entity meleeWeapon = player.GetMeleeWeapon() + float attackRange = meleeWeapon.GetMeleeAttackRange() + + if ( player.Lunge_IsGroundExecute() ) + attackRange = 150 + +#if SERVER && DEV + print( "SERVER: " + player + " is calling PlayerMelee_AttackTrace() from HumanMeleeAttack()\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " is calling PlayerMelee_AttackTrace() from HumanMeleeAttack()\n" ) +#endif + table traceResult = PlayerMelee_AttackTrace( player, attackRange, CodeCallback_IsValidMeleeAttackTarget ) + + entity hitEnt = expect entity( traceResult.ent ) + if ( !IsValid( hitEnt ) ) + { +#if SERVER && DEV + print( "SERVER: " + player + " call to PlayerMelee_AttackTrace() did NOT hit\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " call to PlayerMelee_AttackTrace() did NOT hit\n" ) +#endif + return + } + +#if SERVER && DEV + print( "SERVER: " + player + " call to PlayerMelee_AttackTrace() hit " + hitEnt + "\n" ) +#elseif CLIENT && DEV + print( "CLIENT: " + player + " call to PlayerMelee_AttackTrace() hit " + hitEnt + "\n" ) +#endif + + if ( PlayerMelee_IsServerSideEffects() ) + { +#if SERVER + vector hitNormal = Normalize( traceResult.startPosition - traceResult.position ) + player.DispatchImpactEffects( hitEnt, traceResult.startPosition, traceResult.position, hitNormal, traceResult.surfaceProp, traceResult.staticPropIndex, traceResult.damageType, meleeWeapon.GetImpactTableIndex(), player, traceResult.impactEffectFlags | IEF_SERVER_SIDE_EFFECT ) +#endif + } + else + { + vector hitNormal = Normalize( traceResult.startPosition - traceResult.position ) + player.DispatchImpactEffects( hitEnt, traceResult.startPosition, traceResult.position, hitNormal, traceResult.surfaceProp, traceResult.staticPropIndex, traceResult.damageType, meleeWeapon.GetImpactTableIndex(), player, traceResult.impactEffectFlags ) + } + + player.PlayerMelee_SetAttackHitEntity( hitEnt ) + if ( !hitEnt.IsWorld() ) + player.PlayerMelee_SetAttackRecoveryShouldBeQuick( true ) + + if ( hitEnt.IsTitan() ) + DoReactionForTitanHit( player, hitEnt ) + + if ( hitEnt.IsBreakableGlass() ) + { +#if SERVER + hitEnt.BreakSphere( traceResult.position, 50 ) +#endif // #if SERVER + } + else + { + if ( player.IsInputCommandHeld( IN_MELEE ) && AttemptHumanMeleeExecution( player, hitEnt, meleeWeapon, traceResult ) ) + return + +#if CLIENT + //MeleeImpactFX( player, meleeWeapon, hitEnt ) +#else + HumanMeleeAttack_DoImpact( player, meleeWeapon, traceResult ) +#endif + const float SCALE_WHEN_ENEMY = 1.0 + const float SCALE_WHEN_NOT_ENEMY = 0.5 + float severityScale = IsEnemyTeam( player.GetTeam(), hitEnt.GetTeam() ) ? SCALE_WHEN_ENEMY : SCALE_WHEN_NOT_ENEMY + meleeWeapon.DoMeleeHitConfirmation( severityScale ) + } +} + +#if 0 //CLIENT +function MeleeImpactFX( entity player, entity meleeWeapon, entity target ) +{ + if ( !target.IsWorld() ) + { + entity cockpit = player.GetCockpit() + if ( IsValid( cockpit ) ) + StartParticleEffectOnEntity( cockpit, GetParticleSystemIndex( $"P_melee_player" ), FX_PATTACH_ABSORIGIN_FOLLOW, -1 ) //P_MFD works well too + } +} +#endif // CLIENT + +#if SERVER +function HumanMeleeAttack_DoImpact( entity player, entity meleeWeapon, traceResult ) +{ + local angles = player.EyeAngles() + entity target = expect entity( traceResult.ent ) + player.PlayerMelee_SetAttackHitEntity( target ) + + string weaponName = meleeWeapon.GetWeaponClassName() + local damageSource = eDamageSourceId[weaponName] + int damageAmount = GetDamageAmountForTarget( meleeWeapon, target ) + + if ( IsHumanSized( target ) ) + { + if ( target.IsPlayer() ) //Strip away rodeo protection + { + entity titanBeingRodeoed = GetTitanBeingRodeoed( target ) + if ( IsValid( titanBeingRodeoed ) ) + TakeAwayFriendlyRodeoPlayerProtection( titanBeingRodeoed ) + } + + // ?? + target.SetContinueAnimatingAfterRagdoll( true ) + } + + vector oldVelocity = target.GetVelocity() + vector damageForce = AnglesToForward( angles ) * meleeWeapon.GetWeaponDamageForce() + + print( "SERVER: HumanMeleeAttack_DoImpact() applying damage to " + target + "\n" ) + + if ( target.IsNPC() && target.CanBeGroundExecuted() ) + target.TakeDamage( target.GetHealth(), player, player, { scriptType = DF_RAGDOLL | meleeWeapon.GetWeaponDamageFlags(), damageType = DMG_MELEE_ATTACK, damageSourceId = damageSource, origin = traceResult.position, force = Vector( 0, 0, 0 ) } ) + else + target.TakeDamage( damageAmount, player, player, { scriptType = meleeWeapon.GetWeaponDamageFlags(), damageType = DMG_MELEE_ATTACK, damageSourceId = damageSource, origin = traceResult.position, force = damageForce } ) + + // PROTO DEV + if ( IsSingleplayer() ) + { + if ( PROTO_ShouldActivateSlowMo( target, meleeWeapon ) ) + { + thread PROTO_SlowMoMelee( player, target, meleeWeapon ) + } + } + + // triggers: + { + local triggerTraceDir = Normalize( traceResult.position - traceResult.startPosition ) + player.TraceAttackToTriggers( damageAmount, player, player, { scriptType = meleeWeapon.GetWeaponDamageFlags(), damageType = DMG_MELEE_ATTACK, damageSourceId = damageSource, force = damageForce }, traceResult.startPosition, traceResult.position, triggerTraceDir ) + } + + if ( target.IsPlayerDecoy() ) + { + player.PlayerMelee_EndAttack() + } +} + +int function GetDamageAmountForTarget( entity meleeWeapon, entity target ) +{ + // special case + if ( IsTurret( target ) && IsHumanSized( target ) ) + return target.GetMaxHealth() + 1 + + // default + return meleeWeapon.GetDamageAmountForArmorType( target.GetArmorType() ) +} + + +// HACK - testing linked slow mo melee +void function PROTO_SlowMoMelee( entity player, entity currentEnemy, entity meleeWeapon ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "StopSlowMoMelee" ) + + float duration = 1.75 //1.75 + float timescale = 0.4 + float lastKillTimescale = 0.2 + + var SlowMoTimeRemaining = player.s.meleeSlowMoEndTime - Time() + + meleeWeapon.SetMods( [ "SlowMoLinked" ] ) // need to switch to the other mod to get the longer lunge range + + // find an enemy close enough that we can melee him next + entity nextEnemy = PROTO_GetNextMeleeEnemy( player, meleeWeapon, currentEnemy ) + + if ( !IsValid( nextEnemy ) ) + { + meleeWeapon.SetMods( [ "SlowMo" ] ) + if ( SlowMoTimeRemaining > 0 ) + { + // do extra slowdown for the last kill in a linked slow-mo melee chain. + ServerCommand( "host_timescale " + string( lastKillTimescale ) ) + wait 0.2 + player.Signal( "StopSlowMoMelee" ) // this will also end this thread + } + + return + } + + if ( player.s.meleeSlowMoEndTime > Time() ) + { + // if we are already in slow-mo just turn towards the next enemy and extend the duration + thread PROTO_TurnViewTowardsClosestEnemy( player, nextEnemy ) + player.s.meleeSlowMoEndTime = Time() + duration // += duration + return + } + + // require a 5 second cool down between leaving and reentering slow mo. + if ( SlowMoTimeRemaining > -5 ) + return + + thread PROTO_TurnViewTowardsClosestEnemy( player, nextEnemy ) + + // enter slow mo + ServerCommand( "host_timescale " + string( timescale ) ) + player.s.meleeSlowMoEndTime = Time() + duration + meleeWeapon.SetMods( [ "SlowMoLinked" ] ) + + float range = meleeWeapon.GetMeleeLungeTargetRange() + array enemyArray = PROTO_GetMeleeEnemiesWithinRange( player.GetOrigin(), player.GetTeam(), range ) + foreach( enemy in enemyArray ) + thread PROTO_HighlightValidMeleeEnemy( player, enemy, meleeWeapon ) + + player.SetInvulnerable() + + OnThreadEnd( + function() : ( player, meleeWeapon ) + { + if ( IsValid( meleeWeapon ) ) + meleeWeapon.SetMods( [ "SlowMo" ] ) + + if ( IsValid( player ) ) + { + player.ClearInvulnerable() + player.s.meleeSlowMoEndTime = 0 + } + + thread PROTO_EaseOutSlowMo() + } + ) + + while( Time() <= player.s.meleeSlowMoEndTime ) + { + var waitTime = player.s.meleeSlowMoEndTime - Time() + wait waitTime + } + + player.Signal( "StopSlowMoMelee" ) +} + +void function PROTO_EaseOutSlowMo() +{ + ServerCommand( "host_timescale 0.4" ) + wait 0.1 + ServerCommand( "host_timescale 0.7" ) + wait 0.1 + ServerCommand( "host_timescale 1.0" ) +} + +bool function PROTO_IsSlowMoWeapon( entity meleeWeapon ) +{ + return ( meleeWeapon.HasMod( "SlowMo" ) || meleeWeapon.HasMod( "SlowMoLinked" ) ) +} + +bool function PROTO_ShouldActivateSlowMo( entity enemy, entity meleeWeapon ) +{ + if ( !PROTO_IsSlowMoWeapon( meleeWeapon ) ) + return false + + if ( !IsHumanSized( enemy ) ) + return false + + return true +} + +void function PROTO_TurnViewTowardsClosestEnemy( entity player, entity nextEnemy ) +{ + player.EndSignal( "OnDeath" ) + + OnThreadEnd( + function() : ( player ) + { + if ( IsValid( player ) ) + { + player.ClearParent() + player.PlayerCone_Disable() + } + } + ) + + // turn player view towards next enemy + vector vec = nextEnemy.GetOrigin() - player.GetOrigin() + vector newAngles = VectorToAngles( vec ) + + entity scriptMover = CreateScriptMover( player.GetOrigin(), player.GetAngles() ) + player.SetParent( scriptMover ) + + player.PlayerCone_SetLerpTime( 0.15 ) + + player.PlayerCone_FromAnim() + player.PlayerCone_SetMinYaw( -15 ) + player.PlayerCone_SetMaxYaw( 15 ) + player.PlayerCone_SetMinPitch( -5 ) + player.PlayerCone_SetMaxPitch( 15 ) + + wait 0.2 + + scriptMover.NonPhysicsRotateTo( newAngles, 0.4, 0.2, 0.2 ) + wait 0.4 +} + +entity function PROTO_GetNextMeleeEnemy( entity player, entity meleeWeapon, entity lastEnemy ) +{ + float range = meleeWeapon.GetMeleeLungeTargetRange() + array enemyArray = PROTO_GetMeleeEnemiesWithinRange( player.GetOrigin(), player.GetTeam(), range ) + entity nextEnemy = null + + foreach ( enemy in enemyArray ) + { + float heightDif = enemy.GetOrigin().z - player.GetOrigin().z + if ( heightDif < -96 || heightDif > 48 ) + continue + + float frac = TraceLineSimple( player.EyePosition(), enemy.EyePosition(), enemy ) + if ( frac < 1 ) + continue + + if ( enemy == lastEnemy ) + continue + + nextEnemy = enemy + break + } + + return nextEnemy +} + +array function PROTO_GetMeleeEnemiesWithinRange( vector playerOrigin, int playerTeam, float range ) +{ + array enemyArray = GetNPCArrayEx( "npc_soldier", TEAM_ANY, playerTeam, playerOrigin, range ) + enemyArray.extend( GetNPCArrayEx( "npc_spectre", TEAM_ANY, playerTeam, playerOrigin, range ) ) + + return enemyArray +} + +void function PROTO_HighlightValidMeleeEnemy( entity player, entity enemy, entity meleeWeapon ) +{ + enemy.Signal( "StopHighlightValidMeleeEnemy" ) + enemy.EndSignal( "StopHighlightValidMeleeEnemy" ) + + player.EndSignal( "StopSlowMoMelee" ) + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + + enemy.EndSignal( "OnDestroy" ) + + OnThreadEnd( + function() : ( enemy ) + { + if ( IsValid( enemy ) ) + Highlight_ClearEnemyHighlight( enemy ) + } + ) + + float range = meleeWeapon.GetMeleeLungeTargetRange() + float minDot = AngleToDot( meleeWeapon.GetMeleeLungeTargetAngle() ) + + while( true ) + { + vector viewVector = player.GetViewVector() + vector enemyVector = enemy.GetCenter() - player.EyePosition() + float dist = expect float( enemyVector.Norm() ) + + if ( DotProduct( enemyVector, viewVector ) > minDot && dist < range ) + Highlight_SetEnemyHighlight( enemy, "enemy_sur_base" ) // enemy_sur_base, enemy_sonar, map_scan + else + Highlight_ClearEnemyHighlight( enemy ) + + wait 0.1 + } +} + +#endif // #if SERVER + +bool function AttemptHumanMeleeExecution( entity player, entity syncedTarget, entity meleeWeapon, table traceResult ) +{ + if ( player.PlayerMelee_GetState() == PLAYER_MELEE_STATE_NONE ) + return false + + if ( !IsAlive( player ) ) + return false + + if ( player.IsPhaseShifted() ) + return false + + if ( !CodeCallback_IsValidMeleeExecutionTarget( player, syncedTarget ) ) + return false + + #if SERVER + player.Anim_StopGesture( 0 ) + #endif + + thread PlayerTriesSyncedMelee_FallbackToHumanMeleeAttack( player, syncedTarget, meleeWeapon, traceResult ) + return true +} + +void function PlayerTriesSyncedMelee_FallbackToHumanMeleeAttack( entity player, entity target, entity meleeWeapon, table traceResult ) +{ +#if SERVER && DEV + print( "SERVER: PlayerTriesSyncedMelee_FallbackToHumanMeleeAttack() for " + player + "\n" ) +#elseif CLIENT && DEV + print( "CLIENT: PlayerTriesSyncedMelee_FallbackToHumanMeleeAttack() for " + player + "\n" ) +#endif + if ( !PlayerTriesSyncedMelee( player, target ) ) + { +#if SERVER && DEV + print( "SERVER: PlayerTriesSyncedMelee() for " + player + " failed\n" ) +#elseif CLIENT && DEV + print( "CLIENT: PlayerTriesSyncedMelee() for " + player + " failed\n" ) +#endif +#if SERVER + HumanMeleeAttack_DoImpact( player, meleeWeapon, traceResult ) +#endif + } + else + { +#if SERVER && DEV + print( "SERVER: PlayerTriesSyncedMelee() for " + player + " succeeded\n" ) +#elseif CLIENT && DEV + print( "CLIENT: PlayerTriesSyncedMelee() for " + player + " succeeded\n" ) +#endif + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut index 1102aae1c..dc2bf0c62 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut @@ -5,20 +5,122 @@ global function SPMP_UpdateNPCProficiency global function SPMP_Callback_ForceAIMissPlayer global function IsAutoPopulateEnabled +global function AILoadout_SetupNPCWeapons +global function AILoadout_SetupNPCAntiTitanWeapons +global function AILoadout_GetRandomWeaponForClass +global function AILoadout_GetRandomATWeaponForClass + +struct{ + table< string, array > customNPCWeapons + table< string, array > customNPCATWeapons + + table< string, array > defaultNPCWeapons + table< string, array > defaultNPCATWeapons +}file + + + + + + + + + + + +/* + █████ ██ ██ ██████ █████ ██████ ██████ ██ ██ ████████ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ███████ ██████ ██ ██ ██████ ██████ ██████ ██ ███████ +*/ + void function MpInitAILoadouts() { + file.defaultNPCWeapons["npc_soldier"] <- [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] + file.defaultNPCWeapons["npc_spectre"] <- [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] + file.defaultNPCWeapons["npc_stalker"] <- [ "mp_weapon_hemlok_smg", "mp_weapon_lstar", "mp_weapon_mastiff" ] + + file.defaultNPCATWeapons["npc_soldier"] <- [ "mp_weapon_defender", "mp_weapon_rocket_launcher" ] + file.defaultNPCATWeapons["npc_spectre"] <- [ "mp_weapon_defender", "mp_weapon_rocket_launcher" ] + file.defaultNPCATWeapons["npc_stalker"] <- [ "mp_weapon_defender", "mp_weapon_rocket_launcher" ] +} + +void function AILoadout_SetupNPCWeapons( string npcClass, array weapons ) +{ + if ( !( npcClass in file.customNPCWeapons ) ) + file.customNPCWeapons[ npcClass ] <- [] + + file.customNPCWeapons[ npcClass ] = weapons +} + +void function AILoadout_SetupNPCAntiTitanWeapons( string npcClass, array weapons ) +{ + if ( !( npcClass in file.customNPCATWeapons ) ) + file.customNPCATWeapons[ npcClass ] <- [] + + file.customNPCATWeapons[ npcClass ] = weapons +} + +string function AILoadout_GetRandomWeaponForClass( entity npc ) +{ + string className = npc.GetClassName() + if ( className in file.customNPCWeapons ) + { + if ( file.customNPCWeapons[ className ].len() ) + return file.customNPCWeapons[ className ].getrandom() + } + else if ( className in file.defaultNPCWeapons ) + return file.defaultNPCWeapons[ className ].getrandom() + + return "" +} + +string function AILoadout_GetRandomATWeaponForClass( entity npc ) +{ + string className = npc.GetClassName() + if ( className in file.customNPCATWeapons ) + { + if ( file.customNPCATWeapons[ className ].len() ) + return file.customNPCATWeapons[ className ].getrandom() + } + else if ( className in file.defaultNPCATWeapons ) + return file.defaultNPCATWeapons[ className ].getrandom() + return "" } + + + + + + + + + + +/* + █████ ██ ██████ ██████ ██████ ███████ ██ ██████ ███████ ███ ██ ██████ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ +███████ ██ ██████ ██████ ██ ██ █████ ██ ██ █████ ██ ██ ██ ██ ████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ██ ██ ██ ██████ ██ ██ ██████ ███████ ██ ████ ██████ ██ +*/ + void function SetProficiency( entity npc ) { - // unsure what the logic for deciding this should be so just going to default good - npc.kv.WeaponProficiency = eWeaponProficiency.VERYGOOD + npc.kv.WeaponProficiency = level.nv.aiLethality } void function SPMP_UpdateNPCProficiency( entity npc ) { - + #if MP + UpdateNPCForAILethality( npc ) + #else + SetProficiency( npc ) + #endif } bool function IsAutoPopulateEnabled( var team = null ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_superspectre.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_superspectre.nut index 68e888f41..a63e3eb01 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_superspectre.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_superspectre.nut @@ -378,7 +378,15 @@ void function ReaperMinionLauncherThink( entity reaper ) if ( GetBugReproNum() != 221936 ) reaper.kv.squadname = "" - StationaryAIPosition launchPos = GetClosestAvailableStationaryPosition( reaper.GetOrigin(), 8000, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + reaper.EndSignal( "OnDeath" ) + StationaryAIPosition ornull launchPos = GetClosestAvailableStationaryPosition( reaper.GetOrigin(), 8000, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + while ( launchPos == null ) + { + // incase all stationary reaper positions are in use wait for one to become available + wait 5 + launchPos = GetClosestAvailableStationaryPosition( reaper.GetOrigin(), 8000, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + } + expect StationaryAIPosition( launchPos ) launchPos.inUse = true OnThreadEnd( @@ -387,8 +395,7 @@ void function ReaperMinionLauncherThink( entity reaper ) launchPos.inUse = false } ) - - reaper.EndSignal( "OnDeath" ) + reaper.AssaultSetFightRadius( 96 ) reaper.AssaultSetGoalRadius( reaper.GetMinGoalRadius() ) @@ -398,17 +405,17 @@ void function ReaperMinionLauncherThink( entity reaper ) if ( Distance( reaper.GetOrigin(), launchPos.origin ) > 96 ) { - printt( reaper," ASSAULT:", launchPos.origin, Distance( reaper.GetOrigin(), launchPos.origin ) ) - reaper.AssaultPoint( launchPos.origin ) + //printt( reaper," ASSAULT:", launchPos.origin, Distance( reaper.GetOrigin(), launchPos.origin ) ) + reaper.AssaultPointClamped( launchPos.origin ) table signalData = WaitSignal( reaper, "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) - printt( reaper," END ASSAULT:", launchPos.origin, signalData.signal ) + //printt( reaper," END ASSAULT:", launchPos.origin, signalData.signal ) if ( signalData.signal == "OnFailedToPath" ) continue } - printt( reaper," LAUNCH:", launchPos.origin ) + //printt( reaper," LAUNCH:", launchPos.origin ) waitthread Reaper_LaunchFragDrone_Think( reaper, "npc_frag_drone_fd" ) - printt( reaper," END LAUNCH:", launchPos.origin ) + //printt( reaper," END LAUNCH:", launchPos.origin ) while ( GetScriptManagedEntArrayLen( reaper.ai.activeMinionEntArrayID ) > 2 ) WaitFrame() } @@ -429,7 +436,7 @@ void function Reaper_LaunchFragDrone_Think( entity reaper, string fragDroneSetti if ( minionsToSpawn <= 0 ) return - array targetOrigins = GetFragDroneTargetOrigins( reaper, reaper.GetOrigin(), 200, 2000, 64, MAX_TICKS ) + array targetOrigins = GetFragDroneTargetOrigins( reaper, reaper.GetOrigin(), 64, 200, 6, MAX_TICKS ) if ( targetOrigins.len() < minionsToSpawn ) return @@ -447,7 +454,7 @@ void function Reaper_LaunchFragDrone_Think( entity reaper, string fragDroneSetti } ) - printt( reaper, " BEGIN LAUNCHING: ", minionsToSpawn, reaper.GetCurScheduleName() ) + //printt( reaper, " BEGIN LAUNCHING: ", minionsToSpawn, reaper.GetCurScheduleName() ) reaper.EndSignal( "OnDeath" ) @@ -464,7 +471,7 @@ void function Reaper_LaunchFragDrone_Think( entity reaper, string fragDroneSetti if ( minionsToSpawn <= 0 ) break - printt( reaper, " LAUNCHING: ", minionsToSpawn ) + //printt( reaper, " LAUNCHING: ", minionsToSpawn ) thread LaunchSpawnerProjectile( reaper, targetOrigin, activeMinions_EntArrayID, fragDroneSettings ) minionsToSpawn-- @@ -513,7 +520,7 @@ array function GetFragDroneTargetOrigins( entity npc, vector origin, flo if ( traceFrac < 1 ) return targetOrigins; - array< vector > randomSpots = NavMesh_RandomPositions_LargeArea( origin, HULL_HUMAN, randomCount, minRadius, maxRadius ) + array< vector > randomSpots = NavMesh_RandomPositions( origin, HULL_HUMAN, randomCount, minRadius, maxRadius ) int numFragDrones = 0 foreach( spot in randomSpots ) @@ -678,6 +685,7 @@ function SuperSpectre_WarpFall( entity ai ) local e = {} e.warpfx <- PlayFX( TURBO_WARP_FX, warpPos + < 0, 0, -104 >, mover.GetAngles() ) + e.warpfx.DisableHibernation() e.smokeFx <- null OnThreadEnd( @@ -706,6 +714,7 @@ function SuperSpectre_WarpFall( entity ai ) ai.Show() e.smokeFx = PlayFXOnEntity( TURBO_WARP_COMPANY, ai, "", <0.0, 0.0, 152.0> ) + e.smokeFx.DisableHibernation() local time = 0.2 mover.MoveTo( origin, time, 0, 0 ) @@ -717,12 +726,7 @@ function SuperSpectre_WarpFall( entity ai ) e.smokeFx.Destroy() PlayFX( $"droppod_impact", origin ) - Explosion_DamageDefSimple( - damagedef_reaper_fall, - origin, - ai, // attacker - ai, // inflictor - origin ) + Explosion_DamageDefSimple( damagedef_reaper_fall, origin, ai, ai, origin ) wait 0.1 } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut index 77399b601..842d82421 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut @@ -67,6 +67,7 @@ function BaseGametype_Init() RegisterSignal( "SimulateGameScore" ) RegisterSignal( "ObserverThread" ) RegisterSignal( "CE_FLAGS_CHANGED" ) + RegisterSignal( "player_exits_droppod" ) //Required for Drop Pod Animations from Titanfall 1, has no real use tho RegisterSignal( "Stop_OnStartTouch_EntityOutOfBounds" ) RegisterSignal( "Stop_OnEndTouch_EntityBackInBounds" ) @@ -749,15 +750,11 @@ bool function PlayerOrNPCKilled( entity ent, var damageInfo ) //Do callbacks. Main reason we call this here as opposed to CodeCallback_OnNPCKilled() is legacy script compatibility reasons. //For example: In script immediately above this we change the attacker to get the player behind the kill, e.g. owner of a pet titan, etc. Bunch of registered callbacks depends on this. foreach( callbackFunc in svGlobal.onNPCKilledCallbacks ) - { callbackFunc( ent, attacker, damageInfo ) - } } if ( ent.IsTitan() ) - { thread TitanVO_DelayedTitanDown( ent ) - } if ( !attacker.IsPlayer() ) { @@ -771,9 +768,7 @@ bool function PlayerOrNPCKilled( entity ent, var damageInfo ) // Hack - attacker history isn't on client to calculate if a player should get credit for a kill when AI steals the final killing shot while a player is damaging them. array playerArray = GetPlayerArray() foreach ( player in playerArray ) - { Remote_CallFunction_Replay( player, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), ent.GetEncodedEHandle(), attackerInfo.assistTime ) - } } // player attacker only from here down diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut index 3e1bcaa2b..312727c51 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -10,35 +10,33 @@ global function RespawnAsPilot global function RespawnAsTitan global function TryGameModeAnnouncement -global function SetKillcamsEnabled -global function KillcamsEnabled global function SetPlayerDeathsHidden global function TrackTitanDamageInPlayerGameStat +global function CheckGameStateForPlayerMovement global function ShouldEntTakeDamage_SPMP global function GetTitanBuildTime -global function TitanPlayerHotDropsIntoLevel global function SetGamemodeAllowsTeamSwitch global function SetRecalculateRespawnAsTitanStartPointCallback struct { - bool killcamsEnabled = true bool playerDeathsHidden = false int titanDamageGameStat = -1 - entity intermissionCamera - array specCams + array intermissionCameras entity functionref( entity player, entity basePoint ) recalculateRespawnAsTitanStartPointCallback table playerChangeTeamTimeBuffer bool gamemodeTeamSwitchEnabled = true + + table playerRespawnPlayerIntoTitan } file void function BaseGametype_Init_MPSP() { AddClientCommandCallback( "changeteam", ClientCommandCallbackChangeTeam ) - AddSpawnCallback( "info_intermission", SetIntermissionCamera ) + AddSpawnCallback( "info_intermission", AddIntermissionCamera ) AddPostDamageCallback( "player", AddToTitanDamageStat ) AddPostDamageCallback( "npc_titan", AddToTitanDamageStat ) @@ -46,15 +44,31 @@ void function BaseGametype_Init_MPSP() AddCallback_OnNPCKilled( CheckForAutoTitanDeath ) AddCallback_OnPlayerKilled( CheckForAutoTitanDeath ) AddCallback_OnPlayerAssist( PlayerAssistedKill ) + AddCallback_OnTitanBecomesPilot( CheckGameStateForTitanEjection ) + AddCallback_OnPlayerGetsNewPilotLoadout( CheckPlayerGetsNewLoadout ) + RegisterSignal( "PlayerRespawnStarted" ) RegisterSignal( "KillCamOver" ) - FlagInit( "WeaponDropsAllowed", true ) } -void function SetIntermissionCamera( entity camera ) +void function AddIntermissionCamera( entity camera ) +{ + file.intermissionCameras.append( camera ) +} + +entity function GetRandomIntermissionCamera() { - file.intermissionCamera = camera + if ( !file.intermissionCameras.len() ) + return null + + return file.intermissionCameras.getrandom() +} + +void function CheckServerIdlingState() +{ + if ( GetPlayerArray().len() <= 1 && Time() >= 60 * GetConVarInt( "ns_server_idle_time_refresh_max_time" ) ) + ServerCommand( "changelevel " + GetMapName() ) } @@ -136,23 +150,34 @@ void function CodeCallback_OnClientConnectionStarted( entity player ) Assert( !player._entityVars ) InitEntityVars( player ) - + // Added via AddCallback_OnClientConnecting foreach ( callbackFunc in svGlobal.onClientConnectingCallbacks ) - { callbackFunc( player ) + + if ( !IsLobby() && GetGameState() <= eGameState.Epilogue && GetConVarBool( "ns_autobalance_teams_on_player_join" ) ) + { + if ( GetCurrentPlaylistVarInt( "max_teams", 0 ) > 1 && !IsFFAGame() ) + { + if ( GetTeamPlayerCount( TEAM_MILITIA ) > GetTeamPlayerCount( TEAM_IMC ) ) + SetTeam( player, TEAM_IMC ) + else + SetTeam( player, TEAM_MILITIA ) + } } - + printl( "Player connect started: " + player + "---UID:" + player.GetUID() ) InitPassives( player ) + + CheckServerIdlingState() } // playerconnected void function CodeCallback_OnClientConnectionCompleted( entity player ) { InitPersistentData( player ) - + if ( IsLobby() ) { Lobby_OnClientConnectionCompleted( player ) @@ -195,10 +220,12 @@ void function CodeCallback_OnClientConnectionCompleted( entity player ) svGlobal.levelEnt.Signal( "PlayerDidSpawn", { player = player } ) + player.SetPersistentVar( "spawnAsTitan", false ) // Reset this to avoid players spawning directly as titans on join if ( GetConVarBool( "ns_allow_spectators" ) ) { if ( IsPrivateMatchSpectator( player ) ) { + SetPlayerEliminated( player ) InitialisePrivateMatchSpectatorPlayer( player ) return } @@ -207,21 +234,52 @@ void function CodeCallback_OnClientConnectionCompleted( entity player ) player.SetPersistentVar( "privateMatchState", 0 ) // handle spawning late joiners - if ( GetGameState() == eGameState.Playing ) + if ( GetGameState() >= eGameState.Playing ) { - if ( RespawnsEnabled() ) + if ( SpectatePlayerDuringPickLoadout() ) + thread SpectateTTSMenuPlayer( player ) + else if ( !IsEliminationBased() ) { - // likely temp, deffo needs some work - if ( Riff_SpawnAsTitan() == 1 ) // spawn as titan + if ( Riff_IsTitanAvailable( player ) || ShouldIntroSpawnAsTitan() || svGlobal.forceSpawnAsTitan ) //Handles the conditions to spawn player as Titan right away or not thread RespawnAsTitan( player ) - else // spawn as pilot + else RespawnAsPilot( player ) } else - thread PlayerBecomesSpectator( player ) + { + SetPlayerEliminated( player ) + InitialisePrivateMatchSpectatorPlayer( player ) + } } } +void function SpectateTTSMenuPlayer( entity player ) +{ + player.EndSignal( "OnDestroy" ) + OnThreadEnd( + function() : ( player ) + { + if ( IsValid( player ) ) + { + if ( !IsEliminationBased() ) + { + if ( ShouldIntroSpawnAsTitan() && Riff_TitanAvailability() != eTitanAvailability.Never || svGlobal.forceSpawnAsTitan ) + thread RespawnAsTitan( player ) + else + RespawnAsPilot( player ) + } + else + { + SetPlayerEliminated( player ) + InitialisePrivateMatchSpectatorPlayer( player ) + } + } + } + ) + + player.WaitSignal( "StopSendingTTSMenuCommand" ) +} + void function CodeCallback_OnClientDisconnected( entity player, string reason ) { if ( IsLobby() ) @@ -270,19 +328,36 @@ void function CodeCallback_OnPlayerRespawned( entity player ) player.s.respawnTime = Time() ClearRecentDamageHistory( player ) - player.Signal( "OnRespawned" ) // kill any postdeaththreads that could be running + if ( player.IsDissolving() ) + player.DissolveStop() + ClearPlayerAnimViewEntity( player ) + player.Signal( "OnRespawned" ) // kill any postdeaththreads that could be running Loadouts_TryGivePilotLoadout( player ) - //player.SetPredictionEnabled( true ) doesn't seem needed, as native code seems to set this foreach ( entity weapon in player.GetMainWeapons() ) weapon.SetProScreenOwner( player ) - + + bool spawnAsTitan = expect bool( player.GetPersistentVar( "spawnAsTitan" ) ) + if ( ( player in file.playerRespawnPlayerIntoTitan && file.playerRespawnPlayerIntoTitan[ player ] ) || ( ( spawnAsTitan || svGlobal.forceSpawnIntoTitan ) && PlayerCanSpawnIntoTitan( player ) ) ) + { + if ( player in file.playerRespawnPlayerIntoTitan && file.playerRespawnPlayerIntoTitan[ player ] ) + file.playerRespawnPlayerIntoTitan[ player ] = false + + entity titan = player.GetPetTitan() + + TeleportToEnt( player, titan ) + PilotBecomesTitan( player, titan ) + + titan.Destroy() + } + foreach ( void functionref( entity ) callback in svGlobal.onPlayerRespawnedCallbacks ) callback( player ) Remote_CallFunction_NonReplay( player, "ServerCallback_YouRespawned" ) ClearLastAttacker( player ) // so dying to anything doesn't credit the same attacker after respawning + ClearPlayerEliminated( player ) } @@ -328,7 +403,7 @@ void function PostDeathThread_MP( entity player, var damageInfo, bool gamePlayin return float timeOfDeath = Time() - player.p.postDeathThreadStartTime = Time() + player.p.postDeathThreadStartTime = timeOfDeath Assert( IsValid( player ), "Not a valid player" ) player.EndSignal( "OnDestroy" ) @@ -345,31 +420,22 @@ void function PostDeathThread_MP( entity player, var damageInfo, bool gamePlayin player.SetNoTarget( false ) player.SetNoTargetSmartAmmo( false ) player.ClearExtraWeaponMods() - + // disable prediction to prevent it messing with ragdoll in some places, as well as killreplay and such player.SetPredictionEnabled( false ) - + if ( player.IsTitan() ) SoulDies( player.GetTitanSoul(), damageInfo ) // cleanup some titan stuff, no idea where else to put this - - ClearRespawnAvailable( player ) - - // reset this so that we default to pilot spawn - player.SetPersistentVar( "spawnAsTitan", false ) + ClearRespawnAvailable( player ) + OnThreadEnd( function() : ( player ) { - if ( !IsValid( player ) ) - return - - player.s.inPostDeath = false + if ( IsValid( player ) ) + player.s.inPostDeath = false }) entity attacker = DamageInfo_GetAttacker( damageInfo ) - entity inflictor = DamageInfo_GetInflictor( damageInfo ) - int eHandle = attacker.GetEncodedEHandle() - if ( inflictor && ShouldTryUseProjectileReplay( player, attacker, damageInfo, false ) ) - eHandle = inflictor.GetEncodedEHandle() int methodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) player.p.rematchOrigin = player.p.deathOrigin @@ -381,14 +447,14 @@ void function PostDeathThread_MP( entity player, var damageInfo, bool gamePlayin player.Signal( "RodeoOver" ) player.ClearParent() - + // do some pre-replay stuff if we're gonna do a replay float replayLength = CalculateLengthOfKillReplay( player, methodOfDeath ) - bool shouldDoReplay = Replay_IsEnabled() && KillcamsEnabled() && IsValid( attacker ) && ShouldDoReplay( player, attacker, replayLength, methodOfDeath ) + bool shouldDoReplay = Replay_IsEnabled() && IsValid( attacker ) && ShouldDoReplay( player, attacker, replayLength, methodOfDeath ) table replayTracker = { validTime = null } if ( shouldDoReplay ) thread TrackDestroyTimeForReplay( attacker, replayTracker ) - + player.StartObserverMode( OBS_MODE_DEATHCAM ) if ( ShouldSetObserverTarget( attacker ) ) player.SetObserverTarget( attacker ) @@ -397,118 +463,129 @@ void function PostDeathThread_MP( entity player, var damageInfo, bool gamePlayin if ( gamePlayingOrSuddenDeath && !file.playerDeathsHidden ) player.AddToPlayerGameStat( PGS_DEATHS, 1 ) - + if ( !file.playerDeathsHidden ) Remote_CallFunction_NonReplay( player, "ServerCallback_YouDied", attacker.GetEncodedEHandle(), GetHealthFrac( attacker ), methodOfDeath ) float deathcamLength = GetDeathCamLength( player ) wait deathcamLength + + player.SetPlayerSettings( "spectator" ) // prevent a crash with going from titan => pilot on respawn + player.StopPhysics() // need to set this after SetPlayerSettings + player.SetPhysics( MOVETYPE_NONE ) // so they don't move around while dead, resets to default automatically on respawn // use info_intermission camera after deathcam, if it exists - if ( file.intermissionCamera != null ) + entity mapCamera = GetRandomIntermissionCamera() + if ( mapCamera != null && !player.GetParent() ) { - player.SetObserverModeStaticPosition( file.intermissionCamera.GetOrigin() ) - player.SetObserverModeStaticAngles( file.intermissionCamera.GetAngles() ) + player.SetObserverModeStaticPosition( mapCamera.GetOrigin() ) + player.SetObserverModeStaticAngles( mapCamera.GetAngles() ) player.StartObserverMode( OBS_MODE_STATIC_LOCKED ) player.SetObserverTarget( null ) } // hack: double check if killcams are enabled and valid here in case gamestate has changed this - shouldDoReplay = shouldDoReplay && Replay_IsEnabled() && KillcamsEnabled() && IsValid( attacker ) + shouldDoReplay = shouldDoReplay && Replay_IsEnabled() && IsValid( attacker ) && !IsRoundWinningKillReplayPlaying() // quick note: in cases where player.Die() is called: e.g. for round ends, player == attacker - if ( shouldDoReplay ) + if ( shouldDoReplay ) { - player.watchingKillreplayEndTime = Time() + replayLength + player.watchingKillreplayEndTime = Time() + replayLength float beforeTime = GetKillReplayBeforeTime( player, methodOfDeath ) - - replayTracker.validTime <- null - + + replayTracker.validTime <- null + float respawnTime = Time() - 2 // seems to get the killreplay to end around the actual kill if ( "respawnTime" in attacker.s ) respawnTime = Time() - expect float ( attacker.s.respawnTime ) - - thread PlayerWatchesKillReplayWrapper( player, attacker, eHandle, respawnTime, timeOfDeath, beforeTime, replayTracker ) - } - player.SetPlayerSettings( "spectator" ) // prevent a crash with going from titan => pilot on respawn - player.StopPhysics() // need to set this after SetPlayerSettings + thread PlayerWatchesKillReplayWrapper( player, attacker, respawnTime, timeOfDeath, beforeTime, replayTracker ) + } - if ( RespawnsEnabled() ) + if ( !IsEliminationBased() || IsEliminationBased() && !IsPlayerEliminated( player ) ) { // is it a good idea to do respawn code in postdeaththread? fuck if i know lol float respawnDelay = max( 0, GetCurrentPlaylistVarFloat( "respawn_delay", 0.0 ) - deathcamLength ) print( "respawn delay " + respawnDelay ) - + UpdateNextRespawnTime( player, Time() + respawnDelay ) SetRespawnAvailable( player ) - + wait respawnDelay int forceRespawn = GetCurrentPlaylistVarInt( "player_force_respawn", -1 ) // -1 is disabled, anything over is the time we wait in seconds // before respawning the player - if( forceRespawn >= 0 ) + if ( forceRespawn >= 0 ) thread ForceRespawnMeSignalAfterDelay( player, forceRespawn ) - - player.WaitSignal( "RespawnMe" ) // set in base_gametype: ClientCommand_RespawnPlayer + + if ( !player.s.respawnSelectionDone && GetGameState() != eGameState.SuddenDeath ) // Only wait outside Sudden Death since players gets inputs blocked to respawn if they die before Sudden Death starts + player.WaitSignal( "RespawnMe" ) ClearRespawnAvailable( player ) // need so the respawn icon doesn't show for like a frame on next death - - if ( ( expect bool( player.GetPersistentVar( "spawnAsTitan" ) ) && IsTitanAvailable( player ) ) || ( Riff_SpawnAsTitan() > 0 && Riff_ShouldSpawnAsTitan( player ) ) ) // spawn as titan + + TitanLoadoutDef loadout = GetTitanLoadoutForPlayer( player ) + bool spawnAsTitan = expect bool( player.GetPersistentVar( "spawnAsTitan" ) ) + + if ( IsPrivateMatchSpectator( player ) ) // Spectators can still die from kill triggers + InitialisePrivateMatchSpectatorPlayer( player ) + else if ( spawnAsTitan && IsReplacementTitanAvailable( player ) || Riff_SpawnAsTitan() == eSpawnAsTitan.Always || svGlobal.forceSpawnAsTitan ) thread RespawnAsTitan( player ) - else // spawn as pilot + else RespawnAsPilot( player ) } else if ( gamePlayingOrSuddenDeath || GetGameState() == eGameState.Epilogue ) { if ( shouldDoReplay && player.IsWatchingKillReplay() ) player.WaitSignal( "KillCamOver" ) - - thread PlayerBecomesSpectator( player ) + + InitialisePrivateMatchSpectatorPlayer( player ) } } // idk if this is a good delay or if it matches vanilla void function ForceRespawnMeSignalAfterDelay( entity player, int delay = 5 ) { + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) player.EndSignal( "RespawnMe" ) player.EndSignal( "OnDestroy" ) - if( player.IsWatchingKillReplay() ) + if ( player.IsWatchingKillReplay() ) player.WaitSignal( "KillCamOver" ) wait delay - printt( format( "Forcing player respawn for player %s (took >%d seconds to respawn)", player.GetPlayerName(), delay ) ) - player.Signal( "RespawnMe" ) + if ( IsRespawnAvailable( player ) ) + { + #if DEV + printt( format( "Forcing player respawn for player %s (took >%d seconds to respawn)", player.GetPlayerName(), delay ) ) + #endif + player.Signal( "RespawnMe" ) + } } -void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, int eHandle, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker ) +void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker ) { player.EndSignal( "RespawnMe" ) player.EndSignal( "OnRespawned" ) - + player.EndSignal( "OnDestroy" ) attacker.EndSignal( "OnDestroy" ) - + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) - + OnThreadEnd( function() : ( player ) - { - // don't clear if we're in a roundwinningkillreplay - if ( IsValid( player ) && !( ( GetGameState() == eGameState.SwitchingSides || GetGameState() == eGameState.WinnerDetermined ) && IsRoundWinningKillReplayEnabled() ) ) + { + if ( IsValid( player ) ) { player.Signal( "KillCamOver" ) player.ClearReplayDelay() player.ClearViewEntity() - //player.SetPredictionEnabled( true ) doesn't seem needed, as native code seems to set this on respawn } }) - - player.SetPredictionEnabled( false ) - PlayerWatchesKillReplay( player, eHandle, attacker.GetIndexForEntity(), timeSinceAttackerSpawned, timeOfDeath, beforeTime, replayTracker ) + + PlayerWatchesKillReplay( player, attacker.GetEncodedEHandle(), attacker.GetIndexForEntity(), timeSinceAttackerSpawned, timeOfDeath, beforeTime, replayTracker ) } @@ -530,104 +607,112 @@ void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, in void function DecideRespawnPlayer( entity player ) { - // this isn't even used atm, could likely be removed if some vanilla code didn't rely on it + // Unused, TF1 legacy code } void function RespawnAsPilot( entity player ) { - // respawn crash exploit hotfix - if(IsAlive( player )) return + if ( !PlayerCanSpawn( player ) ) + return + + entity spawnpoint = FindSpawnPoint( player, false, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) ) + DoRespawnPlayer( player, spawnpoint ) + + player.isSpawning = false + player.isSpawningHotDroppingAsTitan = false - player.RespawnPlayer( FindSpawnPoint( player, false, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) && !IsFFAGame() ) ) + // Dying as Titan and respawning as Pilot keeps the Titan Icon over the player's name instead of reverting to the normal patch such player uses + CallsignIcon callsignIcon = PlayerCallsignIcon_GetActive( player ) + player.SetTargetInfoIcon( callsignIcon.smallImage ) } -void function RespawnAsTitan( entity player, bool manualPosition = false ) +void function RespawnAsTitan( entity player ) { - // respawn crash exploit hotfix - if(IsAlive( player )) return - + if ( !PlayerCanSpawn( player ) ) + return + player.Signal( "PlayerRespawnStarted" ) player.isSpawning = true - entity spawnpoint = FindSpawnPoint( player, true, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) && !IsFFAGame() ) + player.isSpawningHotDroppingAsTitan = true + entity spawnpoint = FindSpawnPoint( player, true, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) ) if ( file.recalculateRespawnAsTitanStartPointCallback != null ) spawnpoint = file.recalculateRespawnAsTitanStartPointCallback( player, spawnpoint ) + ToggleSpawnNodeInUse( spawnpoint, true ) TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player ) asset model = GetPlayerSettingsAssetForClassName( titanLoadout.setFile, "bodymodel" ) Attachment warpAttach = GetAttachmentAtTimeFromModel( model, "at_hotdrop_01", "offset", spawnpoint.GetOrigin(), spawnpoint.GetAngles(), 0 ) - PlayFX( TURBO_WARP_FX, warpAttach.position, warpAttach.angle ) - + entity warpFX = PlayFX( TURBO_WARP_FX, warpAttach.position, warpAttach.angle ) + warpFX.FXEnableRenderAlways() + warpFX.DisableHibernation() + entity titan = CreateAutoTitanForPlayer_FromTitanLoadout( player, titanLoadout, spawnpoint.GetOrigin(), spawnpoint.GetAngles() ) DispatchSpawn( titan ) - player.SetPetTitan( null ) // prevent embark prompt from showing up + titan.ContextAction_SetBusy() // This is prevent a race condition with the ability of players being able to spawn into their Titans + HideName( titan ) + titan.SetValidHealthBarTarget( false ) // Hide HP bar overhead + titan.UnsetUsable() // Prevent embark prompt from showing up + ClearTitanAvailable( player ) // Clear titan availability, so faction leader won't advise "Titan Ready" during spawn AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) // hide hud - // do titanfall scoreevent - if ( !level.firstTitanfall ) - { - AddPlayerScore( player, "FirstTitanfall", player ) - - #if HAS_STATS - UpdatePlayerStat( player, "misc_stats", "titanFallsFirst" ) - #endif + player.EndSignal( "OnDeath" ) // In case of cinematic titanfall and Round End code is killing everything in cleanup function + player.EndSignal( "OnDestroy" ) - level.firstTitanfall = true - } - else - { - AddPlayerScore( player, "Titanfall", player ) - } - entity camera = CreateTitanDropCamera( spawnpoint.GetAngles(), < 90, titan.GetAngles().y, 0 > ) camera.SetParent( titan ) - // calc offset for spawnpoint angle - // todo this seems bad but too lazy to figure it out rn - //vector xyOffset = RotateAroundOrigin2D( < 44, 0, 0 >, < 0, 0, 0>, spawnpoint.GetAngles().y ) - //xyOffset.z = 520 // < 44, 0, 520 > at 0,0,0, seems to be the offset used in tf2 - //print( xyOffset ) - vector xyOffset = RotateAroundOrigin2D( < 44, 0, 520 >, < 0, 0, 0 >, spawnpoint.GetAngles().y ) camera.SetLocalOrigin( xyOffset ) camera.SetLocalAngles( < camera.GetAngles().x, spawnpoint.GetAngles().y, camera.GetAngles().z > ) // this straight up just does not work lol - camera.Fire( "Enable", "!activator", 0, player ) + player.SetViewEntity( camera, true ) - player.EndSignal( "OnDestroy" ) + titan.EndSignal( "OnDeath" ) titan.EndSignal( "OnDestroy" ) - OnThreadEnd( function() : ( player, titan, camera ) + TeleportToEnt( titan, spawnpoint ) + + OnThreadEnd( function() : ( player, titan, camera, spawnpoint ) { if ( IsValid( player ) ) { RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) // show hud player.isSpawning = false + player.isSpawningHotDroppingAsTitan = false + + GiveTitanfallScoreMedal( player ) // In case of classic Warpfall animation, give the Titanfall Score Medal at this moment, so player can actually see it + + PutEntityInSafeSpot( player, null, null, spawnpoint.GetOrigin(), player.GetOrigin() ) // Just to Ensure player is not clipping in any geometry } - + if ( IsValid( titan ) ) - titan.Destroy() // pilotbecomestitan leaves an npc titan that we need to delete - else + titan.Destroy() + else if ( !IsAlive( player ) ) RespawnAsPilot( player ) // this is 100% an edgecase, just avoid softlocking if we ever hit it in playable gamestates + + if ( IsValid( camera ) ) + camera.Destroy() - camera.Fire( "Disable", "!activator", 0, player ) - camera.Destroy() + if ( IsValid( spawnpoint ) ) + ToggleSpawnNodeInUse( spawnpoint, false ) }) - + waitthread TitanHotDrop( titan, "at_hotdrop_01", spawnpoint.GetOrigin(), spawnpoint.GetAngles(), player, camera ) // do hotdrop anim - - player.RespawnPlayer( null ) // spawn player as pilot so they get their pilot loadout on embark - player.SetOrigin( titan.GetOrigin() ) - ClearTitanAvailable( player ) // titanfall succeed, clear titan availability - - // don't make player titan when entity batteryContainer is not valid. - // This will prevent a servercrash that sometimes occur when evac is disabled and somebody is calling a titan in the defeat screen. - if( IsValid( titan.GetTitanSoul().soul.batteryContainer ) ) - PilotBecomesTitan( player, titan ) // make player titan - else - print( "batteryContainer is not a valid entity in RespawnAsTitan(). Skipping PilotBecomesTitan()." ) + + file.playerRespawnPlayerIntoTitan[ player ] <- true + + DoRespawnPlayer( player, spawnpoint ) +} + +void function OnReplacementTitanSecondStage( entity player ) +{ + vector origin = expect vector( GetOptionalAnimEventVar( player, "second_stage" ) ) + EmitSoundOnEntityOnlyToPlayer( player, player, "titan_drop_pod_turbo_landing" ) + EmitSoundOnEntityOnlyToPlayer( player, player, "titan_drop_pod_turbo_landing" ) // Double sound just to volume it up because it's also quiet in 1st Person + EmitSoundAtPositionExceptToPlayer( player.GetTeam(), origin, player, "titan_drop_pod_turbo_landing_3P" ) } @@ -647,22 +732,12 @@ void function RespawnAsTitan( entity player, bool manualPosition = false ) ██████ ██ ██ ███████ ██ ██ ██ */ -void function TryGameModeAnnouncement( entity player ) // only putting this here because it's here in gametype_sp lol +void function TryGameModeAnnouncement( entity player ) { Remote_CallFunction_NonReplay( player, "ServerCallback_GameModeAnnouncement" ) PlayFactionDialogueToPlayer( GameMode_GetGameModeAnnouncement( GAMETYPE ), player ) } -void function SetKillcamsEnabled( bool enabled ) -{ - file.killcamsEnabled = enabled -} - -bool function KillcamsEnabled() -{ - return file.killcamsEnabled -} - void function SetPlayerDeathsHidden( bool hidden ) { file.playerDeathsHidden = hidden @@ -682,26 +757,29 @@ void function AddToTitanDamageStat( entity victim, var damageInfo ) float amount = DamageInfo_GetDamage( damageInfo ) if ( attacker.IsPlayer() && attacker != victim ) - attacker.AddToPlayerGameStat( file.titanDamageGameStat, amount ) // titan damage on + attacker.AddToPlayerGameStat( file.titanDamageGameStat, amount ) } void function CheckForAutoTitanDeath( entity victim, entity attacker, var damageInfo ) { - if( !IsValid(victim) || !victim.IsTitan() ) + if ( !IsValid( victim ) || !victim.IsTitan() || victim == attacker ) return - if( !victim.IsPlayer() ) - { - if (GetPetTitanOwner(victim) && GetPetTitanOwner(victim) != attacker) - foreach(player in GetPlayerArray()) - Remote_CallFunction_NonReplay( player, "ServerCallback_OnTitanKilled", attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), DamageInfo_GetCustomDamageType( damageInfo ), DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) - } - else + if ( GetPetTitanOwner( victim ) == attacker ) + return + + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + if ( IsValid( inflictor ) ) { - if (victim != attacker) - foreach(player in GetPlayerArray()) - Remote_CallFunction_NonReplay( player, "ServerCallback_OnTitanKilled", attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), DamageInfo_GetCustomDamageType( damageInfo ), DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) + if ( inflictor.IsProjectile() && IsValid( inflictor.GetOwner() ) && inflictor.GetOwner().IsTitan() ) + attacker = inflictor.GetOwner() + + else if ( IsNPCTitan( inflictor ) ) + attacker = inflictor } + + foreach ( player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_OnTitanKilled", attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), DamageInfo_GetCustomDamageType( damageInfo ), DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) } void function SetRecalculateRespawnAsTitanStartPointCallback( entity functionref( entity player, entity basePoint ) callbackFunc ) @@ -709,6 +787,48 @@ void function SetRecalculateRespawnAsTitanStartPointCallback( entity functionref file.recalculateRespawnAsTitanStartPointCallback = callbackFunc } +void function CheckGameStateForPlayerMovement( entity player ) +{ + if ( !IsAlive( player ) ) + return + + if ( GetGameState() == eGameState.WinnerDetermined || GetGameState() == eGameState.SwitchingSides || GetGameState() == eGameState.Postmatch ) + { + if ( level.endOfRoundPlayerState == ENDROUND_FREEZE ) + player.FreezeControlsOnServer() + else if ( level.endOfRoundPlayerState == ENDROUND_MOVEONLY ) + { + player.DisableWeapon() + player.Server_TurnOffhandWeaponsDisabledOn() + } + } +} + +void function CheckGameStateAfterSpawn_Threaded( entity player, float waitTime = 0.1 ) +{ + player.EndSignal( "OnDestroy" ) + wait waitTime + CheckGameStateForPlayerMovement( player ) +} + +void function CheckGameStateForTitanEjection( entity pilot, entity titan ) +{ + thread CheckGameStateAfterSpawn_Threaded( pilot, 0.5 ) +} + +void function CheckPlayerGetsNewLoadout( entity player, PilotLoadoutDef loadout ) +{ + thread CheckGameStateAfterSpawn_Threaded( player ) + + foreach ( entity weapon in player.GetMainWeapons() ) + { + if ( weapon.GetWeaponClassName() == "mp_weapon_rocket_launcher" && !weapon.HasMod( "fast_lock" ) && GetCurrentPlaylistVarInt( "archer_fast_lock", 0 ) == 1 ) + weapon.AddMod( "fast_lock" ) + if ( weapon.GetWeaponClassName() == "mp_weapon_epg" && !weapon.HasMod( "jump_kit" ) && GetCurrentPlaylistVarInt( "epg_splash_push", 0 ) == 1 ) + weapon.AddMod( "jump_kit" ) + } +} + void function SetGamemodeAllowsTeamSwitch( bool enabled ) { file.gamemodeTeamSwitchEnabled = enabled @@ -718,7 +838,7 @@ bool function ClientCommandCallbackChangeTeam( entity player, array args { if ( !GetConVarBool( "ns_allow_team_change" ) || IsPrivateMatchSpectator( player ) ) return true - + if ( !file.gamemodeTeamSwitchEnabled ) { SendHudMessage( player, "#TEAMSWITCH_GAMEMODE", -1, 0.4, 255, 255, 255, 255, 0.15, 3.0, 0.5 ) @@ -746,6 +866,7 @@ bool function ClientCommandCallbackChangeTeam( entity player, array args SendHudMessage( player, "#TEAMSWITCH_GAMEPLAY", -1, 0.4, 255, 255, 255, 255, 0.15, 3.0, 0.5 ) return true } + if ( GetCurrentPlaylistVarInt( "max_teams", 0 ) > 1 && !IsFFAGame() ) SetTeam( player, GetOtherTeam( player.GetTeam() ) ) else @@ -754,23 +875,18 @@ bool function ClientCommandCallbackChangeTeam( entity player, array args return true } -// stuff to change later - bool function ShouldEntTakeDamage_SPMP( entity ent, var damageInfo ) { - // dropships are immune to being crushed if ( ( IsDropship( ent ) || IsEvacDropship( ent ) ) && IsTitanCrushDamage( damageInfo ) ) return false - + return true } -float function GetTitanBuildTime(entity player) +float function GetTitanBuildTime( entity player ) { - return 100.0 -} - -void function TitanPlayerHotDropsIntoLevel( entity player ) -{ - -} + if ( player.titansBuilt == 0 ) + return GetCurrentPlaylistVarFloat( "titan_build_time", 180 ) + + return GetCurrentPlaylistVarFloat( "titan_rebuild_time", 180 ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut index ea88c1bce..2bc42ef97 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut @@ -156,8 +156,9 @@ void function ApplyBatteryToBatteryPort( entity player, entity batteryPort ) var useBatteryPort = batteryPort.s.useBattery useBatteryPort( batteryPort, player ) - // all things done, destroy this batt - battery.Destroy() + // all things done, destroy this batt if counter is on 0 + if( player.GetPlayerNetInt( "batteryCount" ) == 0 ) + battery.Destroy() } // for disabling cloak diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_bleedout.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_bleedout.gnut index cb7580681..a03b1da6d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_bleedout.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_bleedout.gnut @@ -176,8 +176,6 @@ void function EnablePlayerRes( entity player ) player.EndSignal( "BleedOut_OnStartDying" ) player.EndSignal( "BleedOut_OnRevive" ) - Highlight_SetFriendlyHighlight( player, "interact_object_los_line" ) - if ( IsPilotEliminationBased() ) SetPlayerEliminated( player ) @@ -185,10 +183,7 @@ void function EnablePlayerRes( entity player ) function() : ( player ) { if ( IsValid( player ) ) - { player.UnsetUsable() - Highlight_ClearFriendlyHighlight( player ) - } } ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index 016097f20..2278559e4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -105,11 +105,11 @@ void function RegisterChallenges_OnMatchEnd() if( RandomIntRange( 0, 100 ) <= 30 ) //30% Chance to trigger akin to vanilla, apply always since all players have paid cosmetics unlocked eliteWarpaintRNG = true + SetUIVar( level, "showGameSummary", true ) foreach( player in GetPlayerArray() ) { player.SetPersistentVar( "isPostGameScoreboardValid", true ) player.SetPersistentVar( "isFDPostGameScoreboardValid", false ) //FD itself overrides this right after when match ends - SetUIVar( level, "showGameSummary", true ) if( eliteWarpaintRNG ) SetPlayerChallengeSquadLeader( player ) @@ -161,8 +161,10 @@ void function FFAChallenges_OnPlayerKilled( entity victim, entity attacker, var bool function HasPlayerCompletedMeritScore( entity player ) { - Assert( player in file.playerChallenge, player + " is not registered in the challenge pool hooks." ) - return file.playerChallenge[ player ] + if ( player in file.playerChallenge ) + return file.playerChallenge[ player ] + + return false } @@ -187,10 +189,17 @@ void function SetPlayerChallengeEvacState( entity player, int successEvac = 0 ) else if( successEvac == 1 ) //Player itself managed to evac { - file.playerTotalMeritCount[ player ]++ + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 1 ) player.SetPersistentVar( "xp_match[" + XP_TYPE.EVAC + "]", 1 ) - Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", meritCount ) } else if( successEvac == 2 ) //Team managed to evac @@ -201,11 +210,18 @@ void function SetPlayerChallengeMatchWon( entity player, bool playerWon ) { if( playerWon ) { - file.playerTotalMeritCount[ player ]++ + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 1 ) player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_VICTORY + "]", 1 ) player.SetPersistentVar( "matchWin", true ) - Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", meritCount ) } else Remote_CallFunction_UI( player, "SCB_SetWinMeritState", -1 ) @@ -213,11 +229,18 @@ void function SetPlayerChallengeMatchWon( entity player, bool playerWon ) void function SetPlayerChallengeMatchComplete( entity player ) { - file.playerTotalMeritCount[ player ]++ + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 1 ) player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_COMPLETED + "]", 1 ) player.SetPersistentVar( "matchComplete", true ) - Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", meritCount ) } void function SetPlayerChallengeSquadLeader( entity player ) @@ -242,8 +265,17 @@ void function SetPlayerChallengeMeritScore( entity player ) { if( !HasPlayerCompletedMeritScore( player ) ) { - file.playerChallenge[ player ] = true - file.playerTotalMeritCount[ player ]++ + if ( player in file.playerChallenge ) + file.playerChallenge[ player ] = true + + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 1 ) player.SetPersistentVar( "xp_match[" + XP_TYPE.SCORE_MILESTONE + "]", 1 ) player.SetPersistentVar( "matchScoreEvent", true ) @@ -254,23 +286,44 @@ void function SetPlayerChallengeMeritScore( entity player ) void function IncrementPlayerChallengeTitanLeveledUp( entity player ) { player.p.meritData.titanMerits++ - file.playerTotalMeritCount[ player ]++ + + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", player.p.meritData.titanMerits++ ) - Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", meritCount ) } void function IncrementPlayerChallengeWeaponLeveledUp( entity player ) { player.p.meritData.weaponMerits++ - file.playerTotalMeritCount[ player ]++ + + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", player.p.meritData.weaponMerits ) - Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", meritCount ) } void function IncrementPlayerChallengeFactionLeveledUp( entity player ) { - file.playerTotalMeritCount[ player ]++ - Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + int meritCount = 0 + + if ( player in file.playerTotalMeritCount ) + { + file.playerTotalMeritCount[ player ]++ + meritCount = file.playerTotalMeritCount[ player ] + } + + Remote_CallFunction_UI( player, "SCB_SetMeritCount", meritCount ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut index 0ababfc71..aa998decc 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut @@ -60,12 +60,15 @@ void function PopulatePostgameData() { // show the postgame scoreboard summary SetUIVar( level, "showGameSummary", true ) - + + int playerPerTeam = GetCurrentPlaylistVarInt( "max_players", 16 ) + bool teamBased = !IsFFAGame() + bool isListenServer = !NSIsDedicated() + array scoreTypes = GameMode_GetScoreboardColumnScoreTypes( GAMETYPE ) + int persistenceArrayCount = PersistenceGetArrayCount( "postGameData.players" ) + foreach ( entity player in GetPlayerArray() ) { - int teams = GetCurrentPlaylistVarInt( "max_teams", 2 ) - bool standardTeams = teams != 2 - int enumModeIndex = 0 int enumMapIndex = 0 @@ -80,15 +83,15 @@ void function PopulatePostgameData() player.SetPersistentVar( "postGameData.myXuid", player.GetUID() ) player.SetPersistentVar( "postGameData.gameMode", enumModeIndex ) player.SetPersistentVar( "postGameData.map", enumMapIndex ) - player.SetPersistentVar( "postGameData.teams", standardTeams ) - player.SetPersistentVar( "postGameData.maxTeamSize", teams ) - player.SetPersistentVar( "postGameData.privateMatch", true ) + player.SetPersistentVar( "postGameData.teams", teamBased ) + player.SetPersistentVar( "postGameData.maxTeamSize", playerPerTeam ) + player.SetPersistentVar( "postGameData.privateMatch", isListenServer ) player.SetPersistentVar( "postGameData.ranked", true ) player.SetPersistentVar( "postGameData.hadMatchLossProtection", false ) player.SetPersistentVar( "isFDPostGameScoreboardValid", GAMETYPE == FD ) - if ( standardTeams ) + if ( teamBased && MAX_TEAMS > 1 ) { if ( player.GetTeam() == TEAM_MILITIA ) { @@ -108,16 +111,33 @@ void function PopulatePostgameData() { player.SetPersistentVar( "postGameData.factionMCOR", GetFactionChoice( player ) ) player.SetPersistentVar( "postGameData.scoreMCOR", GameRules_GetTeamScore( player.GetTeam() ) ) + player.SetPersistentVar( "postGameData.factionIMC", GetEnemyFaction( player ) ) + player.SetPersistentVar( "postGameData.scoreIMC", 0 ) + } + + //Clear scoreboard first in case current match finished with less players than previous + //The reason for this is that the post-scoreboard would mix playersets from both matches resulting in a confusing scoreboard + for( int i = 0; i < persistenceArrayCount; i++ ) + { + player.SetPersistentVar( "postGameData.players[" + i + "].team", TEAM_UNASSIGNED ) + player.SetPersistentVar( "postGameData.players[" + i + "].name", "" ) + player.SetPersistentVar( "postGameData.players[" + i + "].xuid", "" ) + player.SetPersistentVar( "postGameData.players[" + i + "].level", -1 ) + player.SetPersistentVar( "postGameData.players[" + i + "].gen", -1 ) + player.SetPersistentVar( "postGameData.players[" + i + "].callsignIconIndex", -1 ) + + for ( int j = 0; j < scoreTypes.len(); j++ ) + player.SetPersistentVar( "postGameData.players[" + i + "].scores[" + j + "]", -1 ) } array otherPlayers = GetPlayerArray() - array scoreTypes = GameMode_GetScoreboardColumnScoreTypes( GAMETYPE ) - int persistenceArrayCount = PersistenceGetArrayCount( "postGameData.players" ) for ( int i = 0; i < min( otherPlayers.len(), persistenceArrayCount ); i++ ) { player.SetPersistentVar( "postGameData.players[" + i + "].team", otherPlayers[ i ].GetTeam() ) player.SetPersistentVar( "postGameData.players[" + i + "].name", otherPlayers[ i ].GetPlayerName() ) player.SetPersistentVar( "postGameData.players[" + i + "].xuid", otherPlayers[ i ].GetUID() ) + player.SetPersistentVar( "postGameData.players[" + i + "].level", otherPlayers[ i ].GetLevel() ) + player.SetPersistentVar( "postGameData.players[" + i + "].gen", otherPlayers[ i ].GetGen() ) player.SetPersistentVar( "postGameData.players[" + i + "].callsignIconIndex", otherPlayers[ i ].GetPersistentVarAsInt( "activeCallsignIconIndex" ) ) for ( int j = 0; j < scoreTypes.len(); j++ ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut index 33bc8155f..dc438c8c9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut @@ -41,7 +41,7 @@ struct { void function ClassicMp_Init() { // default level intros - if ( IsFFAGame() ) + if ( IsFFAGame() || !GetClassicMPMode() ) ClassicMP_SetLevelIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) else ClassicMP_SetLevelIntro( ClassicMP_DefaultDropshipIntro_Setup, DROPSHIP_INTRO_LENGTH ) @@ -99,7 +99,7 @@ void function ClassicMP_OnIntroFinished() SetGameState( eGameState.Playing ) } -float function ClassicMP_GetIntroLength() +float function ClassicMP_GetIntroLength() { if ( file.customIntroSetupFunc != null ) return file.customIntroLength @@ -127,7 +127,7 @@ void function ClassicMP_SetupEpilogue() bool function GetClassicMPMode() { - return GetCurrentPlaylistVarInt( "classic_mp", 1 ) == 1 + return GetCurrentPlaylistVarInt( "run_intro", 1 ) == 1 } bool function ClassicMP_ShouldRunEpilogue() 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 d6ce9acd7..64f91b63f 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 @@ -29,8 +29,6 @@ global const float DROPSHIP_INTRO_LENGTH = 15.0 // TODO tweak this struct { table< entity, array > militiaDropships table< entity, array > imcDropships - - float introStartTime } file @@ -53,16 +51,15 @@ void function DropshipIntro_OnClientConnected( entity player ) void function OnPrematchStart() { - thread OnPrematchStart_Threaded() + thread OnPrematchStart_Thread() } -void function OnPrematchStart_Threaded() +void function OnPrematchStart_Thread() { FlagWait( "EntitiesDidLoad" ) ClassicMP_OnIntroStarted() - print( "starting dropship intro!" ) - file.introStartTime = Time() + print( "Starting Dropship Intro!" ) // Clear Dropship arrays of Teams for Match Restarts (i.e Half-Times) file.militiaDropships.clear() @@ -84,7 +81,9 @@ void function OnPrematchStart_Threaded() if ( validDropshipSpawns.len() < 2 ) validDropshipSpawns = dropshipSpawns - // spawn dropships + validDropshipSpawns.reverse() // Flip cuz idk why Dropships are in mirrored order in comparison to vanilla + + // Spawn the Dropships foreach ( entity dropshipSpawn in validDropshipSpawns ) { int createTeam = HasSwitchedSides() ? GetOtherTeam( dropshipSpawn.GetTeam() ) : dropshipSpawn.GetTeam() @@ -97,32 +96,38 @@ void function OnPrematchStart_Threaded() AddAnimEvent( dropship, "dropship_warpout", WarpoutEffect ) dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) - if ( dropshipSpawn.GetTeam() == TEAM_IMC ) + if ( createTeam == TEAM_IMC ) dropship.SetValueForModelKey( $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" ) DispatchSpawn( dropship ) + dropship.ai.spawnTime = Time() + dropship.s.deployedPilots <- false + dropship.s.deployedTime <- 0.0 dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) - if ( dropshipSpawn.GetTeam() == TEAM_IMC ) + if ( createTeam == TEAM_IMC ) dropship.SetModel( $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" ) + dropship.SetInvulnerable() + + NPC_NoTarget( dropship ) + teamDropships[ dropship ] <- [ null, null, null, null ] - thread PlayAnim( dropship, "dropship_classic_mp_flyin" ) - - if ( file.imcDropships.len() >= 2 && file.militiaDropships.len() >= 2 ) - break + thread PlayAnim( dropship, GetDropshipIntroAnimation() ) + thread WaitForDropshipDeploy( dropship ) } // Populate Dropships foreach ( entity player in GetPlayerArray() ) { - if ( !IsPrivateMatchSpectator( player ) ) + if( !IsPrivateMatchSpectator( player ) ) { if( PlayerCanSpawn( player ) ) DoRespawnPlayer( player, null ) PutPlayerInDropship( player ) + ResetPlayerCooldowns( player ) // Prevention of case they used abilities or grenades near round end } else RespawnPrivateMatchSpectator( player ) @@ -133,18 +138,30 @@ void function OnPrematchStart_Threaded() void function EndIntroWhenFinished() { - wait DROPSHIP_INTRO_LENGTH + while ( Time() < expect float( level.nv.gameStartTime ) ) + WaitFrame() + ClassicMP_OnIntroFinished() } +void function WaitForDropshipDeploy( entity dropship ) +{ + dropship.EndSignal( "OnDestroy" ) + dropship.EndSignal( "OnDeath" ) + + dropship.WaitSignal( "deploy" ) + + dropship.s.deployedPilots = true + dropship.s.deployedTime = Time() +} + void function PutPlayerInDropship( entity player ) { //Find the player's dropship and seat - table< entity, array > teamDropships + table< entity, array< entity > > teamDropships + teamDropships = file.imcDropships if ( player.GetTeam() == TEAM_MILITIA ) teamDropships = file.militiaDropships - else - teamDropships = file.imcDropships entity playerDropship array< int > availableShipSlots @@ -180,53 +197,40 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e player.EndSignal( "OnDestroy" ) player.EndSignal( "OnDeath" ) - OnThreadEnd( function() : ( player, playerDropshipIndex, playerDropship ) - { - if ( IsValid( player ) ) - { - player.ClearParent() - ClearPlayerAnimViewEntity( player ) - } - if( IsAlive( playerDropship ) ) - { - if ( playerDropship.GetTeam() == TEAM_MILITIA ) - file.militiaDropships[ playerDropship ][ playerDropshipIndex ] = null - else - file.imcDropships[ playerDropship ][ playerDropshipIndex ] = null - } - }) - HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() - UnMuteAll( player ) - StopSoundOnEntity( player, "Duck_For_FrontierDefenseTitanSelectScreen" ) - - // hide hud and fade screen out from black + player.MovementDisable() AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) - ScreenFadeFromBlack( player, 0.5, 0.5 ) - // faction leaders are done clientside, spawn them here - Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.GetEncodedEHandle(), file.introStartTime ) - - // 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 - waitthread FirstPersonSequence( idleSequence, player, playerDropship ) - // 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 + thread DelayedFrameFadeout( player ) + + if( GameRules_GetGameMode() == FD ) + { + if( player.GetTeam() == TEAM_MILITIA ) //IMC Side will have empty Intro Dropship for FD in specific + Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.GetEncodedEHandle(), playerDropship.ai.spawnTime ) + } + else + Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.GetEncodedEHandle(), playerDropship.ai.spawnTime ) + + Remote_CallFunction_NonReplay( player, "ServerCallback_CreateDropShipIntLighting", playerDropship.GetEncodedEHandle(), playerDropship.GetTeam() ) + + if( !playerDropship.s.deployedPilots ) + { + FirstPersonSequenceStruct idleSequence + idleSequence.firstPersonAnim = DROPSHIP_IDLE_ANIMS_POV[ playerDropshipIndex ] + idleSequence.thirdPersonAnim = DROPSHIP_IDLE_ANIMS[ playerDropshipIndex ] + idleSequence.attachment = "ORIGIN" + idleSequence.teleport = true + idleSequence.viewConeFunction = ViewConeRampFree + thread FirstPersonSequence( idleSequence, player, playerDropship ) + playerDropship.WaitSignal( "deploy" ) + } + FirstPersonSequenceStruct jumpSequence jumpSequence.firstPersonAnim = DROPSHIP_JUMP_ANIMS_POV[ playerDropshipIndex ] jumpSequence.thirdPersonAnim = DROPSHIP_JUMP_ANIMS[ playerDropshipIndex ] jumpSequence.attachment = "ORIGIN" jumpSequence.viewConeFunction = ViewConeFree - jumpSequence.setInitialTime = max( 0.0, Time() - ( file.introStartTime + 11.0 ) ) // 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 + jumpSequence.setInitialTime = max( 0.0, Time() - playerDropship.s.deployedTime ) #if BATTLECHATTER_ENABLED if( playerDropshipIndex == 0 ) @@ -234,6 +238,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e #endif waitthread FirstPersonSequence( jumpSequence, player, playerDropship ) + wait 0.3 // Blendout time from the function thread PlayerJumpsFromDropship( player ) } @@ -250,21 +255,44 @@ void function PlayerJumpsFromDropship( entity player ) // show weapon viewmodel and hud and let them move again player.MovementEnable() player.EnableWeaponViewModel() + player.UnfreezeControlsOnServer() DeployAndEnableWeapons( player ) RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } }) // wait for player to hit the ground + ClearPlayerAnimViewEntity( player ) player.ClearParent() - WaitFrame() - player.SetVelocity( < 0, 0, -100 > ) // Toss players a bit down so it makes a smoother transition when jumping off the Dropship - player.MovementDisable() // Disable all movement but let them look around still player.ConsumeDoubleJump() // MovementDisable doesn't prevent double jumps WaitFrame() + player.SetVelocity( < 0, 0, -100 > ) while ( !player.IsOnGround() && !player.IsWallRunning() && !player.IsWallHanging() ) // todo this needs tweaking WaitFrame() - if ( GetRoundsPlayed() == 0 ) //Intro is announced only for the first round in Vanilla as certain gamemodes have different announcements for rounds restarts + if ( GetRoundsPlayed() == 0 || HasSwitchedSides() == 1 ) //Intro is announced only for the first round in Vanilla as certain gamemodes have different announcements for rounds restarts TryGameModeAnnouncement( player ) } + +string function GetDropshipIntroAnimation() +{ + switch ( GetMapName() ) + { + case "mp_grave": + return "dropship_classic_mp_flyin_grave" + + case "mp_complex3": + return "dropship_classic_mp_flyin_timeshift" + } + return "dropship_classic_mp_flyin" +} + +void function DelayedFrameFadeout( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + WaitFrame() + ScreenFadeFromBlack( player, 1, 1 ) + UnMuteAll( player ) + StopSoundOnEntity( player, "Duck_For_FrontierDefenseTitanSelectScreen" ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_no_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_no_intro.gnut index 7901e3a23..3f4e0c37f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_no_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_no_intro.gnut @@ -3,9 +3,7 @@ untyped global function ClassicMP_DefaultNoIntro_Setup global function ClassicMP_DefaultNoIntro_GetLength -global const float NOINTRO_INTRO_PILOT_LENGTH = 10.0 -global const float TITAN_DROP_SPAWN_INTRO_LENGTH = 0.0 // this intro shouldn't have a countdown visually, so we have to set the length of this intro to 0 -global const float TITAN_DROP_SPAWN_INTRO_REAL_LENGTH = 2.0 // we wait roughly this long during the intro, even when it's technically over +global const float NOINTRO_LENGTH = 5.0 void function ClassicMP_DefaultNoIntro_Setup() { @@ -15,12 +13,7 @@ void function ClassicMP_DefaultNoIntro_Setup() float function ClassicMP_DefaultNoIntro_GetLength() { - if ( ShouldIntroSpawnAsTitan() ) - return TITAN_DROP_SPAWN_INTRO_LENGTH - else - return NOINTRO_INTRO_PILOT_LENGTH - - unreachable + return NOINTRO_LENGTH } void function ClassicMP_DefaultNoIntro_Start() @@ -30,21 +23,15 @@ void function ClassicMP_DefaultNoIntro_Start() foreach ( entity player in GetPlayerArray() ) ClassicMP_DefaultNoIntro_SpawnPlayer( player ) - if ( ShouldIntroSpawnAsTitan() ) - wait TITAN_DROP_SPAWN_INTRO_REAL_LENGTH - else - { - wait NOINTRO_INTRO_PILOT_LENGTH + while ( Time() < expect float( level.nv.gameStartTime ) ) + WaitFrame() - foreach ( entity player in GetPlayerArray() ) + foreach ( entity player in GetPlayerArray() ) + { + if ( !IsPrivateMatchSpectator( player ) ) { - if ( !IsPrivateMatchSpectator( player ) ) - { - player.UnfreezeControlsOnServer() - RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) - } - - TryGameModeAnnouncement( player ) + player.UnfreezeControlsOnServer() + RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } } @@ -55,16 +42,7 @@ void function ClassicMP_DefaultNoIntro_SpawnPlayer( entity player ) { if ( GetGameState() != eGameState.Prematch ) return - - if ( IsPrivateMatchSpectator( player ) ) // private match spectators use custom spawn logic - { - RespawnPrivateMatchSpectator( player ) - return - } - - if ( IsAlive( player ) ) - player.Die() - + if ( ShouldIntroSpawnAsTitan() ) thread ClassicMP_DefaultNoIntro_TitanSpawnPlayer( player ) else @@ -75,16 +53,44 @@ void function ClassicMP_DefaultNoIntro_SpawnPlayer( entity player ) // spawn as pilot for intro void function ClassicMP_DefaultNoIntro_PilotSpawnPlayer( entity player ) { - RespawnAsPilot( player ) + player.EndSignal( "OnDestroy" ) + if( PlayerCanSpawn( player ) ) + RespawnAsPilot( player ) + player.FreezeControlsOnServer() + HolsterAndDisableWeapons( player ) + ResetPlayerCooldowns( player ) // Prevention of case they used abilities or grenades near round end + WaitFrame() AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) - ScreenFadeFromBlack( player, 0.5, 0.5 ) + ScreenFadeFromBlack( player, 1, 1 ) + + while ( Time() < expect float( level.nv.gameStartTime ) ) + WaitFrame() + + TryGameModeAnnouncement( player ) + DeployAndEnableWeapons( player ) } // spawn as titan for intro void function ClassicMP_DefaultNoIntro_TitanSpawnPlayer( entity player ) { - // blocking call - RespawnAsTitan( player, false ) + player.EndSignal( "OnDestroy" ) + WaitFrame() + ScreenFadeFromBlack( player, 1, 1 ) + + entity intermissionCam = GetEntArrayByClass_Expensive( "info_intermission" )[ 0 ] + player.SetObserverModeStaticPosition( intermissionCam.GetOrigin() ) + player.SetObserverModeStaticAngles( intermissionCam.GetAngles() ) + player.StartObserverMode( OBS_MODE_STATIC_LOCKED ) + + while ( Time() < expect float( level.nv.gameStartTime ) ) // Wait until match actually starts to spawn them + WaitFrame() + + if( PlayerCanSpawn( player ) ) + { + player.StopObserverMode() + RespawnAsTitan( player ) + } + TryGameModeAnnouncement( player ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut index 0d1b42b7e..c8c21559b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut @@ -20,9 +20,9 @@ global function CodeCallback_CheckPassThroughAddsMods global function SetTitanMeterGainScale #if MP -global function CodeCallback_OnServerAnimEvent global function CodeCallback_WeaponDropped global function AddCallback_OnWeaponDropped +global function CodeCallback_OnServerAnimEvent #endif struct AccumulatedDamageData diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 17323c38b..800ded3ea 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -7,9 +7,8 @@ global function WaittillGameStateOrHigher global function AddCallback_OnRoundEndCleanup global function SetShouldUsePickLoadoutScreen +global function SetShouldSpectateInPickLoadoutScreen global function SetSwitchSidesBased -global function SetSuddenDeathBased -global function SetTimerBased global function SetShouldUseRoundWinningKillReplay global function SetRoundWinningKillReplayKillClasses global function SetRoundWinningKillReplayAttacker @@ -18,35 +17,28 @@ global function ShouldTryUseProjectileReplay global function SetWinner global function SetTimeoutWinnerDecisionFunc global function AddTeamScore -global function GetWinningTeamWithFFASupport + +// For more complex logics involving rounds (i.e flag condition in Live-Fire) +global function AddTeamRoundScoreNoStateChange global function GameState_GetTimeLimitOverride global function IsRoundBasedGameOver +global function SpectatePlayerDuringPickLoadout global function ShouldRunEvac global function GiveTitanToPlayer global function GetTimeLimit_ForGameMode struct { - // used for togglable parts of gamestate bool usePickLoadoutScreen + bool spectateInPickLoadoutScreen = false // This is so joining players stay absent from distracting others with invulnerability given by the Titan Selection Screen bool switchSidesBased - bool suddenDeathBased - bool timerBased = true int functionref() timeoutWinnerDecisionFunc - // for waitingforplayers - int numPlayersFullyConnected - bool hasSwitchedSides - int announceRoundWinnerWinningSubstr - int announceRoundWinnerLosingSubstr - bool roundWinningKillReplayTrackPilotKills = true bool roundWinningKillReplayTrackTitanKills = false - bool gameWonThisFrame - bool hasKillForGameWonThisFrame float roundWinningKillReplayTime entity roundWinningKillReplayVictim entity roundWinningKillReplayAttacker @@ -77,14 +69,8 @@ struct { void function PIN_GameStart() { - // todo: using the pin telemetry function here, weird and was done veeery early on before i knew how this all worked, should use a different one - - // called from InitGameState - //FlagInit( "ReadyToStartMatch" ) - SetServerVar( "switchedSides", 0 ) - SetServerVar( "winningTeam", -1 ) - + AddCallback_GameStateEnter( eGameState.WaitingForCustomStart, GameStateEnter_WaitingForCustomStart ) AddCallback_GameStateEnter( eGameState.WaitingForPlayers, GameStateEnter_WaitingForPlayers ) AddCallback_OnClientConnected( WaitingForPlayers_ClientConnected ) @@ -100,14 +86,14 @@ void function PIN_GameStart() AddCallback_OnPlayerKilled( OnPlayerKilled ) AddDeathCallback( "npc_titan", OnTitanKilled ) AddCallback_EntityChangedTeam( "player", OnPlayerChangedTeam ) + PilotBattery_SetMaxCount( GetCurrentPlaylistVarInt( "pilot_battery_inventory_size", 1 ) ) // Game unironically supports players carrying more than one battery RegisterSignal( "CleanUpEntitiesForRoundEnd" ) } void function GameState_EntitiesDidLoad() { - if ( GetClassicMPMode() || ClassicMP_ShouldTryIntroAndEpilogueWithoutClassicMP() ) - ClassicMP_SetupIntro() + ClassicMP_SetupIntro() } void function WaittillGameStateOrHigher( int gameState ) @@ -129,13 +115,13 @@ bool function ShouldTryUseProjectileReplay( entity victim, entity attacker, var /// Also possibly prevents mods that spawns other types of NPCs that players can own from breaking when switching (i.e Drones, Hacked Reapers) void function OnPlayerChangedTeam( entity player ) { - if ( !player.hasConnected ) // Prevents players who just joined to trigger below code, as server always pre setups their teams + if ( !player.hasConnected ) //Prevents players who just joined to trigger below code, as server always pre setups their teams return - if( IsIMCOrMilitiaTeam( player.GetTeam() ) ) + if ( IsIMCOrMilitiaTeam( player.GetTeam() ) ) NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) - foreach( npc in GetNPCArray() ) + foreach ( npc in GetNPCArray() ) { entity bossPlayer = npc.GetBossPlayer() if ( IsValidPlayer( bossPlayer ) && bossPlayer == player && IsAlive( npc ) ) @@ -168,66 +154,112 @@ void function SetGameState( int newState ) SetServerVar( "gameState", newState ) svGlobal.levelEnt.Signal( "GameStateChanged" ) - // added in AddCallback_GameStateEnter foreach ( callbackFunc in svGlobal.gameStateEnterCallbacks[ newState ] ) callbackFunc() } void function AddTeamScore( int team, int amount ) { - GameRules_SetTeamScore( team, GameRules_GetTeamScore( team ) + amount ) - GameRules_SetTeamScore2( team, GameRules_GetTeamScore2( team ) + amount ) + AddTeamRoundScoreNoStateChange( team, amount ) + + int scoreLimit = GameMode_GetScoreLimit( GAMETYPE ) + int score = GameRules_GetTeamScore( team ) - int scoreLimit if ( IsRoundBased() ) + { scoreLimit = GameMode_GetRoundScoreLimit( GAMETYPE ) - else - scoreLimit = GameMode_GetScoreLimit( GAMETYPE ) - - int score = GameRules_GetTeamScore( team ) - if ( score >= scoreLimit || GetGameState() == eGameState.SuddenDeath ) - SetWinner( team ) + score = GameRules_GetTeamScore2( team ) + } + + if ( score >= scoreLimit && ( IsRoundBased() && !HasRoundScoreLimitBeenReached() ) ) + SetWinner( team, "#GAMEMODE_ROUND_LIMIT_REACHED", "#GAMEMODE_ROUND_LIMIT_REACHED" ) + else if ( score >= scoreLimit ) + SetWinner( team, "#GAMEMODE_SCORE_LIMIT_REACHED", "#GAMEMODE_SCORE_LIMIT_REACHED" ) + else if ( GetGameState() == eGameState.SuddenDeath ) + SetWinner( team, "#SUDDEN_DEATH_WIN_ANNOUNCEMENT", "#SUDDEN_DEATH_LOSS_ANNOUNCEMENT" ) else if ( ( file.switchSidesBased && !file.hasSwitchedSides ) && score >= ( scoreLimit.tofloat() / 2.0 ) ) SetGameState( eGameState.SwitchingSides ) } -void function SetWinner( int team, string winningReason = "", string losingReason = "" ) -{ - SetServerVar( "winningTeam", team ) +void function AddTeamRoundScoreNoStateChange( int team, int amount = 1 ) +{ + int scoreLimit = GameMode_GetScoreLimit( GAMETYPE ) + int score = GameRules_GetTeamScore( team ) + + if ( IsRoundBased() ) + { + scoreLimit = GameMode_GetRoundScoreLimit( GAMETYPE ) + score = GameRules_GetTeamScore2( team ) + } + + int newScore = score + amount + if( newScore > scoreLimit && !GameScore_AllowPointsOverLimit() ) // Don't allow over the limit if not enabled + newScore = scoreLimit + + GameRules_SetTeamScore( team, newScore ) + GameRules_SetTeamScore2( team, newScore ) +} + +void function SetWinner( int ornull team, string winningReason = "", string losingReason = "" ) +{ + if ( !GamePlayingOrSuddenDeath() ) // SetWinner should not be used outside the gamestates that can decide a winner + return - file.gameWonThisFrame = true - thread UpdateGameWonThisFrameNextFrame() + if ( team != null ) // Team being null means to ServerCallback_AnnounceRoundWinner and ServerCallback_AnnounceWinner to display "DRAW" + SetServerVar( "winningTeam", team ) - if ( winningReason.len() == 0 ) - file.announceRoundWinnerWinningSubstr = 0 + int announceRoundWinnerWinningSubstr + int announceRoundWinnerLosingSubstr + if ( winningReason == "" ) + announceRoundWinnerWinningSubstr = 0 else - file.announceRoundWinnerWinningSubstr = GetStringID( winningReason ) + announceRoundWinnerWinningSubstr = GetStringID( winningReason ) - if ( losingReason.len() == 0 ) - file.announceRoundWinnerLosingSubstr = 0 + if ( losingReason == "" ) + announceRoundWinnerLosingSubstr = 0 else - file.announceRoundWinnerLosingSubstr = GetStringID( losingReason ) + announceRoundWinnerLosingSubstr = GetStringID( losingReason ) - if ( GamePlayingOrSuddenDeath() ) + float endTime + if ( IsRoundBased() ) + endTime = expect float( GetServerVar( "roundEndTime" ) ) + else + endTime = expect float( GetServerVar( "gameEndTime" ) ) + + foreach ( entity player in GetPlayerArray() ) { - if ( IsRoundBased() ) - { - if ( team != TEAM_UNASSIGNED ) - { - GameRules_SetTeamScore( team, GameRules_GetTeamScore( team ) + 1 ) - GameRules_SetTeamScore2( team, GameRules_GetTeamScore2( team ) + 1 ) - } - - SetGameState( eGameState.WinnerDetermined ) - ScoreEvent_RoundComplete( team ) - } - else + int announcementSubstr = announceRoundWinnerLosingSubstr + + if( team != null && player.GetTeam() == team ) + announcementSubstr = announceRoundWinnerWinningSubstr + + if( Flag( "AnnounceWinnerEnabled" ) ) { - SetGameState( eGameState.WinnerDetermined ) - ScoreEvent_MatchComplete( team ) - - RegisterMatchStats_OnMatchComplete() + if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceRoundWinner", 0, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME, GameRules_GetTeamScore2( TEAM_MILITIA ), GameRules_GetTeamScore2( TEAM_IMC ) ) + else + Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceWinner", 0, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) } + + if( team != null && player.GetTeam() == team ) + UnlockAchievement( player, achievements.MP_WIN ) + } + + if ( !team ) // This is to make GetWinningTeam return TEAM_UNASSIGNED for clients so they don't crash due to music logic upon entering WinnerDetermined state + SetServerVar( "winningTeam", GetWinningTeam() ) + + SetGameState( eGameState.WinnerDetermined ) + if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() ) + { + if ( team != null && team != TEAM_UNASSIGNED ) + ScoreEvent_RoundComplete( expect int( team ) ) + } + else + { + if ( team != null && team != TEAM_UNASSIGNED ) + ScoreEvent_MatchComplete( expect int( team ) ) + + RegisterMatchStats_OnMatchComplete() } } @@ -251,19 +283,19 @@ void function SetShouldUsePickLoadoutScreen( bool shouldUse ) file.usePickLoadoutScreen = shouldUse } -void function SetSwitchSidesBased( bool switchSides ) +void function SetShouldSpectateInPickLoadoutScreen( bool shouldSpec ) { - file.switchSidesBased = switchSides + file.spectateInPickLoadoutScreen = shouldSpec } -void function SetSuddenDeathBased( bool suddenDeathBased ) +bool function SpectatePlayerDuringPickLoadout() { - file.suddenDeathBased = suddenDeathBased + return ( file.usePickLoadoutScreen && file.spectateInPickLoadoutScreen ) } -void function SetTimerBased( bool timerBased ) +void function SetSwitchSidesBased( bool switchSides ) { - file.timerBased = timerBased + file.switchSidesBased = switchSides } void function SetShouldUseRoundWinningKillReplay( bool shouldUse ) @@ -293,8 +325,6 @@ void function SetRoundWinningKillReplayAttacker( entity attacker, int inflictorE - - /* ██████ ██ ██ ███████ ████████ ██████ ███ ███ ███████ ████████ █████ ██████ ████████ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ @@ -317,7 +347,6 @@ void function GameStateEnter_WaitingForCustomStart() - /* ██ ██ █████ ██ ████████ ██ ███ ██ ██████ ███████ ██████ ██████ ██████ ██ █████ ██ ██ ███████ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ @@ -328,27 +357,48 @@ void function GameStateEnter_WaitingForCustomStart() void function GameStateEnter_WaitingForPlayers() { - foreach ( entity player in GetPlayerArray() ) - WaitingForPlayers_ClientConnected( player ) - - thread WaitForPlayers() // like 90% sure there should be a way to get number of loading clients on server but idk it + thread WaitForPlayers() } -void function WaitForPlayers( ) +void function WaitForPlayers() { - // note: atm if someone disconnects as this happens the game will just wait forever float endTime = Time() + 30.0 - while ( ( GetPendingClientsCount() != 0 && endTime > Time() ) || GetPlayerArray().len() == 0 ) + SetServerVar( "connectionTimeout", endTime ) // This makes a clock ticking sound and is used to tell server when to force start the match + while ( GetPendingClientsCount() != 0 && endTime > Time() || !GetPlayerArray().len() ) WaitFrame() - print( "done waiting!" ) + // The wait from above works just fine alone, but this one makes fancier in terms of making server truly wait for everyone being fully loaded and ready + bool allClientsConnected = false + while ( !allClientsConnected && endTime > Time() ) + { + array< entity > pendingLoadingClients + foreach ( player in GetPlayerArray() ) + { + if ( !player.hasConnected ) + pendingLoadingClients.append( player ) + } + + if ( !pendingLoadingClients.len() ) + allClientsConnected = true + + WaitFrame() + } - wait 1.0 // bit nicer - if ( file.usePickLoadoutScreen ) - SetGameState( eGameState.PickLoadout ) + print( "Finished waiting for players, starting match." ) + + wait 2 + + if ( IsFFAGame() ) // FFA has no Dropships and logic crash clients if casted into PickLoadout + SetGameState( eGameState.Prematch ) else - SetGameState( eGameState.Prematch ) + { + float pickloadoutLength = GameMode_GetLoadoutSelectTime() // Default is 5 seconds from playlistvar, for the Dropship warp sound + pickloadoutLength += GetCurrentPlaylistVarFloat( "pick_loadout_extension", 0 ) // Actual addition of time for the Titan Selection Screen + SetServerVar( "minPickLoadOutTime", Time() + pickloadoutLength ) + + SetGameState( eGameState.PickLoadout ) // Even if the game mode don't use it, vanilla still cast this game state to make the dropship jump sound when match starts + } } void function WaitingForPlayers_ClientConnected( entity player ) @@ -379,11 +429,8 @@ void function GameStateEnter_PickLoadout() } void function GameStateEnter_PickLoadout_Threaded() -{ - float pickloadoutLength = 20.0 // may need tweaking - SetServerVar( "minPickLoadOutTime", Time() + pickloadoutLength ) - - // titan selection menu can change minPickLoadOutTime so we need to wait manually until we hit the time +{ + // The Titan Selection Screen can extend the minPickLoadOutTime, so wait for natural expire while ( Time() < GetServerVar( "minPickLoadOutTime" ) ) WaitFrame() @@ -398,7 +445,6 @@ void function GameStateEnter_PickLoadout_Threaded() - /* ██████ ██████ ███████ ███ ███ █████ ████████ ██████ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ @@ -413,42 +459,19 @@ void function GameStateEnter_Prematch() if ( file.switchSidesBased ) timeLimit /= 2 // endtime is half of total per side - SetServerVar( "gameEndTime", Time() + timeLimit + ClassicMP_GetIntroLength() ) - SetServerVar( "roundEndTime", Time() + ClassicMP_GetIntroLength() + GameMode_GetRoundTimeLimit( GAMETYPE ) * 60 ) + if ( IsRoundBased() ) // Override with roundtimelimits even if it have switching sides enabled + timeLimit = int( GameMode_GetRoundTimeLimit( GAMETYPE ) * 60 ) if ( !GetClassicMPMode() && !ClassicMP_ShouldTryIntroAndEpilogueWithoutClassicMP() ) - thread StartGameWithoutClassicMP() - - // Initialise any spectators. Hopefully they are all initialised already in CodeCallback_OnClientConnectionCompleted - // (_base_gametype_mp.gnut) but for modes like LTS this doesn't seem to happen late enough to work properly. - foreach ( player in GetPlayerArray() ) { - if ( IsPrivateMatchSpectator( player ) ) - InitialisePrivateMatchSpectatorPlayer( player ) + SetGameEndTime( timeLimit + ClassicMP_DefaultNoIntro_GetLength() ) + SetRoundEndTime( timeLimit + ClassicMP_DefaultNoIntro_GetLength() ) } -} - -void function StartGameWithoutClassicMP() -{ - foreach ( entity player in GetPlayerArray() ) - if ( IsAlive( player ) ) - player.Die() - - WaitFrame() // wait for callbacks to finish - - // need these otherwise game will complain - SetServerVar( "gameStartTime", Time() ) - SetServerVar( "roundStartTime", Time() ) - - foreach ( entity player in GetPlayerArray() ) + else { - if ( !IsPrivateMatchSpectator( player ) ) - RespawnAsPilot( player ) - - ScreenFadeFromBlack( player, 0 ) + SetGameEndTime( timeLimit + ClassicMP_GetIntroLength() ) + SetRoundEndTime( timeLimit + ClassicMP_GetIntroLength() ) } - - SetGameState( eGameState.Playing ) } @@ -459,7 +482,6 @@ void function StartGameWithoutClassicMP() - /* ██████ ██ █████ ██ ██ ██ ███ ██ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ @@ -470,39 +492,48 @@ void function StartGameWithoutClassicMP() void function GameStateEnter_Playing() { + GameRules_MarkGameStatePrematchEnding() thread GameStateEnter_Playing_Threaded() } void function GameStateEnter_Playing_Threaded() { - WaitFrame() // ensure timelimits are all properly set + WaitFrame() + if( Flag( "AnnounceProgressEnabled" ) ) + thread DialoguePlayNormal() - thread DialoguePlayNormal() // runs dialogue play function + float timeWithPlayers = Time() while ( GetGameState() == eGameState.Playing ) { - // could cache these, but what if we update it midgame? float endTime if ( IsRoundBased() ) endTime = expect float( GetServerVar( "roundEndTime" ) ) else endTime = expect float( GetServerVar( "gameEndTime" ) ) + + if ( GetPlayerArray().len() ) + timeWithPlayers = Time() + else if ( timeWithPlayers + 10.0 < Time() ) + GameRules_EndMatch() - // time's up! - if ( Time() >= endTime && file.timerBased ) + if ( Time() >= endTime && !Flag( "DisableTimeLimit" ) ) { int winningTeam if ( file.timeoutWinnerDecisionFunc != null ) winningTeam = file.timeoutWinnerDecisionFunc() else - winningTeam = GetWinningTeamWithFFASupport() + winningTeam = GetWinningTeam() - if ( file.switchSidesBased && !file.hasSwitchedSides && !IsRoundBased() ) // in roundbased modes, we handle this in setwinner + if ( file.switchSidesBased && !file.hasSwitchedSides && !IsRoundBased() ) SetGameState( eGameState.SwitchingSides ) - else if ( file.suddenDeathBased && winningTeam == TEAM_UNASSIGNED ) // suddendeath if we draw and suddendeath is enabled and haven't switched sides + else if ( IsSuddenDeathGameMode() && winningTeam == TEAM_UNASSIGNED ) SetGameState( eGameState.SuddenDeath ) else - SetWinner( winningTeam ) + { + SetWinner( winningTeam, "#GAMEMODE_TIME_LIMIT_REACHED", "#GAMEMODE_TIME_LIMIT_REACHED" ) + SetServerVar( "replayDisabled", true ) + } } WaitFrame() @@ -517,7 +548,6 @@ void function GameStateEnter_Playing_Threaded() - /* ██ ██ ██ ███ ██ ███ ██ ███████ ██████ ██████ ███████ ████████ ███████ ██████ ███ ███ ██ ███ ██ ███████ ██████ ██ ██ ██ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ @@ -526,42 +556,25 @@ void function GameStateEnter_Playing_Threaded() ███ ███ ██ ██ ████ ██ ████ ███████ ██ ██ ██████ ███████ ██ ███████ ██ ██ ██ ██ ██ ██ ████ ███████ ██████ */ -// these are likely innacurate -const float ROUND_END_FADE_KILLREPLAY = 1.0 -const float ROUND_END_DELAY_KILLREPLAY = 3.0 -const float ROUND_END_FADE_NOKILLREPLAY = 8.0 -const float ROUND_END_DELAY_NOKILLREPLAY = 10.0 - void function GameStateEnter_WinnerDetermined() -{ +{ + GameRules_MarkGameStateWinnerDetermined() thread GameStateEnter_WinnerDetermined_Threaded() } void function GameStateEnter_WinnerDetermined_Threaded() { - // do win announcement - int winningTeam = GetWinningTeamWithFFASupport() - - DialoguePlayWinnerDetermined() // play a faction dialogue when winner is determined - - foreach ( entity player in GetPlayerArray() ) - { - int announcementSubstr - if ( winningTeam != TEAM_UNASSIGNED ) - announcementSubstr = player.GetTeam() == winningTeam ? file.announceRoundWinnerWinningSubstr : file.announceRoundWinnerLosingSubstr + int winningTeam = GetWinningTeam() + DialoguePlayWinnerDetermined() - if ( IsRoundBased() ) - Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceRoundWinner", winningTeam, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME, GameRules_GetTeamScore2( TEAM_MILITIA ), GameRules_GetTeamScore2( TEAM_IMC ) ) - else - Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceWinner", winningTeam, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) - - if ( player.GetTeam() == winningTeam ) - UnlockAchievement( player, achievements.MP_WIN ) - } + if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() ) + svGlobal.levelEnt.Signal( "RoundEnd" ) + else + svGlobal.levelEnt.Signal( "GameEnd" ) WaitFrame() // wait a frame so other scripts can setup killreplay stuff - // set gameEndTime to current time, so hud doesn't display time left in the match + // Finish timers to make HUD not display more SetServerVar( "gameEndTime", Time() ) SetServerVar( "roundEndTime", Time() ) @@ -569,76 +582,92 @@ void function GameStateEnter_WinnerDetermined_Threaded() bool doReplay = Replay_IsEnabled() && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker ) && !ClassicMP_ShouldRunEpilogue() && Time() - file.roundWinningKillReplayTime <= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY && winningTeam != TEAM_UNASSIGNED - float replayLength = 2.0 // extra delay if no replay + SetServerVar( "roundWinningKillReplayPlaying", doReplay ) if ( doReplay ) { - bool killcamsWereEnabled = KillcamsEnabled() - if ( killcamsWereEnabled ) // dont want killcams to interrupt stuff - SetKillcamsEnabled( false ) - - replayLength = ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY + float replayLength = ROUND_WINNING_KILL_REPLAY_TOTAL_LENGTH if ( "respawnTime" in replayAttacker.s && Time() - replayAttacker.s.respawnTime < replayLength ) replayLength += Time() - expect float ( replayAttacker.s.respawnTime ) SetServerVar( "roundWinningKillReplayEntHealthFrac", file.roundWinningKillReplayHealthFrac ) foreach ( entity player in GetPlayerArray() ) - thread PlayerWatchesRoundWinningKillReplay( player, replayLength ) - - wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME - CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see - wait replayLength + { + ClearPlayerFromReplay( player ) // If there's a replay already happening, cut it + CheckGameStateForPlayerMovement( player ) + } + wait 1.5 + foreach ( entity player in GetPlayerArray() ) + ScreenFadeToBlackForever( player, 2.0 ) - WaitFrame() // prevent a race condition with PlayerWatchesRoundWinningKillReplay - file.roundWinningKillReplayAttacker = null // clear this - file.roundWinningKillReplayInflictorEHandle = -1 + wait 2 - if ( killcamsWereEnabled ) - SetKillcamsEnabled( true ) - } - else if ( IsRoundBased() || !ClassicMP_ShouldRunEpilogue() ) - { - // these numbers are temp and should really be based on consts of some kind - foreach( entity player in GetPlayerArray() ) + foreach ( entity player in GetPlayerArray() ) + thread PlayerWatchesRoundWinningReplay( player, replayLength ) + + wait replayLength + foreach ( entity player in GetPlayerArray() ) { - player.FreezeControlsOnServer() - ScreenFadeToBlackForever( player, 4.0 ) + ClearPlayerFromReplay( player ) + WaitFrame() + ScreenFadeToBlackForever( player, 0.0 ) } - wait ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY - CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see + if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() && HasSwitchedSides() == 0 ) + CleanUpEntitiesForRoundEnd() - foreach( entity player in GetPlayerArray() ) - player.UnfreezeControlsOnServer() + SetServerVar( "roundWinningKillReplayPlaying", false ) } - - if ( IsRoundBased() ) + else if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() || !ClassicMP_ShouldRunEpilogue() ) { - svGlobal.levelEnt.Signal( "RoundEnd" ) - int roundsPlayed = expect int ( GetServerVar( "roundsPlayed" ) ) - SetServerVar( "roundsPlayed", roundsPlayed + 1 ) + // Observation from vanilla hints that the gamemodes can choose how players will behave once match is over + foreach ( entity player in GetPlayerArray() ) + CheckGameStateForPlayerMovement( player ) - int winningTeam = GetWinningTeamWithFFASupport() + wait GAME_WINNER_DETERMINED_WAIT + + foreach ( entity player in GetPlayerArray() ) + ScreenFadeToBlackForever( player, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) - int highestScore = GameRules_GetTeamScore( winningTeam ) + wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME + if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() && HasSwitchedSides() == 0 ) // Repeat check here just for the case match is over and epilogue is disabled, so it doesn't kill players randomly + CleanUpEntitiesForRoundEnd() + } + + wait CLEAR_PLAYERS_BUFFER // Required to properly restart without players in Titans crashing it in FD + + file.roundWinningKillReplayAttacker = null // Clear Replays + file.roundWinningKillReplayInflictorEHandle = -1 + if ( IsRoundBased() && !HasRoundScoreLimitBeenReached() ) + { + ClearDroppedWeapons() + int roundsPlayed = GetRoundsPlayed() + roundsPlayed++ + SetServerVar( "roundsPlayed", roundsPlayed ) + + int highestScore = GameRules_GetTeamScore2( winningTeam ) int roundScoreLimit = GameMode_GetRoundScoreLimit( GAMETYPE ) if ( highestScore >= roundScoreLimit ) { - if ( ClassicMP_ShouldRunEpilogue() ) + if ( ShouldRunEvac() ) { ClassicMP_SetupEpilogue() SetGameState( eGameState.Epilogue ) } else + { + foreach ( entity player in GetPlayerArray() ) + CheckGameStateForPlayerMovement( player ) + + RegisterChallenges_OnMatchEnd() SetGameState( eGameState.Postmatch ) + } } - else if ( file.switchSidesBased && !file.hasSwitchedSides && highestScore >= ( roundScoreLimit.tofloat() / 2.0 ) ) // round up - SetGameState( eGameState.SwitchingSides ) // note: switchingsides will handle setting to pickloadout and prematch by itself - else if ( file.usePickLoadoutScreen ) + else if ( file.usePickLoadoutScreen && GetCurrentPlaylistVarInt( "pick_loadout_every_round", 1 ) ) //Playlist var needs to be enabled as well SetGameState( eGameState.PickLoadout ) else - SetGameState ( eGameState.Prematch ) + SetGameState( eGameState.Prematch ) } else { @@ -649,48 +678,47 @@ void function GameStateEnter_WinnerDetermined_Threaded() SetGameState( eGameState.Epilogue ) } else + { + foreach ( entity player in GetPlayerArray() ) + CheckGameStateForPlayerMovement( player ) + SetGameState( eGameState.Postmatch ) + } } + + AllPlayersUnMuteAll() } -void function PlayerWatchesRoundWinningKillReplay( entity player, float replayLength ) +void function PlayerWatchesRoundWinningReplay( entity player, float replayLength ) { - // end if player dcs - player.EndSignal( "OnDestroy" ) - - player.FreezeControlsOnServer() - ScreenFadeToBlackForever( player, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) - wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME - - player.SetPredictionEnabled( false ) // prediction fucks with replays - entity attacker = file.roundWinningKillReplayAttacker - if ( IsValid( attacker ) ) - { - player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) - player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle ) - player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) - player.SetViewIndex( attacker.GetIndexForEntity() ) - player.SetIsReplayRoundWinning( true ) - } - - if ( replayLength >= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY - 0.5 ) // only do fade if close to full length replay - { - // this doesn't work because fades don't work on players that are in a replay, unsure how official servers do this - wait replayLength - 2.0 - ScreenFadeToBlackForever( player, 2.0 ) + if ( !IsValidPlayer( player ) || !IsValid( attacker ) ) + return - wait 2.0 - } - else - wait replayLength - - //player.SetPredictionEnabled( true ) doesn't seem needed, as native code seems to set this on respawn + player.Signal( "KillCamOver" ) + player.SetPredictionEnabled( false ) // Disable prediction to prevent issues with replays, respawning code restores it automatically player.ClearReplayDelay() player.ClearViewEntity() - player.UnfreezeControlsOnServer() + + player.watchingKillreplayEndTime = Time() + replayLength + player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) + player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle ) + player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) + player.SetViewIndex( attacker.GetIndexForEntity() ) + + if( !HasRoundScoreLimitBeenReached() ) + player.SetIsReplayRoundWinning( true ) } +void function ClearPlayerFromReplay( entity player ) +{ + if ( !IsValidPlayer( player ) ) + return + + player.Signal( "KillCamOver" ) + player.ClearReplayDelay() + player.ClearViewEntity() +} @@ -710,91 +738,79 @@ void function PlayerWatchesRoundWinningKillReplay( entity player, float replayLe void function GameStateEnter_SwitchingSides() { + thread DialogueAnnounceSwitchingSides() thread GameStateEnter_SwitchingSides_Threaded() } void function GameStateEnter_SwitchingSides_Threaded() { - bool killcamsWereEnabled = KillcamsEnabled() - if ( killcamsWereEnabled ) // dont want killcams to interrupt stuff - SetKillcamsEnabled( false ) - - WaitFrame() // wait a frame so callbacks can set killreplay info + WaitFrame() + + svGlobal.levelEnt.Signal( "RoundEnd" ) entity replayAttacker = file.roundWinningKillReplayAttacker bool doReplay = Replay_IsEnabled() && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker ) && !IsRoundBased() // for roundbased modes, we've already done the replay - && Time() - file.roundWinningKillReplayTime <= SWITCHING_SIDES_DELAY + && Time() - file.roundWinningKillReplayTime <= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY + + float replayLength = ROUND_WINNING_KILL_REPLAY_STARTUP_WAIT + SetServerVar( "roundWinningKillReplayPlaying", doReplay ) + + foreach ( entity player in GetPlayerArray() ) + { + ClearPlayerFromReplay( player ) + CheckGameStateForPlayerMovement( player ) + } + wait 1.5 + foreach ( entity player in GetPlayerArray() ) + ScreenFadeToBlackForever( player, 2.0 ) - float replayLength = SWITCHING_SIDES_DELAY_REPLAY // extra delay if no replay if ( doReplay ) - { - replayLength = SWITCHING_SIDES_DELAY + { + replayLength = ROUND_WINNING_KILL_REPLAY_TOTAL_LENGTH if ( "respawnTime" in replayAttacker.s && Time() - replayAttacker.s.respawnTime < replayLength ) replayLength += Time() - expect float ( replayAttacker.s.respawnTime ) SetServerVar( "roundWinningKillReplayEntHealthFrac", file.roundWinningKillReplayHealthFrac ) + + wait 2 + + foreach ( entity player in GetPlayerArray() ) + thread PlayerWatchesRoundWinningReplay( player, replayLength ) } - foreach ( entity player in GetPlayerArray() ) - thread PlayerWatchesSwitchingSidesKillReplay( player, doReplay, replayLength ) - - wait SWITCHING_SIDES_DELAY_REPLAY - CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see wait replayLength + foreach ( entity player in GetPlayerArray() ) + { + ClearPlayerFromReplay( player ) + WaitFrame() + ScreenFadeToBlackForever( player, 0.0 ) + } + CleanUpEntitiesForRoundEnd() + wait CLEAR_PLAYERS_BUFFER - if ( killcamsWereEnabled ) - SetKillcamsEnabled( true ) + ClearDroppedWeapons() + SetServerVar( "roundWinningKillReplayPlaying", false ) file.hasSwitchedSides = true - svGlobal.levelEnt.Signal( "RoundEnd" ) // might be good to get a new signal for this? not 100% necessary tho i think SetServerVar( "switchedSides", 1 ) file.roundWinningKillReplayAttacker = null // reset this after replay file.roundWinningKillReplayInflictorEHandle = -1 - if ( file.usePickLoadoutScreen ) + if ( file.usePickLoadoutScreen && GetCurrentPlaylistVarInt( "pick_loadout_every_round", 1 ) ) //Playlist var needs to be enabled too SetGameState( eGameState.PickLoadout ) else - SetGameState ( eGameState.Prematch ) + SetGameState( eGameState.Prematch ) } -void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doReplay, float replayLength ) +void function DialogueAnnounceSwitchingSides() { - player.EndSignal( "OnDestroy" ) - player.FreezeControlsOnServer() + foreach ( entity player in GetPlayerArray() ) + PlayFactionDialogueToPlayer( "mp_halftime", player ) - ScreenFadeToBlackForever( player, SWITCHING_SIDES_DELAY_REPLAY ) // automatically cleared - wait SWITCHING_SIDES_DELAY_REPLAY - - if ( doReplay ) - { - player.SetPredictionEnabled( false ) // prediction fucks with replays - - // delay seems weird for switchingsides? ends literally the frame the flag is collected - - entity attacker = file.roundWinningKillReplayAttacker - player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) - player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle ) - player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) - player.SetViewIndex( attacker.GetIndexForEntity() ) - player.SetIsReplayRoundWinning( true ) - - if ( replayLength >= SWITCHING_SIDES_DELAY - 0.5 ) // only do fade if close to full length replay - { - // this doesn't work because fades don't work on players that are in a replay, unsure how official servers do this - wait replayLength - ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME - ScreenFadeToBlackForever( player, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) + wait ROUND_WINNING_KILL_REPLAY_DELAY_BETWEEN_ANNOUNCEMENTS - wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME - } - else - wait replayLength - } - else - wait SWITCHING_SIDES_DELAY_REPLAY // extra delay if no replay - - //player.SetPredictionEnabled( true ) doesn't seem needed, as native code seems to set this on respawn - player.ClearReplayDelay() - player.ClearViewEntity() + foreach ( entity player in GetPlayerArray() ) + PlayFactionDialogueToPlayer( "mp_sideSwitching", player ) } @@ -805,7 +821,6 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla - /* ███████ ██ ██ ██████ ██████ ███████ ███ ██ ██████ ███████ █████ ████████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ @@ -816,24 +831,57 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla void function GameStateEnter_SuddenDeath() { - // disable respawns, suddendeath calling is done on a kill callback - SetRespawnsEnabled( false ) - - // defensive fixes, so game won't stuck in SuddenDeath forever - bool mltElimited = false - bool imcElimited = false - if( GetPlayerArrayOfTeam_Alive( TEAM_MILITIA ).len() < 1 ) - mltElimited = true - if( GetPlayerArrayOfTeam_Alive( TEAM_IMC ).len() < 1 ) - imcElimited = true - if( mltElimited && imcElimited ) - SetWinner( TEAM_UNASSIGNED ) - else if( mltElimited ) - SetWinner( TEAM_IMC ) - else if( imcElimited ) - SetWinner( TEAM_MILITIA ) + Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) + + // Restart the timer for Timelimits to show Sudden Death extra time (Because it does have it) + float timeLimit = GetCurrentPlaylistVarFloat( "suddendeath_timelimit", 2.0 ) + bool useSDTimelimit = false + if( timeLimit > 0 ) + { + timeLimit *= 60 // Minutes conversion + SetGameEndTime( timeLimit ) + SetRoundEndTime( timeLimit ) + useSDTimelimit = true + } + else if( timeLimit == 0 ) // Allows 0 to make SD fallback into Draw directly (used by Live-Fire) + { + SetWinner( null, "#GENERIC_DRAW_ANNOUNCEMENT", "#GENERIC_DRAW_ANNOUNCEMENT" ) + return + } + + // If SD timer playlistvar was set to a negative value, then SD will stay on forever until the tiebreaker is score or elimination + thread GameStateEnter_SuddenDeath_Threaded( useSDTimelimit ) } +void function GameStateEnter_SuddenDeath_Threaded( bool useTimelimit ) +{ + while ( GetGameState() == eGameState.SuddenDeath ) + { + WaitFrame() + + float endTime + if ( IsRoundBased() ) + endTime = expect float( GetServerVar( "roundEndTime" ) ) + else + endTime = expect float( GetServerVar( "gameEndTime" ) ) + + if( !IsFFAGame() ) // Death callbacks have dedicated logic to handle FFA modes + { + bool mltElimited = IsTeamEliminated( TEAM_MILITIA ) + bool imcElimited = IsTeamEliminated( TEAM_IMC ) + + if ( mltElimited && imcElimited ) + SetWinner( null, "#GENERIC_DRAW_ANNOUNCEMENT", "#GENERIC_DRAW_ANNOUNCEMENT" ) + else if ( mltElimited ) + SetWinner( TEAM_IMC, "#GAMEMODE_ENEMY_PILOTS_ELIMINATED", "#GAMEMODE_FRIENDLY_PILOTS_ELIMINATED" ) + else if ( imcElimited ) + SetWinner( TEAM_MILITIA, "#GAMEMODE_ENEMY_PILOTS_ELIMINATED", "#GAMEMODE_FRIENDLY_PILOTS_ELIMINATED" ) + } + + if ( Time() >= endTime && useTimelimit ) + SetWinner( null, "#GENERIC_DRAW_ANNOUNCEMENT", "#GENERIC_DRAW_ANNOUNCEMENT" ) + } +} @@ -853,36 +901,29 @@ void function GameStateEnter_SuddenDeath() void function GameStateEnter_Postmatch() { + SetServerVar( "replayDisabled", true ) //Disable kill replays on this moment just to ensure no camera problems foreach ( entity player in GetPlayerArray() ) { player.FreezeControlsOnServer() + player.SetNoTarget( true ) //Stop AI from targeting this player at this state of the match + player.SetInvulnerable() //Players could still die to some post-damaging stuff they might release (i.e: Electric Smokes, AI) thread ForceFadeToBlack( player ) } - + thread GameStateEnter_Postmatch_Threaded() } void function GameStateEnter_Postmatch_Threaded() { wait GAME_POSTMATCH_LENGTH - + + AllPlayersMuteAll( 2 ) //Vanilla has a fadeout in sound right before it really finishes the match + + wait 2.0 + GameRules_EndMatch() } -void function ForceFadeToBlack( entity player ) -{ - // todo: check if this is still necessary - player.EndSignal( "OnDestroy" ) - - // hack until i figure out what deathcam stuff is causing fadetoblacks to be cleared - while ( true ) - { - WaitFrame() - ScreenFadeToBlackForever( player, 0.0 ) - } -} - - @@ -901,26 +942,40 @@ void function ForceFadeToBlack( entity player ) void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { + if ( IsEliminationBased() ) + SetPlayerEliminated( victim ) + + // MVP kills in vanilla is just the top scoring player of a Team + array players = GetSortedPlayers( GetScoreboardCompareFunc(), victim.GetTeam() ) + if( IsFFAGame() || IsSingleTeamMode() ) + players = GetSortedPlayers( GetScoreboardCompareFunc(), 0 ) + + if ( victim == players[0] && attacker.IsPlayer() && attacker != victim ) + AddPlayerScore( attacker, "KilledMVP" ) + if ( !GamePlayingOrSuddenDeath() ) + return + + if ( IsTitanEliminationBased() && victim.IsTitan() ) // need an extra check for this { - if ( file.gameWonThisFrame ) - { - if ( file.hasKillForGameWonThisFrame ) - return - } - else - return + OnTitanKilled( victim, damageInfo ) + return } + CheckEliminationRiffMode( victim, attacker ) + entity inflictor = DamageInfo_GetInflictor( damageInfo ) bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, attacker, damageInfo, true ) + if ( victim.IsPlayer() ) + { + victim.p.numberOfDeaths++ + ShowDeathHint( victim, damageInfo ) + } // set round winning killreplay info here if we're tracking pilot kills // todo: make this not count environmental deaths like falls, unsure how to prevent this if ( file.roundWinningKillReplayTrackPilotKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) ) { - if ( file.gameWonThisFrame ) - file.hasKillForGameWonThisFrame = true file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim file.roundWinningKillReplayAttacker = attacker @@ -929,20 +984,41 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) file.roundWinningKillReplayTimeOfDeath = Time() file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) } +} - if ( ( Riff_EliminationMode() == eEliminationMode.Titans || Riff_EliminationMode() == eEliminationMode.PilotsTitans ) && victim.IsTitan() ) // need an extra check for this - OnTitanKilled( victim, damageInfo ) - - if ( !GamePlayingOrSuddenDeath() ) +void function OnTitanKilled( entity victim, var damageInfo ) +{ + if ( !GamePlayingOrSuddenDeath() || victim.IsNPC() && !IsValid( victim.GetBossPlayer() ) ) return + entity attacker = DamageInfo_GetAttacker( damageInfo ) + CheckEliminationRiffMode( victim, attacker ) + + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, DamageInfo_GetAttacker( damageInfo ), damageInfo, true ) + + // set round winning killreplay info here if we're tracking titan kills + // todo: make this not count environmental deaths like falls, unsure how to prevent this + if ( file.roundWinningKillReplayTrackTitanKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) ) + { + file.roundWinningKillReplayTime = Time() + file.roundWinningKillReplayVictim = victim + file.roundWinningKillReplayAttacker = attacker + file.roundWinningKillReplayInflictorEHandle = ( shouldUseInflictor ? inflictor : attacker ).GetEncodedEHandle() + file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + file.roundWinningKillReplayTimeOfDeath = Time() + file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) + } +} + +void function CheckEliminationRiffMode( entity victim, entity attacker ) +{ // note: pilotstitans is just win if enemy team runs out of either pilots or titans - if ( IsPilotEliminationBased() || GetGameState() == eGameState.SuddenDeath ) + if ( IsPilotEliminationBased() ) { - if ( GetPlayerArrayOfTeam_Alive( victim.GetTeam() ).len() == 0 ) + if ( IsTeamEliminated( victim.GetTeam() ) ) { - // for ffa we need to manually get the last team alive - if ( IsFFAGame() ) + if ( IsFFAGame() ) // for ffa we need to manually get the last team alive { array teamsWithLivingPlayers foreach ( entity player in GetPlayerArray_Alive() ) @@ -952,61 +1028,35 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) } if ( teamsWithLivingPlayers.len() == 1 ) - SetWinner( teamsWithLivingPlayers[ 0 ], "#GAMEMODE_ENEMY_PILOTS_ELIMINATED", "#GAMEMODE_FRIENDLY_PILOTS_ELIMINATED" ) + { + if( IsRoundBased() ) + AddTeamRoundScoreNoStateChange( teamsWithLivingPlayers[0] ) + + SetWinner( teamsWithLivingPlayers[0], "#GAMEMODE_ENEMY_PILOTS_ELIMINATED", "#GAMEMODE_FRIENDLY_PILOTS_ELIMINATED" ) + + if( IsValidPlayer( attacker ) ) + AddPlayerScore( attacker, "VictoryKill", attacker ) + } else if ( teamsWithLivingPlayers.len() == 0 ) // failsafe: only team was the dead one - SetWinner( TEAM_UNASSIGNED, "#GAMEMODE_ENEMY_PILOTS_ELIMINATED", "#GAMEMODE_FRIENDLY_PILOTS_ELIMINATED" ) // this is fine in ffa + SetWinner( null, "#GENERIC_DRAW_ANNOUNCEMENT", "#GENERIC_DRAW_ANNOUNCEMENT" ) // this is fine in ffa } else + { + if( IsRoundBased() ) + AddTeamRoundScoreNoStateChange( GetOtherTeam( victim.GetTeam() ) ) + SetWinner( GetOtherTeam( victim.GetTeam() ), "#GAMEMODE_ENEMY_PILOTS_ELIMINATED", "#GAMEMODE_FRIENDLY_PILOTS_ELIMINATED" ) - } - } -} -void function OnTitanKilled( entity victim, var damageInfo ) -{ - if ( !GamePlayingOrSuddenDeath() ) - { - if ( file.gameWonThisFrame ) - { - if ( file.hasKillForGameWonThisFrame ) - return + if( IsValidPlayer( attacker ) ) + AddPlayerScore( attacker, "VictoryKill", attacker ) + } } - else - return - } - - entity inflictor = DamageInfo_GetInflictor( damageInfo ) - bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, DamageInfo_GetAttacker( damageInfo ), damageInfo, true ) - - // set round winning killreplay info here if we're tracking titan kills - // todo: make this not count environmental deaths like falls, unsure how to prevent this - entity attacker = DamageInfo_GetAttacker( damageInfo ) - if ( file.roundWinningKillReplayTrackTitanKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) ) - { - if ( file.gameWonThisFrame ) - file.hasKillForGameWonThisFrame = true - file.roundWinningKillReplayTime = Time() - file.roundWinningKillReplayVictim = victim - file.roundWinningKillReplayAttacker = attacker - file.roundWinningKillReplayInflictorEHandle = ( shouldUseInflictor ? inflictor : attacker ).GetEncodedEHandle() - file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) - file.roundWinningKillReplayTimeOfDeath = Time() - file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) } - - if ( !GamePlayingOrSuddenDeath() ) - return - // note: pilotstitans is just win if enemy team runs out of either pilots or titans if ( IsTitanEliminationBased() ) { - int livingTitans - foreach ( entity titan in GetTitanArrayOfTeam( victim.GetTeam() ) ) - livingTitans++ - - if ( livingTitans == 0 ) + if ( !GetPlayerTitansOnTeam( victim.GetTeam() ).len() ) { - // for ffa we need to manually get the last team alive if ( IsFFAGame() ) { array teamsWithLivingTitans @@ -1017,12 +1067,28 @@ void function OnTitanKilled( entity victim, var damageInfo ) } if ( teamsWithLivingTitans.len() == 1 ) - SetWinner( teamsWithLivingTitans[ 0 ], "#GAMEMODE_ENEMY_TITANS_DESTROYED", "#GAMEMODE_FRIENDLY_TITANS_DESTROYED" ) - else if ( teamsWithLivingTitans.len() == 0 ) // failsafe: only team was the dead one - SetWinner( TEAM_UNASSIGNED, "#GAMEMODE_ENEMY_TITANS_DESTROYED", "#GAMEMODE_FRIENDLY_TITANS_DESTROYED" ) // this is fine in ffa + { + if( IsRoundBased() ) + AddTeamRoundScoreNoStateChange( teamsWithLivingTitans[0] ) + + SetWinner( teamsWithLivingTitans[0], "#GAMEMODE_ENEMY_TITANS_DESTROYED", "#GAMEMODE_FRIENDLY_TITANS_DESTROYED" ) + + if( IsValidPlayer( attacker ) ) + AddPlayerScore( attacker, "VictoryKill", attacker ) + } + else if ( teamsWithLivingTitans.len() == 0 ) + SetWinner( null, "#GENERIC_DRAW_ANNOUNCEMENT", "#GENERIC_DRAW_ANNOUNCEMENT" ) } else + { + if( IsRoundBased() ) + AddTeamRoundScoreNoStateChange( GetOtherTeam( victim.GetTeam() ) ) + SetWinner( GetOtherTeam( victim.GetTeam() ), "#GAMEMODE_ENEMY_TITANS_DESTROYED", "#GAMEMODE_FRIENDLY_TITANS_DESTROYED" ) + + if( IsValidPlayer( attacker ) ) + AddPlayerScore( attacker, "VictoryKill", attacker ) + } } } } @@ -1044,76 +1110,67 @@ void function OnTitanKilled( entity victim, var damageInfo ) ██ ██████ ██████ ███████ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ */ +void function ForceFadeToBlack( entity player ) +{ + player.EndSignal( "OnDestroy" ) + while ( true ) + { + WaitFrame() + ScreenFadeToBlackForever( player, 0.0 ) + } +} + void function CleanUpEntitiesForRoundEnd() { - // this function should clean up any and all entities that need to be removed between rounds, ideally at a point where it isn't noticable to players - SetPlayerDeathsHidden( true ) // hide death sounds and such so people won't notice they're dying - + SetPlayerDeathsHidden( true ) + svGlobal.levelEnt.Signal( "CleanUpEntitiesForRoundEnd" ) foreach ( entity player in GetPlayerArray() ) { + if ( IsPrivateMatchSpectator( player ) ) + continue + + PlayerEarnMeter_Reset( player ) ClearTitanAvailable( player ) PROTO_CleanupTrackedProjectiles( player ) player.SetPlayerNetInt( "batteryCount", 0 ) + player.ClearInvulnerable() + player.SetNoTarget( false ) + player.ClearParent() //Dropship parenting causes observer mode crash if ( IsAlive( player ) ) - player.Die( svGlobal.worldspawn, svGlobal.worldspawn, { damageSourceId = eDamageSourceId.round_end } ) + KillPlayer( player, eDamageSourceId.round_end ) } foreach ( entity npc in GetNPCArray() ) { - if ( !IsValid( npc ) || !IsAlive( npc ) ) + if ( !IsAlive( npc ) ) + continue + + if ( npc.e.fd_roundDeployed != -1 || npc.ai.buddhaMode ) // FD uses this var to cleanup stuff placed in current wave restart, buddha is for offline Turrets continue - // kill rather than destroy, as destroying will cause issues with children which is an issue especially for dropships and titans - npc.Die( svGlobal.worldspawn, svGlobal.worldspawn, { damageSourceId = eDamageSourceId.round_end } ) + + if ( npc.IsTitan() ) + { + npc.e.forceRagdollDeath = true + if ( !( "silentDeath" in npc.s ) ) // Ensure no background explosions will be heard from titans dying to round cleanup + npc.s.silentDeath <- true + } + else + npc.EnableNPCFlag( NPC_NO_WEAPON_DROP ) + + // Kill rather than destroy, as destroying will cause issues with children which is an issue especially for dropships and titans + npc.Die( svGlobal.worldspawn, svGlobal.worldspawn, { scriptType = DF_SKIP_DAMAGE_PROT | DF_SKIPS_DOOMED_STATE | DF_GIB, damageSourceId = eDamageSourceId.round_end } ) } - // destroy weapons - ClearDroppedWeapons() - foreach ( entity battery in GetEntArrayByClass_Expensive( "item_titan_battery" ) ) battery.Destroy() - // allow other scripts to clean stuff up too - svGlobal.levelEnt.Signal( "CleanUpEntitiesForRoundEnd" ) foreach ( void functionref() callback in file.roundEndCleanupCallbacks ) callback() - SetPlayerDeathsHidden( false ) -} - -void function UpdateGameWonThisFrameNextFrame() -{ WaitFrame() - file.gameWonThisFrame = false - file.hasKillForGameWonThisFrame = false -} - -int function GetWinningTeamWithFFASupport() -{ - if ( !IsFFAGame() ) - return GameScore_GetWinningTeam() - else - { - // custom logic for calculating ffa winner as GameScore_GetWinningTeam doesn't handle this - int winningTeam = TEAM_UNASSIGNED - int winningScore = 0 - - foreach ( entity player in GetPlayerArray() ) - { - int currentScore = GameRules_GetTeamScore( player.GetTeam() ) - - if ( currentScore == winningScore ) - winningTeam = TEAM_UNASSIGNED // if 2 teams are equal, return TEAM_UNASSIGNED - else if ( currentScore > winningScore ) - { - winningTeam = player.GetTeam() - winningScore = currentScore - } - } - - return winningTeam - } - unreachable + ClearDroppedWeapons() + SetPlayerDeathsHidden( false ) } float function GameState_GetTimeLimitOverride() @@ -1128,57 +1185,78 @@ bool function IsRoundBasedGameOver() bool function ShouldRunEvac() { - return true + if( !IsFFAGame() ) + { + int losingTeam = GetOtherTeam( GetWinningTeam() ) + if( IsEliminationBased() && IsTeamEliminated( losingTeam ) ) + return false + } + + return GameMode_GetEvacEnabled( GAMETYPE ) && ClassicMP_ShouldRunEpilogue() } void function GiveTitanToPlayer( entity player ) { - + if ( !IsValidPlayer( player ) || IsPrivateMatchSpectator( player ) ) + return + + PlayerEarnMeter_SetMode( player, eEarnMeterMode.DEFAULT ) + PlayerEarnMeter_AddEarnedAndOwned( player, 1.0, 1.0 ) } float function GetTimeLimit_ForGameMode() { string mode = GameRules_GetGameMode() string playlistString = "timelimit" + + if ( IsRoundBased() ) + playlistString = "roundtimelimit" - // default to 10 mins, because that seems reasonable return GetCurrentPlaylistVarFloat( playlistString, 10 ) } void function DialoguePlayNormal() { + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + int totalScore = GameMode_GetScoreLimit( GameRules_GetGameMode() ) int winningTeam int losingTeam - float diagIntervel = 71 // play a faction dailogue every 70 + 1s to prevent play together with winner dialogue + float diagInterval = 91 - while( GetGameState() == eGameState.Playing ) + while( GamePlaying() ) { - wait diagIntervel - if( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) ) + wait diagInterval + + if ( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) ) { winningTeam = TEAM_IMC losingTeam = TEAM_MILITIA } - if( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) ) + + if ( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) ) { winningTeam = TEAM_MILITIA losingTeam = TEAM_IMC } - if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 ) + + if ( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 ) { PlayFactionDialogueToTeam( "scoring_winningLarge", winningTeam ) PlayFactionDialogueToTeam( "scoring_losingLarge", losingTeam ) } - else if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 ) + + else if ( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 ) { PlayFactionDialogueToTeam( "scoring_winningClose", winningTeam ) PlayFactionDialogueToTeam( "scoring_losingClose", losingTeam ) } - else if( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) ) + + else if ( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) ) { continue } + else { PlayFactionDialogueToTeam( "scoring_winning", winningTeam ) @@ -1193,36 +1271,42 @@ void function DialoguePlayWinnerDetermined() int winningTeam int losingTeam - if( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) ) + if ( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) ) { winningTeam = TEAM_IMC losingTeam = TEAM_MILITIA } - if( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) ) + + if ( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) ) { winningTeam = TEAM_MILITIA losingTeam = TEAM_IMC } - if( IsRoundBased() ) // check for round based modes + + if ( IsRoundBased() ) { - if( GameRules_GetTeamScore( winningTeam ) != GameMode_GetRoundScoreLimit( GAMETYPE ) ) // no winner dialogue till game really ends + if ( GameRules_GetTeamScore( winningTeam ) != GameMode_GetRoundScoreLimit( GAMETYPE ) ) return } - if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 ) + + if ( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 ) { PlayFactionDialogueToTeam( "scoring_wonMercy", winningTeam ) PlayFactionDialogueToTeam( "scoring_lostMercy", losingTeam ) } - else if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 ) + + else if ( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 ) { PlayFactionDialogueToTeam( "scoring_wonClose", winningTeam ) PlayFactionDialogueToTeam( "scoring_lostClose", losingTeam ) } - else if( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) ) + + else if ( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) ) { PlayFactionDialogueToTeam( "scoring_tied", winningTeam ) PlayFactionDialogueToTeam( "scoring_tied", losingTeam ) } + else { PlayFactionDialogueToTeam( "scoring_won", winningTeam ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index 6f0641cc7..406b2cafa 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -22,7 +22,10 @@ void function Score_Init() { SvXP_Init() AddCallback_OnClientConnected( InitPlayerForScoreEvents ) + AddCallback_OnPlayerAssist( TitanAssistedKill ) + ScoreEvent_SetDisplayType( GetScoreEvent( "KillingSpree" ), eEventDisplayType.GAMEMODE | eEventDisplayType.MEDAL | eEventDisplayType.CALLINGCARD ) + ScoreEvent_SetDisplayType( GetScoreEvent( "Rampage" ), eEventDisplayType.GAMEMODE | eEventDisplayType.MEDAL | eEventDisplayType.CALLINGCARD ) } void function InitPlayerForScoreEvents( entity player ) @@ -40,13 +43,13 @@ void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity { ScoreEvent event = GetScoreEvent( scoreEventName ) - if ( !event.enabled || !IsValid( targetPlayer ) || !targetPlayer.IsPlayer() ) + if ( !event.enabled || !IsValidPlayer( targetPlayer ) ) return var associatedHandle = 0 if ( associatedEnt != null ) associatedHandle = associatedEnt.GetEncodedEHandle() - + if ( pointValueOverride != -1 ) event.pointValue = pointValueOverride @@ -55,7 +58,21 @@ void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity float earnValue = event.earnMeterEarnValue * scale float ownValue = event.earnMeterOwnValue * scale + if ( !PlayerEarnMeter_Enabled() && !targetPlayer.IsTitan() ) // Don't show earning points if earn meter is not enabled and player is not a special case of being a titan + { + earnValue = 0.0 + ownValue = 0.0 + } + + // Both checks below are mostly a visual fix because the score medals would still show the adds into the total value + if ( PlayerEarnMeter_GetPilotOverdriveEnum() == ePilotOverdrive.Disabled ) + earnValue = 0.0 + + if ( PlayerEarnMeter_GetPilotOverdriveEnum() == ePilotOverdrive.Only ) + ownValue = 0.0 + PlayerEarnMeter_AddEarnedAndOwned( targetPlayer, earnValue * scale, ownValue * scale ) + SharedEarnMeter_AddEarnedAndOwned( targetPlayer, earnValue, ownValue ) // PlayerEarnMeter_AddEarnedAndOwned handles this scaling by itself, we just need to do this for the visual stuff float pilotScaleVar = ( expect string ( GetCurrentPlaylistVarOrUseValue( "earn_meter_pilot_multiplier", "1" ) ) ).tofloat() @@ -63,8 +80,16 @@ void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity if ( targetPlayer.IsTitan() ) { - earnValue *= titanScaleVar - ownValue *= titanScaleVar + if ( targetPlayer.GetPlayerNetInt( EARNMETER_MODE ) == eEarnMeterMode.CORE_ACTIVE ) // While core is active, Titans can't gain meter + { + earnValue = 0.0 + ownValue = 0.0 + } + else + { + earnValue *= titanScaleVar + ownValue *= titanScaleVar + } } else { @@ -72,7 +97,7 @@ void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity ownValue *= pilotScaleVar } - Remote_CallFunction_NonReplay( targetPlayer, "ServerCallback_ScoreEvent", event.eventId, event.pointValue, event.displayType, associatedHandle, ownValue, earnValue ) + Remote_CallFunction_NonReplay( targetPlayer, "ServerCallback_ScoreEvent", event.eventId, event.pointValue, event.displayType, associatedHandle, earnValue, ownValue ) if ( event.displayType & eEventDisplayType.CALLINGCARD ) // callingcardevents are shown to all players { @@ -150,9 +175,9 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag // untimed killstreaks attacker.s.currentKillstreak++ if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT ) - AddPlayerScore( attacker, "KillingSpree" ) + AddPlayerScore( attacker, "KillingSpree", attacker ) else if ( attacker.s.currentKillstreak == RAMPAGE_KILL_REQUIREMENT ) - AddPlayerScore( attacker, "Rampage" ) + AddPlayerScore( attacker, "Rampage", attacker ) // increment untimed killstreaks against specific players if ( !( victim in attacker.p.playerKillStreaks ) ) @@ -204,21 +229,19 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage if ( attacker.IsTitan() ) { - if( victim.GetBossPlayer() || victim.IsPlayer() ) // to confirm this is a pet titan or player titan + if ( victim.GetBossPlayer() || victim.IsPlayer() ) // to confirm this is a pet titan or player titan AddPlayerScore( attacker, "TitanKillTitan", attacker ) // this will show the "Titan Kill" callsign event else AddPlayerScore( attacker, "TitanKillTitan" ) } else { - if( victim.GetBossPlayer() || victim.IsPlayer() ) + KilledPlayerTitanDialogue( attacker, victim ) + if ( victim.GetBossPlayer() || victim.IsPlayer() ) AddPlayerScore( attacker, "KillTitan", attacker ) else AddPlayerScore( attacker, "KillTitan" ) } - - if( !victim.IsNPC() ) // don't let killing a npc titan plays dialogue - KilledPlayerTitanDialogue( attacker, victim ) } void function TitanAssistedKill( entity attacker, entity victim ) @@ -232,16 +255,19 @@ void function TitanAssistedKill( entity attacker, entity victim ) void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageInfo ) { + if ( !attacker.IsPlayer() ) + return + + if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT ) + AddPlayerScore( attacker, "NPCHeadshot" ) + try { // have to trycatch this because marvins will crash on kill if we dont AddPlayerScore( attacker, ScoreEventForNPCKilled( victim, damageInfo ), victim ) } catch ( ex ) {} - - if ( !attacker.IsPlayer() ) - return - + // mayhem/onslaught (timed killstreaks vs AI) // reset before checking @@ -279,6 +305,7 @@ void function ScoreEvent_MatchComplete( int winningTeam ) { AddPlayerScore( player, "MatchComplete" ) SetPlayerChallengeMatchComplete( player ) + if ( player.GetTeam() == winningTeam ) { AddPlayerScore( player, "MatchVictory" ) @@ -311,7 +338,7 @@ void function ScoreEvent_SetupEarnMeterValuesForMixedModes() // mixed modes in t { // todo needs earn/overdrive values // player-controlled stuff - ScoreEvent_SetEarnMeterValues( "KillPilot", 0.07, 0.15, 0.33 ) // 5% for titan cores + ScoreEvent_SetEarnMeterValues( "KillPilot", 0.07, 0.15, 0.33 ) ScoreEvent_SetEarnMeterValues( "KillTitan", 0.0, 0.15 ) ScoreEvent_SetEarnMeterValues( "TitanKillTitan", 0.0, 0.0 ) // unsure ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.35 ) // this actually just doesn't have overdrive in vanilla even @@ -335,17 +362,13 @@ void function ScoreEvent_SetupEarnMeterValuesForTitanModes() // faction dialogue void function KilledPlayerTitanDialogue( entity attacker, entity victim ) { - if( !attacker.IsPlayer() ) + if ( !IsValidPlayer( attacker ) ) return - entity titan - if ( victim.IsTitan() ) - titan = victim - - if( !IsValid( titan ) ) + + if ( !IsValid( victim ) || !victim.IsTitan() ) return - string titanCharacterName = GetTitanCharacterName( titan ) - - switch( titanCharacterName ) + + switch( GetTitanCharacterName( victim ) ) { case "ion": PlayFactionDialogueToPlayer( "kc_pilotkillIon", attacker ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut index 510a9b7e0..21d0a58e4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut @@ -2,7 +2,6 @@ global function Spectator_Init // stuff called by _base_gametype_mp and such global function InitialisePrivateMatchSpectatorPlayer -global function PlayerBecomesSpectator global function RespawnPrivateMatchSpectator // custom spectator state functions @@ -92,22 +91,54 @@ void function RespawnPrivateMatchSpectator( entity player ) void function PlayerBecomesSpectator( entity player ) { - player.StopPhysics() + player.EndSignal( "OnDestroy" ) + + WaittillGameStateOrHigher( eGameState.Prematch ) + + if ( IsPrivateMatchSpectator( player ) ) + { + entity intermissionCam = GetEntArrayByClass_Expensive( "info_intermission" )[ 0 ] + DoRespawnPlayer( player, null ) + TakeAllPassives( player ) + TakeAllWeapons( player ) + player.SetPlayerSettingsWithMods( "spectator", [] ) + player.StopPhysics() + player.SetPhysics( MOVETYPE_NOCLIP ) + player.SetAimAssistAllowed( false ) + player.MakeInvisible() + NPC_NoTarget( player ) + HideName( player ) + PlayerEarnMeter_SetMode( player, eEarnMeterMode.DISABLED ) + player.Minimap_Hide( TEAM_MILITIA, null ) + player.Minimap_Hide( TEAM_IMC, null ) + player.SetInvulnerable() + AddCinematicFlag( player, CE_FLAG_HIDE_MAIN_HUD ) + if( IsValid( intermissionCam ) ) + { + player.SetOrigin( intermissionCam.GetOrigin() ) + player.SetAngles( intermissionCam.GetAngles() ) + } + + return + } + player.EndSignal( "OnRespawned" ) - player.EndSignal( "OnDestroy" ) player.EndSignal( "PlayerRespawnStarted" ) OnThreadEnd( function() : ( player ) { if ( IsValid( player ) ) + { player.StopObserverMode() + HACKCleanupStaticObserverStuff( player ) + } }) // keeps track of the most recent func this player has completed // this is to ensure that custom spectator funcs are only run once per player even before being cleared int funcIndex = 0 - + WaitFrame() while ( true ) { SpectatorFunc nextSpectatorFunc = file.defaultSpectatorFunc @@ -128,6 +159,9 @@ void function PlayerBecomesSpectator( entity player ) void function SpectatorFunc_Default( entity player ) { + player.EndSignal( "OnRespawned" ) + player.EndSignal( "OnDestroy" ) + svGlobal.levelEnt.EndSignal( "SpectatorFuncChanged" ) int targetIndex @@ -138,7 +172,7 @@ void function SpectatorFunc_Default( entity player ) array targets targets.extend( file.staticSpecCams ) - if ( IsFFAGame() ) + if ( IsFFAGame() || IsPrivateMatchSpectator( player ) ) targets.extend( GetPlayerArray_Alive() ) else targets.extend( GetPlayerArrayOfTeam_Alive( player.GetTeam() ) ) @@ -160,6 +194,7 @@ void function SpectatorFunc_Default( entity player ) entity target = targets[ targetIndex ] + player.ClearReplayDelay() player.StopObserverMode() if ( player.IsWatchingSpecReplay() ) player.SetSpecReplayDelay( 0.0 ) // clear spectator replay @@ -170,9 +205,7 @@ void function SpectatorFunc_Default( entity player ) { player.SetObserverTarget( target ) player.StartObserverMode( OBS_MODE_CHASE ) - // the delay of 0.1 seems to fix the spec_mode command not working - // when using the keybind - player.SetSpecReplayDelay( 0.1 ) + player.SetSpecReplayDelay( 0.1 ) // Spectators uses the Replay Buffer to watch others, so it can't be Realtime } catch ( ex ) { } } @@ -180,7 +213,11 @@ void function SpectatorFunc_Default( entity player ) { player.SetObserverModeStaticPosition( target.GetOrigin() ) player.SetObserverModeStaticAngles( target.GetAngles() ) - player.StartObserverMode( OBS_MODE_STATIC ) + + if ( IsPrivateMatchSpectator( player ) ) + player.StartObserverMode( OBS_MODE_ROAMING ) + else + player.StartObserverMode( OBS_MODE_STATIC ) } } @@ -191,7 +228,7 @@ void function SpectatorFunc_Default( entity player ) bool function ClientCommandCallback_spec_next( entity player, array args ) { - if ( player.GetObserverMode() == OBS_MODE_CHASE || player.GetObserverMode() == OBS_MODE_STATIC || player.GetObserverMode() == OBS_MODE_IN_EYE ) + if ( player.GetObserverMode() == OBS_MODE_CHASE || player.GetObserverMode() == OBS_MODE_STATIC || player.GetObserverMode() == OBS_MODE_IN_EYE || player.GetObserverMode() == OBS_MODE_ROAMING ) player.Signal( "ObserverTargetChanged", { next = true } ) return true @@ -199,7 +236,7 @@ bool function ClientCommandCallback_spec_next( entity player, array args bool function ClientCommandCallback_spec_prev( entity player, array args ) { - if ( player.GetObserverMode() == OBS_MODE_CHASE || player.GetObserverMode() == OBS_MODE_STATIC || player.GetObserverMode() == OBS_MODE_IN_EYE ) + if ( player.GetObserverMode() == OBS_MODE_CHASE || player.GetObserverMode() == OBS_MODE_STATIC || player.GetObserverMode() == OBS_MODE_IN_EYE || player.GetObserverMode() == OBS_MODE_ROAMING ) player.Signal( "ObserverTargetChanged", { next = false } ) return true @@ -218,9 +255,6 @@ bool function ClientCommandCallback_spec_mode( entity player, array args else if ( player.GetObserverMode() == OBS_MODE_IN_EYE ) { // set to third person spectate - - // the delay of 0.1 seems to fix the spec_mode command not working - // when using the keybind player.SetSpecReplayDelay( 0.1 ) player.StartObserverMode( OBS_MODE_CHASE ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 84b09ec8d..c0ff70208 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -582,10 +582,9 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo ) // totalAssists // assistsTotal ( weapon_kill_stats ) - // note: eww table alreadyAssisted // titans store their recentDamageHistory in the soul - entity assistVictim = ( victim.IsTitan() && IsValid( victim.GetTitanSoul() ) ) ? victim.GetTitanSoul() : victim + entity assistVictim = ( victim.IsTitan() && IsValid( victim.GetTitanSoul() ) ) ? victim.GetTitanSoul() : victim foreach( DamageHistoryStruct attackerInfo in assistVictim.e.recentDamageHistory ) { if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == assistVictim ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut index 91b178404..139ef28de 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut @@ -3,6 +3,7 @@ global function SetupLiveFireMaps // live fire maps don't support alot of things like intros and titans, this makes sure those things are disabled void function SetupLiveFireMaps() { + FlagSet( "LevelHasRoof" ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) ClassicMP_SetLevelIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) // ClassicMP_ForceDisableEpilogue( true ) // don't do this because evac handles this now diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut index 8b2a40605..143a9e9ae 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut @@ -25,6 +25,12 @@ void function CodeCallback_MapInit() // there are some really busted titan startspawns that are on the fucking other side of the map from where they should be, so we remove them AddSpawnCallback( "info_spawnpoint_titan_start", TrimBadTitanStartSpawns ) AddSpawnCallback( "sky_camera", FixSkycamFog ) + + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() + } void function FixBatterySpawns( entity spawn ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city_fd.nut index 37b891699..a16819424 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city_fd.nut @@ -1 +1,384 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + AddCallback_RegisterCustomFDContent( RegisterCustomFDContent ) + PlaceFDShop( < -913, 3933, 320 >, < 0, -15, 0 > ) + SetFDDropshipSpawn( < -331, 3791, 141 >, < 0, -180, 0 > ) + SetFDGroundSpawn( < -644, 4469, 318 >, < 0, -145, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeCloakDrone" ) + AddWaveAnnouncement( "fd_soonNukeTitans" ) + AddWaveAnnouncement( "fd_waveTypeTitanMortar" ) + AddWaveAnnouncement( "fd_incReaperClump" ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_Announce( wave1, "MortarSpectre", 0.0 ) + if( RandomInt( 100 ) >= 50 ) + { + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1329, 4456, 141 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2305, 2042, 128 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2464, 3354, 129 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 895, 2330, 122 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1485, 3100, 200 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1738, 2588, 56 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 3750, -2068, 200 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 2863, -1938, 200 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1529, -1644, 128 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 3494, -1511, 200 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2874, -1148, 200 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 3359, -2836, 200 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2129, -959, 120 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 603, -233, 112 >, 0.0, "", 1.0, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -593, -268, 128 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -513, -900, 32 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 97, -2104, 16 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 277, -926, 128 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 1287, -109, 128 >, 90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 28, 454, 122 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -1392, 162, 128 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -3055, -191, 98 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -3710, 557, 168 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -3645, 1859, 120>, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2642, 1017, 120 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -4376, 1276, 168 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -4373, 2237, 40 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -4990, 345, 128 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -4386, 4153, 51 >, -15, "" ) + } + else + { + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 3750, -2068, 200 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 2863, -1938, 200 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1529, -1644, 128 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 3494, -1511, 200 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2874, -1148, 200 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 3359, -2836, 200 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2129, -959, 120 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -3055, -191, 98 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -3710, 557, 168 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -3645, 1859, 120>, 0.0, "", 1.0, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2642, 1017, 120 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -4376, 1276, 168 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -4373, 2237, 40 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -4990, 345, 128 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -4386, 4153, 51 >, -15, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1329, 4456, 141 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2305, 2042, 128 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2464, 3354, 129 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 895, 2330, 122 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1485, 3100, 200 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1738, 2588, 56 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 603, -233, 112 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -593, -268, 128 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -513, -900, 32 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 97, -2104, 16 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 277, -926, 128 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 1287, -109, 128 >, 90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 28, 454, 122 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -1392, 162, 128 >, 0.0, "" ) + } + + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 984, 1687, 135 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 330, 1195, 104 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -393, 1047, 104 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 516, 2054, 137 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -759, 1753, 128 >, 0.0, "" ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_TitanSpawn( wave2, "Tone", < 2445, 2661, 56 >, 180, "", 1.5, "fd_waveTypeTitanReg" ) + WaveSpawn_TitanSpawn( wave2, "Tone", < -881, 692, 120 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -2805, 385, 176 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < 2058, -103, 120 >, 130, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < -3985, -268, 168 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 1466, 3266, 200 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 672, -535, 112 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1680, -234, 128 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -3923, 2719, 120 >, -105, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < -1541, 794, 2580 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 2445, 2661, 2580 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 1669, -1055, 2580 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 1311, -197, 128 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < 2445, 2661, 56 >, 180, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -3765, -676, 168 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < -3985, -268, 168 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -2092, 1463, 119 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < -881, 692, 120 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -428, 1298, 104 >, -45, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1288, 217, 128 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < -1541, 794, 2580 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 1669, -1055, 2580 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < -881, 692, 2580 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -2669, -933, 97 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3227, -672, 99 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -4085, -147, 168 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "ArcTitan", < -881, 692, 120 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -4689, 280, 136 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1412, 122, 128 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2105, 1, 120 >, 130, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < -1541, 794, 2580 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 1669, -1055, 2580 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 1490, 3130, 2580 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -1699, -390, 128 >, 90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3738, -1022, 213 >, 125, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 495, 1588, 128 >, 45, "", 1.4 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2206, 0, 120 >, 180, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1490, 3130, 200 >, 0.0, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "Ion", < 3554, 926, 171 >, 180, "", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "Ion", < 1581, -2287, 136 >, 90, "", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -2114,- 673, 17 >, 90, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3554, 926, 171 >, 180, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 1581, -2287, 136 >, 90, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -2114,- 673, 17 >, 90, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 905, -2813, 51 >, 131, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -1295, -289, 128 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -3765, -644, 168 >, 131, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3738, -1022, 213 >, 125, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 0 ) + + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3448, 354, 160 >, 135, "", 5.0, "fd_waveTypeTitanNuke" ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3742, -546, 196 >, 180, "", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 1734, 432, 120 >, 180, "", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 2351, 3434, 141 >, 180, "", 10.0 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -1253, -291, 128 >, 90, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 2766, 1723, 120 >, 180, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 2035, 3927, 129 >, 180, "", 2.0 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3567, -1036, 200 >, 180, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3537, -1442, 200 >, 135, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 2855, -2081, 200 >, 135, "", 5.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 0 ) + + WaveSpawn_TitanSpawn( wave3, "Nuke", < -1246, 186, 128 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -2987, -703, 92 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -3911, -271, 168 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -4492, -187, 168 >, 90, "", 10.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -4183, -632, 168 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -2562, -1210, 105 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 2121, -3630, 192 >, 90, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3667, 1015, 171 >, 180, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 2578, 3266, 132 >, 180, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 0 ) + + WaveSpawn_TitanSpawn( wave3, "Scorch", < -2892, -1269, 107 >, 90, "", 0.6, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -2621, -1261, 107 >, 90, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -3184, -1291, 115 >, 90, "", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 0 ) + + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3566, -2058, 200 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2858, -2095, 200 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3791, -993, 210 >, 180, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3666, -1772, 200 >, 90, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2862, -1274, 201 >, 90, "", 0.3 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3432, -1335, 200 >, 90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3954, -2189, 199 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3465, -1828, 201 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2601, -2129, 200 >, 90, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 1729, -2497, 128 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3542, -1556, 202 >, 90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3649, -1110, 201 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2875, -1728, 200 >, 90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 1508, -2593, 128 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2142, -2629, 193 >, 90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 3721, -666, 194 >, 90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3386, -633, 196 >, 90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3305, -1001, 200 >, 90, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3643, -2083, 200 >, 90, "", 3.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3537, -1321, 200 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3548, -1793, 202 >, 180, "" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3554, 926, 171 >, 180, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1581, -2287, 136 >, 90, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -2114,- 673, 17 >, 90, "", 1.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3567, -1036, 200 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 1729, -2509, 128 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -3366, -652, 123 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 1714, 4170, 129 >, 180, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 308, 935, 103 >, 90, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3941, -1996, 200 >, 180, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 1 ) + + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1263, -408, 130 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -881, 692, 120 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -2445, 2169, 128 >, 75, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1873, 3508, 141 >, 45, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -3366, -652, 123 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 1714, 4170, 129 >, 180, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 1729, -2509, 128 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3567, -1036, 200 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3537, -1442, 200 >, 135, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 2855, -2081, 200 >, 135, "", 5.0 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 1288, -154, 128 >, 90, "", 0.8 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -2661, -579, 96 >, 90, "", 0.8 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 2687, 2571, 56 >, 180, "", 0.5 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_TitanSpawn( wave4, "Mortar", < -5017, 681, 128 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -3725, -521, 168 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 975, -2801, 58 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 2121, -3630, 192 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3667, 1015, 171 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 2578, 3266, 132 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -490, -719, 19 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < 2143, -170, 120 >, 135, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -583, -332, 128 >, 90, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 495, 1596, 127 >, 75, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.8, "fd_waveTypeReapers", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.6, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.8, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4049, -239, 177 >, 90, "", 1.2, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 1.0, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -3760, -564, 168 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.8, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4049, -239, 177 >, 90, "", 1.0, "", 300.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -4185, -564, 168 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3554, 926, 171 >, 180, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.8, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4049, -239, 177 >, 90, "", 1.0, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.8, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -3346, -660, 118 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 1.2, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4049, -239, 177 >, 90, "", 0.8, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1581, -2287, 136 >, 90, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3567, -1036, 200 >, 180, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 1729, -2509, 128 >, 90, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 1714, 4170, 129 >, 180, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.8, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.8, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 1.0, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -4890, 493, 128 >, 90, "", 0.8, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.6, "", 300.0 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -2981, -730, 92 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.4, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 1.0, "", 300.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -4511, -81, 168 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -4925, 245, 127 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.8, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4890, 493, 128 >, 90, "", 0.5, "", 300.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4049, -239, 177 >, 90, "", 0.8, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 1.0, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -2952, -667, 93 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4049, -239, 177 >, 90, "", 0.4, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 1.0, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -3977, -406, 177 >, 135, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -4049, -239, 177 >, 90, "", 0.6, "", 300.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -2114,- 673, 17 >, 90, "", 1.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -1699, -390, 128 >, 90, "", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 3738, -1022, 213 >, 125, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 495, 1588, 128 >, 45, "", 1.4, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 2206, 0, 120 >, 180, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < -2692, -623, 93 >, 180, "", 0.8, "fd_incTitansNukeClump" ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -3130, -758, 98 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -2911, -949, 98 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -2667, -1124, 100 >, 180, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -3105, -657, 96 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.5, "", 440.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2798, -981, 97 >, 90, "", 0.6, "", 440.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -3285, -1340, 114 >, 135, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -2184, -772, 33 >, 90, "" ) + + WaveSpawnEvents.append( wave5 ) +} + +void function RegisterCustomFDContent() +{ + AddFDCustomTitanStart( < -2221, 5230, 128 >, < 0, -105, 0 > ) + AddFDCustomTitanStart( < -3058, 4741, 102 >, < 0, -15, 0 > ) + + //Add those OOB because some "smart" fellas wont stop climbing these places to snipe with Charge Rifle/Archer and do nothing else + AddOutOfBoundsTriggerWithParams( < -75, 1146, 1360 >, 160, 320 ) //Center Radio Tower + AddOutOfBoundsTriggerWithParams( < -1720, 1243, 1360 >, 80, 256 ) //Sea Food building Antenna +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal.nut index 2e35417fe..7892f78c5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal.nut @@ -4,6 +4,12 @@ void function CodeCallback_MapInit() { // there are some really busted titan startspawns that are on the fucking other side of the map from where they should be, so we remove them AddSpawnCallback( "info_spawnpoint_titan_start", TrimBadTitanStartSpawns ) + + AddSpawnCallback( "sky_camera", FixSkycamFog ) + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() } void function TrimBadTitanStartSpawns( entity spawn ) @@ -16,4 +22,10 @@ void function TrimBadTitanStartSpawns( entity spawn ) if ( Distance2D( spawn.GetOrigin(), comparisonOrigin ) >= 1000.0) spawn.Destroy() +} + +void function FixSkycamFog( entity skycam ) +{ + if ( skycam.GetTargetName() == "skybox_cam_level" ) + skycam.kv.useworldfog = 1 } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal_fd.nut index 37b891699..09ea36021 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_black_water_canal_fd.nut @@ -1 +1,348 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + PlaceFDShop( < 3314, -846, -256 >, < 0, -45, 0 > ) + SetFDDropshipSpawn( < 1664, 404, 0 >, < 0, -90, 0 > ) + SetFDGroundSpawn( < 1869, -938, -63 >, < 0, 90, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeTitanReg" ) + AddWaveAnnouncement( "fd_introMedium" ) + AddWaveAnnouncement( "fd_waveComboNukeMortar" ) + AddWaveAnnouncement( "fd_introHard" ) + + AddOutOfBoundsTriggerWithParams( < 1935, -752, 1382 >, 160, 512 ) //Add OOB because some "smart" fellas wont stop climbing that water tank tower to snipe with Charge Rifle/Archer and do nothing else + AddFDCustomProp( $"models/containers/container_medium_tanks_blue.mdl", < 184, 120, -8 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/containers/container_medium_tanks_blue.mdl", < 553, -427, -8 >, < 0, 0, 0 > ) + AddFDCustomTitanStart( < 3668, -174, -347 >, < 0, 135, 0 > ) + AddFDCustomTitanStart( < 432, -1397, 0 >, < 0, 45, 0 > ) + + /* + AddStationaryAIPosition( < -295, 3262, -128>, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < 1844, 4549, -130>, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < 3790, -2236, -128>, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < 485, 2651, -241>, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + */ + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 386, 2347, -257 >, 0.0, "", 1.4, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2465, 2750, -224 >, 0.0, "", 1.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1351, 2342, -257 >, 0.0, "", 1.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 883, 1423, 6 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2718, -2737, -150 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3792, -2984, -128 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4077, -3882, -373 >, 0.0, "", 1.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4196, -4507, -385 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -648, -1449, 0 >, 0.0, "", 1.8 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -774, 2019, -123 >, 0.0, "", 1.6, "fd_waveTypeMortarSpectre" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -602, -1941, -100 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1370, 2340, -256 >, 0.0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1242, -1637, -147 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1805, 163, -384 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 464, -2049, 0 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1132, 447, -369 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2614, -3115, -179 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1234, 694, -359 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -22, -1934, 96 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1289, -2721, -192 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 2416, 2803, -222 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2021, 2214, -178 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -511, 933, 2 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1748, 1927, -88 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave1, "Northstar", < -1559, 134, -384 >, -21, "" ) + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_TitanSpawn( wave2, "Tone", < -2224, 1581, -384 >, -24, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < -1632, 1873, -349 >, -175, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < -2143, 2096, -384 >, -63, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -317, 4073, -256 >, -121, "", 1.0, "fd_incReaperClump" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -962, 3699, -256 >, -51, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -664, 4864, -252 >, -90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1017, 4442, -257 >, -139, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 849, 3811, -257 >, -2, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1486, 4156, -257 >, -83, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1901, 130, -366 >, -12, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -2267, 1816, -384 >, -39, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -803, -1142, -237 >, 93, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 2232, 2681, -254 >, 0.0, "", 0.5, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 384, 2359, -257 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 908, 1411, 6 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 0 ) + + WaveSpawn_TitanSpawn( wave2, "Ion", < -887, -2015, -121 >, 92, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -403, -1996, -64 >, 175, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < -1314, -1643, -142 >, 56, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1001, -2726, -64 >, 94, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < -1436, -2592, -73 >, 20, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1351, 242, -384 >, -50, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4599, -4396, -385 >, 100, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1030, 340, -368 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4014, -3870, -365 >, 44, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 1317, -2732, -192 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3935, -4654, -380 >, 63, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 3600, -3070, -128 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 776, 3047, -241 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 0 ) + + WaveSpawn_TitanSpawn( wave2, "Ronin", < -1256, 257, -384 >, -53, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1928, 85, -362 >, -1, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 3600, -3070, -128>, 0.0, "", 1.5, "fd_waveTypeTicks" ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < -2080, 1907, -384 >, -61, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < -2163, 2999, -384 >, -79, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1049, 634, -346 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1450, 8, -384 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < -1271, -1672, -141 >, 63, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -691, -1929, -114 >, 130, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -667, -1450, 0 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < -940, -2319, -97 >, 93, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1139, -1621, -156 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -1132, -2205, -123 >, 0.0, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 1295, -2779, -190 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4610, -4392, -385 >, 113, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 4014, -3919, -364>, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 4139, -4615, -385>, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 1355, 2328, -257 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 1591, 2736, -256 >, 0.0, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "Sniper", < -1445, 156, -384 >, -23, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -1288, 1021, -341 >, -75, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -968, -1689, -155 >, 90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -1425, -2653, -71 >, 64, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -2386, 1491, -384 >, -72, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1994, 1687, -384 >, -54, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -2227, 692, -365 >, -50, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1577, 1895, -343 >, -136, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -572, -1938, -97 >, 165, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1198, -2422, -104 >, 79, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1182, -2522, -101 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", < -946, 2488, -123 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 503, 2283, -257 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2087, 2557, -256 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_TitanSpawn( wave3, "Scorch", < -1445, 156, -384 >, -23, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < -1288, 1021, -341 >, -75, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < -968, -1689, -155 >, 90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < -1425, -2653, -71 >, 64, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < -2386, 1491, -384 >, -72, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -572, -1938, -97 >, 165, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1198, -2422, -104 >, 79, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1182, -2522, -101 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1577, 1895, -343 >, -136, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -2227, 692, -365 >, -50, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1994, 1687, -384 >, -54, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", < 3454, -2823, -175 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -1004, 254, -374 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -1129, -256, -384 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -1803, 171, -384 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_TitanSpawn( wave3, "Ronin", < -761, 4563, -260 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < -477, 4738, -256 >, -91, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < -1035, 4759, -256 >, -92, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -2183, 1800, -384 >, -45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -1629, 1847, -348 >, -145, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1513, 4552, -255 >, -51, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -91, 4352, -260 >, 180, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1724, 2582, -360 >, -108, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -2382, 1396, -384 >, -72, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_Announce( wave3, "PreNukeTitan", 0.0 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < 1163, -4728, -200 >, 45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 1111, -5127, -188 >, 45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 776, -4803, -192 >, 45, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 3782, -5270, -385 >, 64, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 4336, -4715, -385 >, 82, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3896, -4403, -359 >, 76, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 4667, -3768, -385 >, 121, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2110, -4748, -194 >, 71, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1519, -3988, -192 >, 0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", < 2294, 2786, -249 >, 0.0, "" ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 603, 2260, -257 >, 16, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -1445, 156, -384 >, -23, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -1229, -1677, -142 >, 65, "", 0.8, "fd_waveTypeTitanNuke" ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -1276, 949, -345 >, -71, "", 0.6 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -803, -2011, -116 >, 107, "", 0.4 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -1762, 1412, -365 >, -49, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -1139, 430, -372 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -410, -1932, -64 >, 0.0, "" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_TitanSpawn( wave4, "Tone", < -1041, 505, -353 >, -94, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -1189, -1453, -177 >, 60, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -2022, 1696, -384 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -1362, 1050, -347 >, -73, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -883, -1918, -133 >, 95, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -948, -2064, -119 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -2080, 1613, -384 >, -39, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -1128, -2315, -116 >, 80, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1028, 426, -359 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -572, -1999, -91 >, 130, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1118, -1876, -131 >, 77, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1851, 128, -374 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -987, -2036, -123 >, 91, "", 1.5, "fd_incTitansNukeClump" ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -2097, 458, -365 >, -31, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_TitanSpawn( wave4, "Scorch", < 4326, -4660, -381 >, 135, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 4076, -4940, -382 >, 135, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 970, 4457, -256 >, -135, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 593, 4903, -251 >, -90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -843, -2285, -90 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1178, -2009, -122 >, 90, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1855, 1651, -370 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < -1010, 4734, -260 >, -90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < -515, 4717, -260 >, -90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1855, 146, -373 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 1324, -5086, -186 >, -45, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 1000, -4711, -198 >, -45, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -809, -1143, -236 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2204, 1643, -382 >, -90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1688, 1905, -355 >, -90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_TitanSpawn( wave4, "Nuke", < 872, -4932, -200 >, 45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -819, 4933, -256 >, -90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1938, 231, -366 >, -20, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2232, 1641, -383 >, -25, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1286, -1639, -142 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1220, -1991, -120 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < 4509, -4418, -384 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < 637, 4923, -251 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -1023, -2245, -112 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -2091, 467, -364 >, 45, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -998, 4710, -257 >, -90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1058, -1014, -249 >, 0.0, "", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 4308, -4846, -384 >, 135, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1451, 92, -382 >, 0.0, "", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -538, 4830, -248 >, -90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -698, -104, -382 >, 0.0, "" ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3674, -5445, -384 >, -90, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2251, 2429, -382 >, 0, "", 0.6, "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2144, 3006, -382 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2080, 2655, -382 >, 0, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -2239, 2685, -381 >, 0, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4566, -4426, -384 >, 90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4630, -3787, -383 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 3913, -4263, -355 >, 90, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 4316, -4560, -385 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 941, 1328, 6 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 2356, -2651, -156 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_Announce( wave5, "Everything", 0.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -1265, -1658, -141 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -1962, 1510, -382 >, -45, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -863, -2221, -99 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -2399, 1343, -382 >, -45, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -920, -1329, -215 >, 90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1750, 1880, -361 >, -45, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -1198, -2339, -107 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -2195, 1876, -382 >, -45, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < -1768, 143, -383 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -2070, 456, -363 >, -45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1055, -2259, -112 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 897, -4927, -198 >, 45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1071, 4792, -256 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4585, -4410, -384 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 4619, -3710, -383 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 702, 4869, -256 >, -90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 286, 4965, -253 >, -90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 1279, -5194, -185 >, 45, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -311, 4097, -255 >, -90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4030, -4151, -363 >, 45, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 948, 4473, -255 >, 45, "", 1.5 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Ion", < -1196, 781, -350 >, -81, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < -1655, 1328, -359 >, -55, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -520, -1944, -95 >, 161, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -1218, -1638, -149 >, 62, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < -1352, 11, -384 >, -13, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1244, -1721, -135 >, 65, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1185, 852, -343 >, -83, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1662, 119, -383 >, 0, "", 0.8, "fd_waveComboNukeTrain" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -761, -1120, -238 >, 90, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1961, 1531, -382 >, -45, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1226, -1350, -187 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4550, -4410, -383 >, 135, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4406, -4621, -383 >, 135, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 544, 4922, -250 >, -90, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 259, 4846, -255 >, -90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4652, -3711, -384 >, 135, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4566, -3959, -384 >, 135, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 791, 4603, -255 >, -90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 280, 4666, -258 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1236, -5132, -186 >, 45, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 916, -4786, -198 >, 45, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1366, -4290, -199 >, 45, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1582, -4708, -187 >, 45, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1205, -4654, -199 >, 45, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -783, 3943, -255 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -544, 3978, -251 >, -90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -343, 3774, -254 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -954, 3758, -254 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -693, 3654, -252 >, -90, "" ) + + WaveSpawnEvents.append( wave5 ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02.nut index 0079d7e90..bca0d7c36 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02.nut @@ -3,6 +3,11 @@ global function CodeCallback_MapInit void function CodeCallback_MapInit() { AddCallback_EntitiesDidLoad( CreateEvacNodes ) + AddSpawnCallback( "sky_camera", FixSkycamFog ) + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() } void function CreateEvacNodes() @@ -16,4 +21,10 @@ void function CreateEvacNodes() AddEvacNode( CreateScriptRef( < -1035.991211, -671.114380, 824.180908 >, < 16.220453, -24.511070, 0 > ) ) SetEvacSpaceNode( GetEnt( "intro_spacenode" ) ) +} + +void function FixSkycamFog( entity skycam ) +{ + if ( skycam.GetTargetName() == "skybox_cam_level" ) + skycam.kv.useworldfog = 1 } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02_fd.nut index 37b891699..23b286b6f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_colony02_fd.nut @@ -1 +1,554 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + useCustomFDLoad = true + AddCallback_RegisterCustomFDContent( RegisterCustomFDContent ) + PlaceFDShop( < 1179, 561, 60 > ) + SetFDDropshipSpawn( < 830, -194, 112 >, < 0, 180, 0 > ) + SetFDGroundSpawn( < 1334, -273, 201 >, < 0, 90, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_soonNukeTitans" ) + AddWaveAnnouncement( "fd_waveTypeFlyers" ) + AddWaveAnnouncement( "fd_introMedium" ) + AddWaveAnnouncement( "fd_waveComboMultiMix" ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_SmokeWall( wave1, < -2318, -1783, 159 >, 0.3 ) + WaveSpawn_SmokeWall( wave1, < -1896, -3214, 160 >, 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "DropshipGrunt", < -3702, -2366, 121 >, 0.0, "", 1.0, "fd_waveTypeInfantry", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2951, -3326, 137 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2675, -2922, 224 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3666, -2825, 137 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "Reaper", < -1834, 3471, -13 >, -60, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "DropshipGrunt", < -2614, 3932, -135 >, -86, "", 1.0, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2026, 2598, 0 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1468, 4859, -39 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1899, 4559, -14 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "Reaper", < 2657, 4815, 27 >, -90, "", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -979, 1179, 16 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -461, 1457, 6 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -769, -805, 122 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1194, -578, 98 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1160, -2042, 244 >, 0.0, "", 0.5, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1487, -1875, 243 >, 0.0, "", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1875, 4550, -19 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 54, 3290, -48 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 387, 3142, -52 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -2717, -1600, 178 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -2575, -1874, 158 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 297, -2336, 254 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -4408, -1446, 262 >, 0, "", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -120, 5065, -59 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 182, 4734, -18 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 399, 2965, -54 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -26, 3275, -48 >, 0.0, "", 0.8 ) + WaveSpawn_TitanSpawn( wave1, "Ion", < -1981, 2989, -12 >, -43, "" ) + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_TitanSpawn( wave2, "Ion", < -1867, -2933, 160 >, 60, "", 1.5, "fd_waveTypeTitanReg" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3287, -3334, 135 >, 0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3327, -1678, 143 >, 0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -593, -685, 129 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -845, 971, 34 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "DropshipGrunt", < -1147, -681, 107 >, -93, "", 1.0, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_Announce( wave2, "PreNukeTitan", 0.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -2774, -3192, 183 >, 0.0, "", 0.3, "fd_waveTypeTicks" ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -2661, -1672, 164 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -3200, -2351, 137 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3287, -3334, 135 >, 0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < -3650, -2071, 119 >, 0, "", 0.6 ) + WaveSpawn_TitanSpawn( wave2, "Ronin", < -1892, -3463, 160 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "DropshipGrunt", < -3777, -2305, 106 >, -5, "", 1.0, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_Announce( wave2, "PreMortarTitan", 0.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_TitanSpawn( wave2, "Nuke", < 285, -2380, 258 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -192, -2409, 241 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -4270, -2113, 148 >, 0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -197, -2282, 221 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -402, -2006, 170 >, 0.0, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 922, -2220, 243 >, 90, "", 1.0, "fd_waveTypeReaperTicks" ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -4331, 156, 132 >, 0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -4584, -2727, 131 >, 0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -4635, -1772, 187 >, 0.0, "", 0.8 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -4486, -2772, 131 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Scorch", < -2820, -1801, 151 >, 0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < -2814, -3358, 159 >, 60, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Northstar", < -4269, -2819, 131 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -3226, -1638, 141 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -3708, -2145, 123 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1240, -1957, 243 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -1300, -2936, 203 >, 90, "", 0.5, "fd_waveComboNukeMortar" ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -2061, -3021, 171 >, 45, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -4436, -39, 144 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -4178, 1909, 190 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -2801, -1570, 185 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -2206, -939, 146 >, 0, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "Sniper", < 75, 5262, -59 >, -90.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < -206, 5486, -70 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 263, 5483, -12 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < -3717, 3239, 2560 >, 0.0, "", 1.5, "fd_waveTypeCloakDrone", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 2332, 4558, 34 >, -90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -1858, 6423, -104 >, -90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1601, 4971, -10 >, -90, "", 0.2, "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2029, 4709, 23 >, -90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1118, 3271, 1 >, 0, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1000, 3644, 11 >, 0, "", 0.8 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < -2563, 2956, -55 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -2196, 3600, -66 >, -45, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < -2884, 3580, -152 >, -35, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 3.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -1143, 3460, 8 >, 0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -182, 1865, 4 >, 75, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 467, 3264, -51 >, -100, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 299, -2440, 272 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -2274, 2186, 12 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2023, 4714, 23 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 1571, 4986, -13 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 942, 4508, 2560 >, 0.0, "", 3.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < -1968, 1751, 15 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 73, 5400, -59 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -4133, 2150, 186 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -3680, 5041, -40 >, 0, "", 0.5 ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1957, 1745, 15 >, 0, "", 0.5, "fd_incReaperClump" ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1157, 3358, 3 >, 0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -392, 1393, 7 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -846, 1228, 10 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < -1998, 3000, -13 >, -35, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -2260, 2742, -13 >, -35, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -1913, 3414, -13 >, -35, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 2023, 4714, 23 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 1571, 4986, -13 >, -90, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 1801, 4594, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 488, 3305, -51 >, -110, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 2811, 4636, 54 >, -90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -26, 3275, -48 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 346, 3190, -50 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -827, 1481, 5 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -2770, -1812, 158 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -220, -2390, 237 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 97, 4826, -38 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 97, 5386, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 2 ) + + WaveSpawn_TitanSpawn( wave4, "Legion", < -1998, 3000, -13 >, -35, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -2260, 2742, -13 >, -35, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -1913, 3414, -13 >, -35, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -1966, 2649, 1 >, 0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -1693, 3165, 3 >, 0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -4332, 74, 135 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -3573, 5198, -14 >, -45, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1825, 6377, -102 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -4215, 1997, 194 >, 0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -4037, 1280, 228 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -4122, 768, 205 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -4006, 5990, -162 >, -90.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -3118, 6392, -60 >, -90.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -1333, -2934, 202 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -2025, -2993, 169 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 287, -2327, 253 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -239, -2371, 232 >, 90, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_SmokeWall( wave5, < 2064, 4431, -4 >, 0.2 ) + WaveSpawn_SmokeWall( wave5, < 117, 4365, 13 >, 0.4 ) + WaveSpawn_SmokeWall( wave5, < -1503, 2655, 12 >, 0.6 ) + WaveSpawn_SmokeWall( wave5, < -2321, -1784, 159 >, 0.8 ) + WaveSpawn_SmokeWall( wave5, < -1905, -3238, 161 >, 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -182, 1865, 4 >, 75, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 299, -2440, 272 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "DropshipGrunt", < -1602, -907, 121 >, -5, "", 1.5, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave5, "DropshipGrunt", < -2614, 3932, -135 >, -86, "", 1.5, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < -461, 1432, 6 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < -655, -694, 126 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 75, 5262, -59 >, -90, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 288, -2361, 257 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2678, 4752, 36 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 1801, 4594, 2560 >, 0.0, "", 0.1, "fd_incCloakDroneClump", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_InfantrySpawn( wave5, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1207, -1974, 244 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1924, -2125, 286 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 1537, -2282, 2560 >, 0.0, "", 1.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -1998, 3000, -13 >, -35, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < -2739, -1805, 158 >, 0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -1319, -2979, 203 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 3188, 3720, 194 >, 180, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < -3753, -2485, 129 >, 0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -3297, -1772, 128 >, 0, "", 0.8, "fd_waveComboArcNuke" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1909, -3472, 160 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 287, -2327, 253 >, 90, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -239, -2371, 232 >, 90, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < -2448, -2597, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Legion", < 75, 5262, -59 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -206, 5486, -70 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 263, 5483, -12 >, -90, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -1825, 6377, -102 >, -90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -4215, 1997, 194 >, 0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "DropshipGrunt", < -3661, -2309, 121 >, -10, "", 2.5, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave5, "DropshipGrunt", < -38, 5420, -62 >, 0.0, "", 1.5, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 287, -2327, 253 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -239, -2371, 232 >, 90, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 1537, -2282, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1603, 4951, -14 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2015, 4716, 21 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 813, 7910, 128 >, -90, "droneFarmside", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1991, 2615, 1 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1672, 3122, 3 >, -50, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 488, 3305, -51 >, -110, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 2811, 4636, 54 >, -90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1976, 4717, 11 >, -90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2408, 4537, 40 >, -90, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 1801, 4594, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + + WaveSpawnEvents.append( wave5 ) +} + +void function RegisterCustomFDContent() +{ + array dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" ) + foreach ( entity dropshipSpawn in dropshipSpawns ) + dropshipSpawn.Destroy() + + array aiPositions = GetEntArrayByClass_Expensive( "info_target" ) + foreach ( entity position in aiPositions ) + if( position.HasKey( "editorclass" ) && position.kv.editorclass == "info_fd_ai_position" && expect string( position.kv.aiType ).tointeger() != eStationaryAIPositionTypes.LAUNCHER_REAPER ) + position.Destroy() + + AddFDCustomShipStart( < 1967, 1863, 660 >, < 0, -120, 0 >, TEAM_MILITIA ) + AddFDCustomShipStart( < 1180, 1863, 660 >, < 0, -90, 0 >, TEAM_MILITIA ) + AddFDCustomShipStart( < -4614, 3969, 1280 >, < 0, -45, 0 >, TEAM_IMC ) + AddFDCustomShipStart( < -3501, 4923, 1280 >, < 0, -45, 0 >, TEAM_IMC ) + + AddFDCustomTitanStart( < 1336, 3, 37 >, < 0, 90, 0 > ) + AddFDCustomTitanStart( < 2762, 1840, 72 >, < 0, 180, 0 > ) + + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < 1682, 2485, -8 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < 1672, 2366, -4 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white.mdl", < 1809, 2412, -8 >, < 0, -45, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white.mdl", < 1663, 2368, 90 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < 1793, 2507, 90 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < 1804, 2535, -8 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < 1410, 2501, 182 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < 1635, 2390, 182 >, < 0, 90, 0 > ) + + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < 2444, 1930, 16 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white.mdl", < 2444, 2033, 16 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < 2444, 1930, 114 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < 2444, 2033, 114 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < 2444, 1983, 212 >, < 0, 45, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < 2328, 2020, 4 >, < 0, 0, 0 > ) + + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white.mdl", < 1210, 3017, -5 >, < 0, -45, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < 1329, 3073, 5 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < 1210, 3021, 92 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < 1311, 3072, 102 >, < 0, 0, 0 > ) + + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -188, 4469, 6 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -310, 4469, 6 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -431, 4469, 6 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -432, 4469, 104 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -309, 4469, 104 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -188, 4469, 104 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -309, 4566, -5 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < -210, 4473, 203 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < -172, 4569, -5 >, < 0, 90, 0 > ) + + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -569, -1010, 159 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -569, -1137, 159 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -569, -1010, 257 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white.mdl", < -569, -1137, 257 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -573, -1072, 353 >, < 0, 90, 0 > ) + + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -1142, -1081, 159 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -1269, -1081, 159 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -1396, -1081, 159 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -1142, -978, 142 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -1269, -978, 142 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -1395, -978, 142 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -1142, -1081, 256 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -1269, -1081, 256 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_white_open.mdl", < -1395, -1081, 256 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -1269, -978, 238 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -1394, -978, 238 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -1164, -1084, 352 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < -1029, -1091, 156 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/containers/cargo_container_white_separate.mdl", < -1369, -1092, 352 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -1406, -868, 115 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_blue.mdl", < -1406, -868, 213 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -1132, -1201, 165 >, < 0, 90, 0 > ) + AddFDCustomProp( $"models/imc_base/cargo_container_imc_01_red.mdl", < -1132, -1201, 264 >, < 0, 90, 0 > ) + + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < 1307, 3816, 157 >, < 0, 180, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < 1181, 3686, 157 >, < 0, -90, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_curved_01.mdl", < 1173, 3738, 157 >, < 0, -90, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_curved_01.mdl", < 1258, 3554, 157 >, < 0, 0, 0 > ) + + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -503, 2807, 157 >, < 0, 160, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -666, 2727, 157 >, < 0, -110, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_curved_01.mdl", < -656, 2779, 157 >, < 0, -110, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_curved_01.mdl", < -639, 2577, 157 >, < 0, -20, 0 > ) + + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -1384, 917, 328 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -1270, 917, 328 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -1156, 917, 328 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -1324, 530, 328 >, < 0, 0, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -1211, 530, 328 >, < 0, 0, 0 > ) + + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -240, -888, 557 >, < 0, 250, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < -161, -1057, 557 >, < 0, -20, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_curved_01.mdl", < -212, -1044, 557 >, < 0, -20, 0 > ) + + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < 37, 3063, 233 >, < 0, 160, 0 > ) + AddFDCustomProp( $"models/barriers/sandbags_large_01.mdl", < 147, 3023, 233 >, < 0, 160, 0 > ) + + CreateColonyZipline( < 2061, 3294, 590 >, < 1716, 1508, 597 > ) + CreateColonyZipline( < 2061, 3294, 590 >, < 177, 2433, 676 > ) + CreateColonyZipline( < 152, 2377, 804 >, < -1510, 524, 650 > ) + CreateColonyZipline( < -1510, 524, 650 >, < -1728, -1878, 460 > ) + CreateColonyZipline( < 1059, -1708, 860 >, < -1136, -2008, 502 > ) + CreateColonyZipline( < -2921, 5036, 105 >, < -1500, 2791, 542 > ) + CreateColonyZipline( < -1510, 524, 650 >, < -4534, 1180, 563 > ) + + AddStationaryAIPosition(< -2478, 6083, -92 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -2783, 5964, -55 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -854, 6282, -134 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -524, 6548, -133 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -3707, 808, 122 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -4038, -2909, 136 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -4486, -2159, 164 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -3688, 1412, 125 >, eStationaryAIPositionTypes.MORTAR_TITAN) + + AddStationaryAIPosition(< 1430, -2443, 526 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< -1410, 717, 328 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< 2334, 5538, 55 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< -4605, -2510, 145 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< -1711, 6043, -100 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< -1534, -3469, 186 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + + AddStationaryAIPosition(< 2243, -1663, 235 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< 2564, 3061, 15 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -2250, 5372, 56 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -3199, -1855, 118 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -242, -2169, 200 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< 50, 5776, -65 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -4160, 1020, 219 >, eStationaryAIPositionTypes.SNIPER_TITAN) + + AddStationaryAIPosition(< -3561, -1761, 287 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< -1069, 5534, 270 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + + routes[ "outskirtCamp" ] <- [] + routes[ "outskirtCamp" ].append( < -3065, -1856, 116 > ) + routes[ "outskirtCamp" ].append( < -1886, -1452, 176 > ) + routes[ "outskirtCamp" ].append( < 862, -1926, 254 > ) + routes[ "outskirtCamp" ].append( < 2036, -1935, 272 > ) + routes[ "outskirtCamp" ].append( < 2159, -292, 165 > ) + routes[ "outskirtCamp" ].append( < 1888, 342, 97 > ) + + routes[ "outskirtCampCorner" ] <- [] + routes[ "outskirtCampCorner" ].append( < -2559, -3368, 175 > ) + routes[ "outskirtCampCorner" ].append( < -1291, -2700, 204 > ) + routes[ "outskirtCampCorner" ].append( < 715, -1635, 238 > ) + routes[ "outskirtCampCorner" ].append( < 698, -1149, 203 > ) + routes[ "outskirtCampCorner" ].append( < 2003, -1078, 233 > ) + routes[ "outskirtCampCorner" ].append( < 2850, -367, 179 > ) + routes[ "outskirtCampCorner" ].append( < 2508, 565, 278 > ) + routes[ "outskirtCampCorner" ].append( < 2373, 875, 103 > ) + + routes[ "outskirtMainGateShort" ] <- [] + routes[ "outskirtMainGateShort" ].append( < -2046, 3024, -21 > ) + routes[ "outskirtMainGateShort" ].append( < 167, 1999, 8 > ) + routes[ "outskirtMainGateShort" ].append( < 687, 1140, 17 > ) + routes[ "outskirtMainGateShort" ].append( < 1357, 1000, 3 > ) + + routes[ "plantationGate1" ] <- [] + routes[ "plantationGate1" ].append( < 92, 4956, -54 > ) + routes[ "plantationGate1" ].append( < 113, 4025, -23 > ) + routes[ "plantationGate1" ].append( < 1047, 3441, -27 > ) + routes[ "plantationGate1" ].append( < 879, 2835, -35 > ) + routes[ "plantationGate1" ].append( < 1237, 2039, 7 > ) + routes[ "plantationGate1" ].append( < 2057, 1467, 13 > ) + + routes[ "plantationGate2" ] <- [] + routes[ "plantationGate2" ].append( < 1714, 4697, -21 > ) + routes[ "plantationGate2" ].append( < 2225, 4242, 21 > ) + routes[ "plantationGate2" ].append( < 1633, 3857, 14 > ) + routes[ "plantationGate2" ].append( < 1987, 2900, 0 > ) + routes[ "plantationGate2" ].append( < 2077, 1531, 14 > ) + + routes[ "infantryShortBuilding" ] <- [] + routes[ "infantryShortBuilding" ].append( < 283, 3255, -48 > ) + routes[ "infantryShortBuilding" ].append( < 1224, 2559, 5 > ) + routes[ "infantryShortBuilding" ].append( < 1386, 1223, 15 > ) + + routes[ "infantryCloseMainGate" ] <- [] + routes[ "infantryCloseMainGate" ].append( < -680, 1367, 5 > ) + routes[ "infantryCloseMainGate" ].append( < -130, 1525, 22 > ) + routes[ "infantryCloseMainGate" ].append( < 42, 1260, 21 > ) + routes[ "infantryCloseMainGate" ].append( < 226, 1052, 19 > ) + routes[ "infantryCloseMainGate" ].append( < 1045, 1278, 31 > ) + routes[ "infantryCloseMainGate" ].append( < 1072, 1566, 31 > ) + routes[ "infantryCloseMainGate" ].append( < 1512, 1557, 31 > ) + routes[ "infantryCloseMainGate" ].append( < 1862, 1392, 14 > ) + + routes[ "infantryCrateStack" ] <- [] + routes[ "infantryCrateStack" ].append( < -961, -640, 100 > ) + routes[ "infantryCrateStack" ].append( < -502, -240, 99 > ) + routes[ "infantryCrateStack" ].append( < -489, 253, 100 > ) + routes[ "infantryCrateStack" ].append( < 781, 337, 30 > ) + routes[ "infantryCrateStack" ].append( < 1766, 579, 44 > ) + + routes[ "infantryTickRadioStation" ] <- [] + routes[ "infantryTickRadioStation" ].append( < 1406, -2056, 243 > ) + routes[ "infantryTickRadioStation" ].append( < 1547, -1512, 244 > ) + routes[ "infantryTickRadioStation" ].append( < 1084, -836, 239 > ) + routes[ "infantryTickRadioStation" ].append( < 754, -61, 36 > ) + routes[ "infantryTickRadioStation" ].append( < 1847, 564, 53 > ) + + routes[ "radioStationMain" ] <- [] + routes[ "radioStationMain" ].append( < -47, -1986, 205 > ) + routes[ "radioStationMain" ].append( < 686, -1376, 207 > ) + routes[ "radioStationMain" ].append( < -10, -343, 92 > ) + routes[ "radioStationMain" ].append( < 138, 317, 36 > ) + routes[ "radioStationMain" ].append( < 1554, 231, 49 > ) + routes[ "radioStationMain" ].append( < 1816, 554, 51 > ) + + routes[ "insideGrassfield" ] <- [] + routes[ "insideGrassfield" ].append( < -741, 3426, 5 > ) + routes[ "insideGrassfield" ].append( < 149, 3301, -46 > ) + routes[ "insideGrassfield" ].append( < 164, 2543, -1 > ) + routes[ "insideGrassfield" ].append( < 231, 1958, 9 > ) + routes[ "insideGrassfield" ].append( < 672, 1100, 15 > ) + routes[ "insideGrassfield" ].append( < 1441, 1009, 5 > ) + + routes[ "droneFarmside" ] <- [] + routes[ "droneFarmside" ].append( < 1708, 3068, 128 > ) + routes[ "droneFarmside" ].append( < 2115, 2246, 4 > ) + routes[ "droneFarmside" ].append( < 2142, 315, 267 > ) + routes[ "droneFarmside" ].append( < 1855, -841, 304 > ) + routes[ "droneFarmside" ].append( < 789, -1166, 212 > ) + routes[ "droneFarmside" ].append( < 7, -382, 97 > ) + routes[ "droneFarmside" ].append( < -445, 906, 322 > ) + routes[ "droneFarmside" ].append( < -1148, 2202, 17 > ) + routes[ "droneFarmside" ].append( < -308, 3759, 0 > ) + routes[ "droneFarmside" ].append( < 883, 3721, 128 > ) +} + +void function CreateColonyZipline( vector startPos, vector endPos ) +{ + string startpointName = UniqueString( "rope_startpoint" ) + string endpointName = UniqueString( "rope_endpoint" ) + + entity rope_start = CreateEntity( "move_rope" ) + SetTargetName( rope_start, startpointName ) + rope_start.kv.NextKey = endpointName + rope_start.kv.MoveSpeed = 64 + rope_start.kv.Slack = 0 + rope_start.kv.Subdiv = "4" + rope_start.kv.Width = "2" + rope_start.kv.Type = "0" + rope_start.kv.TextureScale = "1" + rope_start.kv.RopeMaterial = "cable/zipline.vmt" + rope_start.kv.PositionInterpolator = 2 + rope_start.kv.Zipline = "1" + rope_start.kv.ZiplineAutoDetachDistance = "150" + rope_start.kv.ZiplineSagEnable = "1" + rope_start.kv.ZiplineSagHeight = "120" + rope_start.SetOrigin( startPos ) + + entity rope_end = CreateEntity( "keyframe_rope" ) + SetTargetName( rope_end, endpointName ) + rope_end.kv.MoveSpeed = 64 + rope_end.kv.Slack = 0 + rope_end.kv.Subdiv = "4" + rope_end.kv.Width = "2" + rope_end.kv.Type = "0" + rope_end.kv.TextureScale = "1" + rope_end.kv.RopeMaterial = "cable/zipline.vmt" + rope_end.kv.PositionInterpolator = 2 + rope_end.kv.Zipline = "1" + rope_end.kv.ZiplineAutoDetachDistance = "150" + rope_end.kv.ZiplineSagEnable = "1" + rope_end.kv.ZiplineSagHeight = "120" + rope_end.SetOrigin( endPos ) + + DispatchSpawn( rope_start ) + DispatchSpawn( rope_end ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut index 2568b6231..b10f2b046 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut @@ -1,12 +1,41 @@ global function CodeCallback_MapInit +global function SwitchComplexRingsSpeed void function CodeCallback_MapInit() { - AddCallback_EntitiesDidLoad( InitComplexRings ) + AddCallback_EntitiesDidLoad( InitComplex ) } -void function InitComplexRings() +void function InitComplex() { entity rings = GetEntByScriptName( "rings_pristine" ) - thread PlayAnim( rings, "animated_slow" ) + rings.Anim_Play( "animated_slow" ) +} + +void function SwitchComplexRingsSpeed( int speed = 0 ) +{ + entity rings = GetEntByScriptName( "rings_pristine" ) + + switch ( speed ) + { + case 0: + rings.Anim_Play( "animated_slow" ) + break + + case 1: + rings.Anim_Play( "animated" ) + break + + case 2: + rings.Anim_Play( "animated_damaged_stage_1" ) + break + + case 3: + rings.Anim_Play( "animated_damaged_stage_2" ) + break + + case 4: + rings.Anim_Play( "animated_damaged_stage_3" ) + break + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_crashsite3.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_crashsite3.nut index f169d0c79..b63872343 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_crashsite3.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_crashsite3.nut @@ -1,4 +1,3 @@ -untyped global function CodeCallback_MapInit void function CodeCallback_MapInit() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock.nut index 37b891699..a9e1435ec 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock.nut @@ -1 +1,8 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock_fd.nut index 37b891699..14aacc41b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_drydock_fd.nut @@ -1 +1,347 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + PlaceFDShop( < -710, 210, 408 >, < 0, -90, 0 > ) + SetFDDropshipSpawn( < 2430, 594, 128 >, < 0, 180, 0 > ) + SetFDGroundSpawn( < 961, 845, 409 >, < 0, -130, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeTicks" ) + AddWaveAnnouncement( "fd_waveTypeReaperTicks" ) + AddWaveAnnouncement( "fd_waveTypeFlyers" ) + AddWaveAnnouncement( "fd_waveTypeTitanArc" ) + + AddFDCustomTitanStart( < 1563, 1481, 256 >, < 0, 180, 0 > ) + AddFDCustomTitanStart( < 258, 144, 404 >, < 0, 0, 0 > ) + + AddStationaryAIPosition( < -31, -3695, 335 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < -830, 3465, 470 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 127, 3712, 412 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 2069, -1881, 256 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1291, 1519, 256 >, 0.0, "leftNear", 1.5, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1844, -2248, 101 >, 0.0, "midHalfway_infantry", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1198, 1588, 208 >, 0.0, "leftHalfway_infantry", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1000, -3102, 127 >, 0.0, "right_infantry", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -375, -2590, 185 >, 0.0, "infantyPerch_right1", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1638, -2005, 240 >, 0.0, "rightHalfway_infantry" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1000, -3102 , 127 >, 0.0, "midNear", 1.0, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 177, 3409, 120 >, 0.0, "leftFar0", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2295, -2782, -45 >, 0.0, "rightFar02", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2488, 3691, -101 >, 0.0, "leftFar1", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -485, -1377, 256 >, 0.0, "midNear", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -774, -3387, 144 >, 0.0, "midHalfway_infantry" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1811, 1345, 84 >, 0.0, "leftHalfway_infantry", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2336, -1184, -75 >, 0.0, "midNear", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1803, 3370, 84 >, 0.0, "leftHalfway_infantry", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1105, -1909, 240 >, 0.0, "midNear", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -695, 2408, 128 >, 0.0, "leftHalfway_infantry", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -591, -1787, 240 >, 0.0, "midNear", 1.0 ) + WaveSpawn_ReaperSpawn( wave1, "Reaper", < 2720, -3720, -51 >, 90, "rightFar01" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -354, -1161, 256 >, 0.0, "infantyPerch_right3", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1173, 1859, 258 >, 0.0, "leftNear", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 488, 1548, 256 >, 0.0, "leftNear", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 919, -966, 255 >, 0.0, "midNear", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 728, 3312, 81 >, 0.0, "leftFar1", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -1202, 2671, 74 >, 0.0, "leftFar0", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 211, -3057, 165 >, 0.0, "right_infantry" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1844, -2248, 101 >, 0.0, "midHalfway_infantry", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1173, 1859, 258 >, 0.0, "leftNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1198, 1588, 208 >, 0.0, "leftHalfway_infantry", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2488, 3691, -101 >, 0.0, "leftFar1", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1000, -3102, 127 >, 0.0, "right_infantry", 0.5 ) + WaveSpawn_ReaperSpawn( wave1, "Reaper", < 636, 3499, 81 >, -90, "leftFar0" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1291, 1519, 256 >, 0.0, "leftNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -774, -3387, 144 >, 0.0, "midHalfway_infantry", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -354, -1161, 256 >, 0.0, "infantyPerch_right3", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 488, 1548, 256 >, 0.0, "leftNear", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 177, 3409, 120 >, 0.0, "leftFar0" ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_SmokeWall( wave2, < 1236, 2449, 82 >, 1.0 ) + WaveSpawn_SmokeWall( wave2, < -305, 1646, 256 >, 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1605 , 3012 , 86 >, 0.0, "leftFar0", 1.2, "fd_waveTypeTicks" ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 570 , 2765 , 76 >, 0.0, "leftFar0", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1053 , 3099 , 96 >, 0.0, "leftFar0", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1299 , 2639 , 84 >, 0.0, "leftFar0" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -1693 , 2672 , 92 >, 0.0, "leftFar0", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -2033 , 3516 , 126 >, 0.0, "leftFar0", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -1445 , 3084 , 112 >, 0.0, "leftFar0", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -923 , 3165 , 177 >, 0.0, "leftFar0" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1106 , 5144 , 251 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1410 , 4322 , 142 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 422 , 4292 , 124 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 776 , 4689 , 223 >, 0.0, "leftFar0" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -481, -1272, 256 >, 0.0, "midNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1053 , 3099 , 96 >, 0.0, "leftFar0", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 570 , 2765 , 76 >, 0.0, "leftFar0", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 636, 3499, 81 >, -90, "leftFar0", 2.0 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < 3313, -527, -70 >, 180, "", 1.5, "fd_waveTypeTitanReg" ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1605 , 3012 , 86 >, 0.0, "leftFar0", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1299 , 2639 , 84 >, 0.0, "leftFar0" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 1178, 1370, 256 >, 0.0, "leftNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -179 , -1193 , 256 >, 0.0, "midNear", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -520 , -1109 , 256 >, 0.0, "midNear", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2226, -3592, -64 >, 90, "rightFar02", 2.0 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < 210, 3401, 120 >, -55, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -467 , -1788 , 240 >, 0.0, "midNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 924 , -1128 , 256 >, 0.0, "midNear" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Ronin", < -1809, 1301, 84 >, -90, "rightSwitchShort1", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Ronin", < -1784, -1113, 101 >, -90, "rightSwitchShort1", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1053 , 3099 , 96 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1299 , 2639 , 84 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1638, -2005, 240 >, 0.0, "rightHalfway_infantry", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 1268, -3696, 144 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1605 , 3012 , 86 >, 0.0, "leftFar0", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -179 , -1193 , 256 >, 0.0, "midNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -1693 , 2672 , 92 >, 0.0, "leftFar0", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -1808, -1112, 101 >, 0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1106 , 5144 , 251 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -1820, 1308, 84 >, 0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1053 , 3099 , 96 >, 0.0, "leftFar0" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1105, -1909, 240 >, 0.0, "midNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -1202, 2671, 74 >, 0.0, "leftFar0", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 211, -3057, 165 >, 0.0, "right_infantry", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 636, 3499, 81 >, -90, "leftFar0", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2226, -3592, -64 >, 90, "rightFar02" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 919, -966, 255 >, 0.0, "midNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1000, -3102 , 127 >, 0.0, "midNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 728, 3312, 81 >, 0.0, "leftFar1", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 3380, 2238, -47 >, 180, "leftFar1", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2720, -3720, -51 >, 90, "rightFar01", 1.5, "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3372, -416, -72 >, -145, "rightFar01", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -1446, 3687, 215 >, -90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -1900, -2244, 101 >, 0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -485, -1377, 256 >, 0.0, "midNear", 0.4 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2295, -2782, -45 >, 0.0, "rightFar02", 0.2 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -354, -1161, 256 >, 0.0, "infantyPerch_right3", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -1782, -2253, 101 >, -90, "leftSwitchShort02", 2.5 ) + WaveSpawn_SmokeWall( wave3, < 1236, 2449, 82 >, 0.5 ) + WaveSpawn_SmokeWall( wave3, < -305, 1646, 256 >, 0.5 ) + WaveSpawn_SmokeWall( wave3, < 2181, -963, -39 >, 0.5 ) + WaveSpawn_SmokeWall( wave3, < -523, -2326, 240 >, 0.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2775, -3683, -66 >, 90, "rightFar01", 1.5, "fd_waveComboArcNuke" ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2704, 3655, -111 >, -90, "leftFar1", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -1225, 3397, 179 >, -90, "leftFar0" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Ion", < 1239, -3684, 146 >, 180, "rightFar02", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2336, -1184, -75 >, 0.0, "midNear", 3.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -442, -3685, 144 >, 90, "rightNear", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -481, -1272, 256 >, 0.0, "midNear", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 501, -3710, 144 >, -145, "rightNear", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -591, -1787, 240 >, 0.0, "midNear" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_TitanSpawn( wave3, "Nuke", < 2621, 3662, -111 >, -90, "leftFar1", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3382, 3304, -47 >, 180, "leftFar1", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3356, -365, -65 >, -180, "rightFar02", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 2378, -2216, -72 >, 0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -1883, 3478, 84 >, -90, "rightSwitchShort1", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -363, 1601, 256 >, 0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -1830, -1105, 101 >, 0, "leftSwitchShort02" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3596, -5433, 320 >, 90 , "rightDrone01", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 2563, -5827, 320 >, 90 , "rightDrone01", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 1477, -6026, 320 >, 90 , "rightDrone02", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 62, -6254, 320 >, 90 , "rightDrone03", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -600, -6465, 320 >, 90 , "rightDrone04" ) + WaveSpawn_SmokeWall( wave4, < 450, -1024, 256 >, 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 12 ) + + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3596, -5433, 320 >, 90 , "rightDrone01", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 2563, -5827, 320 >, 90 , "rightDrone01", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 1477, -6026, 320 >, 90 , "rightDrone02", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 62, -6254, 320 >, 90 , "rightDrone03", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -600, -6465, 320 >, 90 , "rightDrone04" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1842, 3301, 86 >, -35, "leftFar0", 0.8, "fd_incReaperClump" ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2271, 2787, 152 >, 0, "leftFar0", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -363, 1601, 256 >, 0, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 210, 3401, 120 >, -55, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 62, -6254, 320 >, 90 , "rightDrone03", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2967, -3395, -73 >, 90, "rightFar01", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2386, -3242, -72 >, 90, "rightFar01", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 351, -3754, 144 >, 90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 3313, -527, -70 >, 180, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 2563, -5827, 320 >, 90 , "rightDrone01", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -442, -3685, 144 >, 90, "rightNear", 4.0 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 2629, -5409, 2560 >, 0 , "", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 632, 3000, 2560 >, 0 , "", 2.0 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1291, 1519, 256 >, 0.0, "leftNear", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 857, 2639, 83 >, 0.0, "leftNear" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3413, 3326, -48 >, 180, "leftFar1", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2778, 3681, -112 >, 225, "leftFar1", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1440, 3731, 216 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < 3397, 2145, -48 >, 180, "leftFar1", 5.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -762, -3475, 144 >, 90, "rightNear", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 255, -2990, 164 >, 180, "rightNear", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1928, -2201, 103 >, 0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 62, -6254, 320 >, 90 , "rightDrone03", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 1477, -6026, 320 >, 90 , "rightDrone02", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -600, -6465, 320 >, 90 , "rightDrone04", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -6, -3462, 121 >, 90, "rightNear", 5.0 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1000, -3102 , 127 >, 0.0, "midNear", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1105, -1909, 240 >, 0.0, "midNear" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2573, 3587, -107 >, -90, "leftFar1", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 919, -966, 255 >, 0.0, "midNear", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 1018, 3234, 110 >, -90, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -402, -2545, 188 >, 0.0, "rightNear", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2026, 3459, 122 >, -90, "leftFar0", 0.8 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 211, -3057, 165 >, 0.0, "right_infantry", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 3550, -2110, 0 >, -90, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 397, 1701, 256 >, -90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -354, -1161, 256 >, 0.0, "infantyPerch_right3" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3596, -5433, 320 >, 90 , "rightDrone01", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 1477, -6026, 320 >, 90 , "rightDrone02", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 62, -6254, 320 >, 90 , "rightDrone03", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -600, -6465, 320 >, 90 , "rightDrone04", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 1477, -6026, 320 >, 90 , "rightDrone02" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 10 ) + + WaveSpawn_TitanSpawn( wave4, "Ion", < 2970, -3597, -68 >, 90, "rightNear", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 2521, -3597, -68 >, 90, "rightNear", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3648, 1286, 0 >, 180, "rightFar01", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3648, 2037, 0 >, 180, "rightFar01", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 1505, 3090, 95 >, 90, "leftNear", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 1086, 3090, 96 >, 90, "leftNear", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -1785, -2252, 101 >, 90, "rightNear", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 1477, -6026, 320 >, 90 , "rightDrone02", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3596, -5433, 320 >, 90 , "rightDrone01" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1722, -3681, 50 >, 90, "rightFar01", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1867, 3529, 86 >, -90, "leftFar0", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -2261, 3078, 152 >, -90, "rightSwitchLong1", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 3400, 1243, -65 >, 180, "midFar", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 3644, 2023, 0 >, 180, "midFar", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 151, 3402, 121 >, -90, "leftFar1", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 613, 3522, 83 >, -90, "leftFar1", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2756, -3626, -71 >, 90, "rightFar01", 4.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 2756, -3626, 2560 >, 0 , "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < -1786, -2257, 101 >, 0.0, "midHalfway_infantry", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1867 , 3356 , 96 >, -90 , "rightSwitchShort1", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -2203 , 2963 , 164 >, -35 , "rightSwitchShort1", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1858 , 3613 , 96 >, -90 , "rightSwitchShort1" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 2 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3417, 3310, -46 >, 180, "rightSwitchLong2", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3417, 3689, -46 >, 180, "rightSwitchLong2", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -442, -3685, 144 >, 90, "rightNear", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -1909, 3657, 85 >, -90, "rightSwitchShort1", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -1909, 3373, 86 >, -90, "rightSwitchShort1", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 3313, -527, -70 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 1721, 3440, 95 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < -354, -1161, 256 >, 0.0, "infantyPerch_right3", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1858 , 3613 , 96 >, -90 , "rightSwitchShort1", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -2215 , 3278 , 164 >, -90 , "rightSwitchShort1", 1.8 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1443 , 3100 , 124 >, -65 , "rightSwitchShort1" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -442, -3685, 144 >, 90, "rightNear" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 2 ) + + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2970, -3597, -68 >, 90, "rightFar01", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2521, -3597, -68 >, 90, "rightFar01", 7.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2970, -3597, -68 >, 90, "rightFar01", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2521, -3597, -68 >, 90, "rightFar01", 7.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1909, 3657, 85 >, -90, "rightSwitchLong1", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1909, 3373, 86 >, -90, "rightSwitchLong1", 5.0 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -1007, 3246, 178 >, -90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 776, 3582, 83 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2621, 3662, -111 >, -90, "leftFar1", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1793, -2237, 101 >, 0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1784, -1120, 101 >, 0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 4 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1909, 3657, 85 >, -90, "leftFar0", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1909, 3373, 86 >, -90, "leftFar0", 3.0 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 2695, -3333, -73 >, 90, "leftSwitchShort01", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 2854, -3538, -73 >, 90, "leftSwitchShort01", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 2554, -3538, -73 >, 90, "leftSwitchShort01", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -1793, -2237, 101 >, 0, "rightNear",1.0 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -1784, -1120, 101 >, 0, "rightNear", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1443 , 3100 , 124 >, -65 , "rightSwitchShort1", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1867 , 3356 , 96 >, -90 , "rightSwitchShort1", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -2203 , 2963 , 164 >, -35 , "rightSwitchShort1" ) + + WaveSpawnEvents.append( wave5 ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_eden.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_eden.nut index 37b891699..5af152cf9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_eden.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_eden.nut @@ -1 +1,5 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai.nut index 345a86d9b..94ef7c4a7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai.nut @@ -1,5 +1,6 @@ global function CodeCallback_MapInit + struct { int batteryIndex = 0 } file @@ -14,6 +15,10 @@ void function CodeCallback_MapInit() { // Battery spawns (in LTS/Free Agents) are in old locations, so we move them to the proper locations AddSpawnCallbackEditorClass( "script_ref", "script_power_up_other", FixBatterySpawns ) + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() } void function FixBatterySpawns( entity spawn ) @@ -24,4 +29,4 @@ void function FixBatterySpawns( entity spawn ) PowerUp powerupDef = GetPowerUpFromItemRef( expect string( spawn.kv.powerUpType ) ) if ( powerupDef.spawnFunc() ) spawn.SetOrigin( BATTERY_SPAWNS[file.batteryIndex++] ) -} \ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai_fd.nut index 37b891699..e7806ca1c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_forwardbase_kodai_fd.nut @@ -1 +1,393 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + PlaceFDShop( < -3792, 1297, 1043 > ) + SetFDDropshipSpawn( < -536, 2188, 1452 >, < 0, -160, 0 > ) + SetFDGroundSpawn( < -3021, -255, 1165 >, < 0, 180, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeTitanReg" ) + AddWaveAnnouncement( "fd_introMedium" ) + AddWaveAnnouncement( "fd_soonNukeTitans" ) + AddWaveAnnouncement( "fd_introHard" ) + + AddFDCustomTitanStart( < -3580, 1985, 1012 >, < 0, 0, 0 > ) + AddFDCustomTitanStart( < -1721, 218, 988 >, < 0, 180, 0 > ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array< WaveSpawnEvent > wave1 + WaveSpawn_SmokeWall( wave1, < -12, 1720, 1540 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < -64, 964, 1540 >, 0.4 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 975, 738, 1349 >, 0.0, "hillRouteClose", 0.9, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 842, 1505, 1405 >, 0.0, "hillRouteClose", 1.1 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1189, 461, 1349 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1246, 1938, 1306 >, 0.0, "hillRouteClose", 0.9 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1236, 1441, 1320 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 975, 738, 1349 >, 0.0, "hillRouteClose", 1.1 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 842, 1505, 1405 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1189, 461, 1349 >, 0.0, "hillRouteClose", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1246, 1938, 1306 >, 0.0, "hillRouteClose", 0.6, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1263, 974, 1321 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 975, 738, 1349 >, 0.0, "hillRouteClose", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 842, 1505, 1405 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1189, 461, 1349 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1246, 1938, 1306 >, 0.0, "hillRouteClose", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1236, 1441, 1320 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 975, 738, 1349 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 842, 1505, 1405 >, 0.0, "hillRouteClose", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1189, 461, 1349 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1246, 1938, 1306 >, 0.0, "hillRouteClose", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1263, 974, 1321 >, 0.0, "hillRouteClose", 1.1 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 975, 738, 1349 >, 0.0, "hillRouteClose", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 842, 1505, 1405 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1189, 461, 1349 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1246, 1938, 1306 >, 0.0, "hillRouteClose", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1236, 1441, 1320 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1263, 974, 1321 >, 0.0, "hillRouteClose", 1.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1236, 1441, 1320 >, 0.0, "hillRouteClose", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1475, 1236, 1304 >, 0.0, "hillRouteClose", 1.4 ) + WaveSpawn_TitanSpawn( wave1, "Sniper", < 1268, 1243, 1323 >, 180 ) + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array< WaveSpawnEvent > wave2 + WaveSpawn_SmokeWall( wave2, < -12, 1720, 1540 >, 0.2 ) + WaveSpawn_SmokeWall( wave2, < -64, 964, 1540 >, 0.2 ) + + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 864, 693, 1379 >, 0.0, "hillRouteClose", 0.7, "fd_waveTypeTicks" ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 884, 1721, 1377 >, 0.0, "hillRouteClose", 1.6 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1226, 1391, 1334 >, 0.0, "hillRouteClose", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 1258, 921, 1330 >, 0.0, "hillRouteClose", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < 1373, 1219, 1314 >, 170, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < 1209, 579, 1332 >, 170, "", 0.8 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < 2475, -3544, 810 >, 90, "", 1.3 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < 2665, 4456, 960 >, -141, "", 1.1 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 864, 693, 1379 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 884, 1721, 1377 >, 0.0, "", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1226, 1391, 1334 >, 0.0, "", 1.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 864, 693, 1379 >, 0.0, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1258, 921, 1330 >, 0.0, "", 1.3 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 864, 693, 1379 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 884, 1721, 1377 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1226, 1391, 1334 >, 0.0, "", 1.4 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < 2475, -3544, 810 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < 2665, 4456, 960 >, -141, "", 0.6 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 0 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1856, -3177, 812 >, -162, "", 1.0, "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3123, 4201, 950 >, -117, "", 1.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 681, -3538, 813 >, -169, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2614, 4771, 947 >, -141, "", 1.1 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2184, -3550, 819 >, 177, "", 1.4 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1764, 4424, 953 >, -170, "", 1.6 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 3248, 161, 951 >, 0.0, "hillRouteClose", 1.1 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 3156, 2266, 951 >, 0.0, "hillRouteClose" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 3248, 161, 951 >, 0.0, "hillRouteClose", 1.1 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < 3156, 2266, 951 >, 0.0, "hillRouteClose", 0.8 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < 4466, 1469, 947 >, 170, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2336, 1968, 953 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 3248, 161, 951 >, 0.0, "", 2.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2336, 1968, 953 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4163, 1471, 944 >, 180, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4210, 895, 944 >, -164, "", 1.7 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3577, 1491, 944 >, 170, "", 1.1 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3982, 1778, 944 >, 180, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2457, -2563, 789 >, 0.0, "", 1.3 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1935, 3727, 931 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2182, -3549, 819 >, 177, "", 0.1 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1045, -2843, 804 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2357, 4476, 962 >, 177, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2111, 3295, 939 >, 0.0, "", 0.5 ) + WaveSpawn_SmokeWall( wave2, < 2684, 1252, 1092 >, 0.2 ) + WaveSpawn_SmokeWall( wave2, < 2452, 1812, 1092 >, 0.2 ) + WaveSpawn_SmokeWall( wave2, < 2336, 636, 1092 >, 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2343, -3185, 788 >, 174, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2338, 4684, 952 >, -167, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2177, -3539, 817 >, 180, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2401, 4475, 962 >, 180, "", 0.2 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < 1817, -3585, 813 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2576, -3007, 796 >, -165, "", 0.2 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < 2614, 4771, 951 >, -141, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2828, 4138, 938 >, -171, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2828, 4138, 938 >, -171, "", 0.7 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < 4466, 1469, 947 >, 170, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4182, 917, 944 >, -124, "", 1.3 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2747, 1574, 944 >, -164, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < 2821, -2937, 827 >, 117, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < 3123, 4202, 954 >, -141, "", 0.1 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2169, -3540, 817 >, 178, "", 1.3 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2354, 4476, 962 >, 177, "", 1.3 ) + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array< WaveSpawnEvent > wave3 + WaveSpawn_SmokeWall( wave3, < -2264, -2096, 928 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave3, < -3132, -1904, 928 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave3, < -1548, -2240, 928 >, 0.2, 120 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 1763, -1608, 810 >, 90, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2457, -2563, 789 >, 0.0, "", 1.3 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1045, -2843, 804 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 346, -2838, 803 >, 0.0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1418, -2254, 810 >, 0.0, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2170, -3549, 819 >, 177, "", 1.0, "fd_incReaperClump" ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2577, -3007, 796 >, 165, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1512, -3294, 798 >, 90, "", 1.4 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1531, -1779, 800 >, 135, "", 2.0 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 2475, -3544, 810 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < 2821, -2936, 827 >, 117, "", 0.7 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < 1503, -3600, 813 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 1559, -2024, 803 >, 90, "", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_InfantrySpawn( wave3, "Drones", < 2487, -2561, 2580 >, 0.0, "cliffRouteRight", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 1883, -1569, 1108 >, 0.0, "", 1.0, "fd_waveTypeCloakDrone" ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2457, -2563, 789 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1045, -2843, 804 >, 0.0, "", 1.6 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 346, -2838, 803 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1418, -2254, 810 >, 0.0, "", 1.1 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < 4466, 1469, 947 >, 180, "", 0.6 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 4453, 964, 947 >, 180, "", 1.3 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 1763, -1608, 810 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 2359, -1596, 802 >, 90, "", 1.9 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 2475, -3544, 810 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 2821, -2936, 827 >, 117, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2180, -3539, 817 >, 180, "", 0.6 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 2680, -1724, 809 >, 170, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2533, -3018, 795 >, -165, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 1763, -1608, 810 >, 90, "", 0.1 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 1923, -1544, 1108 >, 0.0, "", 1.0, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1512, -3298, 797 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1499, -1748, 801 >, 135, "", 2.2 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2457, -2563, 789 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1045, -2843, 804 >, 0.0, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 346, -2838, 803 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1418, -2254, 810 >, 0.0, "", 0.7 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 1503, -3600, 813 >, 90, "", 1.3 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 2475, -3544, 810 >, 90, "", 0.4 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 1763, -1608, 810 >, 90, "", 0.9 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 2359, -1596, 802 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 1982, -1598, 1236 >, 0.0, "", 2.0, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 4466, 1469, 947 >, 170, "", 0.7 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 4453, 964, 947 >, -170, "", 1.4 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 3866, 1445, 947 >, -170, "" ) + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array< WaveSpawnEvent > wave4 + WaveSpawn_SmokeWall( wave4, < -2596, 3224, 1104 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < -3252, 3052, 1104 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < -1728, 3136, 1104 >, 0.2 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 2111, 3295, 939 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1935, 3727, 931 >, 0.0, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2665, 4456, 960 >, -140, "", 0.8 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 3123, 4201, 954 >, -140, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 1324, 4820, 937 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 3144, 2935, 917 >, 180, "", 1.2, "fd_waveTypeTitanNuke" ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 3739, 1985, 947 >, 180, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1087, 3863, 931 >, 0.0, "", 1.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 908, 3093, 967 >, 0.0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 3156, 2266, 951 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 3156, 2266, 951 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1935, 3727, 931 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 2111, 3295, 939 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1087, 3863, 931 >, 0.0, "", 0.9 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 2475, -3544, 810 >, 90, "", 0.5, "fd_waveTypeTitanMortar" ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 2821, -2936, 827 >, -140, "", 1.3 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2665, 4456, 960 >, -140, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3123, 4202, 954 >, -140, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 1324, 4820, 937 >, -90, "", 0.9 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 3144, 2935, 917 >, 180, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 3739, 1985, 947 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -31, 4688, 1027 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < -31, 4688, 1027 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 1293, 1827, 1321 >, 180, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 908, 3093, 967 >, 0.0, "", 1.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 3156, 2266, 951 >, 0.0, "", 1.3 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2355, 4472, 963 >, 180, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2835, 4139, 939 >, 180, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 1014, 4844, 941 >, 180, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2833, 2953, 910 >, 180, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 4164, 1471, 944 >, 180, "", 0.1 ) + WaveSpawn_Announce( wave4, "PreArcTitan", 0.4 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1935, 3727, 931 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 4207, 894, 944 >, 180, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 2111, 3295, 939 >, 0.0, "", 0.9 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3570, 1491, 944 >, 180, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1087, 3863, 931 >, 0.0, "", 0.3 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3604, 835, 944 >, 180, "", 0.2 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_SmokeWall( wave4, < -2596, 3224, 1104 >, 0.2, 60 ) + WaveSpawn_SmokeWall( wave4, < -3252, 3052, 1104 >, 0.2, 60 ) + WaveSpawn_SmokeWall( wave4, < -1728, 3136, 1104 >, 0.2, 60 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 2665, 4456, 960 >, 180, "", 0.9 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3123, 4202, 954 >, 180, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 1324, 4820, 937 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3144, 2935, 917 >, 180, "", 0.9 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 3738, 1985, 947 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -31, 4688, 1027 >, -90, "", 1.4 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < 1294, 1827, 1321 >, 180, "", 0.9 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < 4278, 1771, 947 >, 180, "", 1.3 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 4453, 964, 947 >, 180, "", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 3866, 1445, 947 >, 180, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 4432, 1262, 1244 >, 0.0, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3878, 933, 944 >, -90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 4008, 378, 944 >, -120, "", 0.9 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2916, 2679, 939 >, -45, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 545, 1309, 1438 >, -18, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_TitanSpawn( wave4, "Nuke", < 2665, 4456, 960 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 3123, 4202, 954 >, 180, "", 0.9 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 1324, 4820, 937 >, -90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 3739, 1985, 947 >, 180, "" ) + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array< WaveSpawnEvent > wave5 + WaveSpawn_SmokeWall( wave5, < -2596, 3224, 1104 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave5, < -3252, 3052, 1104 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave5, < -1728, 3136, 1104 >, 0.2, 120 ) + + WaveSpawn_SmokeWall( wave5, < -2264, -2096, 928 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave5, < -3132, -1904, 928 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave5, < -1548, -2240, 928 >, 0.2, 120 ) + + WaveSpawn_SmokeWall( wave5, < -12, 1720, 1540 >, 0.2, 120 ) + WaveSpawn_SmokeWall( wave5, < -64, 964, 1540 >, 0.2, 120 ) + + WaveSpawn_Announce( wave5, "Everything", 0.0 ) + + WaveSpawn_InfantrySpawn( wave5, "Ticks", < 864, 693, 1379 >, 0.0, "hillRouteClose", 0.2 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < 884, 1721, 1377 >, 0.0, "hillRouteClose", 0.7 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1226, 1391, 1334 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1258, 921, 1330 >, 0.0, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1094, 1330, 1354 >, 180, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 857, 739, 1373 >, 150, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1048, 1660, 1349 >, -100, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2724, 2458, 946 >, -125, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1092, 1331, 1355 >, 160, "", 1.1 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 938, 707, 1362 >, 160, "", 2.7 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1528, -1443, 816 >, 0.0, "", 1.1 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1418, -2254, 810 >, 0.0, "", 2.2 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 2475, -3544, 810 >, 90, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 2821, -2936, 827 >, 120, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1511, -1445, 825 >, 140, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 1559, -2024, 803 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2086, -1459, 810 >, 140, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 2665, 4456, 960 >, -140, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 3123, 4201, 954 >, -140, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 3144, 2935, 917 >, 180, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 2457, -2563, 789 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1045, -2843, 804 >, 0.0, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 4466, 1469, 947 >, 180, "", 0.9 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 4453, 964, 947 >, 180, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1548, -1475, 805 >, 140, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2087, -1461, 810 >, 140, "", 3.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2475, -3544, 810 >, 90, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 2821, -2936, 827 >, 120, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 1817, -3585, 813 >, 90, "", 0.0 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1528, -1443, 816 >, 0.0, "", 1.1 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1418, -2254, 810 >, 0.0, "", 1.9 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 1559, -2024, 803 >, 90, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2411, -1108, 803 >, 90, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1511, -1437, 826 >, 140, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2129, -1492, 806 >, 140, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_TitanSpawn( wave5, "Tone", < 2665, 4456, 960 >, -140, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 3123, 4201, 954 >, -140, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 1324, 4820, 937 >, -90, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1511, -1437, 826 >, 140, "", 1.1 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2091, -1464, 809 >, 140, "", 1.8 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1528, -1443, 816 >, 0.0, "", 1.1 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1418, -2254, 810 >, 0.0, "", 0.3 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1452, -1794, 804 >, 110, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 896, -1227, 964 >, 0.0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2162, -1065, 806 >, 180, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 2457, -2563, 789 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_TitanSpawn( wave5, "Tone", < 2665, 4456, 960 >, -140, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 3123, 4201, 954 >, -140, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 2674, 4322, 1283 >, 0.0, "", 2.0, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 2475, -3544, 810 >, 90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 2821, -2936, 827 >, 120, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 2363, -3327, 1235 >, 0.0, "", 5.0, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 1763, -1608, 810 >, 90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2359, -1596, 802 >, 90, "", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 1559, -2024, 803 >, 90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 2411, -1108, 803 >, 90, "", 3.0 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 4466, 1469, 947 >, 180, "", 0.9 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 4453, 964, 947 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3867, 1445, 947 >, 180, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2475, -3544, 810 >, 90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2665, 4456, 960 >, -140, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2821, -2937, 827 >, 120, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3123, 4202, 954 >, -140, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1817, -3586, 814 >, 00, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1324, 4820, 937 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 4466, 1469, 947 >, 180, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 4453, 964, 947 >, 180, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 3867, 1445, 947 >, 180, "" ) + WaveSpawnEvents.append( wave5 ) +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch.nut index 37b891699..65fb48a2e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch.nut @@ -1 +1,22 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ + AddDeathCallback( "player", GlitchDissolveDeadEntity ) + AddDeathCallback( "npc_soldier", GlitchDissolveDeadEntity ) + AddDeathCallback( "npc_pilot_elite", GlitchDissolveDeadEntity ) + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() +} + +void function GlitchDissolveDeadEntity( entity deadEnt, var damageInfo ) +{ + EmitSoundAtPosition( TEAM_UNASSIGNED, deadEnt.GetOrigin(), "Object_Dissolve" ) + + if ( deadEnt.IsPlayer() ) + deadEnt.DissolveNonLethal( ENTITY_DISSOLVE_CHAR, < 0, 0, 0 >, 500 ) + else + deadEnt.Dissolve( ENTITY_DISSOLVE_CHAR, < 0, 0, 0 >, 500 ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch_fd.nut index 37b891699..7f248275e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_glitch_fd.nut @@ -1 +1,788 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + useCustomFDLoad = true + AddCallback_RegisterCustomFDContent( RegisterCustomFDContent ) + PlaceFDShop( < -2811, -1176, 128 > ) + SetFDDropshipSpawn( < -2616, -496, 48 > ) + SetFDGroundSpawn( < -3126, -1181, 129 > ) + + AddWaveAnnouncement( "fd_introMedium" ) + AddWaveAnnouncement( "fd_waveTypeReaperTicks" ) + AddWaveAnnouncement( "fd_waveTypeCloakDrone" ) + AddWaveAnnouncement( "fd_introHard" ) + AddWaveAnnouncement( "fd_waveComboNukeTrain" ) + + array infantrySpawns = [] + infantrySpawns.append( < -606, -362, 3 > ) + infantrySpawns.append( < -169, -800, -1 > ) + infantrySpawns.append( < -1092, -1299, 37 > ) + infantrySpawns.append( < -1747, -311, 272 > ) + infantrySpawns.append( < -1261, -121, 272 > ) + infantrySpawns.append( < 563, -825, 54 > ) + infantrySpawns.append( < -209, 1078, -1 > ) + infantrySpawns.append( < -965, 1076, 53 > ) + infantrySpawns.append( < 1171, 408, 272 > ) + infantrySpawns.append( < 1312, 665, 267 > ) + infantrySpawns.append( < 1432, 1419, 271 > ) + infantrySpawns.append( < 289, 676, 0 > ) + + array reaperSpawns = [] + reaperSpawns.append( < 1666, 1392, 272 > ) + reaperSpawns.append( < 2429, 1435, 127 > ) + reaperSpawns.append( < 1224, 509, 272 > ) + reaperSpawns.append( < 3747, 2084, 37 > ) + reaperSpawns.append( < 3674, -217, 29 > ) + reaperSpawns.append( < 3185, 1131, 0 > ) + reaperSpawns.append( < 427, 2277, 15 > ) + reaperSpawns.append( < 565, -1294, 5 > ) + reaperSpawns.append( < 3211, 2594, 19 > ) + reaperSpawns.append( < -571, -178, 0 > ) + + array titanSpawns = [] + titanSpawns.append( < 3543, 2036, 14 > ) + titanSpawns.append( < 3638, 1175, -10 > ) + titanSpawns.append( < 3188, 628, 30 > ) + titanSpawns.append( < 3472, 343, 13 > ) + titanSpawns.append( < 3315, -171, 23 > ) + titanSpawns.append( < 2134, -608, 48 > ) + titanSpawns.append( < 3146, 2516, -4 > ) + titanSpawns.append( < 2178, 2187, 90 > ) + titanSpawns.append( < 2356, 2545, 30 > ) + titanSpawns.append( < 3670, 883, 5 > ) + titanSpawns.append( < 3217, 1705, 19 > ) + + array specialTitanSpawns = [] + specialTitanSpawns.append( < 1972, 993, 17 > ) + specialTitanSpawns.append( < 2663, -1, 33 > ) + specialTitanSpawns.append( < 1369, 2576, 63 > ) + specialTitanSpawns.append( < 1889, 2242, 102 > ) + specialTitanSpawns.append( < 3277, 2127, 17 > ) + specialTitanSpawns.append( < 478, 2205, 3 > ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_SmokeWall( wave1, < -177, 1610, 2 >, 1.0 ) + WaveSpawn_SmokeWall( wave1, < -2243, 931, 34 >, 0.8 ) + WaveSpawn_SmokeWall( wave1, < -2287, -667, 18 >, 0.6 ) + WaveSpawn_SmokeWall( wave1, < -1179, -884, -13 >, 0.4 ) + WaveSpawn_SmokeWall( wave1, < -1887, -1701, 61 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < -3135, 350, 18 >, 2.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ), "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ), "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ), "fd_waveTypeMortarSpectre" ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", infantrySpawns.getrandom(), 0.0, "" ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_TitanSpawn( wave2, "Monarch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ), "fd_waveTypeTitanReg" ) + WaveSpawn_TitanSpawn( wave2, "Monarch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave2, "Monarch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Tone", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave2, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave2, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Legion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave2, "Ronin", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave2, "Ronin", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ), "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_TitanSpawn( wave2, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave2, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2516, 368, 255 >, 0, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 2147, 139, 176 >, 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_TitanSpawn( wave2, "Ronin", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_TitanSpawn( wave2, "Ronin", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_TitanSpawn( wave2, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave2, "Legion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave2, "Scorch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave2, "Legion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave2, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", infantrySpawns.getrandom(), 0.0, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_SmokeWall( wave3, < 3719, 1924, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < -258, 1569, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3168, 866, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3592, 464, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3095, 385, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 764, 2425, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1809, -237, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 2736, 1872, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1683, 2418, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 748, 1091, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 2290, 2371, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 325, 1688, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3588, 1291, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 711, 1474, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1881, 892, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3291, 1839, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1210, -793, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1815, 241, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3496, -65, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 2242, -225, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 3015, 2413, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1348, 1044, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 2084, 1859, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 2843, -72, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 645, -937, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 874, 1817, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1828, -692, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 325, -1421, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 2558, 879, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 80, 701, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < 1486, 1899, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave3, < -282, -1319, 144 >, 2.5, 300 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0, "fd_incCloakDroneClump" ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ), "fd_waveTypeTitanMortar" ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ), "fd_waveComboArcMortar" ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 2516, 368, 255 >, 0, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave3, "MortarSpectre", < 2147, 139, 176 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave3, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", titanSpawns.getrandom(), 180, "" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_TitanSpawn( wave4, "Scorch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Scorch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Scorch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_Announce( wave4, "PreNukeTitan", 0.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 2 ) + + WaveSpawn_TitanSpawn( wave4, "Tone", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Tone", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Tone", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_TitanSpawn( wave4, "Ion", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Tone", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Monarch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ), "fd_waveTypeTitanNuke" ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 2516, 368, 255 >, 0, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 2147, 139, 176 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_TitanSpawn( wave4, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_TitanSpawn( wave4, "Ronin", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Ronin", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Ronin", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave4, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave4, "Northstar", specialTitanSpawns.getrandom(), 0, "", 0.5 ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_Announce( wave5, "Everything", 0.0 ) + WaveSpawn_TitanSpawn( wave5, "Ion", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave5, "Legion", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave5, "Scorch", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave5, "Legion", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave5, "Ion", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", infantrySpawns.getrandom(), 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ), "fd_waveComboArcNuke" ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Northstar", specialTitanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 2516, 368, 255 >, 0, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 2147, 139, 176 >, 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", reaperSpawns.getrandom(), 180, "", RandomFloatRange( 0.4, 1.6 ) ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ), "fd_incTitansMortarClump" ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Ronin", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Ronin", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Ronin", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.6 ) ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.2, 0.8 ) ) + WaveSpawn_TitanSpawn( wave5, "Legion", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Legion", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Scorch", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Scorch", titanSpawns.getrandom(), 0, "", RandomFloatRange( 0.8, 2.4 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 0 ) + + WaveSpawn_SmokeWall( wave5, < 2242, -225, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -243, -795, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 874, 1817, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2242, -2140, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 2736, 1872, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2468, -1608, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2243, -362, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -962, -1887, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -3049, -1672, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -753, -1403, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1809, -237, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 325, -1421, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 711, 1474, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 645, -937, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 764, 2425, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2256, 914, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1683, 2418, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1881, 892, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2191, 211, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 80, 701, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3496, -65, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -3192, 314, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 2843, -72, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1815, 241, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1348, 1044, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -282, -1319, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1758, -2221, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3095, 385, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3291, 1839, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -3764, -1995, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -3495, -1618, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 748, 1091, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1078, 1092, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 2084, 1859, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1156, -1301, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3015, 2413, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 2558, 879, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1933, -808, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2699, -2124, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -833, 1594, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -4054, -1672, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -3221, -2194, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1669, 1037, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 325, 1688, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1210, -793, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3592, 464, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3168, 866, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1237, -2231, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 2290, 2371, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -198, -66, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3719, 1924, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1457, -1721, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2746, -659, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -604, -362, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 3588, 1291, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1946, -1667, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -3237, -691, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -1366, -833, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -258, 1569, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -817, -833, 143 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 27, 462, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1486, 1899, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < 1828, -692, 144 >, 0.2, 300 ) + WaveSpawn_SmokeWall( wave5, < -2617, 475, 144 >, 2.5, 300 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ), "fd_incTitansNukeClump" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_TitanSpawn( wave5, "Mortar", specialTitanSpawns.getrandom(), 180, "", RandomFloatRange( 0.5, 2.0 ) ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", infantrySpawns.getrandom(), 0.0, "", RandomFloatRange( 0.3, 0.9 ) ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", titanSpawns.getrandom() + < 0, 0, 2500 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "", RandomFloatRange( 0.3, 2.5 ) ) + WaveSpawn_TitanSpawn( wave5, "Nuke", titanSpawns.getrandom(), 180, "" ) + + WaveSpawnEvents.append( wave5 ) +} + +void function RegisterCustomFDContent() +{ + array aiPositions = GetEntArrayByClass_Expensive( "info_target" ) + foreach ( entity position in aiPositions ) + if( position.HasKey( "editorclass" ) && position.kv.editorclass == "info_fd_ai_position" ) + position.Destroy() + + AddFDCustomTitanStart( < -3998, 374, 22 >, < 0, -45, 0 > ) + AddFDCustomTitanStart( < -4068, -1818, 31 >, < 0, 45, 0 > ) + + AddStationaryAIPosition( < 1724, 1079, 3 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 1991, -210, -12 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 2917, 2182, 4 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 1506, 2299, 100 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 197, 460, 0 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 897, 1408, 33 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 3119, 186, 19 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + AddStationaryAIPosition( < 3688, 1347, 0 >, eStationaryAIPositionTypes.MORTAR_TITAN ) + + AddStationaryAIPosition( < 2598, 543, 264 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < 1274, 1444, 272 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < 1548, 533, 272 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < -1564, -155, 272 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < -1529, -1201, 272 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + AddStationaryAIPosition( < 1205, 390, 272 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) + + AddStationaryAIPosition( < 2053, -767, 45 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 3649, 1832, 10 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 3417, 902, 8 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 889, 2536, 57 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < -1248, -800, -7 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < -2357, 938, 32 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < -968, -2288, 24 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + + AddStationaryAIPosition( < 1205, 1063, 301 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 2088, 480, 327 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 527, 762, 272 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < -1589, -816, 279 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < -1960, -256, 271 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 2318, 1169, 128 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 3544, -50, 18 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 3371, 2251, 35 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 2215, -455, 23 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + + routes[ "longStraightL" ] <- [] + routes[ "longStraightL" ].append( < 3360, 1881, 11 > ) + routes[ "longStraightL" ].append( < 705, 1840, 4 > ) + routes[ "longStraightL" ].append( < -938, 1354, 2 > ) + routes[ "longStraightL" ].append( < -2423, 571, -16 > ) + routes[ "longStraightL" ].append( < -2252, -681, 18 > ) + routes[ "longStraightL" ].append( < -3650, -657, 25 > ) + + routes[ "longStraightC" ] <- [] + routes[ "longStraightC" ].append( < 3300, 903, 26 > ) + routes[ "longStraightC" ].append( < 392, 1100, 4 > ) + routes[ "longStraightC" ].append( < -581, -655, 1 > ) + routes[ "longStraightC" ].append( < -581, -655, 1 > ) + routes[ "longStraightC" ].append( < -2252, -681, 18 > ) + routes[ "longStraightC" ].append( < -3650, -657, 25 > ) + + routes[ "longStraightR" ] <- [] + routes[ "longStraightR" ].append( < 3292, -7, 32 > ) + routes[ "longStraightR" ].append( < 1153, -797, 3 > ) + routes[ "longStraightR" ].append( < -1082, -1625, 1 > ) + routes[ "longStraightR" ].append( < -3595, -1632, 32 > ) + routes[ "longStraightR" ].append( < -3959, -1138, 1 > ) + + routes[ "longFullCorner" ] <- [] + routes[ "longFullCorner" ].append( < 1685, 2472, 42 > ) + routes[ "longFullCorner" ].append( < 465, 1698, -9 > ) + routes[ "longFullCorner" ].append( < -967, 1131, 40 > ) + routes[ "longFullCorner" ].append( < -2626, 482, 1 > ) + routes[ "longFullCorner" ].append( < -3826, -267, 13 > ) + + routes[ "infantryUpperClose" ] <- [] + routes[ "infantryUpperClose" ].append( < -1340, -289, 271 > ) + routes[ "infantryUpperClose" ].append( < -1840, -810, -27 > ) + routes[ "infantryUpperClose" ].append( < -3604, -526, 31 > ) + + routes[ "infantryUpperFar" ] <- [] + routes[ "infantryUpperFar" ].append( < 1079, 513, 271 > ) + routes[ "infantryUpperFar" ].append( < 729, 1296, -1 > ) + routes[ "infantryUpperFar" ].append( < -921, 1394, 0 > ) + routes[ "infantryUpperFar" ].append( < -2679, 532, 0 > ) + routes[ "infantryUpperFar" ].append( < -3961, -174, 15 > ) + + routes[ "lowerClose" ] <- [] + routes[ "lowerClose" ].append( < -528, -1029, 21 > ) + routes[ "lowerClose" ].append( < -1478, -1617, 12 > ) + routes[ "lowerClose" ].append( < -3715, -1575, 14 > ) + routes[ "lowerClose" ].append( < -4046, -1146, 2 > ) + + routes[ "lowerFar" ] <- [] + routes[ "lowerFar" ].append( < 114, 1273, 20 > ) + routes[ "lowerFar" ].append( < -1018, 1142, 31 > ) + routes[ "lowerFar" ].append( < -2387, 559, -15 > ) + routes[ "lowerFar" ].append( < -3675, -369, 5 > ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave.nut index f4b48f6d4..4a10420d2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave.nut @@ -3,7 +3,13 @@ global function CodeCallback_MapInit void function CodeCallback_MapInit() { // there are some really busted titan startspawns that are on the fucking other side of the map from where they should be, so we remove them - AddSpawnCallback( "info_spawnpoint_titan_start", TrimBadTitanStartSpawns ) + // AddSpawnCallback( "info_spawnpoint_titan_start", TrimBadTitanStartSpawns ) + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() + + FlagSet( "LevelHasRoof" ) // So it forces Warpfall on all Titans like vanilla } void function TrimBadTitanStartSpawns( entity spawn ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave_fd.nut index 37b891699..ab83f67fe 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_grave_fd.nut @@ -1 +1,673 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + useCustomFDLoad = true //Respawn Routes for this map are quite bad ngl + AddCallback_RegisterCustomFDContent( RegisterCustomFDContent ) + PlaceFDShop( < 1767, -4959, 2244> ) + SetFDDropshipSpawn( < 3820, -4181, 2242 > ) + SetFDGroundSpawn( < 3184, -3844, 2377 >, < 0, -45, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeTitanReg" ) + AddWaveAnnouncement( "fd_waveComboNukeCloak" ) + AddWaveAnnouncement( "fd_waveTypeReapers" ) + AddWaveAnnouncement( "fd_finalWaveStartGeneric" ) + + int reaperrain = 0 + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_SmokeWall( wave1, < 5583, -2836, 2236 >, 0.6 ) + WaveSpawn_SmokeWall( wave1, < 5794, -4925, 2237 >, 0.6 ) + WaveSpawn_SmokeWall( wave1, < 3864, -6135, 2237 >, 0.6 ) + WaveSpawn_SmokeWall( wave1, < 4533, -2242, 2114 >, 0.6 ) + WaveSpawn_SmokeWall( wave1, < 3973, -3914, 2235 >, 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6779, -2872, 2236 >, 0.0, "", 0.5, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6497, -3399, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6954, -3714, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6169, -4616, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 7252, -4815, 2242 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6997, -6491, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6247, -3950, 2245 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6348, -1941, 2242 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 5933, -1584, 2242 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 7342, -1539, 2408 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 8577, -2695, 2245 >, 0.0, "", 0.2, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 8173, -3006, 2245 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 8056, -4362, 2135 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 7511, -4658, 2222 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 9726, -5123, 2021 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 9108, -5068, 2085 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 5183, -5068, 2085 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4701, -4435, 2013 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4541, -2687, 2086 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 5462, -1485, 2236 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 6042, -3143, 2243 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 3903, -1883, 2304 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 6777, -5414, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 5751, -5479, 2234 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 5788, -6606, 2242 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 7568, -4097, 2172 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 4642, -5330, 2242 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4411, -4855, 2242 >, 0.0, "" ) + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 4642, -5330, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 6042, -3143, 2243 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 5788, -6606, 2242 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 7568, -4097, 2172 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 6779, -2872, 2236 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 6348, -1941, 2242 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < 8495, -4790, 2100 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < 9321, -4211, 2045 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 6954, -3714, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 6497, -3399, 2242 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 8056, -4362, 2135 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 4541, -2687, 2086 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 6777, -5414, 2242 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 8577, -2695, 2245 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < 9321, -4211, 2045 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < 10154, -3282, 2027 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 4701, -4435, 2013 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 6997, -6491, 2242 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 9108, -5068, 2085 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 4411, -4855, 2242 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 7252, -4815, 2242 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 7342, -1539, 2408 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < 11097, -4024, 1934 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < 11204, -4969, 1884 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 7511, -4658, 2222 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 6169, -4616, 2236 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 5933, -1584, 2242 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 8173, -3006, 2245 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 5751, -5479, 2234 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 3903, -1883, 2304 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Ronin", < 10254, -6570, 1976 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Ronin", < 10338, -6098, 1956 >, 180, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6 ) + + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 5462, -1485, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 5183, -5068, 2085 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 6247, -3950, 2245 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 9726, -5123, 2021 >, 0.0, "", 0.8 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < -412, -6711, 2084 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < -480, -1603, 2088 >, 0.0, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1605, -6286, 2034 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1700, -2687, 1987 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1942, -2210, 1974 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1136, -6756, 2057 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1425, -1635, 2002 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -624, -6285, 2080 >, 0, "" ) + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "Tone", < 8495, -4790, 2100 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 10254, -6570, 1976 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 9321, -4211, 2045 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 10338, -6098, 1956 >, 180, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 9794, -3250, 2084 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 10045, -4569, 1993 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 9485, -4206, 2044 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 7829, -6582, 2242 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 6786, -5415, 2242 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 6868, -2607, 2242 >, 0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 0.5, "fd_waveTypeCloakDrone" ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8008, -1635, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8524, -2702, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8294, -2214, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 7748, -1536, 2238 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_Announce( wave3, "PreNukeTitan", 0.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1605, -6286, 2034 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1425, -1635, 2002 >, 0, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1136, -6756, 2057 >, 0, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1700, -2687, 1987 >, 0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1942, -2210, 1974 >, 0, "", 0.9 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -624, -6285, 2080 >, 0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8606, -2966, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8271, -1544, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8661, -1957, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8484, -1826, 2242 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 11097, -4024, 1934 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 11204, -4969, 1884 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_SmokeWall( wave3, < 8113, -3451, 2233 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 5752, -2898, 2236 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 5800, -4864, 2236 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 9134, -3256, 2176 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 6534, -4256, 2236 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 8711, -6121, 2180 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 9778, -5758, 2035 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 6204, -4586, 2236 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 9404, -3631, 2110 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 10370, -3825, 1945 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 8524, -4331, 2086 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 5905, -6298, 2241 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 8940, -6724, 2116 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 8622, -3919, 2163 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 5503, -4644, 2236 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 9076, -5864, 2079 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 9516, -6777, 2017 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 10034, -4537, 1995 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 8508, -4908, 2113 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 5756, -5591, 2229 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 9295, -6475, 2059 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 7740, -5451, 2242 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 8349, -5821, 2237 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 7095, -3480, 2242 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 6496, -2977, 2290 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 7053, -5648, 2242 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 6390, -5694, 2242 >, 0.5, 180 ) + WaveSpawn_SmokeWall( wave3, < 4749, -6165, 2242 >, 3.0, 180 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9245, -6489, 2060 >, 180, "northForestThroughDebris", 0.5, "fd_incTitansNukeClump" ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9336, -2261, 2106 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9905, -6100, 1981 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 11282, -5322, 1909 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10358, -5975, 1948 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9784, -4432, 2007 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9816, -6601, 2002 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10833, -5919, 1925 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10818, -6493, 1916 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10417, -6471, 1955 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 11318, -5970, 1957 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9934, -3615, 2022 >, 180, "northForestThroughTown", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8484, -1826, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 8008, -1635, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8271, -1544, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 8606, -2966, 2242 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9245, -6489, 2060 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9336, -2261, 2106 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9905, -6100, 1981 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 11282, -5322, 1909 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10358, -5975, 1948 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9784, -4432, 2007 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9816, -6601, 2002 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10833, -5919, 1925 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10818, -6493, 1916 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 10417, -6471, 1955 >, 180, "northForestThroughDebris", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 11318, -5970, 1957 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 9934, -3615, 2022 >, 180, "northForestThroughDebris", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 8661, -1957, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 8524, -2702, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 7748, -1536, 2238 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 8294, -2214, 2242 >, 0.0, "", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -412, -6711, 2084 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -480, -1603, 2088 >, 0, "" ) + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_TitanSpawn( wave4, "Legion", < -2020, -6257, 2011 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < -1652, -5669, 2021 >, 0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -353, -1731, 2093 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 517, -2248, 2082 >, 0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 8484, -1826, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 8524, -2702, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 7748, -1536, 2238 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 8008, -1635, 2242 >, 0.0, "", 5.0 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < -412, -6711, 2084 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < -480, -1603, 2088 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 233, -4389, 2304 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 183, -5512, 2304 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_TitanSpawn( wave4, "Tone", < 8084, -4370, 2132 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 8007, -5207, 2190 >, 180, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 6775, -5415, 2242 >, -135, "", 0.5, "fd_waveTypeReaperTicks" ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 5522, -1508, 2236 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 3591, -1639, 2242 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -431, -1724, 2090 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -1003, -3029, 2024 >, 0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -1273, -6676, 2050 >, 0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -1623, -5591, 2027 >, 0, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 6775, -5415, 2242 >, -135, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 5522, -1508, 2236 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 3591, -1639, 2242 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 233, -4389, 2304 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 183, -5512, 2304 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 8661, -1957, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 8294, -2214, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 8606, -2966, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 8271, -1544, 2242 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 8495, -4790, 2100 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 9321, -4211, 2045 >, 180, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 9321, -4211, 2045 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 10154, -3282, 2027 >, 180, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 11097, -4024, 1934 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 11204, -4969, 1884 >, 180, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < 10254, -6570, 1976 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < 10338, -6098, 1956 >, 180, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 233, -4389, 2304 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 183, -5512, 2304 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 0 ) + + WaveSpawn_TitanSpawn( wave4, "Legion", < -1355, -2128, 2005 >, 0, "", 5.0 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -1580, -2545, 1994 >, 0, "", 5.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 2.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.6, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.4, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.2, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.6, "", 600.0 ) + for( reaperrain = 0; reaperrain < 16; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 24 ) + } + WaveSpawn_TitanSpawn( wave4, "Ronin", < -1580, -2545, 1995 >, 0, "", 0.3 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < -1580, -2097, 1995 >, 0, "", 0.3 ) + for( reaperrain = 0; reaperrain < 16; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 24 ) + } + WaveSpawn_TitanSpawn( wave4, "Ion", < -1580, -2545, 1995 >, 0, "", 0.3 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -1580, -2097, 1995 >, 0, "", 0.3 ) + for( reaperrain = 0; reaperrain < 16; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 24 ) + } + WaveSpawn_TitanSpawn( wave4, "Scorch", < -1580, -2545, 1995 >, 0, "", 0.3 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -1580, -2097, 1995 >, 0, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.2, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.4, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.6, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 2.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.5, "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 4 ) + + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 7252, -4815, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 6497, -3399, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 6779, -2872, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 6169, -4616, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Spectre", < 6954, -3714, 2236 >, 0.0, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 6775, -5415, 2242 >, -135, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 5522, -1508, 2236 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 3591, -1639, 2242 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 233, -4389, 2304 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 183, -5512, 2304 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -412, -6711, 2084 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -480, -1603, 2088 >, 0, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_Announce( wave5, "MediumWave", 0.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 9245, -6489, 2060 >, 180, "northForestThroughTown", 0.2 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 9336, -2261, 2106 >, 180, "northForestThroughTown", 0.3 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 9905, -6100, 1981 >, 180, "northForestLongUnderpass", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 11282, -5322, 1909 >, 180, "northForestThroughTown", 0.7 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 10358, -5975, 1948 >, 180, "northForestThroughTown", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 9784, -4432, 2007 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 9816, -6601, 2002 >, 180, "northForestLongUnderpass", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 10833, -5919, 1925 >, 180, "northForestLongUnderpass", 0.2 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 10818, -6493, 1916 >, 180, "northForestThroughTown", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 10417, -6471, 1955 >, 180, "northForestLongUnderpass", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 11318, -5970, 1957 >, 180, "northForestLongUnderpass", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 9934, -3615, 2022 >, 180, "northForestThroughTown", 0.8 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 5120, -4779, 1986 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 4765, -4527, 2010 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 6035, -3184, 2243 >, 35, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_Announce( wave5, "PreArcTitan", 0.0 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 9245, -6489, 2060 >, 180, "northForestThroughTown", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 9336, -2261, 2106 >, 180, "northForestThroughTown", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 9905, -6100, 1981 >, 180, "northForestThroughTown", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 11282, -5322, 1909 >, 180, "northForestThroughTown", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 10358, -5975, 1948 >, 180, "northForestThroughTown", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 9784, -4432, 2007 >, 180, "northForestThroughTown", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 9816, -6601, 2002 >, 180, "northForestThroughTown", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 10833, -5919, 1925 >, 180, "northForestThroughTown", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 10818, -6493, 1916 >, 180, "northForestLongUnderpass", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 10417, -6471, 1955 >, 180, "northForestLongUnderpass", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 11318, -5970, 1957 >, 180, "northForestLongUnderpass", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 9934, -3615, 2022 >, 180, "northForestLongUnderpass", 1.2 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 4984, -1991, 2165 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 5437, -1868, 2236 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 6833, -2650, 2242 >, 180, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Legion", < 9245, -6489, 2060 >, 180, "northForestLongUnderpass", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 9336, -2261, 2106 >, 180, "northForestThroughTown", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 9905, -6100, 1981 >, 180, "northForestLongUnderpass", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 11282, -5322, 1909 >, 180, "northForestThroughTown", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 10358, -5975, 1948 >, 180, "northForestThroughTown", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 9784, -4432, 2007 >, 180, "northForestThroughTown", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 9816, -6601, 2002 >, 180, "northForestThroughTown", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 10833, -5919, 1925 >, 180, "northForestThroughTown", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 10818, -6493, 1916 >, 180, "northForestLongUnderpass", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 10417, -6471, 1955 >, 180, "northForestLongUnderpass", 1.8 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 11318, -5970, 1957 >, 180, "northForestLongUnderpass", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 9934, -3615, 2022 >, 180, "northForestLongUnderpass", 0.6 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 3543, -1595, 2244 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 2928, -1864, 2304 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 5130, -4887, 1986 >, 135, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 9245, -6489, 2060 >, 180, "northForestThroughTown", 0.5, "fd_waveTypeTitanArc" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 9336, -2261, 2106 >, 180, "trenchDebrisMain", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 9905, -6100, 1981 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 11282, -5322, 1909 >, 180, "trenchDebrisMain", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 10358, -5975, 1948 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 9784, -4432, 2007 >, 180, "trenchDebrisMain", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 9816, -6601, 2002 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10833, -5919, 1925 >, 180, "trenchDebrisMain", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 10818, -6493, 1916 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10417, -6471, 1955 >, 180, "trenchDebrisMain", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 11318, -5970, 1957 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 9934, -3615, 2022 >, 180, "trenchDebrisMain", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 4643, -5283, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 4381, -4825, 2242 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 5980, -5529, 2258 >, -65, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 1.5, "fd_incCloakDroneClump" ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10833, -5919, 1925 >, 180, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10818, -6493, 1916 >, 180, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 9816, -6601, 2002 >, 180, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10358, -5975, 1948 >, 180, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 11282, -5322, 1909 >, 180, "", 0.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10417, -6471, 1955 >, 180, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 11318, -5970, 1957 >, 180, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 9905, -6100, 1981 >, 180, "", 3.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -959, -4208, 2096 >, 0, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -1741, -4984, 2016 >, 0, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -1188, -5954, 2083 >, 0, "", 0.2 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -618, -2785, 2002 >, 0, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1712, -3176, 1987 >, 0, "", 6.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 612, -5513, 2304 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 175, -4574, 2304 >, 0.0, "", 5.0 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 7168, -4750, 2242 >, 0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 5590, -1948, 2236 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 6515, -2554, 2242 >, -90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 4055, -2955, 2239 >, -145, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9336, -2261, 4000 >, 180, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9245, -6489, 4000 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 0 ) + + WaveSpawn_TitanSpawn( wave5, "Ronin", < 9816, -6601, 2002 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 11318, -5970, 1957 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 9784, -4432, 2007 >, 180, "northForestLongUnderpass", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 11282, -5322, 1909 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 9934, -3615, 2022 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 10818, -6493, 1916 >, 180, "northForestLongUnderpass", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 9816, -6601, 2002 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 9245, -6489, 2060 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < 10358, -5975, 1948 >, 180, "northForestLongUnderpass", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 11318, -5970, 1957 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 10358, -5975, 1948 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 9905, -6100, 1981 >, 180, "northForestLongUnderpass", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 9934, -3615, 2022 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 9336, -2261, 2106 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 11282, -5322, 1909 >, 180, "northForestLongUnderpass", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 10833, -5919, 1925 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 9784, -4432, 2007 >, 180, "northForestLongUnderpass", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 9245, -6489, 2060 >, 180, "northForestLongUnderpass", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 9336, -2261, 2106 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10417, -6471, 1955 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 10833, -5919, 1925 >, 180, "northForestThroughTown", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 9905, -6100, 1981 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 10818, -6493, 1916 >, 180, "northForestThroughTown", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 10417, -6471, 1955 >, 180, "northForestThroughTown", 2.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9934, -3615, 4000 >, 180, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9784, -4432, 4000 >, 180, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9336, -2261, 4000 >, 180, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 9245, -6489, 4000 >, 180, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 0, eFDHT.TITAN ) + + WaveSpawn_Announce( wave5, "NoMoreEnemyTitans", 5.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 2.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.6, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.4, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.2, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.6, "", 600.0 ) + for( reaperrain = 0; reaperrain < 8; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + } + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + for( reaperrain = 0; reaperrain < 8; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 24 ) + } + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + for( reaperrain = 0; reaperrain < 8; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 24 ) + } + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + for( reaperrain = 0; reaperrain < 8; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 24 ) + } + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + for( reaperrain = 0; reaperrain < 8; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 24 ) + } + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + for( reaperrain = 0; reaperrain < 8; reaperrain++ ) + { + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 24 ) + } + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 0.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.2, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.4, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.6, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 1.8, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 2.0, "", 600.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1412, -2284, 1993 >, 0, "", 3.0, "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -1412, -2284, 1993 >, 0.0, "", RandomFloatRange( 0.1, 0.5 ), "", 600.0 ) + + WaveSpawnEvents.append( wave5 ) +} + +void function RegisterCustomFDContent() +{ + array dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" ) + foreach ( entity dropshipSpawn in dropshipSpawns ) + dropshipSpawn.Destroy() + + AddFDCustomShipStart( < 2171, -3772, 2625 >, < 0, -45, 0 >, TEAM_MILITIA ) + AddFDCustomShipStart( < 3037, -5548, 2625 >, < 0, 45, 0 >, TEAM_MILITIA ) + AddFDCustomShipStart( < 8487, -5720, 2625 >, < 0, 180, 0 >, TEAM_IMC ) + AddFDCustomShipStart( < 9482, -3540, 2625 >, < 0, 180, 0 >, TEAM_IMC ) + + AddStationaryAIPosition( < 1808, -1942, 2167 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 4503, -6460, 2242 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 5025, -3465, 2253 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 1934, -6668, 2261 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 3619, -2267, 2230 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 9411, -6612, 2054 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + AddStationaryAIPosition( < 7512, -4631, 2220 >, eStationaryAIPositionTypes.SNIPER_TITAN ) + + AddStationaryAIPosition( < 5024, -2475, 2450 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 5533, -3809, 2628 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 7105, -2347, 2593 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 4817, -6732, 2507 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 6194, -2435, 2506 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 5014, -1615, 2500 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 4114, -1651, 2468 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 6800, -4578, 2505 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 5925, -4451, 2623 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + + AddOutOfBoundsTriggerWithParams( < 5584, -4354, 3053 >, 200, 256 ) + + routes[ "townInfantryCrossroad" ] <- [] + routes[ "townInfantryCrossroad" ].append( < 6756, -3414, 2236 > ) + routes[ "townInfantryCrossroad" ].append( < 4888, -3853, 2264 > ) + routes[ "townInfantryCrossroad" ].append( < 2896, -4846, 2242 > ) + + routes[ "trenchCloseInfantry" ] <- [] + routes[ "trenchCloseInfantry" ].append( < 4644, -5091, 2242 > ) + routes[ "trenchCloseInfantry" ].append( < 3815, -4471, 2376 > ) + routes[ "trenchCloseInfantry" ].append( < 3453, -5208, 2376 > ) + routes[ "trenchCloseInfantry" ].append( < 2846, -5137, 2236 > ) + + routes[ "trenchDebrisMain" ] <- [] + routes[ "trenchDebrisMain" ].append( < 5751, -6467, 2242 > ) + routes[ "trenchDebrisMain" ].append( < 3922, -6140, 2246 > ) + routes[ "trenchDebrisMain" ].append( < 2895, -5200, 2236 > ) + + routes[ "trenchRampsMain" ] <- [] + routes[ "trenchRampsMain" ].append( < 4635, -2001, 2125 > ) + routes[ "trenchRampsMain" ].append( < 2765, -2884, 2195 > ) + routes[ "trenchRampsMain" ].append( < 2254, -4602, 2226 > ) + + routes[ "dropPodsInfantry" ] <- [] + routes[ "dropPodsInfantry" ].append( < 6228, -1779, 2242 > ) + routes[ "dropPodsInfantry" ].append( < 4635, -2001, 2125 > ) + routes[ "dropPodsInfantry" ].append( < 2765, -2884, 2195 > ) + routes[ "dropPodsInfantry" ].append( < 2254, -4602, 2226 > ) + + routes[ "parkingLotInfantry" ] <- [] + routes[ "parkingLotInfantry" ].append( < 7974, -2288, 2232 > ) + routes[ "parkingLotInfantry" ].append( < 7165, -2677, 2416 > ) + routes[ "parkingLotInfantry" ].append( < 6486, -1863, 2242 > ) + routes[ "parkingLotInfantry" ].append( < 5166, -2778, 2240 > ) + routes[ "parkingLotInfantry" ].append( < 4575, -3832, 1961 > ) + routes[ "parkingLotInfantry" ].append( < 4575, -3832, 1961 > ) + routes[ "parkingLotInfantry" ].append( < 3815, -4471, 2376 > ) + routes[ "parkingLotInfantry" ].append( < 3453, -5208, 2376 > ) + routes[ "parkingLotInfantry" ].append( < 2846, -5137, 2236 > ) + + routes[ "debrisFieldHouse" ] <- [] + routes[ "debrisFieldHouse" ].append( < 7466, -5550, 2242 > ) + routes[ "debrisFieldHouse" ].append( < 5751, -6467, 2242 > ) + routes[ "debrisFieldHouse" ].append( < 3922, -6140, 2246 > ) + routes[ "debrisFieldHouse" ].append( < 2895, -5200, 2236 > ) + + routes[ "northForestThroughDebris" ] <- [] + routes[ "northForestThroughDebris" ].append( < 9222, -6150, 2059 > ) + routes[ "northForestThroughDebris" ].append( < 7466, -5550, 2242 > ) + routes[ "northForestThroughDebris" ].append( < 5751, -6467, 2242 > ) + routes[ "northForestThroughDebris" ].append( < 3922, -6140, 2246 > ) + routes[ "northForestThroughDebris" ].append( < 2895, -5200, 2236 > ) + + routes[ "northForestThroughTown" ] <- [] + routes[ "northForestThroughTown" ].append( < 9068, -3852, 2114 > ) + routes[ "northForestThroughTown" ].append( < 7009, -3527, 2242 > ) + routes[ "northForestThroughTown" ].append( < 4907, -3848, 2264 > ) + routes[ "northForestThroughTown" ].append( < 2897, -4723, 2236 > ) + + routes[ "westBackyardMain" ] <- [] + routes[ "westBackyardMain" ].append( < -1220, -2642, 2008 > ) + routes[ "westBackyardMain" ].append( < 1061, -2242, 2132 > ) + routes[ "westBackyardMain" ].append( < 2203, -2846, 2092 > ) + routes[ "westBackyardMain" ].append( < 2201, -4551, 2226 > ) + + routes[ "eastBackyardMain" ] <- [] + routes[ "eastBackyardMain" ].append( < -1571, -5894, 2038 > ) + routes[ "eastBackyardMain" ].append( < 1192, -6540, 2238 > ) + routes[ "eastBackyardMain" ].append( < 2914, -5157, 2236 > ) + + routes[ "backyardInfantry" ] <- [] + routes[ "backyardInfantry" ].append( < 153, -5021, 2304 > ) + routes[ "backyardInfantry" ].append( < 623, -4959, 2304 > ) + routes[ "backyardInfantry" ].append( < 2192, -5150, 2226 > ) + + routes[ "northForestLongUnderpass" ] <- [] + routes[ "northForestLongUnderpass" ].append( < 11603, -2329, 1886 > ) + routes[ "northForestLongUnderpass" ].append( < 5320, -5811, 2264 > ) + routes[ "northForestLongUnderpass" ].append( < 4947, -4670, 1986 > ) + routes[ "northForestLongUnderpass" ].append( < 4549, -2408, 2115 > ) + routes[ "northForestLongUnderpass" ].append( < 3415, -2581, 2195 > ) + routes[ "northForestLongUnderpass" ].append( < 2147, -2901, 2086 > ) + routes[ "northForestLongUnderpass" ].append( < 2240, -4533, 2226 > ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead.nut index 37b891699..b2f1d6834 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead.nut @@ -1 +1,16 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ + AddSpawnCallback( "sky_camera", FixSkycamFog ) + + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() +} + +void function FixSkycamFog( entity skycam ) +{ + if ( skycam.GetTargetName() == "skybox_cam_level" ) + skycam.kv.useworldfog = 1 +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead_fd.nut index 37b891699..22b6c75cb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_homestead_fd.nut @@ -1 +1,486 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + PlaceFDShop( < -800.156, -4250, -63 >, < 9, 60, 0 > ) + SetFDDropshipSpawn( < -1827, -4105, -64 >, < 0, 60, 0 > ) + SetFDGroundSpawn( < -1507, -3346, -128 >, < 0, 45, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeTitanMortar" ) + AddWaveAnnouncement( "fd_waveComboNukeMortar" ) + AddWaveAnnouncement( "fd_waveTypeReapers" ) + AddWaveAnnouncement( "fd_waveComboNukeTrain" ) + + //AddStationaryAIPosition(< 6328, -968, -155 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + //AddStationaryAIPosition(< -2498, 1079, -160 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + + //AddStationaryAIPosition(< -745, 2309, 82 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + //AddStationaryAIPosition(< 4463, -221, 16 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + + AddFDCustomTitanStart( < -1466, -3750, -115 >, < 0, -45, 0 > ) + AddFDCustomTitanStart( < -361, -4690, -58 >, < 0, 90, 0 > ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_SmokeWall( wave1, < -3762, -1921, -98 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < -2880, -1657, -151 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < -23, -748, -128 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < 750, -806, -141 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < 1759, -1370, -154 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < 1517, -2920, -70 >, 0.2 ) + WaveSpawn_SmokeWall( wave1, < 1691, -3801, 6 >, 3.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3867, -1497, -99 >, 0.0, "", 0.8, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3700, -2686, -68 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2699, 818, -114 >, 0.0, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 2.5 ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < 2227, -145, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2573, -520, -134 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 532, -356, -166 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 4942, -2951, 169 >, 0.0, "", 2.0, "fd_waveTypeMortarSpectre" ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 2.0 ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2, eFDHT.ALL, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 12, eFDHT.ALL, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -624, 2239, 83 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1260, 483, 56 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1186, 1923, 71 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave1, "Nuke", < 2568, -721, -122 >, -125, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave1, "Mortar", < 5982, 51, -86 >, -145, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < 2568, -721, 2560 >, 0.0, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < 5982, 51, 2560 >, 0.0, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4248, -1399, 18 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 4289, -1366, 18 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3779, -2432, -83 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4195, -2250, -81 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < 4696, -647, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 532, -356, -166 >, 0.0, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 4236, -409, 15 >, -125, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3867, -1497, -99 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4195, -2250, -81 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 4314, -215, 13 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < -742, 1759, 79 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -659, 1306, -164 >, 0.0, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 4236, -409, 15 >, -125, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1864, 1118, -160 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -969, 1243, -167 >, -122, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3247, -225, -119 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 4299, -2515, -89 >, -115, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2858, -2692, 71 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -659, 1306, -164 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 1040, 1968, 15 >, -117, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -39, 14, -167 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2573, -520, -134 >, 0.0, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 5365, 154, -168 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2077, -1077, -164 >, 0.0, "" ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_SmokeWall( wave2, < 0, -632, -105 >, 0.2 ) + WaveSpawn_SmokeWall( wave2, < 803, -838, -140 >, 0.2 ) + WaveSpawn_SmokeWall( wave2, < 1939, -1353, -133 >, 3.0 ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 1.8, "fd_waveTypeFlyers" ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 1.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1186, 1923, 71 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2573, -520, -134 >, 0.0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 4942, -2951, 169 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 4195, -2250, -81 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -624, 2239, 83 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 4195, -2250, -81 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 1260, 483, 56 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 4248, -1399, 18 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_Announce( wave2, "PreMortarTitan", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 3779, -2432, -83 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 3700, -2686, -68 >, 0.0, "", 2.0 ) + WaveSpawn_TitanSpawn( wave2, "Sniper", < 1732, 1502, 118 >, -111, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 5365, 154, -168 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -742, 1759, 79 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -3867, -1497, -99 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -2699, 818, -114 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -780, 1165, -167 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2821, -2721, 69 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 2568, -721, -122 >, -125, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "ArcTitan", < 2677, -629, -135 >, -130, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 1343, 540, 55 >, -119, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 2227, -145, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_InfantrySpawn( wave2, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1864, 1118, -160 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -39, 14, -167 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 532, -356, -166 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2858, -2692, 71 >, 0.0, "", 3.0 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 535, -283, -166 >, -90, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "ArcTitan", < 2567, 1038, -141 >, -150, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 4779, -2194, -53 >, -170, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 4696, -647, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 6, eFDHT.ALL, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 12, eFDHT.ALL, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -18, 105, -166 >, -130, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2188, -2607, 81 >, 180, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 3441, 2160, -27 >, -117, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -659, 1306, -164 >, 0.0, "", 1.2 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 5077, 843, -26 >, -117, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.8 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 3433, -2871, -69 >, -141, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -2695, 779, -109 >, -119, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_SmokeWall( wave3, < -3762, -1921, -98 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave3, < -2880, -1657, -151 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave3, < -23, -748, -128 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave3, < 750, -806, -141 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave3, < 1759, -1370, -154 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave3, < 1517, -2920, -70 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave3, < 1691, -3801, 6 >, 3.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -577, 940, -167 >, -128, "", 0.5, "fd_waveTypeTitanReg" ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 3700, -2686, -68 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 3.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < 1454, 1022, 99 >, -109, "", 2.0 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 4236, -409, 15 >, -124, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 4195, -2250, -81 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 532, -356, -166 >, 0.0, "", 4.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < 1454, 1022, 99 >, -109, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 1912, -667, -165 >, -124, "", 1.5, "fd_waveTypeReaperTicks" ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 5.0 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -969, 1243, -167 >, -122, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 4299, -2515, -89 >, -115, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < -2755, 629, -115 >, -112, "", 0.8 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 4759, -2311, -26 >, -150, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_Announce( wave3, "PreNukeTitan", 0.2 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -624, 2239, 83 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2573, -520, -134 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Mortar", < 1017, 1980, 12 >, -119, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3115, 1559, -148 >, -112, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 4392, 1336, 3 >, -112, "", 3.0 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -18, 105, -166 >, -130, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < -18, 105, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 6.0 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 4248, -1399, 18 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -1864, 1118, -160 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -3867, -1497, -99 >, 0.0, "" ) + WaveSpawn_Announce( wave3, "PreArcTitan", 0.2 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Mortar", < -828, 1313, -166 >, -125, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -2401, 1268, -167 >, -110, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3380, -2872, -67 >, -141, "", 0.8 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3844, -2611, -87 >, -147, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 2188, -2607, 81 >, 180, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 2188, -2607, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -1186, 1923, 71 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 3779, -2432, -83 >, 0.0, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -435, 1419, -138 >, -130, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2677, -629, -135 >, -130, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_TitanSpawn( wave3, "Nuke", < -2235, 1205, -167 >, -127, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 4195, -2250, -81 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < -2756, 706, -109 >, -121, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 3.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 5724, -1997, -137 >, -110, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3927, -2546, -89 >, -110, "", 6.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 4295, -2505, -89 >, -165, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2567, 1038, -141 >, -150, "", 4.0 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 1040, 1968, 15 >, -117, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 532, -356, -166 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -3867, -1497, -99 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -2699, 818, -114 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_SmokeWall( wave4, < 0, -632, -105 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < 803, -838, -140 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < 1939, -1353, -133 >, 2.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 2573, -520, -134 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 3700, -2686, -68 >, 0.0, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2614, 1551, -158 >, -148, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2198, 902, -138 >, -136, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 4850, -2053, -65 >, -160, "", 4.0 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 3590, 644, -155 >, -150, "", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < 4093, 584, -104 >, -155, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 532, -356, -166 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -3867, -1497, -99 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -2699, 818, -114 >, 0.0, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 4.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -969, 1243, -167 >, -122, "", 0.3 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 1040, 1968, 15 >, -117, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 4813, 1299, 49 >, -143, "", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < 3310, 1414, -172 >, -122, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 1454, 1022, 99 >, -109, "", 4.0 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 4696, -647, 2560 >, 0.0, "", 0.5, "fd_waveTypeCloakDrone" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_SmokeWall( wave4, < -3762, -1921, -98 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < -2880, -1657, -151 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < -23, -748, -128 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < 750, -806, -141 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < 1759, -1370, -154 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < 1517, -2920, -70 >, 0.2 ) + WaveSpawn_SmokeWall( wave4, < 1691, -3801, 6 >, 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -624, 2239, 83 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 4195, -2250, -81 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 4942, -2951, 169 >, 0.0, "", 4.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 4236, -409, 15 >, -124, "", 0.2, "fd_incReaperClump" ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3432, -2800, -66 >, -130, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -797, 1273, -167 >, -148, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < -18, 105, 2560 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 4147, -2240, -84 >, -145, "", 1.6 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < 3626, -2728, -73 >, -140, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 1260, 483, 56 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 5365, 154, -168 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -3324, -721, -151 >, 0.0, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3852, -2139, -136 >, -125, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 4299, -2515, -89 >, -115, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 4236, -409, 15 >, -124, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 1454, 1022, 99 >, -109, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 2188, -2607, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 2227, -145, 2560 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -2473, 874, -116 >, -115, "", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < -495, 1204, -163 >, -135, "", 5.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3162, -3215, -66 >, -173, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2675, 727, -105 >, -123, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 3779, -2432, -83 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 2591, -600, -132 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_SmokeWall( wave5, < 0, -632, -105 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 803, -838, -140 >, 0.2, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 1939, -1353, -133 >, 5.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3354, 1974, -47 >, -104, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2805, 2784, -89 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4729, 3027, -83 >, -130, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5726, 776, -85 >, -135, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4236, -409, 15 >, -124, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 4289, -1366, 18 >, 0.0, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2614, 1551, -158 >, -148, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2198, 902, -138 >, -136, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -577, 940, -167 >, -128, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 2708, 1109, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < -742, 1759, 79 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 3432, -2800, -66 >, -130, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_InfantrySpawn( wave5, "Drones", < 6050, 132, 2560 >, -115, "centerRightDrones_Loop1", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 3341, 2237, 2560 >, -115, "centerLeftDrones_Loop3", 3.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2677, -629, -135 >, -130, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2567, 1038, -141 >, -150, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 4779, -2194, -53 >, -170, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 5365, 154, -168 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 4696, -647, 2560 >, 0.0, "", 1.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 4738, -2308, -27 >, -160, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 4299, -2515, -89 >, -115, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 1040, 1968, 15 >, -117, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 4942, -2951, 169 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 1260, 483, 56 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4940, 1271, 37 >, -140, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5138, 1917, 35 >, -140, "", 4.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 2227, -145, 2560 >, 0.0, "", 1.0, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 5856, 1190, 2560 >, 0.0, "", 2.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 1454, 1022, 99 >, -109, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2677, -629, -135 >, -130, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2567, 1038, -141 >, -150, "", 3.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3205, 3566, -70 >, -95, "", 1.4 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 4236, -409, 15 >, -124, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4729, 3027, -83 >, -130, "", 0.3 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 3432, -2800, -66 >, -130, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5642, 2495, -32 >, -125, "", 0.2 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2198, 902, -138 >, -136, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3604, 3829, -120 >, -110, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1040, 1968, 15 >, -117, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < 3914, 1702, -59 >, -130, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Scorch", < -577, 940, -167 >, -128, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -2473, 874, -116 >, -115, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 4813, 1299, 49 >, -143, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 1017, 1980, 12 >, -119, "", 3.0 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 4942, -2951, 169 >, 0.0, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 3136, -1582, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 3852, -2139, -136 >, -125, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4850, -2053, -65 >, -160, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2614, 1551, -158 >, -148, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -969, 1243, -167 >, -122, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 2 ) + + WaveSpawn_SmokeWall( wave5, < 2805, 2415, -81 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 3335, 2719, 9 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 4059, 2313, -50 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 4504, 1416, 32 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 4483, 478, -95 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 5155, -2076, -54 >, 3.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2805, 2784, -89 >, -90, "", 0.6, "fd_incTitansNukeClump" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4773, 2413, -21 >, -140, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4712, 3255, -99 >, -100, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3482, 1601, -91 >, -140, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4940, 1271, 37 >, -140, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5726, 776, -85 >, -135, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3779, 2956, 13 >, -120, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3853, 2124, -47 >, -115, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3942, 1431, -2 >, -120, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3205, 3566, -70 >, -95, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 1454, 1022, 99 >, -109, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -435, 1419, -138 >, -130, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 4295, -2505, -89 >, -165, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 4850, -2053, -65 >, -160, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -797, 1273, -167 >, -148, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 2493, 1135, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 4584, 587, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 4236, -409, 15 >, -124, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -969, 1243, -167 >, -122, "", 5.0 ) + WaveSpawn_SmokeWall( wave5, < 2692, 1065, -154 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 3584, 527, -152 >, 5.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 1928, 4, -112 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 2593, -723, -125 >, 5.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 8, -715, -120 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 746, -1012, -136 >, 0.3, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_SmokeWall( wave5, < 1499, -1580, -156 >, 0.5, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2677, -629, -135 >, -130, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 6226, 1367, -145 >, -140, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3853, 2124, -47 >, -115, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3354, 1974, -47 >, -104, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4343, 1432, 2 >, -132, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 5304, 68, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 3070, 167, 2560 >, 0.0, "", 0.5, "", 0.0, eFDSD.EXCLUSIVE | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2567, 1038, -141 >, -150, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5367, 2985, -32 >, -120, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5367, 2985, -32 >, -120, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4712, 3255, -99 >, -100, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5642, 2495, -32 >, -125, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 3590, 644, -155 >, -150, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 4147, -2240, -84 >, -145, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2677, -629, -135 >, -130, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 6151, 176, -63 >, 170, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4343, 1432, 2 >, -132, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2567, 1038, -141 >, -150, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3604, 3829, -120 >, -110, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 6226, 1367, -145 >, -140, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 5138, 1917, 35 >, -140, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 6151, 176, -63 >, 170, "" ) + + WaveSpawnEvents.append( wave5 ) +} \ No newline at end of file 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 d5162f0bd..9b0b92d3b 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 @@ -6,7 +6,7 @@ void function CodeCallback_MapInit() // 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 ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02.nut index 37b891699..9ecdf6661 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02.nut @@ -1 +1,7 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit +void function CodeCallback_MapInit() +{ + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02_fd.nut index 37b891699..db7f359ce 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_relic02_fd.nut @@ -1 +1,429 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + useCustomFDLoad = true + AddCallback_RegisterCustomFDContent( RegisterCustomFDContent ) + + PlaceFDShop( < 3037, -3930, 192 > ) + + SetFDDropshipSpawn( < 3400, -4119, 520 >, < 0, 20, 0 > ) + SetFDGroundSpawn( < 2343, -5258, 128 >, < 0, 135, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeTitanReg" ) + AddWaveAnnouncement( "fd_waveTypeFlyers" ) + AddWaveAnnouncement( "fd_introMedium" ) + AddWaveAnnouncement( "fd_waveComboMultiMix" ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2524, -1974, 42 >, 0.0, "cliffClose", 0.6, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1167, -3639, 217 >, 0.0, "closeInfantrySafeA", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2764, -1997, 37 >, 0.0, "cliffClose", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1452, -3330, 137 >, 0.0, "closeInfantrySafeA" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1291, -5011, 130 >, 0.0, "closeInfantrySafeB", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1774, -5971, 137 >, 0.0, "hillClose", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1241, -4654, 119 >, 0.0, "closeInfantrySafeB", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2282, -6223, 161 >, 0.0, "hillClose" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -2694, -2097, 371 >, -10, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1475, -3202, -4 >, 0.0, "longInfantryShipB", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1354, -3026, -26 >, 0.0, "longInfantryShipB", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1599, -4254, 192 >, 0.0, "longInfantryShipA", 0.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -1402, -4729, 165 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1384, -2596, 133 >, 0.0,"", 0.5, "fd_waveTypeMortarSpectre" ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 1934, -5820, 136 >, 0.0,"", 2.5 ) + WaveSpawn_TitanSpawn( wave1, "Ronin", < 214, -2525, 439 >, -106, "" ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_TitanSpawn( wave2, "Monarch", < -1950, -4592, 261 >, 40, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < -2766, -2484, 468 >, -20, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1475, -3202, -4 >, 0.0, "longInfantryShipB", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1354, -3026, -26 >, 0.0, "longInfantryShipB", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1599, -4254, 192 >, 0.0, "longInfantryShipA", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -3846, -1799, 393 >, 117, "", 1.0, "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -1337, -4795, 156 >, 101, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 1384, -2596, 133 >, 0.0,"", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 1934, -5820, 136 >, 0.0,"", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 1873, -1833, 15 >, 0.0,"" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_Announce( wave2, "PreMortarTitan", 0.1 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1167, -3639, 217 >, 0.0, "closeInfantrySafeA", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1452, -3330, 137 >, 0.0, "closeInfantrySafeA", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1291, -5011, 130 >, 0.0, "closeInfantrySafeB", 0.2 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1241, -4654, 119 >, 0.0, "closeInfantrySafeB", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 2723, -5826, 89 >, 0.0,"", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3091, -4647, 459 >, 32, "infantryReaperShipStraight", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3146, -4024, 474 >, -34, "infantryReaperShipStraight", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -2902, -1197, 164 >, -33, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 220, -2569, 433 >, -105, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Northstar", < -3683, -1100, 448 >, -23, "", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Northstar", < -3009, -4702, 442 >, 52, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_TitanSpawn( wave2, "Ion", < -2013, -1649, 10 >, -40, "", 0.3 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < 171, -2565, 434 >, -85, "", 2.0 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < -3474, -4626, 477 >, 90, "", 0.3 ) + WaveSpawn_TitanSpawn( wave2, "Tone", < -1670, -3201, 28 >, 0, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -3908, -3518, 479 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -5105, -2956, 302 >, 0.0,"", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -5192, -2363, 278 >, -26, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 171, -4495, 296 >, 45, "", 1.0, "fd_waveTypeTitanMortar" ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -3844, -3510, 485 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -4716, -1118, 335 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -5570, -2555, 307 >, -6, "", 5.0 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 1824, -1917, 29 >, -90, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "Legion", < -1950, -4592, 261 >, 40, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < -2766, -2484, 468 >, -20, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 793, -6024, 2000 >, -90, "droneCliffSide", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 793, -6024, 2000 >, -90, "droneCliffSide", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -1621, -3176, 18 >, 0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 220, -2569, 433 >, -105, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -1655, -4722, 163 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Monarch", < -2013, -1649, 10 >, -40, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 171, -2565, 434 >, -85, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 197, -4412, 299 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -7, -2649, 421 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -3683, -1100, 448 >, -23, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -3917, -2910, 465 >, -95, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -3091, -4647, 459 >, 32, "infantryReaperShipStraight", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -3146, -4024, 474 >, -34, "infantryReaperShipStraight", 0.8 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -2902, -1197, 164 >, -33, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2269, -6180, 150 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1862, -5979, 134 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 171, -4495, 296 >, 45, "", 0.6 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -3844, -3510, 485 >, 180, "", 0.8 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -4716, -1118, 335 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -5570, -2555, 307 >, -6, "" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_TitanSpawn( wave4, "Monarch", < 164, -2552, 436 >, -95, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -2807, -2442, 459 >, -28, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1222, -4107, 126 >, 180, "", 1.0, "fd_waveTypeReaperTicks" ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -3806, -1743, 389 >, 88, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1839, -6113, 130 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 1894, -1839, 16 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 2716, -1926, 29 >, -125, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 1788, -1920, 29 >, -90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 2719, -1911, 26 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 1318, -5027, 134 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 2387, -2624, 147 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < 2372, -5841, 115 >, 0.0,"", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < 1385, -5033, 140 >, 106, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -210, -4496, 307 >, 10, "", 3.5 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 1278, -4350, 2560 >, 0.0, "", 0.0, "fd_waveTypeCloakDrone" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_TitanSpawn( wave4, "Tone", < -2457, -4571, 363 >, 16, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -3258, -2804, 489 >, -16, "", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -2256, -1788, 134 >, -16, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 793, -6024, 2000 >, -90, "droneCliffSide", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 793, -6024, 2000 >, -90, "droneCliffSide", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 1156, -3564, 229 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "MortarSpectre", < -4050, -3593, 467 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < -2664, -2716, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1848, -6396, 235 >, 90, "", 0.3 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 2230, -6287, 178 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 2745, -1896, 23 >, -90, "", 0.3 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 2992, -1990, 29 >, -90, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_Announce( wave5, "HeavyWave", 0.0 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -2457, -4571, 363 >, 16, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -3258, -2804, 489 >, -16, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -2256, -1788, 134 >, -16, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -3783, -4540, 518 >, 53, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -4287, -3175, 470 >, 10, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 2716, -1926, 29 >, -125, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 1788, -1920, 29 >, -90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 2 ) + + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -3091, -4647, 459 >, 32, "infantryReaperShipStraight", 0.8 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -3146, -4024, 474 >, -34, "infantryReaperShipStraight", 1.0 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 1688, -5792, 152 >, 0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 4134, 1001, 2000 >, 0, "droneHillSide", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1251, -4961, 122 >, 0.0,"", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Stalker", < 1627, -3331, 121 >, 0.0,"", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < -2605, -2956, 466 >, 173, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 1794, -6388, 242 >, 43, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < 1385, -5033, 140 >, 106, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < -210, -4496, 307 >, 10, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -1740, -2152, -37 >, 0, "", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1848, -6396, 235 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2230, -6287, 178 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2745, -1896, 23 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2992, -1990, 29 >, -90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 2 ) + + WaveSpawn_TitanSpawn( wave5, "Ronin", < -3783, -4540, 518 >, 53, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -4287, -3175, 470 >, 10, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 214, -2525, 439 >, -106, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -4262, -1184, 388 >, -55, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 1894, -1839, 16 >, 0.0,"", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -4870, -3613, 346 >, 0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 1318, -5027, 134 >, 0.0,"", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1494, -4658, 177 >, 107, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "MortarSpectre", < 2372, -5841, 115 >, 0.0,"", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < -2664, -2716, 2560 >, 0.0,"", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < -3033, -4379, 2560 >, 0.0,"", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -3667, -4514, 493 >, 45, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -5370, -2440, 258 >, 12, "" ) + + WaveSpawnEvents.append( wave5 ) +} + +void function RegisterCustomFDContent() +{ + array aiPositions = GetEntArrayByClass_Expensive( "info_target" ) + foreach ( entity position in aiPositions ) + if( position.HasKey( "editorclass" ) && position.kv.editorclass == "info_fd_ai_position" ) + position.Destroy() + + AddFDCustomTitanStart( < 4858, -4093, 173 >, < 0, 180, 0 > ) + AddFDCustomTitanStart( < 4748, -5300, 21 >, < 0, 180, 0 > ) + + AddStationaryAIPosition(< -4425, -1440, 341 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -5544, -2340, 279 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -4394, -3911, 402 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -2652, -3300, 472 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -4335, -2627, 417 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -3079, -4631, 460 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -182, -2449, 452 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -283, -4515, 291 >, eStationaryAIPositionTypes.MORTAR_TITAN) + AddStationaryAIPosition(< -2249, -2556, 456 >, eStationaryAIPositionTypes.MORTAR_TITAN) + + AddStationaryAIPosition(< 1054, -1702, 340 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< 1084, -2689, 336 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< 1932, -5168, 343 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< 1773, -6518, 261 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< 2213, -2993, 531 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< 2327, -5167, 344 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< -5609, -1495, 198 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + AddStationaryAIPosition(< -5255, -3605, 343 >, eStationaryAIPositionTypes.MORTAR_SPECTRE) + + AddStationaryAIPosition(< 348, -4272, 304 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< 3078, -6403, 119 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< 3777, -2374, 45 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< 1419, -4552, 127 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -2712, -1717, 367 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -1467, -2573, 515 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -1508, -4575, 181 >, eStationaryAIPositionTypes.SNIPER_TITAN) + AddStationaryAIPosition(< -4274, -3306, 465 >, eStationaryAIPositionTypes.SNIPER_TITAN) + + AddStationaryAIPosition(< -3114, -1930, 696 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< -3582, -2539, 696 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< 1671, -1371, 184 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< 1022, -1868, 344 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< -664, -4040, 372 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< -4754, -3119, 485 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< -3360, -1102, 448 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + AddStationaryAIPosition(< 2087, -6461, 223 >, eStationaryAIPositionTypes.LAUNCHER_REAPER) + + routes[ "bridgeMainShip" ] <- [] + routes[ "bridgeMainShip" ].append( < -2671, -2742, 460 > ) + routes[ "bridgeMainShip" ].append( < -18, -2710, 408 > ) + routes[ "bridgeMainShip" ].append( < 298, -4172, 318 > ) + routes[ "bridgeMainShip" ].append( < 3937, -4650, 7 > ) + + routes[ "altInShip" ] <- [] + routes[ "altInShip" ].append( < -3100, -4277, 493 > ) + routes[ "altInShip" ].append( < -2645, -2723, 459 > ) + routes[ "altInShip" ].append( < -93, -2536, 444 > ) + routes[ "altInShip" ].append( < 271, -4184, 317 > ) + routes[ "altInShip" ].append( < 1678, -4491, 120 > ) + routes[ "altInShip" ].append( < 3802, -4581, -11 > ) + + routes[ "farInShip" ] <- [] + routes[ "farInShip" ].append( < -3913, -3130, 471 > ) + routes[ "farInShip" ].append( < -2565, -2610, 454 > ) + routes[ "farInShip" ].append( < -51, -2543, 442 > ) + routes[ "farInShip" ].append( < 283, -4176, 318 > ) + routes[ "farInShip" ].append( < 1192, -4453, 160 > ) + routes[ "farInShip" ].append( < 1258, -6193, 152 > ) + routes[ "farInShip" ].append( < 3058, -6084, 104 > ) + routes[ "farInShip" ].append( < 4082, -4993, 12 > ) + + routes[ "longInfantryShipA" ] <- [] + routes[ "longInfantryShipA" ].append( < -1598, -4071, 138 > ) + routes[ "longInfantryShipA" ].append( < -69, -4138, 210 > ) + routes[ "longInfantryShipA" ].append( < 509, -3499, 406 > ) + routes[ "longInfantryShipA" ].append( < 1898, -3000, 167 > ) + routes[ "longInfantryShipA" ].append( < 2969, -2994, 143 > ) + routes[ "longInfantryShipA" ].append( < 3019, -3992, 56 > ) + routes[ "longInfantryShipA" ].append( < 3410, -3984, 56 > ) + routes[ "longInfantryShipA" ].append( < 3800, -4510, -3 > ) + + routes[ "longInfantryShipB" ] <- [] + routes[ "longInfantryShipB" ].append( < -1559, -3202, 4 > ) + routes[ "longInfantryShipB" ].append( < -595, -2662, -23 > ) + routes[ "longInfantryShipB" ].append( < 621, -2499, -79 > ) + routes[ "longInfantryShipB" ].append( < 1107, -2694, 151 > ) + routes[ "longInfantryShipB" ].append( < 1898, -3000, 167 > ) + routes[ "longInfantryShipB" ].append( < 2969, -2994, 143 > ) + routes[ "longInfantryShipB" ].append( < 3019, -3992, 56 > ) + routes[ "longInfantryShipB" ].append( < 3484, -4304, 48 > ) + + routes[ "closeInfantrySafeA" ] <- [] + routes[ "closeInfantrySafeA" ].append( < 1481, -3369, 137 > ) + routes[ "closeInfantrySafeA" ].append( < 1916, -3989, 160 > ) + routes[ "closeInfantrySafeA" ].append( < 2453, -4127, 120 > ) + routes[ "closeInfantrySafeA" ].append( < 3122, -3988, 55 > ) + routes[ "closeInfantrySafeA" ].append( < 3921, -4509, 15 > ) + + routes[ "closeInfantrySafeB" ] <- [] + routes[ "closeInfantrySafeB" ].append( < 1207, -4814, 133 > ) + routes[ "closeInfantrySafeB" ].append( < 1762, -4962, 128 > ) + routes[ "closeInfantrySafeB" ].append( < 2440, -5477, 128 > ) + routes[ "closeInfantrySafeB" ].append( < 2742, -5756, 94 > ) + routes[ "closeInfantrySafeB" ].append( < 3672, -5017, 30 > ) + + routes[ "cliffClose" ] <- [] + routes[ "cliffClose" ].append( < 2550, -2108, 66 > ) + routes[ "cliffClose" ].append( < 3724, -2627, 94 > ) + routes[ "cliffClose" ].append( < 4221, -4126, 57 > ) + + routes[ "hillClose" ] <- [] + routes[ "hillClose" ].append( < 1875, -6113, 131 > ) + routes[ "hillClose" ].append( < 3617, -5881, 43 > ) + routes[ "hillClose" ].append( < 4146, -4977, 20 > ) + + routes[ "mainUnderpass" ] <- [] + routes[ "mainUnderpass" ].append( < -1771, -2087, -33 > ) + routes[ "mainUnderpass" ].append( < 1014, -2051, -87 > ) + routes[ "mainUnderpass" ].append( < 2518, -2204, 88 > ) + routes[ "mainUnderpass" ].append( < 3804, -2704, 78 > ) + routes[ "mainUnderpass" ].append( < 4193, -4122, 56 > ) + + routes[ "altUnderpass" ] <- [] + routes[ "altUnderpass" ].append( < -2107, -4548, 304 > ) + routes[ "altUnderpass" ].append( < -1247, -2024, -192 > ) + routes[ "altUnderpass" ].append( < 1423, -2119, 15 > ) + routes[ "altUnderpass" ].append( < 3541, -2445, 85 > ) + routes[ "altUnderpass" ].append( < 4297, -4043, 61 > ) + + routes[ "altUnderpass2" ] <- [] + routes[ "altUnderpass2" ].append( < -1391, -3497, 16 > ) + routes[ "altUnderpass2" ].append( < -1247, -2024, -192 > ) + routes[ "altUnderpass2" ].append( < 1423, -2119, 15 > ) + routes[ "altUnderpass2" ].append( < 3541, -2445, 85 > ) + routes[ "altUnderpass2" ].append( < 4297, -4043, 61 > ) + + routes[ "farUnderpass" ] <- [] + routes[ "farUnderpass" ].append( < -4444, -1766, 341 > ) + routes[ "farUnderpass" ].append( < -3006, -1346, 255 > ) + routes[ "farUnderpass" ].append( < -1381, -2060, -167 > ) + routes[ "farUnderpass" ].append( < 157, -1236, -238 > ) + routes[ "farUnderpass" ].append( < 1523, -2235, 56 > ) + routes[ "farUnderpass" ].append( < 1497, -3317, 131 > ) + routes[ "farUnderpass" ].append( < 2545, -3328, 107 > ) + routes[ "farUnderpass" ].append( < 3825, -3467, 61 > ) + routes[ "farUnderpass" ].append( < 4224, -4119, 58 > ) + + routes[ "insideShipA" ] <- [] + routes[ "insideShipA" ].append( < 87, -4252, 312 > ) + routes[ "insideShipA" ].append( < 1179, -4251, 170 > ) + routes[ "insideShipA" ].append( < 1588, -3338, 129 > ) + routes[ "insideShipA" ].append( < 2582, -3358, 104 > ) + routes[ "insideShipA" ].append( < 3744, -3474, 60 > ) + routes[ "insideShipA" ].append( < 4357, -4079, 72 > ) + + routes[ "insideShipB" ] <- [] + routes[ "insideShipB" ].append( < -43, -2516, 445 > ) + routes[ "insideShipB" ].append( < 469, -4293, 298 > ) + routes[ "insideShipB" ].append( < 1201, -4481, 155 > ) + routes[ "insideShipB" ].append( < 1234, -6186, 160 > ) + routes[ "insideShipB" ].append( < 3402, -6058, 65 > ) + routes[ "insideShipB" ].append( < 4255, -5030, 9 > ) + + routes[ "droneCliffSide" ] <- [] + routes[ "droneCliffSide" ].append( < 3467, -6004, 59 > ) + routes[ "droneCliffSide" ].append( < 5078, -5539, 19 > ) + routes[ "droneCliffSide" ].append( < 5800, -4222, 60 > ) + routes[ "droneCliffSide" ].append( < 4658, -3256, 86 > ) + routes[ "droneCliffSide" ].append( < 3008, -1867, 11 > ) + routes[ "droneCliffSide" ].append( < 1225, -2843, 525 > ) + routes[ "droneCliffSide" ].append( < 1482, -5185, 639 > ) + routes[ "droneCliffSide" ].append( < 1524, -6117, 768 > ) + + routes[ "droneHillSide" ] <- [] + routes[ "droneHillSide" ].append( < 3972, -3000, 83 > ) + routes[ "droneHillSide" ].append( < 4049, -4589, 28 > ) + routes[ "droneHillSide" ].append( < 3525, -5825, 59 > ) + routes[ "droneHillSide" ].append( < 3525, -5825, 256 > ) + routes[ "droneHillSide" ].append( < 2532, -5460, 500 > ) + routes[ "droneHillSide" ].append( < 1685, -4169, 723 > ) + routes[ "droneHillSide" ].append( < 1277, -2847, 525 > ) + routes[ "droneHillSide" ].append( < 2392, -1935, 42 > ) + + routes[ "infantryReaperShipStraight" ] <- [] + routes[ "infantryReaperShipStraight" ].append( < -1220, -4554, 225 > ) + routes[ "infantryReaperShipStraight" ].append( < -719, -4557, 296 > ) + routes[ "infantryReaperShipStraight" ].append( < 543, -4291, 296 > ) + routes[ "infantryReaperShipStraight" ].append( < 1640, -4456, 120 > ) + routes[ "infantryReaperShipStraight" ].append( < 3883, -4633, -1 > ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise.nut index 37b891699..a9e1435ec 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise.nut @@ -1 +1,8 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise_fd.nut index 37b891699..3bd92063e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_rise_fd.nut @@ -1 +1,374 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + PlaceFDShop( < -5028, -618, 382 > ) + SetFDDropshipSpawn( < -5076, -1381, 1600 >, < 0, 35, 0 > ) + SetFDGroundSpawn( < -5301, -1111, 385 >, < 0, 45, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeReapers" ) + AddWaveAnnouncement( "fd_waveComboArcNuke" ) + AddWaveAnnouncement( "fd_waveTypeFlyers" ) + AddWaveAnnouncement( "fd_waveComboNukeCloak" ) + + AddFDCustomTitanStart( < -5678, -1146, 384 >, < 0, 0, 0 > ) + AddFDCustomTitanStart( < -5537, 275, 300 >, < 0, 0, 0 > ) + + AddStationaryAIPosition( < 2259, 1701, 393 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 2373, 2591, 276 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 1051, 1893, 512 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_TitanSpawn( wave1, "Nuke", < 2479, 1394, 61 >, 180, "rightSwitch", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave1, "Nuke", < 3465, 573, 144 >, 180, "mid" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 0 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3123, 1509, 320 >, 0.0, "", 0.5, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3386, 1388, 320 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2366, -233, 384 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2493, -463, 384 >, 0.0, "", 1.1 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3332, -1759, 384 >, 0.0, "", 1.3 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3541, 204, 144 >, 0.0, "right_infantry" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 2 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3105, 1240, 320 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2570, -303, 384 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -551, -1102, 247 >, 0.0, "", 0.9 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2178, 1383, 36 >, 0.0, "", 1.3, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1352, 1453, 264 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3534, 171, 144 >, 0.0, "infantyPerch_right", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -1007, 410, 246 >, 0.0, "", 0.6 ) + WaveSpawn_TitanSpawn( wave1, "Nuke", < 3571, 165, 144 >, 180, "right", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -978, -1501, 248 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2470, -486, 384 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2819, -1764, 384 >, 0.0, "", 1.1 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -3259, -1760, 384 >, 0.0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -1015, 1485, 264 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -3231, 1428, 320 >, 0.0, "", 1.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3345, 637, 144 >, 0.0, "infantyPerch_right", 0.8 ) + WaveSpawn_ReaperSpawn( wave1, "Reaper", < 831, 1624, 142 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave1, "Nuke", < 3465, 573, 144 >, 180, "midalt", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -3442, 1479, 320 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -511, -1058, 247 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3013, 22, 173 >, 0.0, "infantyPerch_right", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2203, -355, 335 >, 0.0, "", 1.2 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -3312, -1749, 384 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -994, 407, 246 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -3008, 1468, 320 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 3541, 204, 144 >, 0.0, "right_infantry" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 8 ) + + WaveSpawn_ReaperSpawn( wave1, "Reaper", < 2892, 124, 163 >, 180, "midalt", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -2771, -1751, 384 >, 0.0, "", 0.7 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -2463, -476, 384 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3345, 637, 144 >, 0.0, "infantyPerch_right", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 3057, 34, 173 >, 0.0, "right_infantry", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1779, 1573, 13 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -928, 1514, 264 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -554, -1088, 247 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave1, "Nuke", < 3539, 167, 144 >, 180, "right" ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -3084, 1475, 320 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -3382, 1438, 320 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -3145, -1765, 384 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -2443, -546, 384 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1436, 1468, 264 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Scorch", < 3460, 586, 144 >, 180, "mid", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3380, 2657, 88 >, 180, "", 0.6, "fd_incReaperClump" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1921, 3511, 12 >, -90, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2418, 3569, 14 >, -90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 1442, 2248, 8 >, -90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 257, 2104, 180 >, -90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 1882, 1635, 11 >, 180, "", 0.8 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < 3522, 44, 150 >, 180, "mid", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3609, 191, 144 >, 180, "right", 0.4 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3311, 592, 156 >, -90, "right", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3102, 89, 173 >, -90, "midalt", 1.2 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3509, 435, 148 >, -90, "midalt", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3675, 650, 144 >, -90, "right", 0.4 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3624, -33, 216 >, -90, "right" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Scorch", < 3460, 586, 144 >, 180, "right", 0.4 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1453, 3347, 22 >, -90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3458, 3032, 93 >, -90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1818, 3232, 13 >, -90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 535, 471, 255 >, 180, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 76, 1713, 207 >, -90, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -1105, -1679, 248 >, 135, "", 1.2 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < 3522, 44, 150 >, 180, "mid", 1.2 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3624, -33, 216 >, -90, "mid", 1.2 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3509, 435, 148 >, -90, "midalt", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3609, 191, 144 >, 180, "mid", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3102, 89, 173 >, -90, "midalt", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3675, 650, 144 >, -90, "mid", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3311, 592, 156 >, -90, "mid", 0.4 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < 3545, 223, 144 >, 180, "midalt", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2833, 257, 168 >, -90, "right", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3726, 1236, 107 >, -90, "right" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 8, eFDHT.ALL, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawn_TitanSpawn( wave2, "ArcTitan", < 1511, 3356, 15 >, -90, "", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "ArcTitan", < 3573, 184, 144 >, 180, "mid", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "ArcTitan", < 2507, 1438, 58 >, 180, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 257, 2104, 180 >, -90, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 76, 1713, 207 >, -90, "", 0.4, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -2147, -142, 318 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -2147, -477, 318 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -1562, 1587, 265 >, -90, "", 0.4, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -1105, -1679, 248 >, 135, "", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 1511, 3356, 15 >, -90, "", 1.0, "fd_waveTypeTitanArc" ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3573, 184, 144 >, 180, "mid", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 3419, 551, 145 >, 180, "mid", 0.8 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 314, 2055, 168 >, -90, "leftDangerClose", 1.4 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 990, 3545, 74 >, -90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1813, 3481, 18 >, -90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < 3403, 82, 148 >, 180, "", 2.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3545, 223, 144 >, 180, "right", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 314, 2055, 168 >, -90, "leftDangerClose", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2916, 8, 158 >, 0.0, "right_infantry", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -3060, 1477, 320 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1750, 1591, 12 >, 0.0, "left_infantry" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 1511, 3356, 15 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3573, 184, 144 >, 180, "mid", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2507, 1438, 58 >, 180, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 3176, 612, 147 >, 180, "mid", 1.6 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 3460, 586, 144 >, 180, "right", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 3522, 44, 150 >, 180, "right", 1.2 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 1524, 1828, 8 >, 0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < -254, 3054, 2560 >, 0.0, "leftDrone", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 265, -2077, 2560 >, 0.0, "midDrone", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -1031, 408, 245 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -2474, -479, 384 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -3242, 1472, 320 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3441, 565, 145 >, 180, "mid", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3545, 223, 144 >, 180, "mid", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 1372, 3163, 10 >, -90, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 2379, 3533, 16 >, -90, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 8 ) + + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2925, 54, 160 >, 180, "right", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -1100, -1687, 248 >, 135, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2916, 8, 158 >, 0.0, "right_infantry", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 314, 2055, 168 >, -90, "leftDangerClose", 1.2 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 1665, 3238, 14 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 3360, 583, 150 >, 180, "mid", 0.7 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < 3606, 103, 147 >, 180, "right", 1.4 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -1255, 401, 241 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3542, 407, 144 >, 180, "right", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 3136, 589, 146 >, 180, "mid", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 972, 2971, 41 >, -90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 1926, 2160, 2560 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -3053, -1765, 384 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < 3403, 82, 148 >, 180, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3532, 395, 144 >, 180, "right", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3390, 142, 153 >, 180, "right", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 3119, 584, 146 >, 180, "right", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_InfantrySpawn( wave4, "Drones", < -498, 3119, 2560 >, 0.0, "closeDrone3", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -498, 3119, 2560 >, 0.0, "closeDrone3", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 128, -2075, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 1.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_InfantrySpawn( wave4, "Drones", < -498, 3119, 2560 >, 0.0, "closeDrone3", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 128, -2075, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 128, -2075, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 5.0 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1372, 3163, 10 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 2379, 3533, 16 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2798, 250, 166 >, 180, "mid", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3098, 16, 173 >, 180, "right", 1.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3430, 578, 144 >, -90, "", 1.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3596, 165, 144 >, -90, "", 1.8 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 1926, 2160, 2560 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -2098, -589, 303 >, 180, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_InfantrySpawn( wave4, "Drones", < -498, 3119, 2560 >, 0.0, "leftDrone", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 128, -2075, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3128, 44, 169 >, 180, "mid", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3204, 593, 149 >, 180, "mid", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 314, 2055, 168 >, -90, "leftDangerClose", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2798, 250, 166 >, 180, "right", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 2510, 1443, 57 >, -90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2726, 2931, 9 >, -90, "", 1.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 1640, 3091, 8 >, -90, "", 1.4 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -2098, -295, 303 >, 180, "", 1.2, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -3337, 1449, 320 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1207, 1492, 264 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -1065, 416, 245 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 8 ) + + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3247, 590, 157 >, 180, "right", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1901, 3538, 11 >, -90, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1481, 3328, 17 >, -90, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 2215, 3491, 11 >, -90, "", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -254, 3054, 2560 >, 0.0, "leftDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -254, 3054, 2560 >, 0.0, "leftDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2798, 250, 166 >, 180, "mid", 0.6 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3098, 16, 173 >, 180, "midalt", 0.8 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 3403, 82, 148 >, 180, "", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 3542, 407, 144 >, 180, "right", 3.5 ) + WaveSpawn_InfantrySpawn( wave4, "CloakDrone", < 3395, 301, 2560 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2806, 190, 171 >, 180, "mid", 1.2 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3591, 155, 144 >, 180, "midalt", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3133, 69, 168 >, 180, "right", 1.4 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3611, 133, 146 >, 180, "right", 1.4, "", 0.0,eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3226, 62, 159 >, 180, "mid", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 3653, 611, 144 >, 180, "mid", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < 1066, 3110, 40 >, -90, "", 1.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -3092, -1760, 384 >, 0.0, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -2476, -494, 384 >, 0.0, "", 0.4, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -3100, 1254, 320 >, 0.0, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 314, 2055, 168 >, -90, "leftDangerClose", 1.2 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2500, 1433, 58 >, 180, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_InfantrySpawn( wave5, "Drones", < -254, 3054, 2560 >, 0.0, "leftDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 265, -2077, 2560 >, 0.0, "midDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -498, 3119, 2560 >, 0.0, "closeDrone3", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 128, -2075, 2560 >, 0.0, "closeDrone1", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3532, 395, 144 >, 180, "right", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3390, 142, 153 >, 180, "right", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3119, 584, 146 >, 180, "right", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2817, 88, 160 >, 180, "mid", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 3605, -32, 213 >, 180, "midalt", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 314, 2055, 168 >, -90, "leftDangerClose", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3224, 97, 164 >, 180, "mid", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3446, 457, 155 >, 180, "mid", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2662, 2239, 8 >, 180, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2878, 2536, 8 >, 180, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 1926, 2160, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_InfantrySpawn( wave5, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -22, -2102, 2560 >, 0.0, "closeDrone2", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 128, -2075, 2560 >, 0.0, "closeDrone1", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -254, 3054, 2560 >, 0.0, "leftDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -254, 3054, 2560 >, 0.0, "leftDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2774, 2837, 9 >, 180, "", 0.7 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3105, 2975, 13 >, 180, "", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2728, 2292, 16 >, 180, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 1368, 3162, 10 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 1821, 3318, 16 >, -90, "", 1.6 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < 3559, 197, 144 >, 180, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3224, 97, 164 >, 180, "right", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3446, 457, 155 >, 180, "right", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3668, 645, 144 >, 180, "right", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3618, 252, 144 >, 180, "right", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 3395, 301, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3009, 33, 172 >, 180, "right", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 3101, 624, 144 >, 180, "mid", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2421, 1385, 55 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 2296, 1136, 70 >, 180, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3247, 590, 157 >, 180, "right", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1901, 3538, 11 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1481, 3328, 17 >, -90, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2215, 3491, 11 >, -90, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3611, 133, 146 >, 180, "right", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3226, 62, 159 >, 180, "mid", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3653, 611, 144 >, 180, "mid", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1066, 3110, 40 >, -90, "", 1.6 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1562, 3348, 13 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 1821, 3318, 16 >, -90, "", 1.6 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 265, -2077, 2560 >, 0.0, "midDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 265, -2077, 2560 >, 0.0, "midDrone", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -498, 3119, 2560 >, 0.0, "closeDrone3", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -498, 3119, 2560 >, 0.0, "closeDrone3", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3247, 590, 157 >, 180, "midalt", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1901, 3538, 11 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2215, 3491, 11 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3611, 133, 146 >, 180, "midalt", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1066, 3110, 40 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3653, 611, 144 >, 180, "right", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3226, 62, 159 >, 180, "right", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1481, 3328, 17 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1822, 3189, 11 >, -90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 2817, 88, 160 >, 180, "mid", 0.8 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 3395, 301, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 8 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < 987, 2893, 39 >, -90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1347, 3187, 13 >, -90, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1581, 3389, 14 >, -90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2759, 2855, 9 >, 180, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2975, 2677, 8 >, 180, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2780, 2495, 11 >, 180, "", 1.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3189, 608, 146 >, 180, "mid", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3451, 512, 147 >, 180, "mid", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3499, -6, 160 >, 180, "mid", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3101, 77, 172 >, 180, "right", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3537, -41, 191 >, 180, "right", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3593, 227, 144 >, 180, "right", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "CloakDrone", < 3395, 301, 2560 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < 3605, -32, 213 >, 180, "right", 1.4 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < 1885, 3470, 16 >, -90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3640, 640, 144 >, 180, "right", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3507, 426, 148 >, 180, "right", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3542, 126, 145 >, 180, "right" ) + + WaveSpawnEvents.append( wave5 ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw.nut index 37b891699..a9e1435ec 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw.nut @@ -1 +1,8 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw_fd.nut index 37b891699..f57b631a9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_thaw_fd.nut @@ -1 +1,347 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + PlaceFDShop( < -2405, -3182, -541 >, < 0, 17, 0 > ) + SetFDDropshipSpawn( < -1736, -1505, 261 >, < 0, 180, 0 > ) + SetFDGroundSpawn( < -1340, -1989, -192 >, < 0, -15, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeReapers" ) + AddWaveAnnouncement( "fd_soonNukeTitans" ) + AddWaveAnnouncement( "fd_waveTypeFlyers" ) + AddWaveAnnouncement( "fd_waveComboNukeMortar" ) + + AddFDCustomTitanStart( < -2776, -1603, -364 >, < 0, -45, 0 > ) + AddFDCustomTitanStart( < -1960, -3785, -467 >, < 0, 90, 0 > ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -877, 699, -290 >, 0.0, "", 1.0, "fd_waveTypeInfantry" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 586, 100, -191 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -52, 2281, -349 >, 0.0, "", 5.0 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1518, -3368, -249 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1174, -2721, -253 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2097, -2461, -95 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1940, -4357, -238 >, 0.0, "", 0.6, "fd_waveTypeStalkers" ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2371, 1085, -300 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1994, 2572, 79 >, 0.0, "left_infantry", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1529, 2559, 99 >, 0.0, "left_infantry", 1.2 ) + WaveSpawn_InfantrySpawn( wave1, "DropshipGrunt", < -118, -3714, -250 >, -43, "", 0.5, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2433, -3137, -305 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2068, -223, -127 >, 0.0, "", 1.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1458, 110, -243 >, 0.0, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 2164, -735, 16 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -1023, 259, -302 >, 0.0, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -1114, 609, -309 >, 0.0, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 1584, -183, -210 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -881, 642, -289 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -868, 1613, -319 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -562, -169, -234 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "DropshipGrunt", < 3681, -2573, -336 >, 190, "", 2.0, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1972, 2066, -332 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 6 ) + + WaveSpawn_TitanSpawn( wave1, "Nuke", < 614, -781, -308 >, 180, "midNear", 0.3, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave1, "Nuke", < 753, -4250, -213 >, 180, "rightNear", 0.3, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < -96, -3675, -200 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 2872, -2388, -378 >, -176, "", 1.3, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 350, -4402, -194 >, 0.0, "", 1.6 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < -922, 2236, -362 >, -172, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave1, "Stalker", < 1049, -3360, -246 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave1, "Mortar", < 3780, -2470, -334 >, 180, "", 0.3, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_InfantrySpawn( wave2, "DropshipGrunt", < -50, -1004, -422 >,40, "", 1.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD, 6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3648, -3017, -306 >, 180, "", 0.6, "fd_waveTypeReapers" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3687, -1981, -353 >, 180, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3682, -2563, -328 >, 180, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3313, -2788, -334 >, 180, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2984, 450, -313 >, -125, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1486, -2911, -246 >, 0.0, "", 0.3, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < 1571, -43, -221 >, 0.0, "", 5.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 617, 52, -191 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -489, 897, -318 >, -115, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -938, 838, -290 >, -115, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2718, 1120, -280 >, -132, "", 0.4 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1787, 2052, -313 >, 158, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 1018, 2858, -363 >, -156, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 646, -4515, -222 >, 128, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 1895, -4598, -216 >, 86, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "DropshipGrunt", < -118, -3714, -250 >, -43, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD, 6 ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < 3056, -2845, 2816 >, 0.0, "midDrone" ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -1092, 843, -299 >, -90, "leftNear", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -75, -1057, -379 >, 0, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -1, -797, -384 >, 0, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3045, 404, -318 >, -90, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_TitanSpawn( wave2, "Sniper", < 4241, -17, -390 >, -159, "", 2.5, "fd_waveTypeTitanReg" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4323, -362, -405 >, 167, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4165, 146, -380 >, -163, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 4014, -111, -417 >, -158, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2413, 1934, -331 >, -176, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2183, 1783, -321 >, -51, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < 3459, -2928, -301 >, 173, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < -1011, 3878, -463 >, -90, "", 0.3, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2147, 2549, 74 >, 0.0, "left_infantry", 0.2, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1473, 2426, 93 >, 0.0, "left_infantry", 0.4, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave2, "Stalker", < -258, -141, -209 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2848, -4144, -328 >, 160, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2182, -4263, -287 >, 135, "", 1.4 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2004, -4563, -218 >, 86, "", 1.3 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -2369, 1961, -393 >, -39, "", 1.2 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -2073, 1489, -349 >, -31, "", 2.0 ) + WaveSpawn_TitanSpawn( wave2, "Scorch", < -2269, 2679, -475 >, -45, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Nuke", < -1090, 3374, -425 >, -98, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 2696, 1065, -282 >, -90, "", 0.3, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 3451, -3401, -292 >, 145, "", 0.3, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -10, 2062, -327 >, 0.0, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 559, 99, -194 >, 0.0, "", 0.2, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < -2898, 3657, 2560 >, 0.0, "closeDrone1" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 328, 2479, -386 >, -90, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 398, 2722, -420 >, -90, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 1775, -4320, -221 >, 90, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2021, -4477, -225 >, 90, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1940, -4357, -238 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 812, -4289, -214 >, 132, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 3673, -2540, -332 >, 175, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2433, -3137, -305 >, 0.0, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 3197, -3281, -324 >, 148, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -881, 642, -289 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 3752, -1068, -417 >, 164, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 449, -4423, -197 >, 149, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 2164, -735, 16 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Northstar", < 586, 135, -192 >, 180, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 2 ) + + WaveSpawn_TitanSpawn( wave3, "Scorch", < -2416, 2457, -439 >, -50, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < -813, 3976, -473 >, -88, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < -2057, 3627, -482 >, -50, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1972, 2066, -332 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 580, -590, -286 >, -171, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -868, 1613, -319 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 618, 70, -192 >, -177, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -501, 2750, -386 >, 123, "", 0.5, "fd_waveTypeTitanMortar" ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -1424, 4142, -437 >, -91, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -2547, 3096, -473 >, -61, "", 3.0 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 4178, 100, -382 >, 180, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3690, -2637, -320 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 3765, -1241, -419 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < -2898, 3657, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < 759, -4284, -214 >, 180, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 6 ) + + WaveSpawn_TitanSpawn( wave3, "Ion", < 3748, -1859, -359 >, 170, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < 3708, -1242, -413 >, 165, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 1066, 2832, -359 >, -135, "", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 4013, 100, -397 >, -165, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < 4114, -291, -415 >, -173, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 957, 2210, -330 >, 179, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1049, -3360, -246 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 3056, -2845, 2560 >, 0.0, "midDrone", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < -96, -3675, -200 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < 2548, -4935, 2560 >, 0.0, "closeDrone2", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Stalker", < 1280, -5518, -144 >, 0.0, "", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 4204, -308, -357 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 729, -4295, -215 >,91, "", 2.5, "fd_waveTypeTitanNuke" ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 4043, 77, -344 >, -165, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 2013, -4526, -224 >, 87, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < 4098, -87, -405 >, -165, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Nuke", < 2624, -4138, -313 >, 122, "", 5.0 ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -1514, 3897, -470 >, -90, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "Mortar", < -1006, 3891, -464 >, -90, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -93, -914, -404 >, 5, "" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2316, -4487, -293 >, 104, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 1025, 2841, -361 >, -146, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 1962, -4542, -214 >, 102, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -197, 3952, -447 >, -155, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2079, -4227, -272 >,93, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -1539, 4136, -437 >, -73, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3056, -2845, 2560 >, 0.0, "midDrone", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 2548, -4935, 2560 >, 0.0, "closeDrone2", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < 3056, -2845, 2560 >, 0.0, "rightDrone", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -501, 2750, -386 >, 123, "", 1.5, "fd_incTitansMortarClump" ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -1424, 4142, -437 >, -91, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -2547, 3096, -473 >, -61, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3905, 52, -419 >, -159, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Ronin", < 2660, 1057, -285 >, -94, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 3814, 231, -400 >, -167, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3818, -897, -422 >, 177, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 4136, 89, -388 >, -156, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < 3615, -2674, -325 >, -168, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 38, -820, -382 >, 0.0, "", 0.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 74, -4479, -237 >, 0.0, "", 5.0, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -1514, 3897, -470 >, -90, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -1006, 3891, -464 >, -90, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 4178, 100, -382 >, 180, "", 0.7, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3690, -2637, -320 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3765, -1241, -419 >, 180, "", 1.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -2898, 3657, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1725, 2522, -403 >, -89, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3319, -3133, -320 >, 177, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1337, 2796, -399 >, -73, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2796, -4140, -330 >, 140, "", 2.5, "", 0.0, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1100, 3355, -424 >, -49, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 2151, -4485, -270 >, 102, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < 483, -4278, -218 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Stalker", < -185, -159, -208 >, 0.0, "", 5.0 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < 586, 135, -192 >, 180, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -93, -914, -404 >,5, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 2445, -4363, -323 >, 125, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 4218, -286, -408 >, -171, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 4123, 162, -381 >, -161, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3707, -2056, -355 >, 168, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Nuke", < 510, -4507, -231 >, 119, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_Announce( wave5, "MediumWave", 0.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 3056, -2845, 2560 >, 0.0, "midDrone", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 2548, -4935, 2560 >, 0.0, "closeDrone2", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 3056, -2845, 2560 >, 0.0, "rightDrone", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 3472, -2986, -302 >, 176, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 3749, -2088, -354 >, 166, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 4202, 42, -388 >, -151, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 670, -4362, -220 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 0, eFDHT.ALL, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 4, eFDHT.ALL, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1904, 2592, -433 >, -55, "", 1.4, "fd_incTitansNukeClump" ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1161, 3367, -422 >, -54, "", 1.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2153, -4379, -278 >, 131, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2810, -4170, -332 >, 138, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 2394, 1975, -334 >, -143, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -2898, 3657, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1514, 3897, -470 >, -90, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1006, 3891, -464 >, -90, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 4178, 100, -382 >, 180, "", 0.7, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3690, -2637, -320 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3765, -1241, -419 >, 180, "", 1.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 2 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1054, 3271, -422 >, -95, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3708, -2992, -305 >, 164, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1985, 2467, -425 >, -61, "", 0.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1904, 2592, -433 >, -55, "", 1.4, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4053, -83, -410 >, -156, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2153, -4379, -278 >, 131, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2810, -4170, -332 >, 138, "", 1.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1161, 3367, -422 >, -54, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6, eFDHT.ALL, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawn_TitanSpawn( wave5, "Legion", < 3427, -3299, -303 >, 147, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 4219, -42, -393 >, -158, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 4178, 100, -382 >, 180, "", 0.6, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3690, -2637, -320 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3765, -1241, -419 >, 180, "", 0.8, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -613, 3681, -444 >, -79, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1905, 3665, -478 >, -67, "", 1.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1838, 2537, -421 >, -52, "", 1.3 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -2166, 1661, -368 >, -34, "", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1207, 4138, -449 >, -81, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -227, 3983, -448 >, -132, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 0, eFDHT.ALL, eFDSD.EASY | eFDSD.NORMAL | eFDSD.HARD ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 4, eFDHT.ALL, eFDSD.MASTER | eFDSD.INSANE ) + + WaveSpawn_TitanSpawn( wave5, "Scorch", < 3427, -3299, -303 >, 147, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3721, -1174, -415 >, -177, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3657, -2016, -354 >, -175, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2714, -4188, -333 >, 127, "", 2.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 1933, -4395, -234 >, 88, "", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 729, -4295, -215 >,91, "", 0.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2013, -4526, -224 >, 87, "", 0.7, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2624, -4138, -313 >, 122, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 4106, 100, -389 >, -141, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 2419, 1885, -328 >, 180, "", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < 586, 135, -192 >, 180, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -2898, 3657, 2560 >, 0.0, "closeDrone1", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -896, 4959, 2560 >, 0.0, "farDrone1" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 4 ) + + WaveSpawn_TitanSpawn( wave5, "Nuke", < 4053, -83, -410 >, -156, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3795, -1990, -350 >, -179, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 3708, -2992, -305 >, 164, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 552, -4475, -227 >, 134, "", 0.4 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1985, 2467, -425 >, -61, "", 0.2 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1054, 3271, -422 >, -95, "", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1904, 2592, -433 >, -55, "", 1.4, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < -1161, 3367, -422 >, -54, "", 1.2, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2153, -4379, -278 >, 131, "", 1.0, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_TitanSpawn( wave5, "Nuke", < 2810, -4170, -332 >, 138, "", 2.5, "", 0.0, eFDSD.MASTER | eFDSD.INSANE ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 3056, -2845, 2560 >, 0.0, "midDrone", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 2548, -4935, 2560 >, 0.0, "closeDrone2", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < 3056, -2845, 2560 >, 0.0, "rightDrone", 5.0 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -1491, 3937, -471 >, -74, "", 1.0 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -2393, 3087, -470 >, -59, "", 0.8 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 2660, 1079, -285 >, -104, "", 0.6 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3851, 224, -397 >, -139, "" ) + + WaveSpawnEvents.append( wave5 ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut index a8e739c6d..8e93bfb24 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut @@ -22,15 +22,21 @@ void function CodeCallback_MapInit() AddDeathCallback( "npc_spectre", WargamesDissolveDeadEntity ) AddDeathCallback( "npc_pilot_elite", WargamesDissolveDeadEntity ) AddDeathCallback( "npc_marvin", WargamesDissolveDeadEntity ) - AddSpawnCallback( "info_spawnpoint_marvin", AddMarvinSpawner ) AddCallback_GameStateEnter( eGameState.Prematch, SpawnMarvinsForRound ) - // currently disabled until finished: intro - if ( !IsFFAGame() ) - ClassicMP_SetLevelIntro( WargamesIntroSetup, 20.0 ) + // Load Frontier Defense Data + if( GameRules_GetGameMode() == FD ) + initFrontierDefenseData() + else + { + // currently disabled until finished: intro + if ( !IsFFAGame() && GetClassicMPMode() ) + ClassicMP_SetLevelIntro( WargamesIntroSetup, 21.6 ) + } } + void function AddEvacNodes() { AddEvacNode( GetEnt( "evac_location1" ) ) @@ -44,31 +50,12 @@ void function AddEvacNodes() // dissolve effects void function WargamesDissolveDeadEntity( entity deadEnt, var damageInfo ) { - if ( deadEnt.IsPlayer() || GamePlayingOrSuddenDeath() || GetGameState() == eGameState.Epilogue ) - { - deadEnt.Dissolve( ENTITY_DISSOLVE_CHAR, < 0, 0, 0 >, 0 ) - EmitSoundAtPosition( TEAM_UNASSIGNED, deadEnt.GetOrigin(), "Object_Dissolve" ) - - if ( deadEnt.IsPlayer() ) - thread EnsureWargamesDeathEffectIsClearedForPlayer( deadEnt ) - } -} - -void function EnsureWargamesDeathEffectIsClearedForPlayer( entity player ) -{ - // this is slightly shit but whatever lol - player.EndSignal( "OnDestroy" ) - - float startTime = Time() - while ( player.kv.VisibilityFlags != "0" ) - { - if ( Time() > startTime + 4.0 ) // if we wait too long, just ignore - return - - WaitFrame() - } + EmitSoundAtPosition( TEAM_UNASSIGNED, deadEnt.GetOrigin(), "Object_Dissolve" ) - player.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + if ( deadEnt.IsPlayer() ) + deadEnt.DissolveNonLethal( ENTITY_DISSOLVE_CHAR, < 0, 0, 0 >, 500 ) + else + deadEnt.Dissolve( ENTITY_DISSOLVE_CHAR, < 0, 0, 0 >, 500 ) } void function AddMarvinSpawner( entity spawn ) @@ -120,6 +107,10 @@ void function WargamesIntro_AddPlayer( entity player ) void function OnPrematchStart() { + array triggers = GetEntArrayByClass_Expensive( "trigger_hurt" ) // Disable temporarily for intro + foreach ( entity trigger in triggers ) + trigger.kv.triggerFilterPlayer = "none" + ClassicMP_OnIntroStarted() file.introStartTime = Time() @@ -137,72 +128,49 @@ void function OnPrematchStart() thread FirstPersonSequence( openPodSequence, file.militiaPod ) array trackedEntities - + + entity militiaOgre = CreatePropDynamic( $"models/titans/ogre/ogreposeopen.mdl", < -2060, 2856, -1412.5 >, < 0, 0, 0 > ) + // create copies for each team, so that the lights and stuff work, because player faction choices may not match with their actual team foreach ( int team in [ TEAM_IMC, TEAM_MILITIA ] ) { - // militia titans/marvins - entity militiaOgre = CreatePropDynamic( $"models/titans/ogre/ogreposeopen.mdl", < -2060, 2856, -1412.5 >, < 0, 0, 0 > ) - SetTeam( militiaOgre, team ) - trackedEntities.append( militiaOgre ) - - entity militiaIon = CreatePropDynamic( $"models/titans/medium/titan_medium_ajax.mdl", < -1809.98, 2790.39, -1409 >, < 0, 80, 0 > ) - thread PlayAnim( militiaIon, "at_titan_activation_wargames_intro" ) - militiaIon.Anim_SetInitialTime( 4.5 ) - SetTeam( militiaIon, team ) + // militia titan, marvins, and grunts + entity militiaIon = SpawnSkitGuy( "titan_atlas_stickybomb", < -1809.98, 2790.39, -1409 >, < 0, 80, 0 >, "at_titan_activation_wargames_intro", 4.0, team ) + trackedEntities.append( militiaIon ) - entity militiaGrunt = CreatePropDynamic( $"models/humans/grunts/mlt_grunt_rifle.mdl", < 0, 0, 0 >, < 0, 0, 0 > ) - militiaGrunt.SetParent( militiaIon, "HIJACK" ) - militiaGrunt.MarkAsNonMovingAttachment() - militiaGrunt.Anim_Play( "pt_titan_activation_pilot" ) - militiaGrunt.Anim_EnableUseAnimatedRefAttachmentInsteadOfRootMotion() - SetTeam( militiaGrunt, team ) - trackedEntities.append( militiaGrunt ) - - entity militiaOgreMarvin1 = CreatePropDynamic( $"models/robots/marvin/marvin.mdl", < -2113, 2911, -1412 >, < 0, 20, 0 > ) - thread PlayAnim( militiaOgreMarvin1, "mv_idle_weld" ) - SetTeam( militiaOgreMarvin1, team ) - trackedEntities.append( militiaOgreMarvin1 ) - - entity militiaOgreMarvin2 = CreatePropDynamic( $"models/robots/marvin/marvin.mdl", < -2040, 2788, -1412 >, < 0, 140, 0 > ) - thread PlayAnim( militiaOgreMarvin2, "mv_idle_weld" ) - SetTeam( militiaOgreMarvin2, team ) - trackedEntities.append( militiaOgreMarvin2 ) - - entity militiaOgreMarvin3 = CreatePropDynamic( $"models/robots/marvin/marvin.mdl", < -2116, 2868, -1458 >, < 0, 127, 0 > ) - thread PlayAnim( militiaOgreMarvin3, "mv_turret_repair_A_idle" ) - SetTeam( militiaOgreMarvin3, team ) - trackedEntities.append( militiaOgreMarvin3 ) - - entity militiaMarvinChillin = CreatePropDynamic( $"models/robots/marvin/marvin.mdl", < -1786, 3060, -1412 >, < 0, -120, 0 > ) - thread PlayAnim( militiaMarvinChillin, "mv_idle_unarmed" ) - SetTeam( militiaMarvinChillin, team ) - trackedEntities.append( militiaMarvinChillin ) + entity militiaIonGrunt = SpawnSkitGuy( "npc_soldier", < 0, 0, 0 >, < 0, 0, 0 >, "", -1.0, team, $"models/humans/grunts/mlt_grunt_smg.mdl" ) + + militiaIonGrunt.SetParent( militiaIon, "HIJACK" ) + militiaIonGrunt.MarkAsNonMovingAttachment() + militiaIonGrunt.Anim_ScriptedPlay( "pt_titan_activation_pilot" ) + militiaIonGrunt.Anim_EnableUseAnimatedRefAttachmentInsteadOfRootMotion() + trackedEntities.append( militiaIonGrunt ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -2125, 3070, -1411 >, < 0, -121, 0 >, "pt_bored_interface_leanin", -1.0, team, $"models/humans/grunts/mlt_grunt_rifle.mdl" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -2160, 3052, -1411 >, < 0, -132, 0 >, "pt_bored_interface_leanback", -1.0, team, $"models/humans/grunts/mlt_grunt_shotgun.mdl", "mp_weapon_shotgun" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_marvin", < 2040, 2788, -1412 >, < 0, 20, 0 >, "mv_idle_weld", -1.0, team ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_marvin", < -2113, 2911, -1412 >, < 0, 140, 0 >, "mv_idle_weld", 3.0, team ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_marvin", < -2116, 2868, -1458 >, < 0, 127, 0 >, "mv_turret_repair_A_idle", -1.0, team ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_marvin", < -1786, 3060, -1412 >, < 0, -120, 0 >, "mv_idle_unarmed", -1.0, team ) ) // imc grunts - entity imcGrunt1 = CreatePropDynamic( $"models/humans/grunts/imc_grunt_rifle.mdl", < -2915, 2867, -1788 >, < 0, -137, 0 > ) - thread PlayAnim( imcGrunt1, "pt_console_idle" ) - SetTeam( imcGrunt1, team ) - trackedEntities.append( imcGrunt1 ) - - entity imcGrunt2 = CreatePropDynamic( $"models/humans/grunts/imc_grunt_rifle.mdl", < -2870, 2746, -1786 >, < 0, -167, 0 > ) - thread PlayAnim( imcGrunt2, "pt_console_idle" ) - imcGrunt2.Anim_SetInitialTime( 2.0 ) - SetTeam( imcGrunt2, team ) - trackedEntities.append( imcGrunt2 ) - - entity imcGrunt3 = CreatePropDynamic( $"models/humans/grunts/imc_grunt_rifle.mdl", < -3037, 2909, -1786 >, < 0, -60, 0 > ) - thread PlayAnim( imcGrunt3, "pt_console_idle" ) - imcGrunt3.Anim_SetInitialTime( 4.0 ) - SetTeam( imcGrunt3, team ) - trackedEntities.append( imcGrunt3 ) - - entity imcGrunt4 = CreatePropDynamic( $"models/humans/grunts/imc_grunt_rifle.mdl", < -3281, 2941, -1790 >, < 0, 138, 0 > ) - thread PlayAnim( imcGrunt4, "pt_console_idle" ) - imcGrunt4.Anim_SetInitialTime( 6.0 ) - SetTeam( imcGrunt4, team ) - trackedEntities.append( imcGrunt4 ) + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -2915, 2867, -1788 >, < 0, -137, 0 >, "pt_console_idle", -1.0, team, $"models/humans/grunts/imc_grunt_rifle.mdl" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -2870, 2746, -1786 >, < 0, -167, 0 >, "pt_console_idle", 2.0, team, $"models/humans/grunts/imc_grunt_rifle.mdl" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -3037, 2909, -1786 >, < 0, -60, 0 >, "pt_console_idle", 4.0, team, $"models/humans/grunts/imc_grunt_rifle.mdl" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -3200, 3017, -1794 >, < 0, 118, 0 >, "pt_console_idle", 4.5, team, $"models/humans/grunts/imc_grunt_rifle.mdl" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -3281, 2941, -1790 >, < 0, 138, 0 >, "pt_console_idle", 6.0, team, $"models/humans/grunts/imc_grunt_rifle.mdl" ) ) + + trackedEntities.append( SpawnSkitGuy( "npc_soldier", < -3293, 2909, -1788 >, < 0, -64, 0 >, "pt_bored_interface_leanin", -1.0, team, $"models/humans/grunts/imc_grunt_rifle.mdl", "mp_weapon_car" ) ) } // so I don't have to duplicate this on all entities @@ -218,65 +186,117 @@ void function OnPrematchStart() RespawnPrivateMatchSpectator( player ) } - // 7 seconds of nothing until we start the pod sequence - wait 7.0 + // 8 seconds of nothing until we start the pod sequence + wait 8.0 FirstPersonSequenceStruct podCloseSequence podCloseSequence.thirdPersonAnim = "trainingpod_doors_close" podCloseSequence.thirdPersonAnimIdle = "trainingpod_doors_close_idle" + podCloseSequence.setInitialTime = Time() - ( file.introStartTime + 8.0 ) thread FirstPersonSequence( podCloseSequence, file.imcPod ) thread FirstPersonSequence( podCloseSequence, file.militiaPod ) + + thread PodFXCleanupNormalLight_Delayed( file.imcPod ) + thread PodFXCleanupNormalLight_Delayed( file.militiaPod ) - wait 7.0 + wait 6.5 thread PodBootFXThread( file.imcPod ) thread PodBootFXThread( file.militiaPod ) - wait 6.0 + // cleanup intro objects + + if ( IsValid( militiaOgre ) ) + militiaOgre.Destroy() + + foreach ( entity ent in trackedEntities ) + if ( IsValid( ent ) ) + ent.Destroy() + + wait 7.0 ClassicMP_OnIntroFinished() // make sure we stop using viewmodels for these otherwise everyone can see them in the floor 24/7 file.imcPod.RenderWithViewModels( false ) file.militiaPod.RenderWithViewModels( false ) - //PodFXCleanup( file.imcPod ) - //PodFXCleanup( file.militiaPod ) - - // cleanup intro objects - foreach ( entity ent in trackedEntities ) + foreach ( entity trigger in triggers ) + trigger.kv.triggerFilterPlayer = "all" +} + +entity function SpawnSkitGuy( string entityclass, vector origin, vector angles, string animation = "", float animationtime = -1.0, int team = TEAM_UNASSIGNED, asset model = $"", string weapon = "" ) +{ + entity guy = null + + if ( entityclass == "npc_marvin" ) { - if ( IsValid(ent) ) - ent.Destroy() + guy = CreateMarvin( team, origin, angles ) + + DispatchSpawn( guy ) + + guy.Signal( "StopDoingJobs" ) + } + else if ( entityclass == "npc_soldier" ) + { + guy = CreateElitePilot( team, origin, angles ) + + DispatchSpawn( guy ) + + guy.SetValueForModelKey( model ) + guy.SetModel( model ) + + TakeWeaponsForArray( guy, guy.GetMainWeapons() ) + + if ( weapon.len() ) + guy.GiveWeapon( weapon ) } + else + { + guy = CreateNPCTitan( entityclass, team, origin, angles ) + + DispatchSpawn( guy ) + TakeWeaponsForArray( guy, guy.GetMainWeapons() ) + } + + guy.SetInvulnerable() + guy.SetEfficientMode( true ) + guy.SetTitle( "" ) + + if ( animation.len() ) + thread PlayAnim( guy, animation, null, null, DEFAULT_SCRIPTED_ANIMATION_BLEND_TIME, animationtime ) + + return guy } void function PlayerWatchesWargamesIntro( entity player ) { player.EndSignal( "OnDestroy" ) - - if ( IsAlive( player ) ) - player.Die() + player.EndSignal( "OnDeath" ) OnThreadEnd( function() : ( player ) { if ( IsValid( player ) ) { RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) + player.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + ClearPlayerAnimViewEntity( player ) - player.EnableWeaponViewModel() - DeployAndEnableWeapons(player) + DeployViewModelAndEnableWeapons( player ) + player.ClearParent() player.UnforceStand() player.MovementEnable() player.ClearInvulnerable() + Remote_CallFunction_NonReplay( player, "ServerCallback_ClearFactionLeaderIntro" ) + + entity spawnpoint = FindSpawnPoint( player, false, true ) + + player.SetOrigin( spawnpoint.GetOrigin() ) + player.SetAngles( spawnpoint.GetAngles() ) } }) - // we need to wait a frame if we killed ourselves to spawn into this, so just easier to do it all the time to remove any weirdness - WaitFrame() - player.EndSignal( "OnDeath" ) - int factionTeam = ConvertPlayerFactionToIMCOrMilitiaTeam( player ) entity playerPod if ( factionTeam == TEAM_IMC ) @@ -285,10 +305,12 @@ void function PlayerWatchesWargamesIntro( entity player ) playerPod = file.militiaPod // setup player + if( PlayerCanSpawn( player ) ) + DoRespawnPlayer( player, null ) + int podAttachId = playerPod.LookupAttachment( "REF" ) player.SetOrigin( playerPod.GetAttachmentOrigin( podAttachId ) ) player.SetAngles( playerPod.GetAttachmentAngles( podAttachId ) ) - player.RespawnPlayer( null ) player.SetParent( playerPod, "REF" ) player.ForceStand() @@ -298,8 +320,7 @@ void function PlayerWatchesWargamesIntro( entity player ) AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) player.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER TrainingPod_ViewConeLock_PodClosed( player ) - player.DisableWeaponViewModel() - HolsterAndDisableWeapons(player) + HolsterViewModelAndDisableWeapons( player ) player.MovementDisable() player.SetInvulnerable() @@ -325,41 +346,44 @@ void function PlayerWatchesWargamesIntro( entity player ) else if ( file.militiaPodFXEyePos == < 0, 0, 0 > && factionTeam == TEAM_MILITIA ) file.militiaPodFXEyePos = player.EyePosition() - // 7 seconds of nothing before we start the pod sequence - wait ( file.introStartTime + 7.0 ) - Time() + // 8.0 seconds of nothing before we start the pod sequence + wait ( file.introStartTime + 8.0 ) - Time() + + while ( Time() < file.introStartTime + 8.0 ) // note: remove this when wait stops waiting less than the input time + WaitFrame() FirstPersonSequenceStruct podCloseSequence podCloseSequence.firstPersonAnim = "ptpov_trainingpod_doors_close" podCloseSequence.renderWithViewModels = true podCloseSequence.attachment = "REF" podCloseSequence.viewConeFunction = TrainingPod_ViewConeLock_SemiStrict - podCloseSequence.setInitialTime = Time() - ( file.introStartTime + 7.0 ) + podCloseSequence.setInitialTime = Time() - ( file.introStartTime + 8.0 ) waitthread FirstPersonSequence( podCloseSequence, player, playerPod ) - // boot sequence + // wait 0.6 seconds then start boot sequence + wait ( file.introStartTime + 14.2 ) - Time() EmitSoundOnEntityOnlyToPlayer( player, player, "NPE_Scr_SimPod_PowerUp" ) TrainingPod_ViewConeLock_PodClosed( player ) // 10 seconds of starting pod before we run effects and spawn players // note, this is cool because it waits for a specific time, so we can have a blocking call directly before it just fine - wait ( file.introStartTime + 15.5 ) - Time() + wait ( file.introStartTime + 16.8 ) - Time() Remote_CallFunction_NonReplay( player, "ServerCallback_PlayPodTransitionScreenFX" ) // need to wait no matter what the delay is here so fx will sync up - wait 3.5 - - entity spawnpoint = FindSpawnPoint( player, false, true ) - spawnpoint.s.lastUsedTime = Time() - player.SetOrigin( spawnpoint.GetOrigin() ) - player.SetAngles( spawnpoint.GetAngles() ) + wait 4.6 thread DelayedGamemodeAnnouncement( player ) } void function DelayedGamemodeAnnouncement( entity player ) { - wait 1.0 - if ( IsValid( player ) && IsAlive( player ) ) + player.EndSignal( "OnDestroy" ) + + while ( Time() < expect float( level.nv.gameStartTime ) ) + WaitFrame() + + if ( IsAlive( player ) ) TryGameModeAnnouncement( player ) } @@ -423,29 +447,51 @@ void function PodFXLasers( entity pod ) void function PodFXLaserSweep( entity emitter, entity pod, vector eyePos, string attachment ) { - // setup emitter attachments - emitter.SetOrigin( < 5, 5, 5 > ) + emitter.SetOrigin( Vector( 5, 5, 5 ) ) emitter.SetParent( pod, attachment ) - float sweepTime = RandomFloatRange( 2.9, 3.15 ) - - vector centerAng = VectorToAngles( ( eyePos + < 0, 0, 7 > ) - emitter.GetOrigin() ) - vector topAng = centerAng + < -270, 0, 0 > - vector bottomAng = centerAng + < -90, 0, 0 > - + var vecToPlayerEye = ( eyePos + Vector( 0, 0, 7 ) ) - emitter.GetOrigin() + vector centerAng = VectorToAngles( vecToPlayerEye ) + vector topAng = centerAng + Vector( -270, 0, 0 ) + vector bottomAng = centerAng + Vector( -90, 0, 0 ) + vector lastBigSweepAng + + emitter.SetAbsAngles( topAng ) + + lastBigSweepAng = topAng + emitter.s.fxHandle <- PlayLoopFXOnEntity( $"P_pod_scan_laser_FP", emitter ) - + + float sweepTime = RandomFloatRange( 2.9, 3.15 ) float finalCenterTime = sweepTime * 0.15 float bigSweepTime = ( sweepTime - finalCenterTime ) / 2 - - emitter.SetAbsAngles( topAng ) - emitter.NonPhysicsRotateTo( topAng, bigSweepTime, 0.0, bigSweepTime * 0.2 ) - wait bigSweepTime - 0.1 - - emitter.NonPhysicsRotateTo( bottomAng, bigSweepTime, 0.0, bigSweepTime * 0.2 ) - wait bigSweepTime - - emitter.NonPhysicsRotateTo( centerAng, finalCenterTime, 0.0, finalCenterTime * 0.2 ) + float bigSweep_DecelTime = bigSweepTime * 0.2 + vector nextBigSweepAng + + for ( int i = 0; i < 2; i++ ) + { + nextBigSweepAng = topAng + + if ( lastBigSweepAng == topAng ) + nextBigSweepAng = bottomAng + + emitter.NonPhysicsRotateTo( nextBigSweepAng, bigSweepTime, 0, bigSweep_DecelTime ) + + float waitTime = bigSweepTime + + if ( i < 1 ) + waitTime = bigSweepTime - 0.1 + + wait waitTime + + lastBigSweepAng = nextBigSweepAng + } + + float finalCenter_DecelTime = finalCenterTime * 0.2 + + emitter.NonPhysicsRotateTo( centerAng, finalCenterTime, 0, finalCenter_DecelTime ) + + wait finalCenterTime } void function PodFXGlowLights( entity pod ) @@ -485,8 +531,10 @@ void function PodBootFXThread( entity pod ) PodFXLasers( pod ) } -void function PodFXCleanup( entity pod ) +void function PodFXCleanupNormalLight_Delayed( entity pod ) { + wait 2.65 + foreach ( entity handle in pod.s.podLightFXHandles ) { if ( IsValid_ThisFrame( handle ) ) @@ -496,28 +544,6 @@ void function PodFXCleanup( entity pod ) handle.Destroy() } } - + pod.s.podLightFXHandles = [] - - foreach ( entity handle in pod.s.podGlowLightFXHandles ) - { - if ( IsValid_ThisFrame( handle ) ) - { - handle.SetStopType( "DestroyImmediately" ) - handle.ClearParent() - handle.Destroy() - } - } - - pod.s.podGlowLightFXHandles = [] - - pod.s.leftLaserEmitter.s.fxHandle.SetStopType( "DestroyImmediately" ) - pod.s.leftLaserEmitter.s.fxHandle.ClearParent() - pod.s.leftLaserEmitter.s.fxHandle.Destroy() - pod.s.leftLaserEmitter.Destroy() - - pod.s.rightLaserEmitter.s.fxHandle.SetStopType( "DestroyImmediately" ) - pod.s.rightLaserEmitter.s.fxHandle.ClearParent() - pod.s.rightLaserEmitter.s.fxHandle.Destroy() - pod.s.rightLaserEmitter.Destroy() } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames_fd.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames_fd.nut index 37b891699..374f8cf86 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames_fd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames_fd.nut @@ -1 +1,387 @@ -//fuck \ No newline at end of file +global function initFrontierDefenseData +void function initFrontierDefenseData() +{ + AddCallback_RegisterCustomFDContent( RegisterCustomFDContentOGSetup ) + PlaceFDShop( < -1280, 2237, -191 >, < 0, 90, 0 > ) + SetFDDropshipSpawn( < -2033, 2288, 0 > ) + SetFDGroundSpawn( < -960, 1604, -127 >, < 0, 90, 0 > ) + + AddWaveAnnouncement( "fd_introEasy" ) + AddWaveAnnouncement( "fd_waveTypeMortarSpectre" ) + AddWaveAnnouncement( "fd_soonArcTitans" ) + AddWaveAnnouncement( "fd_waveTypeTicks" ) + AddWaveAnnouncement( "fd_introMedium" ) + + AddFDCustomTitanStart( < -1601, 3696, -255 >, < 0, -135, 0 > ) + AddFDCustomTitanStart( < -947, 3696, -255 >, < 0, -45, 0 > ) + + entity refDanger = CreateScriptRef( < 2259, 2363, -127 > ) + AI_CreateDangerousArea_Static( refDanger, null, 160, TEAM_INVALID, true, true, < 2259, 2363, -127 > ) + + /* + __ __ _ + \ \ / /__ _ __ __ ___ / | + \ \/\/ // _` |\ V // -_) | | + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave1 + WaveSpawn_InfantrySpawn( wave1, "DropshipGrunt", < 1174, 2263, -256 >, 250, "", 1.5, "fd_waveTypeInfantry", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -699, 815, -127 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -507, 970, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -196, -588, -127 >, 0.0, "", 0.5 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -460, -737, -127 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2353, -608, -128 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2087, 169, -127 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -4586, 1052, -127 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -4292, 1510, -127 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -2218, -1428, -127 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < -2948, -1334, 2560 >, 0.0, "", 0.5, "fd_waveTypeCloakDrone" ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2532, 0, -228 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2804, 488, -129 >, 0.0, "", 0.8 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -699, 815, -127 >, 0.0, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -507, 970, -127 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -196, -588, -127 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "MortarSpectre", < 760, -2046, -127 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < 2365, 944, 2560 >, 0.0, "", 0.5 ) + WaveSpawn_WaitEnemyAliveAmount( wave1, 4 ) + + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < -460, -737, -127 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2532, 0, -228 >, 0.0, "", 0.3 ) + WaveSpawn_InfantrySpawn( wave1, "PodGrunt", < 2804, 488, -129 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave1, "DropshipGrunt", < -3626, -711, -128 >, 190, "", 1.0, "", 0.0, eFDSD.ALL, 6 ) + WaveSpawn_InfantrySpawn( wave1, "CloakDrone", < 361, -2774, 2560 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave1, "TickReaper", < 2050, 1107, -132 >, 90, "", 0.5 ) + + WaveSpawnEvents.append( wave1 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ |_ ) + \ \/\/ // _` |\ V // -_) / / + \_/\_/ \__,_| \_/ \___| /___| + + */ + array wave2 + WaveSpawn_TitanSpawn( wave2, "Ion", < -3443, -1215, -128 >, 90, "", 1.5, "fd_waveTypeTitanReg" ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -3160, -2090, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -681, 834, -127 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 744, -2090, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Ion", < -280, -3195, -127 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -570, 732, -127 >, 0.0, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -4566, -833, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -2347, 144, -127 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave2, "Legion", < 3184, 1456, -128 >, 90, "", 5.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 1385, 863, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -1902, 290, -127 >, 0.0, "", 1.5 ) + WaveSpawn_Announce( wave2, "PreMortarTitan", 0.2 ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 0 ) + + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -4580, 265, -143 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -2005, -938, -127 >, 90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2680, 610, -127 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 233, -3247, -128 >, 90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 2950, -122, -127 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -716, -1114, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Ronin", < -5044, -453, -127 >, 90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -602, 775, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -4530, 1014, -128 >, 0.0, "", 3.0 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < -2948, -1334, 2560 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 2 ) + + WaveSpawn_TitanSpawn( wave2, "Sniper", < -594, -1096, -127 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -1167, -881, -127 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -664, -2363, -254 >, 90, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "Ticks", < -3675, -221, -135 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -2390, -3278, -127 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < 2056, 1105, -131 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave2, "Mortar", < 3259, 507, -127 >, 90, "", 0.5, "fd_waveTypeTitanMortar" ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 361, -2774, 2560 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 3149, -149, -126 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 2536, 605, -125 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 1179, 2633, -126 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 857, -2375, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 962, -1182, 39 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave2, 4 ) + + WaveSpawn_TitanSpawn( wave2, "Monarch", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5 ) + WaveSpawn_TitanSpawn( wave2, "Monarch", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 1.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < 43, -456, -132 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -1951, -1610, -127 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < -1389, -1083, -127 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave2, "PodGrunt", < -3664, -1638, -127 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave2, "TickReaper", < 2284, 1130, -131 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < -4121, -1045, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 654, -2589, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave2, "Reaper", < 28, -1077, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave2, "CloakDrone", < 2365, 944, 2560 >, 0.0, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 1.5, "fd_waveTypeFlyers" ) + WaveSpawn_InfantrySpawn( wave2, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 3.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -1902, 290, -127 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave2, "MortarSpectre", < -602, 775, -127 >, 0.0, "" ) + + WaveSpawnEvents.append( wave2 ) + + /* + __ __ ____ + \ \ / /__ _ __ __ ___ |__ / + \ \/\/ // _` |\ V // -_) |_ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave3 + WaveSpawn_TitanSpawn( wave3, "Ronin", < -2061, -865, -127 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Ronin", < 2865, 1023, -126 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Monarch", < -2384, -3143, -127 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -3160, -2090, -127 >, 90, "", 0.6, "fd_incReaperClump" ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -4580, 265, -143 >, 0.0, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 233, -3247, -128 >, 90, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -681, 834, -127 >, 0.0, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -716, -1114, -127 >, 90, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -1389, -1083, -127 >, 90, "", 0.6 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -1194, -862, -127 >, 0.0, "", 0.5 ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Monarch", < -2881, -2775, -127 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Sniper", < -594, -1096, -127 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Northstar", < 3377, -105, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 2284, 1130, -131 >, 90, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -4511, 1598, -118 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -4593, 1921, -112 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "CloakDrone", < 361, -2774, 2560 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -3664, -1638, -127 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -2005, -938, -127 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 43, -456, -132 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < -4121, -1045, -127 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Ion", < -1102, -3441, -191 >, 90, "airbase_farRouteAlt", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "Ion", < -1600, -3441, -191 >, 90, "ac_farRoute", 1.5 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < -3443, -1215, -128 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -2531, -1233, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 2680, 610, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -2865, -925, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -570, 732, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -951, -2354, -255 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 857, -2375, -127 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -2390, -3278, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 654, -2589, -127 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave3, 4 ) + + WaveSpawn_TitanSpawn( wave3, "Tone", < -5044, -453, -127 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave3, "Tone", < 749, -3153, -126 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5, "fd_waveTypeTitanArc" ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 0.5 ) + WaveSpawn_TitanSpawn( wave3, "ArcTitan", < -4326, -531, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < 69, -754, -126 >, 0.0, "", 0.2 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -2084, 165, -127 >, 0.0, "", 0.4 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -2196, -619, -127 >, 0.0, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < -664, -2363, -254 >, 90, "", 10.0 ) + WaveSpawn_TitanSpawn( wave3, "Scorch", < -280, -3195, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave3, "Legion", < 3184, 1456, -128 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < -4571, 595, 2560 >, 90,"ac_dronePatrol", 1.0 ) + WaveSpawn_InfantrySpawn( wave3, "Drones", < -4571, 595, 2560 >, 90,"ac_dronePatrol", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < -2347, 144, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "PodGrunt", < 1179, 2633, -126 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < 2513, 1106, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave3, "Ticks", < -4235, 1615, -128 >, 0.0, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "TickReaper", < 744, -2090, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave3, "Reaper", < 2536, 605, -125 >, 90, "" ) + + WaveSpawnEvents.append( wave3 ) + + /* + __ __ _ _ + \ \ / /__ _ __ __ ___ | | | + \ \/\/ // _` |\ V // -_) |_ _| + \_/\_/ \__,_| \_/ \___| |_| + + */ + array wave4 + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 744, -2090, -127 >, 90, "", 1.0, "fd_waveTypeReaperTicks" ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -664, -2363, -254 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2390, -3278, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -1389, -1083, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2284, 1130, -131 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 654, -2589, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 28, -1077, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 2.0 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < -1102, -3441, -191 >, 90, "airbase_farRouteAlt", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Monarch", < -1600, -3441, -191 >, 90, "ac_farRoute", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "DropshipGrunt", < -3626, -711, -128 >, 190, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -4593, 1921, -112 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -4235, 1615, -128 >, 0.0, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -716, -1114, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3149, -149, -126 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -3160, -2090, -127 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -4566, -833, -127 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2005, -938, -127 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 233, -3247, -128 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -716, -1114, -127 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 3149, -149, -126 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < -594, -1096, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < 69, -754, -126 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -2531, -1233, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -2865, -925, -127 >, 0.0, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -1951, -1610, -127 >, 0.0, "", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 2680, 610, -127 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < -2061, -865, -127 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 2865, 1023, -126 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -664, -2363, -254 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -2384, -3143, -127 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -4566, -833, -127 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -4511, 1598, -118 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -2005, -938, -127 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -951, -2354, -255 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 233, -3247, -128 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < 2513, 1106, -127 >, 0.0, "", 2.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 1.0 ) + WaveSpawn_InfantrySpawn( wave4, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5 ) + WaveSpawn_TitanSpawn( wave4, "ArcTitan", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Legion", < 787, -2517, -128 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3259, 507, -127 >, 90, "", 2.5, "fd_waveTypeTitanMortar" ) + WaveSpawn_InfantrySpawn( wave4, "DropshipGrunt", < 1174, 2263, -256 >, 250, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2536, 605, -125 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -4121, -1045, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 744, -2090, -127 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -2084, 165, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -1194, -862, -127 >, 0.0, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -2390, -3278, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -2881, -2775, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 2536, 605, -125 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Ion", < 3081, 764, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 654, -2589, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 3067, 1555, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -1389, -1083, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -4880, -885, -128 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave4, 6 ) + + WaveSpawn_TitanSpawn( wave4, "Tone", < -3564, -1587, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < 2284, 1130, -131 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < -4564, -1166, -127 >, 90, "", 1.0 ) + WaveSpawn_ReaperSpawn( wave4, "TickReaper", < -3160, -2090, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave4, "Tone", < 749, -3153, -126 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 962, -1182, 39 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Sniper", < 3377, -105, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < -2347, 144, -127 >, 0.0, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Northstar", < -4880, -885, -128 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -2196, -619, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < -4378, -232, -126 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave4, "Ticks", < 2741, 183, -186 >, 0.0, "", 2.5 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < -4846, -1205., -126 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Mortar", < 3166, 129, -127 >, 90, "", 2.5 ) + WaveSpawn_InfantrySpawn( wave4, "PodGrunt", < 2950, -122, -127 >, 0.0, "", 0.6 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -4121, -1045, -127 >, 90, "", 0.7 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 28, -1077, -127 >, 90, "", 0.8 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < 744, -2090, -127 >, 90, "", 0.9 ) + WaveSpawn_ReaperSpawn( wave4, "Reaper", < -664, -2363, -254 >, 90, "", 1.0 ) + WaveSpawn_TitanSpawn( wave4, "Scorch", < 3184, 1456, -128 >, 90, "" ) + + WaveSpawnEvents.append( wave4 ) + + /* + __ __ ___ + \ \ / /__ _ __ __ ___ | __| + \ \/\/ // _` |\ V // -_) |__ \ + \_/\_/ \__,_| \_/ \___| |___/ + + */ + array wave5 + WaveSpawn_Announce( wave5, "Everything", 0.1 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 744, -2090, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -664, -2363, -254 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2390, -3278, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -1389, -1083, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -664, -2363, -254 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -2390, -3278, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < -3443, -1215, -128 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < -280, -3195, -127 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < 857, -2375, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < -3664, -1638, -127 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < 3184, 1456, -128 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -5044, -453, -127 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4566, -833, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -2005, -938, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 233, -3247, -128 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Sniper", < -594, -1096, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -716, -1114, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 3149, -149, -126 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2536, 605, -125 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3259, 507, -127 >, 90, "", 0.5, "fd_incTitansMortarClump" ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -4846, -1205., -126 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -1389, -1083, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 2284, 1130, -131 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < -570, 732, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < -2347, 144, -127 >, 0.0, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < -3564, -1587, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -4564, -1166, -127 >, 90, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Scorch", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -4121, -1045, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 654, -2589, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -2881, -2775, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 3081, 764, -127 >, 90, "", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 28, -1077, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 744, -2090, -127 >, 90, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < 2950, -122, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "PodGrunt", < -681, 834, -127 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 1.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -3160, -2090, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -898, -2900, -254 >, 90, "airbase_farRoute", 0.5, "fd_incArcTitanClump" ) + WaveSpawn_TitanSpawn( wave5, "ArcTitan", < -1698, -2900, -254 >, 90, "ac_farRouteAlt1", 2.5 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -4593, 1921, -112 >, 0.0, "", 0.5 ) + WaveSpawn_InfantrySpawn( wave5, "Ticks", < -4235, 1615, -128 >, 0.0, "" ) + WaveSpawn_WaitEnemyAliveAmount( wave5, 6 ) + + WaveSpawn_TitanSpawn( wave5, "Sniper", < 3377, -105, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Northstar", < -4880, -885, -128 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 749, -3153, -126 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Monarch", < 787, -2517, -128 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -4566, -833, -127 >, 90, "", 0.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < -2005, -938, -127 >, 90, "", 1.5 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 1.0 ) + WaveSpawn_InfantrySpawn( wave5, "Drones", < -4571, 595, 2560 >, 90, "ac_dronePatrol", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < -1102, -3441, -191 >, 90, "airbase_farRouteAlt", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Legion", < -1600, -3441, -191 >, 90, "ac_farRoute", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "TickReaper", < 233, -3247, -128 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Tone", < -2384, -3143, -127 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Ion", < 3067, 1555, -127 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Scorch", < -4818, -620, -127 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < 2284, 1130, -131 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < -2061, -865, -127 >, 90, "", 2.5 ) + WaveSpawn_ReaperSpawn( wave5, "Reaper", < -3160, -2090, -127 >, 90, "", 2.5 ) + WaveSpawn_TitanSpawn( wave5, "Ronin", < 2865, 1023, -126 >, 90, "", 1.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < 3166, 129, -127 >, 90, "", 0.5 ) + WaveSpawn_TitanSpawn( wave5, "Mortar", < -3584, -1673, -126 >, 90, "" ) + + WaveSpawnEvents.append( wave5 ) +} + +void function RegisterCustomFDContentOGSetup() +{ + AddStationaryAIPosition( < -894, -1664, 264 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < -322, -187, 383 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < 1275, -1444, 456 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + AddStationaryAIPosition( < -2215, -2096, 200 >, eStationaryAIPositionTypes.LAUNCHER_REAPER ) + + AddStationaryAIPosition( < 2220, 710, 63 >, eStationaryAIPositionTypes.MORTAR_SPECTRE ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/player_cloak.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/player_cloak.nut index 8ef7dcd93..7d2539c82 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/player_cloak.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/player_cloak.nut @@ -142,17 +142,14 @@ void function HandleCloakEnd( entity player ) if ( !IsCloaked( player ) ) return - if ( !IsAlive( player ) || !player.IsHuman() ) - { - DisableCloak( player ) - return - } - + entity playerTactical = player.GetOffhandWeapon( OFFHAND_SPECIAL ) + string playerTacticalName + if ( IsValid( playerTactical ) ) + playerTacticalName = playerTactical.GetWeaponClassName() + float duration = player.GetCloakEndTime() - Time() - if ( duration <= 0 ) - { + if ( !IsAlive( player ) || !player.IsHuman() || duration <= 0 || playerTacticalName != "mp_ability_cloak" ) DisableCloak( player ) - } } ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut index c47552b3e..7a3efe2e3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut @@ -2,13 +2,12 @@ untyped global function Spawn_Init global function FindSpawnPoint +global function ToggleSpawnNodeInUse global function SetSpawnpointGamemodeOverride global function GetSpawnpointGamemodeOverride global function AddSpawnpointValidationRule -global function SetRespawnsEnabled -global function RespawnsEnabled global function CreateNoSpawnArea global function DeleteNoSpawnArea global function SpawnPointInNoSpawnArea @@ -18,6 +17,10 @@ global function RateSpawnpoints_Frontline global function RateSpawnpoints_SpawnZones global function DecideSpawnZone_Generic +#if DEV +global function ShowSpawnPoints +#endif + global struct spawnZoneProperties{ int controllingTeam = TEAM_UNASSIGNED entity minimapEnt = null @@ -37,7 +40,6 @@ struct NoSpawnArea } struct { - bool respawnsEnabled = true array noSpawnAreas string spawnpointGamemodeOverride array< bool functionref( entity, int ) > customSpawnpointValidationRules @@ -95,22 +97,26 @@ void function Spawn_Init() file.shouldCreateMinimapSpawnzones = GetCurrentPlaylistVarInt( "spawn_zone_enabled", 1 ) != 0 } -void function SetRespawnsEnabled( bool enabled ) +void function InitSpawnpoint( entity spawnpoint ) { - file.respawnsEnabled = enabled + if ( file.spawnpointGamemodeOverride != "" ) + { + string gamemodeKey = "gamemode_" + file.spawnpointGamemodeOverride + if ( spawnpoint.HasKey( gamemodeKey ) && ( spawnpoint.kv[ gamemodeKey ] == "0" || spawnpoint.kv[ gamemodeKey ] == "" ) ) + { + spawnpoint.Destroy() + return + } + } + else if ( GameModeRemove( spawnpoint ) ) + spawnpoint.Destroy() } -bool function RespawnsEnabled() +void function ToggleSpawnNodeInUse( entity spawnpoint, bool isInUse ) { - return file.respawnsEnabled + spawnpoint.e.spawnPointInUse = isInUse } -void function InitSpawnpoint( entity spawnpoint ) -{ - spawnpoint.s.lastUsedTime <- -999 - spawnpoint.s.inUse <- false -} - string function CreateNoSpawnArea( int blockSpecificTeam, int blockEnemiesOfTeam, vector position, float lifetime, float radius ) { NoSpawnArea noSpawnArea @@ -150,10 +156,13 @@ bool function SpawnPointInNoSpawnArea( vector vec, int team ) { if ( Distance( noSpawnArea.position, vec ) < noSpawnArea.radius ) { - if ( noSpawnArea.blockedTeam != TEAM_INVALID && noSpawnArea.blockedTeam == team ) + if ( noSpawnArea.blockedTeam == TEAM_ANY || noSpawnArea.blockOtherTeams == TEAM_ANY ) // ESmoke uses this + return true + + if ( noSpawnArea.blockedTeam == TEAM_INVALID && noSpawnArea.blockOtherTeams == TEAM_INVALID ) // Cluster missile does this instead of ESmoke method, not sure why return true - if ( noSpawnArea.blockOtherTeams != TEAM_INVALID && noSpawnArea.blockOtherTeams != team ) + if ( noSpawnArea.blockedTeam == team || noSpawnArea.blockOtherTeams != team ) return true } } @@ -161,9 +170,9 @@ bool function SpawnPointInNoSpawnArea( vector vec, int team ) return false } -bool function IsSpawnpointValidDrop( entity spawnpoint, int team ) +bool function IsSpawnpointValidDrop( entity spawnpoint ) { - if ( spawnpoint.IsOccupied() || spawnpoint.s.inUse ) + if ( spawnpoint.IsOccupied() || spawnpoint.e.spawnPointInUse ) return false return true @@ -207,6 +216,8 @@ string function GetSpawnpointGamemodeOverride() entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnpoint ) { int team = player.GetTeam() + if ( HasSwitchedSides() == 1 && useStartSpawnpoint ) // Start Points don't invert like Dropships do for rounds + team = GetOtherTeam( team ) array spawnpoints if ( useStartSpawnpoint ) @@ -225,7 +236,7 @@ entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnp SpawnPoints_SortTitanStart() else SpawnPoints_SortTitan() - + spawnpoints = useStartSpawnpoint ? SpawnPoints_GetTitanStart( team ) : SpawnPoints_GetTitan() } else @@ -234,17 +245,25 @@ entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnp SpawnPoints_SortPilotStart() else SpawnPoints_SortPilot() - + spawnpoints = useStartSpawnpoint ? SpawnPoints_GetPilotStart( team ) : SpawnPoints_GetPilot() } entity spawnpoint = GetBestSpawnpoint( player, spawnpoints, isTitan ) - - spawnpoint.s.lastUsedTime = Time() + + spawnpoint.e.spawnTime = Time() player.SetLastSpawnPoint( spawnpoint ) //SpawnPoints_DiscardRatings() - + + #if DEV + foreach( string k, float v in spawnpoint.GetRatingData() ) + print( k + ": " + v ) + print( "team: " + spawnpoint.GetTeam() ) + print( "scriptname: " + spawnpoint.GetScriptName() ) + print( "targetname: " + spawnpoint.GetTargetName() ) + #endif + return spawnpoint } @@ -261,18 +280,36 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints, boo else spawnpoints = GetEntArrayByClass_Expensive( "info_spawnpoint_human" ) } - foreach ( entity spawnpoint in spawnpoints ) { if ( IsSpawnpointValid( spawnpoint, player.GetTeam() ) ) validSpawns.append( spawnpoint ) } - if ( !validSpawns.len() ) // First validity check + if ( !validSpawns.len() ) // First validity check, retry without LOS { - CodeWarning( "Map has no valid spawn points for " + GAMETYPE + " gamemode, attempting any other possible spawn point" ) + CodeWarning( "No valid spawn points found, attempting spawn points without Line of Sight checks" ) foreach ( entity spawnpoint in spawnpoints ) - validSpawns.append( spawnpoint ) + { + if ( IsSpawnpointValid( spawnpoint, player.GetTeam(), true ) ) + validSpawns.append( spawnpoint ) + } + } + + if ( !validSpawns.len() ) // Second validity check, retry without LOS and ignoring time since last spawn + { + CodeWarning( "No valid spawn points found, attempting spawn points without Line of Sight checks and ignoring time since last spawn" ) + foreach ( entity spawnpoint in spawnpoints ) + { + if ( IsSpawnpointValid( spawnpoint, player.GetTeam(), true, true ) ) + validSpawns.append( spawnpoint ) + } + } + + if ( !validSpawns.len() ) + { + printt( "Warning: No valid spawn points found for player: " + player + " trying to use all spawn points" ) + validSpawns.extend( spawnpoints ) } if ( !validSpawns.len() ) // On all validity check, just gather the most basic spawn @@ -281,10 +318,7 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints, boo entity start = GetEnt( "info_player_start" ) if ( IsValid( start ) ) - { - start.s.lastUsedTime <- -999 validSpawns.append( start ) - } else throw( "Map has no player spawns at all" ) } @@ -295,35 +329,30 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints, boo return validSpawns[0] // Return first entry in the array because native have already sorted everything through the ratings, so first one is the best one } -bool function IsSpawnpointValid( entity spawnpoint, int team ) +bool function IsSpawnpointValid( entity spawnpoint, int team, bool skipLineOfSightChecks = false, bool skipTimeCheck = false ) { - if ( !spawnpoint.HasKey( "ignoreGamemode" ) || spawnpoint.HasKey( "ignoreGamemode" ) && spawnpoint.kv.ignoreGamemode == "0" ) // used by script-spawned spawnpoints + foreach ( bool functionref( entity, int ) customValidationRule in file.customSpawnpointValidationRules ) { - if ( file.spawnpointGamemodeOverride != "" ) - { - string gamemodeKey = "gamemode_" + file.spawnpointGamemodeOverride - if ( spawnpoint.HasKey( gamemodeKey ) && ( spawnpoint.kv[ gamemodeKey ] == "0" || spawnpoint.kv[ gamemodeKey ] == "" ) ) - return false - } - else if ( GameModeRemove( spawnpoint ) ) + if ( !customValidationRule( spawnpoint, team ) ) return false } - foreach ( bool functionref( entity, int ) customValidationRule in file.customSpawnpointValidationRules ) - if ( !customValidationRule( spawnpoint, team ) ) - return false - - if ( !IsSpawnpointValidDrop( spawnpoint, team ) || Time() - spawnpoint.s.lastUsedTime <= 10.0 ) + if ( !IsSpawnpointValidDrop( spawnpoint ) ) + return false + + if ( !skipTimeCheck && spawnpoint.e.spawnTime != 0 && Time() - spawnpoint.e.spawnTime <= 10.0 ) return false if ( SpawnPointInNoSpawnArea( spawnpoint.GetOrigin(), team ) ) return false + + if ( skipLineOfSightChecks ) + return true // Line of Sight Check, could use IsVisibleToEnemies but apparently that considers only players, not NPCs - array< entity > enemyTitans = GetTitanArrayOfEnemies( team ) if ( GetConVarBool( "spawnpoint_avoid_npc_titan_sight" ) ) { - foreach ( titan in enemyTitans ) + foreach ( titan in GetTitanArrayOfEnemies( team ) ) { if ( IsAlive( titan ) && titan.IsNPC() && titan.CanSee( spawnpoint ) ) return false @@ -351,7 +380,7 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) */ void function RateSpawnpoints_Generic( int checkClass, array spawnpoints, int team, entity player ) -{ +{ foreach ( entity spawnpoint in spawnpoints ) { float currentRating = 0.0 @@ -378,9 +407,9 @@ void function RateSpawnpoints_Frontline( int checkClass, array spawnpoin Frontline currentFrontline = GetFrontline( team ) vector inverseFrontlineDir = currentFrontline.combatDir * -1 - vector adjustedPosition = currentFrontline.origin + currentFrontline.combatDir * 8000 + vector adjustedPosition = currentFrontline.origin + currentFrontline.combatDir * 4000 - SpawnPoints_InitFrontlineData( adjustedPosition, currentFrontline.combatDir, currentFrontline.origin, currentFrontline.friendlyCenter, 4000 ) + SpawnPoints_InitFrontlineData( adjustedPosition, currentFrontline.combatDir, currentFrontline.origin, currentFrontline.friendlyCenter, 2000 ) foreach ( entity spawnpoint in spawnpoints ) { @@ -494,7 +523,7 @@ void function RateSpawnpoints_SpawnZones( int checkClass, array spawnpoi rating = 10.0 else rating = 2.0 * ( 1 - ( distance / 3000.0 ) ) - + spawn.CalculateRating( checkClass, team, rating, rating * 0.25 ) } } @@ -513,17 +542,17 @@ entity function DecideSpawnZone_Generic( array spawnzones, int team ) vector averageFriendlySpawns foreach ( entity spawn in startSpawns ) averageFriendlySpawns += spawn.GetOrigin() - + averageFriendlySpawns /= startSpawns.len() - + vector averageEnemySpawns foreach ( entity spawn in enemyStartSpawns ) averageEnemySpawns += spawn.GetOrigin() - + averageEnemySpawns /= enemyStartSpawns.len() - + float baseDistance = Distance2D( averageFriendlySpawns, averageEnemySpawns ) - + if ( TeamHasDirtySpawnzone( team ) ) { array possibleZones @@ -602,9 +631,68 @@ int function SortPossibleZones( entity a, entity b ) { if ( mapSpawnZones[a].zoneRating > mapSpawnZones[b].zoneRating ) return -1 - + if ( mapSpawnZones[b].zoneRating > mapSpawnZones[a].zoneRating ) return 1 - + return 0 -} \ No newline at end of file +} + + + + + + + + + + + +/* +██████ ███████ ██████ ██ ██ ██████ ██████ ██ ███ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██ ██ █████ ██████ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ███████ ██████ ██████ ██████ ██████ ██ ██ ████ ██████ +*/ + +#if DEV +void function ShowSpawnPoints() +{ + array< entity > spawnPoints = SpawnPoints_GetTitan() + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 255, 255, 0, false, 600 ) + + spawnPoints = SpawnPoints_GetPilot() + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 255, 255, 0, false, 600 ) + + spawnPoints = SpawnPoints_GetDropPod() + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 255, 255, 0, false, 600 ) + + spawnPoints = SpawnPoints_GetTitanStart( TEAM_MILITIA ) + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 255, 0, 0, false, 600 ) + + spawnPoints = SpawnPoints_GetPilotStart( TEAM_MILITIA ) + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 255, 0, 0, false, 600 ) + + spawnPoints = SpawnPoints_GetDropPodStart( TEAM_MILITIA ) + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 255, 0, 0, false, 600 ) + + spawnPoints = SpawnPoints_GetTitanStart( TEAM_IMC ) + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 0, 0, 255, false, 600 ) + + spawnPoints = SpawnPoints_GetPilotStart( TEAM_IMC ) + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 0, 0, 255, false, 600 ) + + spawnPoints = SpawnPoints_GetDropPodStart( TEAM_IMC ) + foreach ( sPoint in spawnPoints ) + DebugDrawSpawnpoint( sPoint, 0, 0, 255, false, 600 ) +} +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn_wave.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn_wave.gnut index b8895c55c..4cac58f4f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn_wave.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn_wave.gnut @@ -1,6 +1,2664 @@ global function SpawnWave_Init +global function eventIterator_FrontierDefense + +global function WaveSpawn_TitanSpawn +global function WaveSpawn_ReaperSpawn +global function WaveSpawn_InfantrySpawn +global function WaveSpawn_SmokeWall +global function WaveSpawn_Announce +global function WaveSpawn_Delay +global function WaveSpawn_WaitEnemyAliveAmount +global function WaveSpawn_WaitSubGroup +global function WaveSpawn_RunCustomFunction + +global function AddMinimapForTitans +global function AddMinimapForHumans +global function PingMinimap +global function GiveShieldByDifficulty + +global function allEventsExecuted +global function resetWaveEvents +global function ShouldSkipEventForDifficulty + +global function NPCNav_FD +global function NPCDroneNav_FD +global function Dev_ShowRoute +global function NPCStuckTracker + +global enum eFDSD //Shortened from eFDSpawn_Difficulty to not make scripts too horrible to read +{ + ALL = 1 << 0, + EASY = 1 << 1, + NORMAL = 1 << 2, + HARD = 1 << 3, + MASTER = 1 << 4, + INSANE = 1 << 5, + EXCLUSIVE = 1 << 6 +} + +global enum eFDHT //Shortened from eFD_HullType +{ + ALL, + SMALL, + MEDIUM, + TITAN +} + +global struct WaveSpawnEvent{ + bool shouldThread = true + vector origin = < 0, 0, 0 > + vector angles = < 0, 0, 0 > + string route = "" + int spawnType + int spawnAmount = 1 + bool shouldLoop = true + bool titanBlocked = false + float spawnradius = 0.0 + int spawnInDifficulty = eFDSD.ALL + string soundEventName = "" + float waitTime = 0.0 + int waitAmount = 0 + int waitHullType = eFDHT.ALL + float smokeDuration = 90.0 + string waveSubGroupName = "" + string waveSubGroupWait = "" + bool executed = false + bool isAnnounceEvent = false + table modExtraData = {} + void functionref( WaveSpawnEvent ornull ) eventFunction = null +} + +struct{ + int difficultyLevel = 0 + table< string, array > waveSubGroups + array waveActiveSubGroups + int gruntAmountWithATWeapons = 0 + int gruntAmountWithShields = 0 +}file + +global array< array > WaveSpawnEvents + +global const float FD_TITAN_AOE_REACTTIME = 3.0 //This is in seconds + + + + + + + + + + +/* Init +██ ███ ██ ██ ████████ ██ █████ ██ ██ ███████ █████ ████████ ██ ██████ ███ ██ +██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ████ ██ +██ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ███ ███████ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ████ ██ ██ ██ ██ ██ ███████ ██ ███████ ██ ██ ██ ██ ██████ ██ ████ +*/ + void function SpawnWave_Init() { + RegisterSignal( "StopWaveSpawner" ) + + file.difficultyLevel = FD_GetDifficultyLevel() //Refresh this only on map load, to avoid midgame commands messing up with difficulties (i.e setting mp_gamemode fd_hard midgame in a regular match through console on local host would immediately make Stalkers spawns with EPG) + file.gruntAmountWithShields = GetCurrentPlaylistVarInt( "fd_grunt_shield_captains", 0 ) + file.gruntAmountWithATWeapons = GetCurrentPlaylistVarInt( "fd_grunt_at_weapon_users", 0 ) +} + +void function eventIterator_FrontierDefense() +{ + print( "Event Iterator Started" ) + svGlobal.levelEnt.EndSignal( "StopWaveSpawner" ) + + OnThreadEnd( + function() : () + { + file.waveSubGroups.clear() + } + ) + + int waveIndex = GetGlobalNetInt( "FD_currentWave" ) + SplitWaveSubgroups( waveIndex ) + + foreach ( WaveSpawnEvent currentEvent in WaveSpawnEvents[waveIndex] ) + { + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + break + + if ( currentEvent.waveSubGroupName != "" ) + { + if ( file.waveActiveSubGroups.find( currentEvent.waveSubGroupName ) == -1 ) + thread eventIterator_SubGroup( waveIndex, currentEvent.waveSubGroupName ) + else + continue + } + + currentEvent.executed = true + + if ( ShouldSkipEventForDifficulty( currentEvent ) ) + continue + + if ( currentEvent.soundEventName != "" && !currentEvent.isAnnounceEvent ) + thread PlayWarning( currentEvent ) + + if ( currentEvent.shouldThread ) + { + if ( currentEvent.eventFunction != null ) + thread currentEvent.eventFunction( currentEvent ) + + if ( currentEvent.waitTime > 0 ) + wait currentEvent.waitTime + } + + else + { + if ( currentEvent.eventFunction != null ) + currentEvent.eventFunction( currentEvent ) + } + } +} + +void function eventIterator_SubGroup( int waveIndex, string subGroupName ) +{ + print( "SubGroup Event Iterator Started: " + subGroupName ) + svGlobal.levelEnt.EndSignal( "StopWaveSpawner" ) + + OnThreadEnd( + function() : ( subGroupName ) + { + delete file.waveSubGroups[ subGroupName ] + + if ( file.waveActiveSubGroups.find( subGroupName ) != -1 ) + file.waveActiveSubGroups.removebyvalue( subGroupName ) + } + ) + + file.waveActiveSubGroups.append( subGroupName ) + foreach ( WaveSpawnEvent currentEvent in file.waveSubGroups[ subGroupName ] ) + { + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + break + + currentEvent.executed = true + + if ( ShouldSkipEventForDifficulty( currentEvent ) ) + continue + + if ( currentEvent.soundEventName != "" && !currentEvent.isAnnounceEvent ) + thread PlayWarning( currentEvent ) + + if ( currentEvent.shouldThread ) + { + if ( currentEvent.eventFunction != null ) + thread currentEvent.eventFunction( currentEvent ) + + if ( currentEvent.waitTime > 0 ) + wait currentEvent.waitTime + } + + else + { + if ( currentEvent.eventFunction != null ) + currentEvent.eventFunction( currentEvent ) + } + } +} + + + + + + + + + + + +/* Wave Spawn Functions +██ ██ █████ ██ ██ ███████ ███████ ██████ █████ ██ ██ ███ ██ ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██ █ ██ ███████ ██ ██ █████ ███████ ██████ ███████ ██ █ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ +██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ███ ███ ██ ██ ████ ███████ ███████ ██ ██ ██ ███ ███ ██ ████ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ +*/ + +void function WaveSpawn_TitanSpawn( array waveName, string spawnType = "", vector origin = < 0, 0, 0 >, float angle = 0.0, string route = "", float waitTime = 0.5, string soundEventName = "", float spawnradius = 0.0, int spawnInDifficulty = eFDSD.ALL, string subGroupName = "" ) +{ + WaveSpawnEvent event + + switch ( spawnType.tolower() ) + { + case "arc titan": + case "arc_titan": + case "arctitan": + case "arc": + event.spawnType = eFD_AITypeIDs.TITAN_ARC + event.eventFunction = SpawnArcTitan + break + + case "nuke titan": + case "nuke_titan": + case "nuketitan": + case "nuke": + event.spawnType = eFD_AITypeIDs.TITAN_NUKE + event.eventFunction = SpawnNukeTitan + break + + case "mortar titan": + case "mortar_titan": + case "mortartitan": + case "mortar": + event.spawnType = eFD_AITypeIDs.TITAN_MORTAR + event.eventFunction = SpawnMortarTitan + break + + case "ronin titan": + case "ronin_titan": + case "ronintitan": + case "ronin": + event.spawnType = eFD_AITypeIDs.RONIN + event.eventFunction = SpawnRoninTitan + break + + case "northstar titan": + case "northstar_titan": + case "northstartitan": + case "northstar": + event.spawnType = eFD_AITypeIDs.NORTHSTAR + event.eventFunction = SpawnSniperTitan + break + + case "scorch titan": + case "scorch_titan": + case "scorchtitan": + case "scorch": + event.spawnType = eFD_AITypeIDs.SCORCH + event.eventFunction = SpawnScorchTitan + break + + case "legion titan": + case "legion_titan": + case "legiontitan": + case "legion": + event.spawnType = eFD_AITypeIDs.LEGION + event.eventFunction = SpawnLegionTitan + break + + case "tone titan": + case "tone_titan": + case "tonetitan": + case "tone": + event.spawnType = eFD_AITypeIDs.TONE + event.eventFunction = SpawnToneTitan + break + + case "ion titan": + case "ion_titan": + case "iontitan": + case "ion": + event.spawnType = eFD_AITypeIDs.ION + event.eventFunction = SpawnIonTitan + break + + case "monarch titan": + case "monarch_titan": + case "monarchtitan": + case "monarch": + event.spawnType = eFD_AITypeIDs.MONARCH + event.eventFunction = SpawnMonarchTitan + break + + case "sniper titan": + case "sniper_titan": + case "tone sniper": + case "sniper": + event.spawnType = eFD_AITypeIDs.TITAN_SNIPER + event.eventFunction = SpawnToneSniperTitan + break + + default: + CodeWarning( "Spawn type string " + spawnType + " couldn't be interpreted (typo maybe?)" ) + unreachable + } + + event.origin = origin + event.angles = < 0, angle, 0 > + event.route = route + event.spawnradius = spawnradius + event.spawnInDifficulty = spawnInDifficulty + event.soundEventName = soundEventName + event.waitTime = waitTime + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_ReaperSpawn( array waveName, string spawnType = "", vector origin = < 0, 0, 0 >, float angle = 0.0, string route = "", float waitTime = 0.5, string soundEventName = "", float spawnradius = 0.0, int spawnInDifficulty = eFDSD.ALL, string subGroupName = "" ) +{ + WaveSpawnEvent event + + event.eventFunction = SpawnSuperSpectre_Normal + + switch ( spawnType.tolower() ) + { + case "tick reaper": + case "ticks reaper": + case "tick_reaper": + case "ticks_reaper": + case "tickreaper": + case "reaper tick": + case "reaper ticks": + case "reaper_tick": + case "reaper_ticks": + case "reapertick": + case "reaperticks": + case "tick": + case "ticks": + event.eventFunction = SpawnSuperSpectre_Launcher + break + } + + event.spawnType = eFD_AITypeIDs.REAPER + event.origin = origin + event.angles = < 0, angle, 0 > + event.route = route + event.spawnradius = spawnradius + event.spawnInDifficulty = spawnInDifficulty + event.soundEventName = soundEventName + event.waitTime = waitTime + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_InfantrySpawn( array waveName, string spawnType = "", vector origin = < 0, 0, 0 >, float angle = 0.0, string route = "", float waitTime = 0.5, string soundEventName = "", float spawnradius = 0.0, int spawnInDifficulty = eFDSD.ALL, int spawnAmount = 4, string subGroupName = "" ) +{ + WaveSpawnEvent event + + event.spawnAmount = spawnAmount + switch ( spawnType.tolower() ) + { + case "pod_grunt": + case "podgrunt": + case "droppod_grunt": + case "droppodgrunt": + event.spawnType = eFD_AITypeIDs.GRUNT + event.eventFunction = SpawnDroppodGrunts + break + + case "dropship_grunt": + case "dropshipgrunt": + event.spawnType = eFD_AITypeIDs.GRUNT + event.eventFunction = SpawnGruntDropship + break + + case "stalker": + case "stalkers": + event.spawnType = eFD_AITypeIDs.STALKER + event.eventFunction = SpawnDroppodStalker + break + + case "spectre": + case "spectres": + event.spawnType = eFD_AITypeIDs.SPECTRE + event.eventFunction = SpawnDroppodSpectre + break + + case "mortarspectre": + case "mortarspectres": + case "spectre mortar": + case "spectremortar": + event.spawnType = eFD_AITypeIDs.SPECTRE_MORTAR + event.eventFunction = SpawnDroppodSpectreMortar + break + + case "tick": + case "ticks": + event.spawnType = eFD_AITypeIDs.TICK + event.eventFunction = SpawnTick + break + + case "drone": + case "drones": + event.spawnType = eFD_AITypeIDs.DRONE + event.eventFunction = SpawnDrones + break + + case "cloak": + case "cloakdrone": + event.spawnType = eFD_AITypeIDs.DRONE_CLOAK + event.eventFunction = SpawnCloakingDrone + event.spawnAmount = 1 //Multiple Cloaks will not spawn, their spawn function don't support that + break + + default: + CodeWarning( "Spawn type string " + spawnType + " couldn't be interpreted (typo maybe?)" ) + unreachable + } + + event.origin = origin + event.angles = < 0, angle, 0 > + event.route = route + event.spawnradius = spawnradius + event.spawnInDifficulty = spawnInDifficulty + event.soundEventName = soundEventName + event.waitTime = waitTime + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_SmokeWall( array waveName, vector origin = < 0, 0, 0 >, float waitTime = 0.5, float durationTime = 90.0, int spawnInDifficulty = eFDSD.ALL, string subGroupName = "" ) +{ + WaveSpawnEvent event + + event.spawnAmount = 0 + event.eventFunction = SpawnSmoke + event.origin = origin + event.spawnInDifficulty = spawnInDifficulty + event.waitTime = waitTime + event.smokeDuration = durationTime + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_Announce( array waveName, string soundAlias = "", float waitTime = 0.5, int spawnInDifficulty = eFDSD.ALL, string subGroupName = "" ) +{ + WaveSpawnEvent event + + switch ( soundAlias.tolower() ) //Adjust some presets if needed + { + case "cloakdrone": + case "cloak": + event.soundEventName = "fd_incCloakDroneClump" + break + + case "arctitan": + case "arc": + event.soundEventName = "fd_incArcTitanClump" + break + + case "reapers": + case "reaper": + event.soundEventName = "fd_incReaperClump" + break + + case "mortartitan": + case "mortar": + event.soundEventName = "fd_incTitansMortarClump" + break + + case "nuketitan": + case "nuke": + event.soundEventName = "fd_incTitansNukeClump" + break + + case "reaperalt": + case "reaper2": + event.soundEventName = "fd_waveTypeReapers" + break + + case "ticks": + case "tick": + event.soundEventName = "fd_waveTypeTicks" + break + + case "stalkers": + case "stalker": + event.soundEventName = "fd_waveTypeStalkers" + break + + case "mortarspectre": + event.soundEventName = "fd_waveTypeMortarSpectre" + break + + case "reapertick": + case "tickreaper": + event.soundEventName = "fd_waveTypeReaperTicks" + break + + case "flyers": + case "drones": + case "drone": + event.soundEventName = "fd_waveTypeFlyers" + break + + case "infantry": + event.soundEventName = "fd_waveTypeInfantry" + break + + case "cloakdroneintro": + case "cloakintro": + event.soundEventName = "fd_waveTypeCloakDrone" + break + + case "enemytitansincoming": + case "incomingtitans": + event.soundEventName = "fd_waveTypeTitanReg" + break + + case "mortartitanintro": + case "mortarintro": + event.soundEventName = "fd_waveTypeTitanMortar" + break + + case "nuketitanintro": + case "nukeintro": + event.soundEventName = "fd_waveTypeTitanNuke" + break + + case "arctitanintro": + case "arcintro": + event.soundEventName = "fd_waveTypeTitanArc" + break + + case "titanfallblock": + case "tfblock": + event.soundEventName = "fd_waveNoTitanDrops" + break + + case "prenuketitan": + case "prenuke": + event.soundEventName = "fd_soonNukeTitans" + break + + case "premortartitan": + case "premortar": + event.soundEventName = "fd_soonMortarTitans" + break + + case "prearctitan": + case "prearc": + event.soundEventName = "fd_soonArcTitans" + break + + case "everything": + event.soundEventName = "fd_waveComboMultiMix" + break + + case "lightwave": + event.soundEventName = "fd_introEasy" + break + + case "mediumwave": + event.soundEventName = "fd_introMedium" + break + + case "heavywave": + event.soundEventName = "fd_introHard" + break + + case "nomoreenemytitans": + case "nomoreenemytitan": + case "nomoretitans": + case "nomoretitan": + event.soundEventName = "fd_waveNoTitans" + break + + case "arcalt": + case "arc2": + event.soundEventName = "fd_nagKillTitanEMP" + break + + case "nukemortar": + case "mortarnuke": + event.soundEventName = "fd_waveComboNukeMortar" + break + + case "arcmortar": + case "mortararc": + event.soundEventName = "fd_waveComboArcMortar" + break + + case "arcnuke": + case "nukearc": + event.soundEventName = "fd_waveComboArcNuke" + break + + case "cloaknuke": + case "nukecloak": + event.soundEventName = "fd_waveComboNukeCloak" + break + + case "nuketrain": + event.soundEventName = "fd_waveComboNukeTrain" + break + + default: + CodeWarning( "Sound string " + soundAlias + " couldn't be interpreted and will return empty (typo maybe?)" ) + } + + event.spawnAmount = 0 + event.eventFunction = PlayWarning + event.isAnnounceEvent = true + event.waitTime = waitTime + event.spawnInDifficulty = spawnInDifficulty + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_Delay( array waveName, float waitTime = 0.5, int spawnInDifficulty = eFDSD.ALL, string subGroupName = "" ) +{ + WaveSpawnEvent event + + event.spawnAmount = 0 + event.waitTime = waitTime + event.spawnInDifficulty = spawnInDifficulty + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_WaitEnemyAliveAmount( array waveName, int waitAmount = 0, int waitHullType = eFDHT.ALL, int spawnInDifficulty = eFDSD.ALL, string subGroupName = "" ) +{ + WaveSpawnEvent event + + event.spawnAmount = 0 + event.eventFunction = waitUntilLessThanAmountAliveEvent + event.shouldThread = false + event.waitHullType = waitHullType + event.waitAmount = waitAmount + event.waveSubGroupName = subGroupName + waveName.append(event) +} + +void function WaveSpawn_WaitSubGroup( array waveName, string subGroupName = "", int spawnInDifficulty = eFDSD.ALL ) +{ + WaveSpawnEvent event + + event.spawnAmount = 0 + event.eventFunction = waitWaveSubGroup + event.shouldThread = false + event.waveSubGroupWait = subGroupName + waveName.append(event) +} + +void function WaveSpawn_RunCustomFunction( array waveName, void functionref( WaveSpawnEvent ornull ) func, int spawnInDifficulty = eFDSD.ALL, int spawnAmount = 0, string subGroupName = "" ) +{ + WaveSpawnEvent event + + event.spawnAmount = spawnAmount + event.eventFunction = func + event.waveSubGroupName = subGroupName + waveName.append(event) +} + + + + + + + + + + +/* Titan Spawn Funcs +████████ ██ ████████ █████ ███ ██ ███████ ██████ █████ ██ ██ ███ ██ ███████ ██ ██ ███ ██ ██████ ███████ + ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ████ ██ ██ ██ + ██ ██ ██ ███████ ██ ██ ██ ███████ ██████ ███████ ██ █ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██ ██ ██ ██ ██ ██ ████ ███████ ██ ██ ██ ███ ███ ██ ████ ██ ██████ ██ ████ ██████ ███████ +*/ + +void function SpawnArcTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Arc Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateArcTitan( TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + SetSpawnOption_AISettings( npc, "npc_titan_stryder_leadwall_arc" ) + SetSpawnOption_Alert( npc ) + DispatchSpawn( npc ) + + npc.kv.reactChance = 50 + npc.kv.WeaponProficiency = eWeaponProficiency.AVERAGE //This is because on Vanilla, Arc Titans don't spam Arc Waves as much and that is related to weapon proficiency + npc.DisableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_USE_SHOOTING_COVER | NPC_ALLOW_PATROL ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + thread EMPTitanThinkConstant( npc ) + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + thread NPCNav_FD( npc, spawnEvent.route ) + if ( GetMapName().find( "mp_lf_" ) == null ) + { + switch ( file.difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + case eFDDifficultyLevel.NORMAL: + npc.AssaultSetFightRadius( 1200 ) + break + case eFDDifficultyLevel.HARD: + case eFDDifficultyLevel.MASTER: + case eFDDifficultyLevel.INSANE: + npc.AssaultSetFightRadius( 0 ) + break + } + } +} + +void function SpawnNukeTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Nuke Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_ogre", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_AISettings( npc, "npc_titan_ogre_minigun_nuke" ) + SetSpawnOption_Titanfall( npc ) + npc.kv.reactChance = 60 + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.EnableNPCMoveFlag( NPCMF_WALK_ALWAYS | NPCMF_WALK_NONCOMBAT ) + npc.DisableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + SlowEnemyMovementBasedOnDifficulty( npc ) + npc.DisableNPCFlag( NPC_DIRECTIONAL_MELEE ) + npc.AssaultSetFightRadius( 0 ) + npc.SetDangerousAreaReactionTime( 30 ) //Lasts longer than any AoE the game has + npc.SetCapabilityFlag( bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK2 | bits_CAP_SYNCED_MELEE_ATTACK , false ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + NukeTitanThink( npc, fd_harvester.harvester ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc, true ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + +void function SpawnMortarTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Mortar Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_atlas", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_AISettings( npc, "npc_titan_atlas_tracker_mortar" ) + SetSpawnOption_Titanfall( npc ) + SetSpawnOption_Alert( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetSkin( 1 ) + npc.SetCamo( -1 ) + npc.DisableNPCFlag( NPC_ALLOW_INVESTIGATE ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + thread MortarTitanThink( npc, fd_harvester.harvester ) + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) +} + +void function SpawnSniperTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Northstar Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_stryder", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + SetSpawnOption_Alert( npc ) + npc.kv.AccuracyMultiplier = 2 + npc.kv.reactChance = 60 + SetSpawnOption_AISettings( npc, "npc_titan_stryder_sniper_fd" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + npc.DisableNPCFlag( NPC_ALLOW_INVESTIGATE ) + npc.AssaultSetFightRadius( 0 ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + thread SniperTitanThink( npc, fd_harvester.harvester ) + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) +} + +void function SpawnToneSniperTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Sniper Tone Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_atlas", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + npc.kv.AccuracyMultiplier = 2 + npc.kv.reactChance = 60 + SetSpawnOption_AISettings( npc, "npc_titan_atlas_tracker_fd_sniper" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + npc.SetSkin( 6 ) + npc.SetCamo( 2 ) + npc.DisableNPCFlag( NPC_ALLOW_INVESTIGATE ) + npc.AssaultSetFightRadius( 0 ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + thread SniperTitanThink( npc, fd_harvester.harvester ) + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) +} + +void function SpawnIonTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Ion Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_atlas", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + npc.kv.reactChance = 60 + if ( file.difficultyLevel == eFDDifficultyLevel.EASY || difficultyLevel == eFDDifficultyLevel.NORMAL ) + SetSpawnOption_AISettings( npc, "npc_titan_atlas_stickybomb" ) + else + SetSpawnOption_AISettings( npc, "npc_titan_atlas_stickybomb_boss_fd" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + +void function SpawnScorchTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Scorch Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_ogre", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + if ( file.difficultyLevel == eFDDifficultyLevel.EASY || difficultyLevel == eFDDifficultyLevel.NORMAL ) + SetSpawnOption_AISettings( npc, "npc_titan_ogre_meteor" ) + else + SetSpawnOption_AISettings( npc, "npc_titan_ogre_meteor_boss_fd" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + npc.kv.reactChance = 60 + npc.kv.AccuracyMultiplier = 0.5 + npc.kv.WeaponProficiency = eWeaponProficiency.AVERAGE + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + +void function SpawnRoninTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Ronin Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_stryder", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + npc.kv.reactChance = 60 + if ( file.difficultyLevel == eFDDifficultyLevel.EASY || difficultyLevel == eFDDifficultyLevel.NORMAL ) + SetSpawnOption_AISettings( npc, "npc_titan_stryder_leadwall" ) + else + SetSpawnOption_AISettings( npc, "npc_titan_stryder_leadwall_boss_fd" ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + npc.kv.AccuracyMultiplier = 0.7 + npc.kv.WeaponProficiency = eWeaponProficiency.AVERAGE + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + +void function SpawnToneTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Tone Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_atlas", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + npc.kv.reactChance = 60 + if ( file.difficultyLevel == eFDDifficultyLevel.EASY || difficultyLevel == eFDDifficultyLevel.NORMAL ) + SetSpawnOption_AISettings( npc, "npc_titan_atlas_tracker" ) + else + SetSpawnOption_AISettings( npc, "npc_titan_atlas_tracker_boss_fd" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + +void function SpawnLegionTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Legion Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_ogre", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + npc.kv.reactChance = 60 + if ( file.difficultyLevel == eFDDifficultyLevel.EASY || difficultyLevel == eFDDifficultyLevel.NORMAL ) + SetSpawnOption_AISettings( npc, "npc_titan_ogre_minigun" ) + else + SetSpawnOption_AISettings( npc, "npc_titan_ogre_minigun_boss_fd" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + +void function SpawnMonarchTitan( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + + #if SERVER && DEV + printt( "Spawning Monarch Titan at: " + spawnorigin ) + #endif + + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + + entity npc = CreateNPCTitan( "titan_atlas", TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_Titanfall( npc ) + npc.kv.reactChance = 60 + if ( file.difficultyLevel == eFDDifficultyLevel.EASY || difficultyLevel == eFDDifficultyLevel.NORMAL ) + SetSpawnOption_AISettings( npc,"npc_titan_atlas_vanguard" ) + else + SetSpawnOption_AISettings( npc,"npc_titan_atlas_vanguard_boss_fd" ) + SlowEnemyMovementBasedOnDifficulty( npc ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) // required for client to create icons + DispatchSpawn( npc ) + npc.SetDangerousAreaReactionTime( FD_TITAN_AOE_REACTTIME ) + spawnedNPCs.append( npc ) + AddMinimapForTitans( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + WaitTillHotDropComplete( npc ) + + npc.GetTitanSoul().SetTitanSoulNetBool( "showOverheadIcon", true ) + GiveShieldByDifficulty( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) +} + + + + + + + + + + +/* Reaper Spawn Funcs +██████ ███████ █████ ██████ ███████ ██████ ███████ ██████ █████ ██ ██ ███ ██ ███████ ██ ██ ███ ██ ██████ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ████ ██ ██ ██ +██████ █████ ███████ ██████ █████ ██████ ███████ ██████ ███████ ██ █ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ███████ ██ ██ ██ ███████ ██ ██ ███████ ██ ██ ██ ███ ███ ██ ████ ██ ██████ ██ ████ ██████ ███████ +*/ + +entity function SpawnSuperSpectre( WaveSpawnEvent spawnEvent ) +{ + vector spawnorigin = spawnEvent.origin + if ( spawnEvent.spawnradius > 0 ) + { + spawnorigin.x += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.y += RandomFloatRange( -spawnEvent.spawnradius, spawnEvent.spawnradius ) + spawnorigin.z += 128 //Ensure we're above all playable geometry + spawnorigin = OriginToGround( spawnorigin ) + } + #if SERVER && DEV + printt( "Spawning Common Reaper at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnorigin.x, spawnorigin.y, 4, 600, 150, 0 ) + wait 4.7 + + entity npc = CreateSuperSpectre( TEAM_IMC, spawnorigin, spawnEvent.angles ) + SetSpawnOption_AISettings( npc, "npc_super_spectre_fd" ) + SetSpawnOption_Alert( npc ) + spawnedNPCs.append( npc ) + DispatchSpawn( npc ) + npc.SetAllowSpecialJump( true ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) + AddMinimapForHumans( npc ) + thread SuperSpectre_WarpFall( npc ) + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + npc.WaitSignal( "WarpfallComplete" ) + + //npc.SetCapabilityFlag( bits_CAP_MOVE_TRAVERSE, true ) + + npc.GetMainWeapons()[0].AddMod( "aggressive_ai_fd" ) + + return npc +} + +void function SpawnSuperSpectre_Normal( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + entity npc = SpawnSuperSpectre( spawnEvent ) + + thread NPCNav_FD( npc, spawnEvent.route ) + + npc.AssaultSetFightRadius( 2000 ) +} + +void function SpawnSuperSpectre_Launcher( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + entity npc = SpawnSuperSpectre( spawnEvent ) + + thread ReaperMinionLauncherThink( npc ) +} + + + + + + + + + + +/* Infantry Spawn Funcs +██ ███ ██ ███████ █████ ███ ██ ████████ ██████ ██ ██ ███████ ██████ █████ ██ ██ ███ ██ ███████ ██ ██ ███ ██ ██████ ███████ +██ ████ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ████ ██ ██ ██ +██ ██ ██ ██ █████ ███████ ██ ██ ██ ██ ██████ ████ ███████ ██████ ███████ ██ █ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ████ ██ ██ ██ ██ ████ ██ ██ ██ ██ ███████ ██ ██ ██ ███ ███ ██ ████ ██ ██████ ██ ████ ██████ ███████ +*/ + +void function SpawnDroppodGrunts( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Grunt Drop Pod at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0 ) + entity pod = CreateDropPod( spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + SetTeam( pod, TEAM_IMC ) + InitFireteamDropPod( pod ) + + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + array guys + + for ( int i = 0; i < spawnEvent.spawnAmount; i++ ) + { + entity guy = CreateSoldier( TEAM_IMC, spawnEvent.origin, < 0, 0, 0 > ) + SetSpawnflags( guy, SF_NPC_START_EFFICIENT ) + if ( i < file.gruntAmountWithShields ) + thread ActivatePersonalShield( guy ) + SetSpawnOption_Alert( guy ) + GiveMinionFDLoadout( guy ) + DispatchSpawn( guy ) + SetupGruntBehaviorFlags( guy ) + guy.SetParent( pod, "ATTACH", true ) + SetSquad( guy, squadName ) + foreach ( entity weapon in guy.GetMainWeapons() ) + { + if ( weapon.GetWeaponClassName() == "mp_weapon_rocket_launcher" ) + guy.TakeWeapon( weapon.GetWeaponClassName() ) + } + + if ( i < file.gruntAmountWithATWeapons ) + guy.GiveWeapon( AILoadout_GetRandomATWeaponForClass( guy ) ) + + SetTargetName( guy, GetTargetNameForID( eFD_AITypeIDs.GRUNT ) ) + guy.MakeInvisible() + entity weapon = guy.GetActiveWeapon() + if ( IsValid( weapon ) ) + weapon.MakeInvisible() + + spawnedNPCs.append( guy ) + guys.append( guy ) + } + + waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + ArrayRemoveDead( guys ) + ActivateFireteamDropPod( pod, guys ) + + if ( !guys.len() ) + CodeWarning( "Attempted to activate grunts from Drop Pod but the array is empty" ) + + foreach ( npc in guys ) + { + AddMinimapForHumans( npc ) + npc.SetEfficientMode( false ) + npc.SetEnemyChangeCallback( GruntTargetsTitan ) + thread NPCNav_FD( npc, spawnEvent.route ) + } +} + +//This function is based off the entire function chain called by AiGameModes_SpawnDropShip(), that function uses table data for modularization and while it +//works just fine if we simply use it here, there's no viable way to add the Grunts into the enemy count pool, plus that function also only works at +//specific nodes found in the maps, that is not needed here, full control over the coordinates where the dropship will drop grunts is better. +void function SpawnGruntDropship( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Grunt Dropship at: " + spawnEvent.origin ) + #endif + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + + vector origin = spawnEvent.origin + origin.z += 640 //Expected to people make coordinates in the ground so we add this up for the hover height + float yaw = spawnEvent.angles.y + int health = 10000 + int shield = 5000 + + CallinData drop + InitCallinData( drop ) + SetCallinStyle( drop, eDropStyle.ZIPLINE_NPC ) + drop.dist = 1300 + drop.origin = origin + drop.yaw = yaw + drop.team = TEAM_IMC + drop.squadname = squadName + + FlightPath flightPath + flightPath = GetAnalysisForModel( DROPSHIP_MODEL, DROPSHIP_DROP_ANIM ) + entity ref = CreateScriptRef() + ref.SetOrigin( origin ) + ref.SetAngles( < 0, yaw, 0 > ) + + DropTable dropTable + dropTable.nodes = DropshipFindDropNodes( flightPath, origin, yaw, "both", true, IsLegalFlightPath_OverTime ) + dropTable.valid = true + + asset model = GetFlightPathModel( "fp_crow_model" ) + waitthread WarpinEffect( model, DROPSHIP_DROP_ANIM, ref.GetOrigin(), ref.GetAngles() ) + entity dropship = CreateDropship( TEAM_IMC, ref.GetOrigin(), ref.GetAngles() ) + SetSpawnOption_SquadName( dropship, squadName ) + dropship.kv.solid = SOLID_VPHYSICS + DispatchSpawn( dropship ) + dropship.SetMaxHealth( health ) + dropship.SetHealth( dropship.GetMaxHealth() ) + dropship.SetShieldHealthMax( shield ) + dropship.SetShieldHealth( dropship.GetShieldHealthMax() ) + dropship.SetHealthPerSegment( 2500 ) + dropship.EndSignal( "OnDeath" ) + dropship.Signal( "WarpedIn" ) + dropship.DisableGrappleAttachment() + ref.Signal( "WarpedIn" ) + dropship.Minimap_AlwaysShow( TEAM_IMC, null ) + dropship.Minimap_AlwaysShow( TEAM_MILITIA, null ) + dropship.Minimap_SetHeightTracking( true ) + + AddDropshipDropTable( dropship, dropTable ) + //string dropshipSound = "Goblin_IMC_TroopDeploy_Flyin" + string dropshipSound = "Beacon_Flying_3_ships_02" + + OnThreadEnd( + function() : ( dropship, ref, dropshipSound ) + { + ref.Destroy() + if ( IsValid( dropship ) ) + StopSoundOnEntity( dropship, dropshipSound ) + if ( IsAlive( dropship ) ) + dropship.Destroy() + } + ) + + array guys + + int dropshipCrewSize = spawnEvent.spawnAmount + if ( dropshipCrewSize > 6 ) + { + dropshipCrewSize = 6 + CodeWarning( "Dropship has a maximum of 6 NPC slots, current value is: " + spawnEvent.spawnAmount ) + } + for ( int i = 0; i < dropshipCrewSize; i++ ) + { + entity guy = CreateSoldier( TEAM_IMC, spawnEvent.origin, < 0, 0, 0 > ) + SetSpawnflags( guy, SF_NPC_START_EFFICIENT ) + if ( i < file.gruntAmountWithShields ) + thread ActivatePersonalShield( guy ) + SetSpawnOption_Alert( guy ) + GiveMinionFDLoadout( guy ) + DispatchSpawn( guy ) + SetupGruntBehaviorFlags( guy ) + SetSquad( guy, squadName ) + foreach ( entity weapon in guy.GetMainWeapons() ) + { + if ( weapon.GetWeaponClassName() == "mp_weapon_rocket_launcher" ) + guy.TakeWeapon( weapon.GetWeaponClassName() ) + } + + if ( i < file.gruntAmountWithATWeapons ) + guy.GiveWeapon( AILoadout_GetRandomATWeaponForClass( guy ) ) + + SetTargetName( guy, GetTargetNameForID( eFD_AITypeIDs.GRUNT ) ) + AddMinimapForHumans( guy ) + spawnedNPCs.append( guy ) + guys.append( guy ) + + table Table = CreateDropshipAnimTable( dropship, "both", i ) + thread GuyDeploysOffShip( guy, Table ) + } + + thread PlayAnimTeleport( dropship, DROPSHIP_DROP_ANIM, ref, 0 ) + EmitSoundOnEntity( dropship, dropshipSound ) + wait 12 + ArrayRemoveDead( guys ) + foreach ( guy in guys ) + { + if ( guy.GetParent() ) + { + guy.EnableNPCFlag( NPC_NO_WEAPON_DROP ) + guy.Die( svGlobal.worldspawn, svGlobal.worldspawn, { scriptType = DF_DISSOLVE, damageSourceId = damagedef_crush } ) //Kill grunts that didn't manage to drop off the ship + } + else + { + guy.SetEfficientMode( false ) + guy.SetEnemyChangeCallback( GruntTargetsTitan ) + thread NPCNav_FD( guy, spawnEvent.route ) + } + } + WaittillAnimDone( dropship ) +} + +void function SpawnDroppodStalker( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Stalker Drop Pod at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0 ) + entity pod = CreateDropPod( spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + SetTeam( pod, TEAM_IMC ) + InitFireteamDropPod( pod ) + + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + array guys + + for ( int i = 0; i < spawnEvent.spawnAmount; i++ ) + { + entity guy = CreateStalker( TEAM_IMC, spawnEvent.origin, < 0, 0, 0 > ) + SetSpawnflags( guy, SF_NPC_START_EFFICIENT ) + SetSpawnOption_AISettings( guy, "npc_stalker_fd" ) + DispatchSpawn( guy ) + guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_NO_WEAPON_DROP ) + guy.DisableNPCFlag( NPC_ALLOW_PATROL ) + guy.SetParent( pod, "ATTACH", true ) + SetSquad( guy, squadName ) + guy.AssaultSetFightRadius( 0 ) // makes them keep moving instead of stopping to shoot you. + guy.MakeInvisible() + spawnedNPCs.append( guy ) + SetTargetName( guy, GetTargetNameForID( eFD_AITypeIDs.STALKER ) ) + guys.append( guy ) + } + + switch ( file.difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + case eFDDifficultyLevel.NORMAL: + foreach ( npc in guys ) + { + npc.TakeActiveWeapon() + npc.EnableNPCFlag( NPC_DISABLE_SENSING | NPC_IGNORE_ALL ) + } + break + case eFDDifficultyLevel.HARD: + case eFDDifficultyLevel.MASTER: + case eFDDifficultyLevel.INSANE: + foreach ( npc in guys ) + { + npc.TakeActiveWeapon() + npc.GiveWeapon( "mp_weapon_epg", ["slowProjectile"] ) + npc.SetActiveWeaponByName( "mp_weapon_epg" ) + entity weapon = npc.GetActiveWeapon() + if ( IsValid( weapon ) ) + weapon.MakeInvisible() + } + break + + default: + unreachable + + } + + waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + ArrayRemoveDead( guys ) + ActivateFireteamDropPod( pod, guys ) + + if ( !guys.len() ) + CodeWarning( "Attempted to activate stalkers from Drop Pod but the array is empty" ) + + foreach ( npc in guys ) + { + AddMinimapForHumans( npc ) + npc.SetEfficientMode( false ) + thread FDStalkerThink( npc , fd_harvester.harvester ) + thread NPCNav_FD( npc, spawnEvent.route ) + } +} + +void function SpawnDroppodSpectreMortar( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Mortar Spectre Drop Pod at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0 ) + entity pod = CreateDropPod( spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + SetTeam( pod, TEAM_IMC ) + InitFireteamDropPod( pod ) + + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + array guys + + for ( int i = 0; i < 4; i++ ) + { + entity guy = CreateSpectre( TEAM_IMC, spawnEvent.origin,< 0, 0, 0 > ) + SetSpawnflags( guy, SF_NPC_START_EFFICIENT ) + SetSpawnOption_AISettings( guy, "npc_spectre_mortar" ) + GiveMinionFDLoadout( guy ) + DispatchSpawn( guy ) + spawnedNPCs.append( guy ) + guy.SetParent( pod, "ATTACH", true ) + SetSquad( guy, squadName ) + SetTargetName( guy, GetTargetNameForID(eFD_AITypeIDs.SPECTRE_MORTAR)) + guy.MakeInvisible() + guys.append( guy ) + } + + waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + ArrayRemoveDead( guys ) + ActivateFireteamDropPod( pod, guys ) + + if ( !guys.len() ) + CodeWarning( "Attempted to activate mortar spectres from Drop Pod but the array is empty" ) + + foreach ( npc in guys ) + { + AddMinimapForHumans( npc ) + npc.SetEfficientMode( false ) + thread NPCStuckTracker( npc ) + } + + thread MortarSpectreSquadThink( guys, fd_harvester.harvester ) +} + +void function SpawnDroppodSpectre( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Spectres Drop Pod at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0 ) + entity pod = CreateDropPod( spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + SetTeam( pod, TEAM_IMC ) + InitFireteamDropPod( pod ) + + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + array guys + + for ( int i = 0; i < 4; i++ ) + { + entity guy = CreateSpectre( TEAM_IMC, spawnEvent.origin,< 0, 0, 0 > ) + SetSpawnflags( guy, SF_NPC_START_EFFICIENT ) + SetSpawnOption_AISettings( guy, "npc_spectre" ) + DispatchSpawn( guy ) + TakeAllWeapons( guy ) + GiveMinionFDLoadout( guy ) + guy.AssaultSetFightRadius( 0 ) + guy.DisableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_USE_SHOOTING_COVER | NPC_ALLOW_PATROL | NPC_ALLOW_FLEE ) + guy.EnableNPCFlag( NPC_NO_WEAPON_DROP ) + spawnedNPCs.append( guy ) + guy.SetParent( pod, "ATTACH", true ) + SetSquad( guy, squadName ) + SetTargetName( guy, GetTargetNameForID( eFD_AITypeIDs.SPECTRE ) ) + guy.MakeInvisible() + guys.append( guy ) + } + + waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + ArrayRemoveDead( guys ) + ActivateFireteamDropPod( pod, guys ) + + if ( !guys.len() ) + CodeWarning( "Attempted to activate spectres from Drop Pod but the array is empty" ) + + foreach ( npc in guys ) + { + AddMinimapForHumans( npc ) + npc.SetEfficientMode( false ) + thread NPCStuckTracker( npc ) + thread NPCNav_FD( npc, spawnEvent.route ) + } +} + +void function SpawnTick( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Tick Drop Pod at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0 ) + entity pod = CreateDropPod( spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + SetTeam( pod, TEAM_IMC ) + InitFireteamDropPod( pod ) + + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + array guys + + for ( int i = 0; i < spawnEvent.spawnAmount; i++ ) + { + entity guy = CreateFragDrone( TEAM_IMC, spawnEvent.origin, < 0, 0, 0 > ) + SetSpawnflags( guy, SF_NPC_START_EFFICIENT ) + SetSpawnOption_AISettings( guy, "npc_frag_drone_fd" ) + SetSpawnOption_Alert( guy ) + DispatchSpawn( guy ) + guy.EnableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_IGNORE_FRIENDLY_SOUND | NPC_NEW_ENEMY_FROM_SOUND ) + guy.EnableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + SetTargetName( guy, GetTargetNameForID( eFD_AITypeIDs.TICK ) ) + guy.SetParent( pod, "ATTACH", true ) + SetSquad( guy, squadName ) + spawnedNPCs.append( guy ) + guy.MakeInvisible() + guy.AssaultSetFightRadius( 600 ) + guys.append( guy ) + } + + waitthread LaunchAnimDropPod( pod, "pod_testpath", spawnEvent.origin, < 0, RandomIntRange( 0, 359 ), 0 > ) + ArrayRemoveDead( guys ) + ActivateFireteamDropPod( pod, guys ) + + if ( !guys.len() ) + CodeWarning( "Attempted to activate ticks from Drop Pod but the array is empty" ) + + foreach ( guy in guys ) + { + if ( IsValid( guy ) ) + { + guy.MakeVisible() + guy.Anim_Stop() //Intentionally cancel the Drop Pod exiting animation for Ticks because it doesnt work for them + guy.SetEfficientMode( false ) + AddMinimapForHumans( guy ) + thread NPCNav_FD( guy, spawnEvent.route ) + } + } +} + +void function SpawnCloakingDrone( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Cloak Drone at: " + spawnEvent.origin ) + #endif + entity npc = SpawnCloakDrone( TEAM_IMC, spawnEvent.origin, spawnEvent.angles, fd_harvester.harvester.GetOrigin() ) + spawnedNPCs.append( npc ) + PlayFX( $"P_phase_shift_main", spawnEvent.origin ) + SetTargetName( npc, GetTargetNameForID( spawnEvent.spawnType ) ) + AddMinimapForHumans( npc ) +} + +void function SpawnDrones( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + #if SERVER && DEV + printt( "Spawning Drones at: " + spawnEvent.origin ) + #endif + PingMinimap( spawnEvent.origin.x, spawnEvent.origin.y, 4, 600, 150, 0 ) + + string squadName = MakeSquadName( TEAM_IMC, UniqueString() ) + for ( int i = 0; i < spawnEvent.spawnAmount; i++ ) + { + vector offsets = Vector( RandomFloatRange( -40, 40 ), RandomFloatRange( -40, 40 ), RandomFloatRange( -40, 40 ) ) + entity guy = CreateGenericDrone( TEAM_IMC, spawnEvent.origin + offsets, spawnEvent.angles ) + SetSpawnOption_AISettings( guy, "npc_drone_plasma_fd" ) + DispatchSpawn( guy ) + guy.DisableNPCFlag( NPC_ALLOW_INVESTIGATE ) + guy.EnableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + SetSquad( guy, squadName ) + SetTargetName( guy, GetTargetNameForID( eFD_AITypeIDs.DRONE ) ) + AddMinimapForHumans( guy ) + spawnedNPCs.append( guy ) + + thread NPCDroneNav_FD( guy, spawnEvent.route, 0, 160, spawnEvent.shouldLoop ) + + guy.GetMainWeapons()[0].AddMod( "fd_damage" ) + } +} + + + + + + + + + + +/* Misc Spawn Funcs +███ ███ ██ ███████ ██████ ███████ ██████ █████ ██ ██ ███ ██ ███████ ██ ██ ███ ██ ██████ ███████ +████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ████ ██ ██ ██ +██ ████ ██ ██ ███████ ██ ███████ ██████ ███████ ██ █ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ███████ ██████ ███████ ██ ██ ██ ███ ███ ██ ████ ██ ██████ ██ ████ ██████ ███████ +*/ + +void function SpawnSmoke( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + vector skypos = GetSkyCeiling( spawnEvent.origin ) + vector groundpos = OriginToGround( skypos ) + + #if SERVER && DEV + printt( "Spawning Smoke at: " + spawnEvent.origin ) + #endif + SmokescreenStruct smokescreen + smokescreen.smokescreenFX = $"P_smokescreen_FD" + smokescreen.isElectric = false + smokescreen.shouldHibernate = false + smokescreen.origin = groundpos + smokescreen.angles = < 0, 0, 0 > + smokescreen.fxXYRadius = 160 + smokescreen.fxZRadius = 128 + smokescreen.lifetime = spawnEvent.smokeDuration + smokescreen.deploySound1p = "SmokeWall_Activate" + smokescreen.deploySound3p = "SmokeWall_Activate" + smokescreen.stopSound1p = "SmokeWall_Stop" + smokescreen.stopSound3p = "SmokeWall_Stop" + + float fxOffset = 200.0 + float fxHeightOffset = 148.0 + + smokescreen.fxOffsets = [ < -fxOffset, 0.0, 20.0>, <0.0, fxOffset, 20.0>, <0.0, -fxOffset, 20.0>, <0.0, 0.0, fxHeightOffset>, < -fxOffset, 0.0, fxHeightOffset> ] + + EmitSoundAtPosition( TEAM_ANY, groundpos, "SmokeWall_Launch" ) + + entity smokenade = CreateEntity( "prop_script" ) + entity mover = CreateOwnedScriptMover( smokenade ) + smokenade.SetValueForModelKey( $"models/weapons/bullets/projectile_rocket_largest.mdl" ) + smokenade.kv.spawnflags = 0 + smokenade.kv.solid = 0 + smokenade.kv.fadedist = 32768 + smokenade.kv.renderamt = 255 + smokenade.kv.rendercolor = "255 255 255" + smokenade.SetParent( mover, "", false, 0 ) + smokenade.EnableRenderAlways() + mover.SetOrigin( skypos ) + mover.SetAngles( < 90, 0, 0 > ) + DispatchSpawn( smokenade ) + PlayLoopFXOnEntity( $"P_SmokeScreen_FD_trail", smokenade, "exhaust" ) + mover.NonPhysicsMoveTo( groundpos, 1.5, 0, 0 ) + wait 1.5 + Smokescreen( smokescreen ) + wait 0.2 + smokenade.Destroy() + mover.Destroy() +} + +void function PlayWarning( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + if ( spawnEvent.soundEventName != "" ) //Sanity check just to prevent crashes from typos since the fallback is to return empty string + PlayFactionDialogueToTeam( spawnEvent.soundEventName, TEAM_MILITIA ) +} + +void function waitUntilLessThanAmountAliveEvent( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + while( true ) + { + WaitFrame() + array npcs = clone spawnedNPCs + ArrayRemoveDead( npcs ) + + if ( spawnEvent.waitHullType != eFDHT.ALL ) + { + foreach ( entity npc in npcs ) + { + switch ( spawnEvent.waitHullType ) + { + case eFDHT.SMALL: + if ( npc.IsTitan() || IsSuperSpectre( npc ) || IsProwler( npc ) ) + npcs.removebyvalue( npc ) + break + + case eFDHT.MEDIUM: + if ( npc.IsTitan() || IsHumanSized( npc ) || IsAirDrone( npc ) || IsFragDrone( npc ) ) + npcs.removebyvalue( npc ) + break + + case eFDHT.TITAN: + if ( IsSuperSpectre( npc ) || IsMinion( npc ) || IsStalker( npc ) || IsAirDrone( npc ) || IsFragDrone( npc ) || IsProwler( npc ) ) + npcs.removebyvalue( npc ) + break + } + } + } + + foreach ( entity npc in npcs ) + { + if ( GetNPCCloakedDrones().find( npc ) != -1 ) //Remove Cloak Drones to avoid softlocks + npcs.removebyvalue( npc ) + } + + if ( npcs.len() <= spawnEvent.waitAmount ) + break + + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + return + } +} + +void function waitWaveSubGroup( WaveSpawnEvent ornull spawnEvent ) +{ + if ( !spawnEvent ) + return + + expect WaveSpawnEvent( spawnEvent ) + + while( file.waveActiveSubGroups.find( spawnEvent.waveSubGroupWait ) != -1 ) + { + WaitFrame() + + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + return + } +} + + + + + + + + + + +/* Tool Functions +████████ ██████ ██████ ██ ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ + ██ ██ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██ ██████ ██████ ███████ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ +*/ + +void function PingMinimap( float x, float y, float duration, float spreadRadius, float ringRadius, int colorIndex ) +{ + if ( GetCurrentPlaylistVarFloat( "riff_minimap_state", 0 ) == 0 ) + { + foreach ( entity player in GetPlayerArrayOfTeam( TEAM_MILITIA ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FD_PingMinimap", x, y, duration, spreadRadius, ringRadius, colorIndex ) + } +} + +void function AddMinimapForTitans( entity titan ) +{ + if ( !IsValid( titan ) ) + return + + titan.Minimap_SetAlignUpright( true ) + titan.Minimap_AlwaysShow( TEAM_IMC, null ) + titan.Minimap_AlwaysShow( TEAM_MILITIA, null ) + titan.Minimap_SetHeightTracking( true ) + titan.Minimap_SetZOrder( MINIMAP_Z_NPC ) + titan.Minimap_SetCustomState( eMinimapObject_npc_titan.AT_BOUNTY_BOSS ) +} + +void function AddMinimapForHumans( entity human ) +{ + if ( !IsValid( human ) ) + return + + human.Minimap_SetAlignUpright( true ) + human.Minimap_AlwaysShow( TEAM_IMC, null ) + human.Minimap_AlwaysShow( TEAM_MILITIA, null ) + human.Minimap_SetHeightTracking( true ) + human.Minimap_SetZOrder( MINIMAP_Z_NPC ) + human.Minimap_SetCustomState( eMinimapObject_npc.AI_TDM_AI ) +} + +void function GiveMinionFDLoadout( entity npc ) +{ + Assert( IsValid( npc ) && IsMinion( npc ), "Entity is not a spectre or grunt: " + npc ) + string className = npc.GetClassName() + + string weaponName = AILoadout_GetRandomWeaponForClass( npc ) + if ( weaponName != "" ) + SetSpawnOption_Weapon( npc, weaponName ) +} + +void function SlowEnemyMovementBasedOnDifficulty( entity npc ) +{ + //This is not exact vanilla behavior i think, but enemies definetely moves slower on Frontier Defense than player autotitans + Assert( IsValid( npc ) && npc.IsNPC(), "Tried to set up movespeed scale in non-NPC entity: " + npc ) + + switch ( file.difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + case eFDDifficultyLevel.NORMAL: + case eFDDifficultyLevel.HARD: + case eFDDifficultyLevel.MASTER: + npc.SetNPCMoveSpeedScale( 0.75 ) + break + case eFDDifficultyLevel.INSANE: + npc.SetNPCMoveSpeedScale( 0.5 ) + break + } +} + +void function SetupGruntBehaviorFlags( entity npc ) +{ + Assert( IsValid( npc ) && IsGrunt( npc ), "Entity is not a Grunt: " + npc ) + + npc.EnableNPCFlag( NPC_ALLOW_HAND_SIGNALS ) + switch ( file.difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + case eFDDifficultyLevel.NORMAL: + npc.EnableNPCFlag( NPC_ALLOW_FLEE | NPC_USE_SHOOTING_COVER ) + npc.DisableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_ALLOW_PATROL ) + break + case eFDDifficultyLevel.HARD: + case eFDDifficultyLevel.MASTER: + case eFDDifficultyLevel.INSANE: + npc.DisableNPCFlag( NPC_ALLOW_INVESTIGATE | NPC_ALLOW_PATROL | NPC_ALLOW_FLEE | NPC_USE_SHOOTING_COVER ) + break + } +} + +void function GruntTargetsTitan( entity npc ) +{ + Assert( IsValid( npc ) && IsGrunt( npc ), "Entity is not a Grunt: " + npc ) + + entity enemy = npc.GetEnemy() + if ( !IsValid( enemy ) ) + return + + OnEnemyChanged_MinionSwitchToHeavyArmorWeapon( npc ) + switch ( file.difficultyLevel ) + { + case eFDDifficultyLevel.EASY: + case eFDDifficultyLevel.NORMAL: + if ( enemy.IsTitan() ) + npc.AssaultSetFightRadius( 800 ) + break + case eFDDifficultyLevel.HARD: + case eFDDifficultyLevel.MASTER: + case eFDDifficultyLevel.INSANE: + npc.AssaultSetFightRadius( 0 ) + break + } +} + +void function GiveShieldByDifficulty( entity titan, bool forceGive = false ) +{ + Assert( IsValid( titan ) && titan.IsNPC() && titan.IsTitan(), "Calling GiveShieldByDifficulty in a Non-Titan NPC: " + titan ) + + if ( GetCurrentPlaylistVarInt( "fd_pro_titan_shields", 0 ) && titan.IsTitan() || forceGive ) + { + entity soul = titan.GetTitanSoul() + if ( IsValid( soul ) ) + soul.SetShieldHealth( soul.GetShieldHealthMax() ) + } +} + +vector function GetSkyCeiling( vector point ) +{ + vector skyOrigin = Vector( point.x, point.y, MAX_WORLD_COORD ) + vector traceFromPos = point + + while ( true ) + { + TraceResults traceResult = TraceLineHighDetail( traceFromPos, skyOrigin, [], TRACE_MASK_SHOT, TRACE_COLLISION_GROUP_NONE ) + + if ( traceResult.hitSky ) + { + skyOrigin = traceResult.endPos + skyOrigin.z -= 1 + break + } + + traceFromPos = traceResult.endPos + traceFromPos.z += 1 + } + + return skyOrigin +} + +bool function allEventsExecuted( int waveIndex ) +{ + foreach ( WaveSpawnEvent event in WaveSpawnEvents[waveIndex] ) + { + if ( !event.executed ) + return false + } + return true +} + +void function resetWaveEvents() +{ + foreach ( WaveSpawnEvent event in WaveSpawnEvents[GetGlobalNetInt( "FD_currentWave" )] ) + event.executed = false +} + +void function SplitWaveSubgroups( int waveIndex ) +{ + foreach ( WaveSpawnEvent event in WaveSpawnEvents[waveIndex] ) + { + if ( event.waveSubGroupName != "" ) + { + if ( !( event.waveSubGroupName in file.waveSubGroups ) ) + file.waveSubGroups[ event.waveSubGroupName ] <- [] + + file.waveSubGroups[ event.waveSubGroupName ].append( event ) + } + } +} + +bool function ShouldSkipEventForDifficulty( WaveSpawnEvent event ) +{ + bool allDifficulties = event.spawnInDifficulty & eFDSD.ALL ? true : false + bool easySpawn = event.spawnInDifficulty & eFDSD.EASY ? true : false + bool normalSpawn = event.spawnInDifficulty & eFDSD.NORMAL ? true : false + bool hardSpawn = event.spawnInDifficulty & eFDSD.HARD ? true : false + bool masterSpawn = event.spawnInDifficulty & eFDSD.MASTER ? true : false + bool insaneSpawn = event.spawnInDifficulty & eFDSD.INSANE ? true : false + bool invertedFilter = event.spawnInDifficulty & eFDSD.EXCLUSIVE ? true : false + + if ( !allDifficulties ) + { + switch ( file.difficultyLevel ) + { + case( eFDDifficultyLevel.EASY ): + return invertedFilter ? easySpawn : !easySpawn + + case( eFDDifficultyLevel.NORMAL ): + return invertedFilter ? normalSpawn : !normalSpawn + + case( eFDDifficultyLevel.HARD ): + return invertedFilter ? hardSpawn : !hardSpawn + + case( eFDDifficultyLevel.MASTER ): + return invertedFilter ? masterSpawn : !masterSpawn + + case( eFDDifficultyLevel.INSANE ): + return invertedFilter ? insaneSpawn : !insaneSpawn + } + + return true + } + return false +} + + + + + + + + + + +/* FD Nav Funcs +███████ ██████ ███ ██ █████ ██ ██ ███████ ██ ██ ███ ██ ██████ ███████ +██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ +█████ ██ ██ ██ ██ ██ ███████ ██ ██ █████ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██████ ██ ████ ██ ██ ████ ██ ██████ ██ ████ ██████ ███████ +*/ + +void function NPCNav_FD( entity npc, string routeName, int nodesToSkip = 1, float nextDistance = -1.0, bool shouldLoop = false ) +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + npc.EndSignal( "OnLeeched" ) + + Assert( IsValid( npc ) && npc.IsNPC(), "AI Navigation function called in non-NPC entity: " + npc ) + + if ( nextDistance == -1 && ( npc.IsTitan() || IsSpectre( npc ) ) ) + nextDistance = npc.GetMinGoalRadius() + else if ( nextDistance == -1 ) + nextDistance = 160 + + string npcName = npc.GetTargetName() + + WaitFrame() + float dist = 65535 + entity targetNode + string routetaken + string routeCompare + string GuySquadName = expect string( npc.kv.squadname ) + array squad + if ( GuySquadName != "" ) + squad = GetNPCArrayBySquad( GuySquadName ) + + if ( !npc.IsTitan() ) + thread NPCStuckTracker( npc ) + + if ( !useCustomFDLoad ) + { + if ( routeName == "" ) + { + foreach ( entity node in routeNodes ) + { + if ( !node.HasKey( "route_name" ) ) + continue + + routeCompare = expect string( node.kv.route_name ).tolower() + if ( routeCompare.find( "drone" ) && !IsAirDrone( npc ) ) //Non-Drones skips + continue + + if ( routeCompare.find( "infantry" ) && !(IsMinion( npc ) || IsStalker( npc )) ) //Non-Grunt, Spectres, Stalker skips + continue + + if ( routeCompare.find( "reaper" ) && !IsSuperSpectre( npc ) ) //Non-Reapers skips + continue + + if ( routeCompare.find( "tick" ) && !IsFragDrone( npc ) ) //Non-Ticks skip (War Games uses this mostly) + continue + + if ( squad.len() > 0 ) + { + if ( Distance( squad[0].GetOrigin(), node.GetOrigin() ) < dist ) + { + dist = Distance( squad[0].GetOrigin(), node.GetOrigin() ) + targetNode = node + } + } + else if ( Distance( npc.GetOrigin(), node.GetOrigin() ) < dist ) + { + dist = Distance( npc.GetOrigin(), node.GetOrigin() ) + targetNode = node + } + } + #if SERVER && DEV + if ( squad.len() > 0 ) + { + if ( npc == squad[0] ) + printt( "Squad entities had no route defined, using nearest node: " + targetNode.kv.route_name ) + } + else + printt( "Single entity had no route defined, using nearest node: " + targetNode.kv.route_name ) + #endif + } + else + targetNode = GetRouteStart( routeName ) + + // skip nodes + for ( int i = 0; i < nodesToSkip; i++ ) + targetNode = targetNode.GetLinkEnt() + } + else + { + if ( routeName == "" ) + { + foreach ( routename, routeamount in routes ) + { + routeCompare = routename.tolower() + if ( routeCompare.find( "drone" ) && !IsAirDrone( npc ) ) //Non-Drones skips + continue + + if ( routeCompare.find( "infantry" ) && !(IsMinion( npc ) || IsStalker( npc )) ) //Non-Grunt, Spectres, Stalker skips + continue + + if ( routeCompare.find( "reaper" ) && !IsSuperSpectre( npc ) ) //Non-Reapers skips + continue + + if ( routeCompare.find( "tick" ) && !IsFragDrone( npc ) ) //Non-Ticks skip (War Games uses this mostly) + continue + + if ( squad.len() > 0 ) + { + if ( Distance( squad[0].GetOrigin(), routeamount[0] ) < dist ) + { + dist = Distance( squad[0].GetOrigin(), routeamount[0] ) + routetaken = routename + } + } + else if ( Distance( npc.GetOrigin(), routeamount[0] ) < dist ) + { + dist = Distance( npc.GetOrigin(), routeamount[0] ) + routetaken = routename + } + } + #if SERVER && DEV + if ( squad.len() > 0 ) + { + if ( npc == squad[0] ) + printt( "Squad entities had no route defined, using nearest node: " + routetaken ) + } + else + printt( "Single entity had no route defined, using nearest node: " + routetaken ) + #endif + } + else + routetaken = routeName + } + + //Ticks, Arc Titans and Combat Reapers have their own Fight Radii defined in spawn code + if ( npc.GetClassName() != "npc_frag_drone" && npcName != "empTitan" && !IsSuperSpectre( npc ) ) + npc.AssaultSetFightRadius( 0 ) + + if ( !useCustomFDLoad ) + { + while ( targetNode != null ) + { + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + return + npc.AssaultPointClamped( targetNode.GetOrigin() ) + npc.AssaultSetGoalRadius( nextDistance ) + + table result = npc.WaitSignal( "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) + + /* + if ( result.signal == "OnFailedToPath" && !npc.IsTitan() && !IsSuperSpectre( npc ) ) + { + entity enemy = npc.GetEnemy() + if ( EntityInSolid( npc ) && enemy == null ) + { + vector ornull clampedPos = NavMesh_ClampPointForAIWithExtents( targetNode.GetOrigin(), npc, < 80, 80, 256 > ) + if ( clampedPos != null && Distance2D( npc.GetOrigin(), expect vector( clampedPos ) ) < 512 ) + npc.SetOrigin( expect vector( clampedPos ) ) + } + } + */ + + targetNode = targetNode.GetLinkEnt() + } + } + + else + { + int routeindex = nodesToSkip + vector routepoint = routes[routetaken][routeindex] + while ( true ) + { + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + return + npc.AssaultPointClamped( routepoint ) + npc.AssaultSetGoalRadius( nextDistance ) + + table result = npc.WaitSignal( "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) + /* + if ( result.signal == "OnFailedToPath" && !npc.IsTitan() && !IsSuperSpectre( npc ) ) + { + entity enemy = npc.GetEnemy() + if ( EntityInSolid( npc ) && enemy != null ) + { + vector ornull clampedPos = NavMesh_ClampPointForAIWithExtents( npc.GetOrigin(), npc, < 80, 80, 250 > ) + if ( clampedPos != null ) + npc.SetOrigin( expect vector( clampedPos ) ) + } + else + { + vector ornull clampedPos = NavMesh_ClampPointForAIWithExtents( routepoint, npc, < 80, 80, 80 > ) + if ( clampedPos != null && Distance2D( npc.GetOrigin(), expect vector( clampedPos ) ) < 512 ) + npc.SetOrigin( expect vector( clampedPos ) ) + } + } + */ + routeindex++ + if ( routeindex < routes[routetaken].len() ) + routepoint = routes[routetaken][routeindex] + else + break + } + } + + if ( ( npc.GetClassName() == "npc_frag_drone" || npc.GetClassName() == "npc_stalker" ) && IsHarvesterAlive( fd_harvester.harvester ) ) + npc.AssaultPointClamped( fd_harvester.harvester.GetOrigin() + < 0, 0, 16 > ) + + if ( npc.GetClassName() == "npc_soldier" || npc.GetClassName() == "npc_spectre" ) + { + npc.AssaultSetFightRadius( 512 ) + npc.SetEnemy( fd_harvester.harvester ) + } + + npc.Signal( "FD_ReachedHarvester" ) +} + +void function NPCDroneNav_FD( entity npc, string routeName, int nodesToSkip = 0, float nextDistance = 160.0, bool shouldLoop = false ) +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + npc.EndSignal( "OnLeeched" ) + + Assert( IsValid( npc ) && npc.IsNPC(), "AI Navigation function called in non-NPC entity: " + npc ) + + WaitFrame() + float dist = 65535 + entity targetNode + entity firstNode + string routetaken + string GuySquadName = expect string( npc.kv.squadname ) + array squad + if ( GuySquadName != "" ) + squad = GetNPCArrayBySquad( GuySquadName ) + + if ( !npc.IsTitan() ) + thread NPCStuckTracker( npc ) + + npc.AssaultSetGoalHeight( 64 ) + npc.AssaultSetFightRadius( 0 ) + + if ( !useCustomFDLoad ) + { + if ( routeName == "" ) + { + foreach ( entity node in routeNodes ) + { + if ( !node.HasKey( "route_name" ) ) + continue + if ( squad.len() > 0 ) + { + if ( Distance( squad[0].GetOrigin(), node.GetOrigin() ) < dist ) + { + dist = Distance( squad[0].GetOrigin(), node.GetOrigin() ) + targetNode = node + firstNode = node + } + } + else if ( Distance( npc.GetOrigin(), node.GetOrigin() ) < dist ) + { + dist = Distance( npc.GetOrigin(), node.GetOrigin() ) + targetNode = node + firstNode = node + } + } + #if SERVER && DEV + if ( squad.len() > 0 ) + { + if ( npc == squad[0] ) + printt( "Squad entities had no route defined, using nearest node: " + targetNode.kv.route_name ) + } + else + printt( "Single entity had no route defined, using nearest node: " + targetNode.kv.route_name ) + #endif + } + else + targetNode = GetRouteStart( routeName ) + + // skip nodes + for ( int i = 0; i < nodesToSkip; i++ ) + { + targetNode = targetNode.GetLinkEnt() + firstNode = targetNode.GetLinkEnt() + } + } + else + { + if ( routeName == "" ) + { + foreach ( routename, routeamount in routes ) + { + if ( squad.len() > 0 ) + { + if ( Distance( squad[0].GetOrigin(), routeamount[0] ) < dist ) + { + dist = Distance( squad[0].GetOrigin(), routeamount[0] ) + routetaken = routename + } + } + else if ( Distance( npc.GetOrigin(), routeamount[0] ) < dist ) + { + dist = Distance( npc.GetOrigin(), routeamount[0] ) + routetaken = routename + } + } + #if SERVER && DEV + if ( squad.len() > 0 ) + { + if ( npc == squad[0] ) + printt( "Squad entities had no route defined, using nearest node: " + routetaken ) + } + else + printt( "Single entity had no route defined, using nearest node: " + routetaken ) + #endif + } + else + routetaken = routeName + } + + if ( !useCustomFDLoad ) + { + while ( targetNode != null ) + { + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + return + npc.AssaultPoint( targetNode.GetOrigin() + < 0, 0, 192 > ) + npc.AssaultSetGoalRadius( nextDistance ) + + table result = npc.WaitSignal( "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) + + targetNode = targetNode.GetLinkEnt() + #if SERVER && DEV + if ( targetNode == null ) + printt( "drone finished pathing" ) + #endif + if ( targetNode == null && shouldLoop ) + { + #if SERVER && DEV + printt( "drone reached end of loop, looping" ) + #endif + targetNode = firstNode + } + } + } + + else + { + int routeindex = nodesToSkip + vector routepoint = routes[routetaken][routeindex] + while ( true ) + { + if ( !IsHarvesterAlive( fd_harvester.harvester ) ) + return + npc.AssaultPoint( routepoint + < 0, 0, 192 > ) + npc.AssaultSetGoalRadius( nextDistance ) + + table result = npc.WaitSignal( "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) + + routeindex++ + if ( routeindex < routes[routetaken].len() ) + routepoint = routes[routetaken][routeindex] + else + { + if ( shouldLoop ) + { + #if SERVER && DEV + printt( "drone reached end of loop, looping" ) + #endif + routeindex = 0 + routepoint = routes[routetaken][routeindex] + } + else + { + #if SERVER && DEV + printt( "drone finished pathing" ) + #endif + break + } + } + } + } + + npc.Signal( "FD_ReachedHarvester" ) +} + +entity function GetRouteStart( string routeName ) +{ + foreach ( entity node in routeNodes ) + { + if ( !node.HasKey( "route_name" ) ) + continue + if ( expect string( node.kv.route_name ) == routeName ) + return node + } +} + +void function Dev_ShowRoute( bool includedrones = false ) +{ + if ( !useCustomFDLoad ) + { + string routename + foreach ( entity node in routeNodes ) + { + if ( !node.HasKey( "route_name" ) ) + continue + + routename = expect string( node.kv.route_name ) + entity routetitle = CreatePointMessage( routename, node.GetOrigin() + < 0, 0, 32 >, 800 ) + if ( routename.tolower().find( "drone" ) && includedrones ) + thread DroneTracksPathing( routename ) + else if ( routename.tolower().find( "drone" ) || routename.tolower().find( "reaper" ) ) + continue + else + thread GruntTracksPathing( routename ) + } + } + else + { + foreach ( routename, routeamount in routes ) + { + entity routetitle = CreatePointMessage( routename, routeamount[0], 800 ) + if ( includedrones && routename.tolower().find( "drone" ) ) + thread DroneTracksPathing( routename ) + else + thread GruntTracksPathing( routename ) + } + } +} + +void function GruntTracksPathing( string route ) +{ + vector routeorigin = < 0, 0, 0 > + if ( useCustomFDLoad ) + routeorigin = routes[route][0] + else + routeorigin = GetRouteStart( route ).GetOrigin() + + entity guy = CreateSoldier( TEAM_MILITIA, routeorigin, < 0, 0, 0 > ) + DispatchSpawn( guy ) + PlayLoopFXOnEntity( $"P_ar_holopilot_trail", guy, "CHESTFOCUS" ) + + guy.NotSolid() + guy.EnableNPCFlag( NPC_DISABLE_SENSING | NPC_IGNORE_ALL ) + guy.EnableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + NPC_NoTarget( guy ) + + WaitFrame() + guy.SetTitle( route ) + while( IsAlive( guy ) ) + { + thread NPCNav_FD( guy, route ) + table result = guy.WaitSignal( "FD_ReachedHarvester" ) + wait 5.0 + if ( IsValid( guy ) ) + guy.SetOrigin( routeorigin ) + } +} + +void function DroneTracksPathing( string route ) +{ + vector routeorigin = < 0, 0, 0 > + if ( useCustomFDLoad ) + routeorigin = routes[route][0] + else + routeorigin = GetRouteStart( route ).GetOrigin() + + entity guy = CreateGenericDrone( TEAM_MILITIA, routeorigin + < 0, 0, 32 >, < 0, 0, 0 > ) + SetSpawnOption_AISettings( guy, "npc_drone_plasma_fd" ) + DispatchSpawn( guy ) + PlayLoopFXOnEntity( $"P_ar_holopilot_trail", guy ) + + guy.NotSolid() + guy.EnableNPCFlag( NPC_DISABLE_SENSING | NPC_IGNORE_ALL ) + guy.EnableNPCMoveFlag( NPCMF_PREFER_SPRINT ) + NPC_NoTarget( guy ) + + WaitFrame() + guy.SetTitle( route ) + thread NPCDroneNav_FD( guy, route ) +} + +void function NPCStuckTracker( entity npc ) //Track if AI is properly pathing, otherwise after ten seconds, it will suicide to prevent softlocking +{ + npc.EndSignal( "OnDeath" ) + npc.EndSignal( "OnDestroy" ) + + int FailCount = 0 + while ( IsAlive( npc ) ) + { + table result = npc.WaitSignal( "OnSeeEnemy", "OnFinishedAssault", "OnEnterGoalRadius", "OnFailedToPath" ) + if ( result.signal == "OnFailedToPath" ) + { + if ( FailCount == 10 ) + npc.Die() + FailCount++ + } + else + FailCount = 0 + + wait 1 + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo.gnut b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo.gnut index 72ff58b78..42897a569 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo.gnut @@ -180,14 +180,22 @@ function PlayerBeginsNPCRodeo( entity player, RodeoPackageStruct rodeoPackage, e if ( IsAlive( player ) ) { - int attachIndex = newRodeoTarget.LookupAttachment( rodeoPackage.attachPoint ) - vector startPos = newRodeoTarget.GetAttachmentOrigin( attachIndex ) - - if ( !PlayerCanTeleportHere( player, startPos, newRodeoTarget ) ) + vector startPos + if( IsValid( newRodeoTarget ) ) { - startPos = newRodeoTarget.GetOrigin() + int attachIndex = newRodeoTarget.LookupAttachment( rodeoPackage.attachPoint ) + startPos = newRodeoTarget.GetAttachmentOrigin( attachIndex ) + if ( !PlayerCanTeleportHere( player, startPos, newRodeoTarget ) ) - startPos = player.GetOrigin() + { + startPos = newRodeoTarget.GetOrigin() + if ( !PlayerCanTeleportHere( player, startPos, newRodeoTarget ) ) + startPos = player.GetOrigin() + } + } + else + { + startPos = player.GetOrigin() } thread PlayerJumpsOffRodeoTarget( player, newRodeoTarget, startPos ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut index 78cfdb27f..48feb3bf3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut @@ -611,14 +611,22 @@ function PlayerBeginsTitanRodeo( entity player, RodeoPackageStruct rodeoPackage, if ( IsAlive( player ) ) { - int attachIndex = newRodeoTitan.LookupAttachment( rodeoPackage.attachPoint ) - vector startPos = newRodeoTitan.GetAttachmentOrigin( attachIndex ) - - if ( !PlayerCanTeleportHere( player, startPos, newRodeoTitan ) ) + vector startPos + if( IsValid( newRodeoTitan ) ) { - startPos = newRodeoTitan.GetOrigin() + int attachIndex = newRodeoTitan.LookupAttachment( rodeoPackage.attachPoint ) + startPos = newRodeoTitan.GetAttachmentOrigin( attachIndex ) + if ( !PlayerCanTeleportHere( player, startPos, newRodeoTitan ) ) - startPos = player.GetOrigin() + { + startPos = newRodeoTitan.GetOrigin() + if ( !PlayerCanTeleportHere( player, startPos, newRodeoTitan ) ) + startPos = player.GetOrigin() + } + } + else + { + startPos = player.GetOrigin() } thread PlayerJumpsOffRodeoTarget( player, newRodeoTitan, startPos ) @@ -1106,7 +1114,10 @@ void function PlayerAppliesBatteryPack( entity rodeoPilot, entity rodeoTitan, en #if MP if ( nukeVersion ) + { tempBattery1p.SetSkin( 1 ) + tempBattery3p.SetSkin( 1 ) + } #endif if ( IsAmpedBattery( battery ) ) { @@ -2396,7 +2407,26 @@ void function RodeoForceNuke( entity pilot ) // THROW RODEO RIDER OFF entity soul = titan.GetTitanSoul() soul.soul.nukeAttacker = pilot - NPC_SetNuclearPayload( titan ) + + if ( titan.IsNPC() ) + { + NPC_SetNuclearPayload( titan ) + } + else + { + GivePassive( titan, ePassives.PAS_NUCLEAR_CORE ) + + if ( PlayerHasPassive( titan, ePassives.PAS_AUTO_EJECT ) ) + TakePassive( titan, ePassives.PAS_AUTO_EJECT ) + + titan.TakeDamage( 1, pilot, pilot, damageTable ) + + if ( HasSoul( titan ) && !titan.GetTitanSoul().IsDoomed() ) + { + titan.GetTitanSoul().EnableDoomed() + titan.SetDoomed() + } + } vector ejectAngles = titan.GetAngles() ejectAngles.x = 270 @@ -2440,13 +2470,15 @@ void function OpenRodeoNukeWindow( entity player, entity titan ) player.WaitSignal( "TryNukeGrenade" ) - if ( !HasSuperRodeoGrenade( player ) ) + entity newtitan = GetTitanBeingRodeoed( player ) + + if ( !HasSuperRodeoGrenade( player ) || !IsValid( newtitan ) || !newtitan.IsTitan() || !HasSoul( newtitan ) ) return file.playersThatWantToUseRodeoGrenade[ player ] <- true MessageToPlayer( player, eEventNotifications.FD_SuperRodeoUsed ) - Rodeo_MoveBatteryDown( titan.GetTitanSoul() ) + Rodeo_MoveBatteryDown( newtitan.GetTitanSoul() ) } bool function ClientCommand_TryNukeGrenade( entity player, array args ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut index 4bf195b6d..df43d6d02 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut @@ -1509,7 +1509,7 @@ string function GetValidatedPersistentLoadoutValue( entity player, string loadou { printt( "Invalid Loadout Property: ", loadoutType, loadoutIndex, loadoutProperty, value ) value = ResetLoadoutPropertyToDefault( player, loadoutType, loadoutIndex, loadoutProperty ) //TODO: This will call player.SetPersistentVar() directly. Awkward to do this in a getter function - NSDisconnectPlayer( player, "#RESETTING_LOADOUT" ) // Kick player out with a "Resetting Invalid Loadout" message. Mainly necessary so UI/Client script don't crash out later with known, bad data from persistence + NSDisconnectPlayer( player, "#RESETTING_LOADOUT" ) //Kick player out with a "Resetting Invalid Loadout" message. Mainly necessary so UI/Client script don't crash out later with known, bad data from persistence } } @@ -1519,8 +1519,7 @@ string function GetValidatedPersistentLoadoutValue( entity player, string loadou { printt( "Invalid Loadout Property: ", loadoutType, loadoutIndex, loadoutProperty, value ) value = ResetLoadoutPropertyToDefault( player, loadoutType, loadoutIndex, loadoutProperty ) //TODO: This will call player.SetPersistentVar() directly. Awkward to do this in a getter function - NSDisconnectPlayer( player, "#RESETTING_LOADOUT" ) // Kick player out with a "Resetting Invalid Loadout" message. Mainly necessary so UI/Client script don't crash out later with known, bad data from persistence - + NSDisconnectPlayer( player, "#RESETTING_LOADOUT" ) //Kick player out with a "Resetting Invalid Loadout" message. Mainly necessary so UI/Client script don't crash out later with known, bad data from persistence } ValidateSkinAndCamoIndexesAsAPair( player, loadoutType, loadoutIndex, loadoutProperty, value ) //TODO: This is awkward, has the potential to call a SetPersistentLoadoutValue() if skinIndex and camoIndex are not correct as a pair @@ -3343,7 +3342,7 @@ string function Loadouts_GetSetFileForRequestedClass( entity player ) #endif loadout = GetTitanLoadoutFromPersistentData( player, loadoutIndex ) - OverwriteLoadoutWithDefaultsForSetFile_ExceptSpecialAndAntiRodeo( loadout ) + OverwriteLoadoutWithDefaultsForSetFile_ExceptSpecialAndAntiRodeo( loadout, player ) if ( player.IsBot() && !player.IsPlayback() ) OverrideBotTitanLoadout( loadout ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts_mp.nut index 3b1c8a8ab..48f00ed0a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts_mp.nut @@ -6,6 +6,13 @@ global function GetNPCDefaultWeaponForLevel global function GetTitanLoadoutForCurrentMap +global struct sTryGetTitanLoadoutCallbackReturn +{ + bool wasChanged = false + bool runMoreCallbacks = true + TitanLoadoutDef& loadout +} + TitanLoadoutDef function GetTitanLoadoutForCurrentMap() { TitanLoadoutDef loadout diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 71dd8f75b..714d0acbb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -237,12 +237,11 @@ void function ValidateEquippedItems( entity player ) } // titan loadouts - int selectedTitanLoadoutIndex = player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) for ( int titanLoadoutIndex = 0; titanLoadoutIndex < NUM_PERSISTENT_TITAN_LOADOUTS; titanLoadoutIndex++ ) { printt( "- VALIDATING TITAN LOADOUT: " + titanLoadoutIndex ) - bool isSelected = titanLoadoutIndex == selectedTitanLoadoutIndex + bool isSelected = titanLoadoutIndex == player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) TitanLoadoutDef loadout = GetTitanLoadout( player, titanLoadoutIndex ) TitanLoadoutDef defaultLoadout = shGlobal.defaultTitanLoadouts[titanLoadoutIndex] @@ -460,18 +459,11 @@ void function ValidateEquippedItems( entity player ) { printt( " - SELECTED TITAN CLASS IS LOCKED, RESETTING" ) player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) - selectedTitanLoadoutIndex = 0 + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", 0 ) } } - if ( selectedTitanLoadoutIndex < 0 || selectedTitanLoadoutIndex >= NUM_PERSISTENT_TITAN_LOADOUTS ) - { - printt( "- SELECTED TITAN CLASS IS INVALID, RESETTING" ) - player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) - selectedTitanLoadoutIndex = 0 - } - - Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", selectedTitanLoadoutIndex ) + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) ) // pilot loadouts for ( int pilotLoadoutIndex = 0; pilotLoadoutIndex < NUM_PERSISTENT_PILOT_LOADOUTS; pilotLoadoutIndex++ ) @@ -649,7 +641,7 @@ void function ValidateEquippedItems( entity player ) { // do nothing } - else if ( loadout.primaryMod3 == "pro_screen" ) + else if ( loadout.primaryMod3 != "pro_screen" ) { // fuck you and your three mod slot stuff printt( " - PRIMARY WEAPON PRO SCREEN IS INVALID, RESETTING" ) @@ -786,7 +778,7 @@ void function ValidateEquippedItems( entity player ) { // do nothing } - else if ( loadout.secondaryMod3 == "pro_screen" ) + else if ( loadout.secondaryMod3 != "pro_screen" ) { // fuck you and your three mod slot stuff printt( " - SECONDARY WEAPON PRO SCREEN IS INVALID, RESETTING" ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut index c87d7f8a2..0d72bc691 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut @@ -34,7 +34,9 @@ global function SetRequestTitanGamemodeRules global function CreateTitanForPlayerAndHotdrop global function SetRequestTitanAllowedCallback +global function ShouldDoTitanfall global function TitanDropDisabledForPlayerTeam +global function GiveTitanfallScoreMedal struct { array ETATimeThresholds = [ 120, 60, 30, 15 ] @@ -63,6 +65,7 @@ const nagInterval = 40 global const float WARPFALL_SOUND_DELAY = 1.1 global const float WARPFALL_FX_DELAY = 0.9 +global const asset ENTITY_MARKER_TELEPORT_FX = $"P_ts_entity" function ReplacementTitans_Init() { @@ -75,6 +78,7 @@ function ReplacementTitans_Init() PrecacheEffect( TURBO_WARP_FX ) PrecacheEffect( TURBO_WARP_COMPANY ) + PrecacheEffect( ENTITY_MARKER_TELEPORT_FX ) AddCallback_OnClientConnecting( ReplacementTitan_InitPlayer ) @@ -649,61 +653,54 @@ bool function ReplacementTitan( entity player ) } #if MP - void function ForcePilotToBecomeTitan( entity player ) { - float fadeTime = 0.5 - float holdTime = 2.0 - - player.EndSignal( "OnDeath" ) - player.EndSignal( "OnDestroy" ) - - if ( GAMETYPE != SST ) + if ( IsValid( player.GetParent() ) ) + return + + TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player ) + entity titan = CreateAutoTitanForPlayer_FromTitanLoadout( player, titanLoadout, player.GetOrigin(), player.GetAngles() ) + DispatchSpawn( titan ) + titan.ContextAction_SetBusy() + HideName( titan ) + titan.SetValidHealthBarTarget( false ) + titan.UnsetUsable() + ClearTitanAvailable( player ) + + vector playerMomentum = player.GetVelocity() + vector playerCallinOrigin = player.GetOrigin() + vector titanOrigin = titan.GetOrigin() + + vector ornull clampedPos = NavMesh_ClampPointForAIWithExtents( titanOrigin, titan, < 1400, 1400, 1400 > ) + if ( clampedPos != null ) { - #if FACTION_DIALOGUE_ENABLED - PlayFactionDialogueToPlayer( "mp_titanInbound" , player ) - #else - if ( player.titansBuilt ) - PlayConversationToPlayer( "TitanReplacement", player ) - else - PlayConversationToPlayer( "FirstTitanInbound", player ) - #endif + expect vector( clampedPos ) + TraceResults result = TraceHull( titanOrigin, titanOrigin, titan.GetBoundingMins(), titan.GetBoundingMaxs(), [titan], TRACE_MASK_TITANSOLID, TRACE_COLLISION_GROUP_NONE ) + if ( result.startSolid || + TraceLineSimple( titanOrigin + < 0, 0, 128 >, clampedPos, titan ) == 1.0 || + TraceLineSimple( titanOrigin + < 0, 0, 200 >, clampedPos, titan ) == 1.0 || + TraceLineSimple( titanOrigin + < 0, 0, 200 >, clampedPos + < 0, 0, 128 >, titan ) == 1.0 ) + { + titan.SetOrigin( clampedPos ) + titan.ForceCheckGroundEntity() + } } - player.Signal( "RodeoOver" ) - player.Signal( "ScriptAnimStop" ) - - table e = {} - e.settingsRestored <- false + PlayFX( ENTITY_MARKER_TELEPORT_FX, playerCallinOrigin + < 0, 0, ( player.GetBoundingMaxs().z / 2 ) > ) + PilotBecomesTitan( player, titan ) + GiveTitanfallScoreMedal( player ) - OnThreadEnd( - function() : ( player, e ) - { - if ( IsValid( player ) && !e.settingsRestored ) - { - Rodeo_Allow( player ) - player.Show() - player.MakeVisible() - } - } - ) - Rodeo_Disallow( player ) - - ScreenFadeToBlack( player, fadeTime, holdTime ) - player.DissolveNonLethal( ENTITY_DISSOLVE_CORE, Vector( 0, 0, 0 ), 500 ) - - wait fadeTime - player.SetInvulnerable() - player.Hide() - - wait holdTime - ScreenFadeFromBlack( player, 1.0, 0.5 ) - waitthread TitanPlayerHotDropsIntoLevel( player ) - e.settingsRestored = true - Rodeo_Allow( player ) - player.Show() - player.MakeVisible() - player.ClearInvulnerable() + titanOrigin = titan.GetOrigin() + vector desiredLocation = titanOrigin + if( TraceLineSimple( titanOrigin, < titanOrigin.x, titanOrigin.y, playerCallinOrigin.z >, titan ) == 1.0 ) + desiredLocation = < titanOrigin.x, titanOrigin.y, playerCallinOrigin.z > + + player.SetOrigin( desiredLocation ) + PutTitanPlayerInSafeSpot( player ) + player.SetVelocity( playerMomentum ) + EmitSoundOnEntity( player, "Timeshift_Scr_InvoluntaryShift" ) + PlayFXOnEntityForEveryoneExceptPlayer( $"P_phase_shift_main_XO", player, player ) + titan.Destroy() } #endif @@ -769,28 +766,7 @@ void function CreateTitanForPlayerAndHotdrop( entity player, Point spawnPoint, T printt( "Dropping replacement titan at " + origin + " with angles " + angles ) - #if HAS_STATS - UpdatePlayerStat( player, "misc_stats", "titanFalls" ) - #endif - #if SERVER && MP - PIN_AddToPlayerCountStat( player, "titanfalls" ) - #endif - - if ( !level.firstTitanfall ) - { - AddPlayerScore( player, "FirstTitanfall", player ) - - #if HAS_STATS - UpdatePlayerStat( player, "misc_stats", "titanFallsFirst" ) - #endif - - level.firstTitanfall = true - } - else - { - AddPlayerScore( player, "Titanfall", player ) - } - + GiveTitanfallScoreMedal( player ) player.Signal( "CalledInReplacementTitan" ) @@ -1214,4 +1190,56 @@ bool function ShouldDoTitanfall() bool function TitanDropDisabledForPlayerTeam( entity player ) { return ( level.nv.titanDropEnabledForTeam != TEAM_BOTH && level.nv.titanDropEnabledForTeam != player.GetTeam() ) -} \ No newline at end of file +} + +void function GiveTitanfallScoreMedal( entity player ) +{ + #if HAS_STATS + UpdatePlayerStat( player, "misc_stats", "titanFalls" ) + #endif + + #if SERVER && MP + PIN_AddToPlayerCountStat( player, "titanfalls" ) + int TitanFallXP = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.TITAN_FALL + "]" ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.TITAN_FALL + "]", TitanFallXP + 1 ) + #endif + + if ( !level.firstTitanfall ) + { + AddPlayerScore( player, "FirstTitanfall", player ) + #if HAS_STATS + UpdatePlayerStat( player, "misc_stats", "titanFallsFirst" ) + #endif + level.firstTitanfall = true + } + else + AddPlayerScore( player, "Titanfall", player ) +} + +#if MP +void function PutTitanPlayerInSafeSpot( entity player ) +{ + int severity = 128 + vector baseOrigin = player.GetOrigin() + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y + severity, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y - severity, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x + severity, baseOrigin.y, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x - severity, baseOrigin.y, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y, baseOrigin.z + severity >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y, baseOrigin.z - severity >, baseOrigin ) ) + return + + return PutTitanPlayerInSafeSpot( player ) +} +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut index 396d5624a..da6561a7c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut @@ -504,9 +504,6 @@ bool function HandleKillshot( entity ent, var damageInfo, TitanDamage titanDamag bool function PlayerHasAutoEject( entity player ) { - if ( player.IsBot() ) - return false - if ( !PlayerHasPassive( player, ePassives.PAS_AUTO_EJECT ) ) return false diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/sh_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/sh_titan.gnut new file mode 100644 index 000000000..e3e2f1e9e --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/sh_titan.gnut @@ -0,0 +1,1280 @@ +untyped + +global function TitanShared_Init +global function CodeCallback_PlayerInTitanCockpit +global function DebugNewTitanModels +global function Titan_CreatePhysicsModelsFromParentedModels +global function TemporarilyNonSolidPlayer + +#if SERVER + global function NPC_GetNuclearPayload + global function NPC_SetNuclearPayload + global function TempAirControl + global function TempLossOfAirControl + global function TitanEjectPlayer + global function TitanStagger + global function EnableTitanExit + global function DisableTitanExit + global function TitanSkipsDeathOnEject +#endif + +global const TITAN_EJECT_SCREECH = "titan_eject_screech" +global const TITAN_DECAY_LIMIT = 0.35 // should be the same as the frac that flames start. + +global const TITAN_NUCLEAR_CORE_FX_3P = $"P_xo_exp_nuke_3P_alt" +global const TITAN_NUCLEAR_CORE_FX_1P = $"P_xo_exp_nuke_1P_alt" +global const TITAN_NUCLEAR_CORE_NUKE_FX = $"P_xo_nuke_warn_flare" + + +global enum eCockpitState +{ + Disabled = 0 + Enabled = 1 + NULL = 3 + Open = 5 + Close = 7 + Eject = 9 +} + +struct +{ + float titanVOEjectNotifyDist = 2000 * 2000 +} file + + +function TitanShared_Init() +{ + level._titanCrushables <- {} + + RegisterSignal( "TitanBeingEntered" ) + RegisterSignal( "TitanEntered" ) + RegisterSignal( "TitanExit" ) + RegisterSignal( "TitanExitComplete" ) + RegisterSignal( "TitanDecay" ) + RegisterSignal( "TitanEjectionStarted" ) + RegisterSignal( "EjectLand" ) + RegisterSignal( "EjectAttempt" ) + RegisterSignal( "TempAirControl" ) + + #if SERVER + AddSoulSettingsChangeFunc( UpdateTitanPanel ) + AddSoulSettingsChangeFunc( UpdateTitanArmBadge ) + AddSoulTransferFunc( SmartAmmo_TransferMissileLockons ) + AddSoulDeathCallback( Titan_RodeoPanelCleanup ) + AddSoulDeathCallback( Titan_ArmBadgeCleanup ) + #endif + + #if SERVER + AddSoulInitFunc( AddPanelToTitan ) + AddSoulInitFunc( AddArmBadgeToTitan ) + + PrecacheParticleSystem( TITAN_NUCLEAR_CORE_FX_3P ) + PrecacheParticleSystem( TITAN_NUCLEAR_CORE_FX_1P ) + PrecacheParticleSystem( TITAN_NUCLEAR_CORE_NUKE_FX ) + + PrecacheModel( $"models/industrial/bolt_tiny01.mdl" ) + #endif +} + +#if SERVER +void function Titan_RodeoPanelCleanup( entity soul, var damageInfo ) +{ + if ( IsValid( soul.soul.batteryContainer ) ) + soul.soul.batteryContainer.Kill_Deprecated_UseDestroyInstead() +} + +void function Titan_ArmBadgeCleanup( entity soul, var damageInfo ) +{ + if ( IsValid( soul.soul.armBadge ) ) + soul.soul.armBadge.Kill_Deprecated_UseDestroyInstead() +} +#endif + +//Can't just do this by default for all children on the Titan since they need to have physics properties defined +function Titan_CreatePhysicsModelsFromParentedModels( parentedModel, entity soul ) +{ + if ( !IsValid( parentedModel ) ) + return + + // Make it not solid so ejection doesn't get caught up on it + parentedModel.NotSolid() + +/* + // Stop any running animations + parentedModel.Anim_Stop() + + // Spawn a physics version of the models + entity prop_physics = CreateEntity( "prop_physics" ) + SetTargetName( prop_physics, UniqueString( "parentedModel" ) ) + prop_physics.SetValueForModelKey( parentedModel.GetModelName() ) + prop_physics.kv.skin = parentedModel.GetSkin() + prop_physics.kv.spawnflags = 4 // debris nocollide + prop_physics.kv.fadedist = -1 + prop_physics.kv.physdamagescale = 0.1 + prop_physics.kv.inertiaScale = 1.0 + prop_physics.kv.renderamt = 255 + prop_physics.kv.rendercolor = "255 255 255" + prop_physics.SetOrigin( parentedModel.GetOrigin() ) + prop_physics.SetAngles( parentedModel.GetAngles() ) + DispatchSpawn( prop_physics ) + //prop_physics.SetAngularVelocity( 0,0,0 ) + //prop_physics.SetVelocity( Vector( 0,0,0) ) + prop_physics.Kill_Deprecated_UseDestroyInstead( 11.0 ) +*/ + + // Hide pod model, and delete it. We have to hide it first because it doesn't get deleted right away for some reason + parentedModel.Hide() + parentedModel.Kill_Deprecated_UseDestroyInstead() + +} + +function CodeCallback_PlayerInTitanCockpit( titan, player ) +{ + expect entity( titan ) + expect entity( player ) + + // clear the damage history when you enter a titan + ClearRecentDamageHistory( player ) + + #if SERVER +// player.SetUsableByGroup( "enemies" ) // rodeo'able + //player.SetUsable() + //player.SetUsePrompts( "Hold [USE] to rodeo.", "Hold [USE] to rodeo." ) + //player.SetUsePrompts( " ", " " ) + + TitanTaken( player, titan ) + titan.GetTitanSoul().soul.lastOwner = player + + Remote_CallFunction_Replay( player, "ServerCallback_TitanCockpitBoot" ) + player.CockpitStartBoot() + + Signal( svGlobal.levelEnt, "TitanEntered", { player = player } ) + Signal( player, "TitanEntered" ) + #elseif CLIENT + Signal( player, "TitanEntered" ) + #endif +} + +#if SERVER +void function AddPanelToTitan( entity soul ) +{ + entity titan = soul.GetTitan() + + string settings = GetSoulPlayerSettings( soul ) + var model = Dev_GetPlayerSettingAssetByKeyField_Global( settings, "hatchmodel" ) + if ( model == $"" ) + return + + expect asset( model ) + + entity rodeoPanel = CreatePropDynamic( model ) + + string titanType = GetSoulTitanSubClass( soul ) + + rodeoPanel.NotSolid() + rodeoPanel.SetParent( titan, "RODEO_BATTERY" ) + rodeoPanel.Anim_Play( GetAnimFromAlias( titanType, "hatch_rodeo_up_idle" ) ) + rodeoPanel.s.opened <- false + rodeoPanel.s.lastDamageStateThreshold <- 1.1 + rodeoPanel.s.lastDamageStateParticleSystem <- null + rodeoPanel.s.damageAnimDone <- true + SetTeam( rodeoPanel, titan.GetTeam() ) + rodeoPanel.MarkAsNonMovingAttachment() + rodeoPanel.RemoveFromSpatialPartition() + rodeoPanel.SetSkin( titan.GetSkin() ) + + soul.soul.batteryContainer = rodeoPanel +} + +void function UpdateTitanPanel( entity soul ) +{ + entity titan = soul.GetTitan() + if ( !IsAlive( titan ) ) + return + + string settings = GetSoulPlayerSettings( soul ) + var model = Dev_GetPlayerSettingAssetByKeyField_Global( settings, "hatchmodel" ) + if ( model == $"" ) + return + + expect asset( model ) + + entity batteryContainer = soul.soul.batteryContainer + if( !IsValid( batteryContainer ) ) + return + + if ( soul.soul.batteryContainerBeingUsed ) + return + + batteryContainer.SetModel( model ) + batteryContainer.SetSkin( titan.GetSkin() ) + batteryContainer.ClearParent() + batteryContainer.SetParent( titan, "RODEO_BATTERY" ) //Needed to fix battery being parented to wrong spot after picking a different titan loadout in grace period. + + string titanType = GetSoulTitanSubClass( soul ) + batteryContainer.Anim_Play( GetAnimFromAlias( titanType, "hatch_rodeo_up_idle" ) ) + +} + +void function AddArmBadgeToTitan( entity soul ) +{ + thread AddArmBadgeToTitan_Internal( soul ) +} + +void function AddArmBadgeToTitan_Internal( entity soul ) +{ + soul.EndSignal( "OnDestroy" ) + + // wait until the end of the frame to allow the soul to become owned by a boss player + WaitEndFrame() + + entity titan = soul.GetTitan() + + var model = GetTitanArmBadge( soul ) + if ( model == $"" ) + return + expect asset( model ) + + entity soulOwner = soul.GetBossPlayer() + if ( !IsValid( soulOwner ) ) + return + + entity armBadge = CreatePropDynamic( model ) + + //string titanType = GetSoulTitanSubClass( soul ) + + armBadge.NotSolid() + armBadge.SetParent( titan, TITAN_ARM_BADGE_ATTACHMENT ) + //armBadge.Anim_Play( GetAnimFromAlias( titanType, "hatch_rodeo_up_idle" ) ) + SetTeam( armBadge, titan.GetTeam() ) + armBadge.MarkAsNonMovingAttachment() + armBadge.RemoveFromSpatialPartition() + #if MP + int difficulty = FD_GetHighestDifficultyForTitan( soulOwner, GetActiveTitanLoadout( soulOwner ).titanClass ) + switch ( difficulty ) + { + case eFDDifficultyLevel.HARD: + armBadge.SetBodygroup( 0, 1 ) + break + case eFDDifficultyLevel.MASTER: + armBadge.SetBodygroup( 0, 2 ) + break + case eFDDifficultyLevel.INSANE: + armBadge.SetBodygroup( 0, 3 ) + break + } + #endif + + soul.soul.armBadge = armBadge +} + +void function UpdateTitanArmBadge( entity soul ) +{ + entity titan = soul.GetTitan() + if ( !IsAlive( titan ) ) + return + + var model = GetTitanArmBadge( soul )//Dev_GetPlayerSettingAssetByKeyField_Global( settings, "hatchmodel" ) + if ( model == $"" ) + return + expect asset( model ) + + entity soulOwner = soul.GetBossPlayer() + if ( !IsValid( soulOwner ) ) + return + + entity armBadge = soul.soul.armBadge + if( !IsValid(armBadge) ) + return + + //armBadge.SetModel( model ) + //armBadge.SetSkin( titan.GetSkin() ) + armBadge.ClearParent() + armBadge.SetParent( titan, TITAN_ARM_BADGE_ATTACHMENT ) +} + +int function NPC_GetNuclearPayload( entity npc ) +{ + return npc.ai.nukeCore +} + +void function NPC_SetNuclearPayload( entity npc, int doSet = 4 ) +{ + npc.ai.nukeCore = doSet +} +#endif //Server only + +function DebugNewTitanModels() +{ + return GetCurrentPlaylistVarInt( "r2_titan_models", 0 ) +} + +/* +open +openIdle +close +closeIdle +frontToBack +backToFront +backIdle +*/ + +#if SERVER +const TITAN_PLAYEREJECT_DELAY = 0.4 +const TITAN_PLAYEREJECT_DURATION = 0.8 // long enough foranimation +const MAX_EJECT_LATENCY_COMPENSATION = 0.4 + +function TitanSkipsDeathOnEject( entity titan ) +{ + entity soul = titan.GetTitanSoul() + soul.soul.diesOnEject = false +} + +function TitanEjectPlayer( entity ejectTitan, bool instant = false ) //TODO: This needs a refactor badly. Way too long and unwieldy. I think it was a mistake to handle both player Titan eject and NPC titan eject in the same function +{ + ejectTitan.Signal( "EjectAttempt" ) + + Assert( ejectTitan.IsTitan() ) + Assert( IsAlive( ejectTitan ), "Ejecting titan expected to be alive. IsPlayer? " + ejectTitan.IsPlayer() + " ent: " + ejectTitan ) + + if ( ejectTitan.ContextAction_IsActive() ) + return + + entity soul = ejectTitan.GetTitanSoul() + + if ( soul.IsEjecting() ) + return + + if ( ejectTitan.IsPlayer() ) + { + if ( IsPlayerDisembarking( ejectTitan ) ) + return + } + + local e = {} + e.titan <- ejectTitan + e.team <- ejectTitan.GetTeam() + + e.player <- null + e.npcPilot <- null + bool ejectTitanHasNpcPilot = false + if ( ejectTitan.IsPlayer() ) + e.player = ejectTitan + + #if NPC_TITAN_PILOT_PROTOTYPE + if ( TitanHasNpcPilot( ejectTitan ) ) + { + ejectTitanHasNpcPilot = true + } + #endif + + e.nukeFX <- [] + e.attacker <- ( "attacker" in soul.lastAttackInfo ) ? soul.lastAttackInfo.attacker : null + e.inflictor <- ( "inflictor" in soul.lastAttackInfo ) ? soul.lastAttackInfo.inflictor : null + e.damageSourceId <- ( "damageSourceId" in soul.lastAttackInfo ) ? soul.lastAttackInfo.damageSourceId : -1 + e.damageTypes <- soul.lastAttackInfo.scriptType + e.overrideAttacker <- soul.soul.nukeAttacker + + local nuclearPayload = 0 + if ( IsValid( e.player ) ) + nuclearPayload = GetNuclearPayload( ejectTitan ) + else + nuclearPayload = NPC_GetNuclearPayload( ejectTitan ) + + e.nuclearPayload <- nuclearPayload + + if ( e.nuclearPayload ) + { + e.needToClearNukeFX <- false + e.nukeFXInfoTarget <- CreateEntity( "info_target" ) + e.nukeFXInfoTarget.kv.spawnflags = SF_INFOTARGET_ALWAYS_TRANSMIT_TO_CLIENT + DispatchSpawn( e.nukeFXInfoTarget ) + + AI_CreateDangerousArea_DamageDef( damagedef_nuclear_core, e.nukeFXInfoTarget, ejectTitan.GetTeam(), true, true ) + } + + entity rodeoPilot = GetRodeoPilot( ejectTitan ) + if ( rodeoPilot && rodeoPilot == e.attacker ) + e.damageSourceId = eDamageSourceId.rodeo_forced_titan_eject + + ejectTitan.Signal( "TitanEjectionStarted" ) + ejectTitan.EndSignal( "OnDeath" ) + + OnThreadEnd( + function() : ( e, ejectTitan ) + { + if ( IsAlive( ejectTitan ) ) + { + thread ClearEjectInvulnerability( ejectTitan ) + } + else if ( IsValid( ejectTitan ) ) + { + ejectTitan.ClearInvulnerable() + } + + if ( IsValid( e.player ) ) + { + e.player.UnfreezeControlsOnServer() + } + + entity titan = expect entity( e.titan ) + + if ( e.nuclearPayload ) + { + if ( e.needToClearNukeFX ) + { + if ( IsAlive( titan ) ) + { + //Nuclear eject sequence got interrupted early, probably because Pilot died + Assert( titan.IsTitan() ) + thread NuclearCoreExplosion( titan.GetOrigin(), e ) + } + else + { + //Nuclear eject fired, needs to be cleaned up + ClearNuclearBlueSunEffect( e ) + } + } + //Nuclear core handles cleaning up the left over titan by itself, so just return out early + return + } + + if ( !IsAlive( titan ) ) + return + + entity soul = titan.GetTitanSoul() + if ( !soul.soul.diesOnEject ) + return + + Assert( titan.IsTitan() ) + Assert( soul.IsEjecting() ) + titan.Die( e.attacker, e.inflictor, { scriptType = damageTypes.titanEjectExplosion | e.damageTypes, damageSourceId = e.damageSourceId } ) + } + ) + + soul.SetEjecting( true ) + ejectTitan.SetInvulnerable() //Give both player and ejectTitan temporary invulnerability in the course of ejecting. Player invulnerability gets cleared in ClearEjectInvulnerability + + #if SERVER + StatusEffect_StopAll( expect entity( e.titan ), eStatusEffect.lockon_detected_titan ) + #endif + + #if HAS_STATS + if ( IsValid( e.player ) ) + { + UpdatePlayerStat( expect entity( e.player ), "misc_stats", "timesEjected" ) + if ( nuclearPayload ) + UpdatePlayerStat( expect entity( e.player ), "misc_stats", "timesEjectedNuclear" ) + } + #endif + #if SERVER && MP + PIN_AddToPlayerCountStat( expect entity( e.player ), "ejects" ) + #endif + + if ( !ejectTitan.ContextAction_IsBusy() ) + ejectTitan.ContextAction_SetBusy() + + local standing = true + if ( IsValid( e.player ) ) + standing = e.player.IsStanding() + else + standing = soul.GetStance() == STANCE_STAND + + local titanEjectAnimPlayer, titanEjectAnimTitan + if ( standing ) + { + if ( nuclearPayload ) + { + titanEjectAnimPlayer = "at_nuclear_eject_standing" + titanEjectAnimTitan = "at_nuclear_eject_standing_idle" + } + else + { + titanEjectAnimPlayer = "at_MP_eject_stand_start" + titanEjectAnimTitan = "at_MP_eject_stand_end" + } + } + else + { + titanEjectAnimPlayer = "at_MP_eject_crouch_idle" + titanEjectAnimTitan = "at_MP_eject_crouch_start" + } + + float ejectDuration // = TITAN_PLAYEREJECT_DURATION + if ( nuclearPayload ) + ejectDuration = TITAN_PLAYEREJECT_DURATION * 2.0 + else + ejectDuration = TITAN_PLAYEREJECT_DURATION + +// ejectDuration = ejectTitan.GetSequenceDuration( titanEjectAnimPlayer ) + + if ( nuclearPayload ) + { + array players = GetPlayerArray() + local frequency = 40 + local duration = 8.5 + vector origin = ejectTitan.GetOrigin() + + foreach ( guy in players ) + { + if ( guy == e.player ) + continue + + if ( !IsAlive( guy ) ) + continue + + float dist = Distance( guy.GetOrigin(), origin ) + float result = Graph( dist, 750, 1500, 5.0, 0.0 ) + Remote_CallFunction_Replay( guy, "ServerCallback_ScreenShake", result, frequency, duration ) + } + + e.needToClearNukeFX = true + e.nukeFXInfoTarget.SetParent( ejectTitan, "CHESTFOCUS" ) //Play FX and sound on entity since we need something that lasts across the player titan -> pilot transition + e.nukeFX.append( PlayFXOnEntity( TITAN_NUCLEAR_CORE_NUKE_FX, expect entity( e.nukeFXInfoTarget ) ) ) + e.nukeFX.append( e.nukeFXInfoTarget ) + //ejectDuration += 0.5 + + EmitSoundOnEntity( e.nukeFXInfoTarget, "titan_nuclear_death_charge" ) + } + + entity rodeoPlayer = GetRodeoPilot( ejectTitan ) + if ( IsValid( rodeoPlayer ) ) + Remote_CallFunction_Replay( rodeoPlayer, "ServerCallback_RodeoerEjectWarning", ejectTitan.GetTitanSoul().GetEncodedEHandle(), TITAN_PLAYEREJECT_DELAY + ejectDuration ) + + if ( IsValid( e.player ) ) + e.player.CockpitStartEject() + + float blendDelay = 0.15 + vector origin = ejectTitan.GetOrigin() + + if ( !instant ) + { + if ( IsValid( e.player ) ) + { + Remote_CallFunction_Replay( e.player, "ServerCallback_EjectConfirmed" ) + EmitSoundAtPositionExceptToPlayer( e.team, ejectTitan.GetOrigin(), e.player, "Titan_Eject_Servos_3P" ) + e.player.FreezeControlsOnServer() + } + else + { + EmitSoundAtPosition( e.team, ejectTitan.GetOrigin(), "Titan_Eject_Servos_3P" ) + } + + if ( !ejectTitan.IsTitan() ) + { + // must be a titan, something bad has happened + KillStuckPlayer( ejectTitan ) + return + } + + ejectTitan.Anim_Play( titanEjectAnimPlayer ) + + wait blendDelay // wait for ejectTitan to blend into disembark pose + + Assert( ejectDuration > MAX_EJECT_LATENCY_COMPENSATION ) + wait ejectDuration - MAX_EJECT_LATENCY_COMPENSATION + + if ( IsValid( e.player ) ) + { + // subtract player latency so that the client gets the eject at the same time they finish the animation + float latency = expect entity( e.player ).GetLatency() + float waitduration = MAX_EJECT_LATENCY_COMPENSATION - min( latency, MAX_EJECT_LATENCY_COMPENSATION ) + //printt( "Eject: compensating for " + latency + " seconds of latency; wait " + waitduration ) + wait waitduration + } + } + + // Defensive fix for if player becomes a spectator between initiating eject and now + if ( IsValid( e.player ) && e.player.GetPlayerSettings() == "spectator" ) + return + + if ( ejectTitan.GetTitanSoul() == null ) + return + + if ( IsValid( e.player ) ) + EmitSoundAtPositionExceptToPlayer( e.team, ejectTitan.GetOrigin(), e.player, "Titan_Eject_PilotLaunch_3P" ) + else + EmitSoundAtPosition( e.team, ejectTitan.GetOrigin(), "Titan_Eject_PilotLaunch_3P" ) + + entity titan + if ( IsValid( e.player ) ) + { + entity player = expect entity( e.player ) + titan = CreateAutoTitanForPlayer_ForTitanBecomesPilot( player ) + DispatchSpawn( titan ) + player.p.lastEjectTime = Time() + HolsterAndDisableWeapons( player ) //Primarily done to not play the holster animation, then deploy animation of weapon if we happened to switch the active weapon in GiveWeaponsFromStoredArray() + TitanBecomesPilot( ejectTitan, titan ) + DeployAndEnableWeapons( player )//Undo Holster + player.UnfreezeControlsOnServer() + } + else + { + // the titan is an AI + titan = ejectTitan + } + + #if NPC_TITAN_PILOT_PROTOTYPE + if ( ejectTitanHasNpcPilot ) + e.npcPilot = NpcTitanBecomesPilot( ejectTitan ) + #endif + + vector titanOrigin = titan.GetOrigin() + + // HACKY, surprised there isn't a wrapper for this yet + if ( !( "disableAutoTitanConversation" in titan.s ) ) + titan.s.disableAutoTitanConversation <- true // no auto titan chatter + + titan.SetInvulnerable() //Titan dies at the end of eject sequence by script + titan.SetNPCPriorityOverride_NoThreat() // AI shouldn't consider this ejecting titan as an enemy and shoot it, etc + + if ( e.nuclearPayload ) + { + e.nukeFXInfoTarget.SetParent( titan, "CHESTFOCUS" ) + } + + local isInDeepWater = ( "isInDeepWater" in ejectTitan.s && ejectTitan.s.isInDeepWater ) + + if ( e.nuclearPayload || isInDeepWater ) + { + thread TitanNonSolidTemp( titan ) + } + + ejectTitan.Anim_Stop() + e.titan = titan + + if ( ejectTitan.ContextAction_IsBusy() ) + ejectTitan.ContextAction_ClearBusy() + + FirstPersonSequenceStruct sequence + sequence.thirdPersonAnim = expect string ( titanEjectAnimTitan ) + sequence.teleport = true + thread FirstPersonSequence( sequence, titan ) + + if ( IsValid( e.player ) ) + { + entity player = expect entity( e.player ) + thread TempAirControl( player ) + + PutEntityInSafeSpot( player, titan, null, origin + <0,0,60>, player.GetOrigin() + <0,0,60> ) + } + + vector ejectAngles = titan.GetAngles() + ejectAngles.x = 270 + //ejectAngles.x = RandomIntRange( 263, 277 ) //5 degrees back of straight up was 245 + + float speed = RandomFloatRange( 1500, 1700 ) //was 1000 + if ( nuclearPayload ) + speed += 400 + + if ( isInDeepWater ) + speed += 1000 + + e.singleRodeoPilot <- null //HACKY. Need to store it off because after time passes we don't have a handle to the rider anymore. Terribly hacky + + entity rider = GetRodeoPilot( titan ) + if ( rider && rider.GetParent() == titan ) + { + e.singleRodeoPilot = rider //Need to store it off because after time passes we don't have a handle to the rider anymore. Terribly hacky + if ( IsValid( e.player ) ) + thread TemporarilyNonSolidPlayer( expect entity( e.player ) ) + + thread TemporarilyNonSolidPlayer( rider ) + + vector riderEjectAngles = AnglesCompose( ejectAngles, < 5, 0, 0 > ) + + float gravityScale = expect float ( rider.GetPlayerSettingsField( "gravityscale" ) ) + vector riderVelocity = AnglesToForward( riderEjectAngles ) * (speed * gravityScale) * 0.95 + + ThrowRiderOff( rider, titan, riderVelocity ) + + wait 0.05 + } + + if ( IsAlive( expect entity( e.player ) ) ) + { + if ( PlayerHasPassive( expect entity( e.player ), ePassives.PAS_PHASE_EJECT ) ) + { + PhaseShift( expect entity( e.player ), 0.0, 3.0 ) + ejectAngles.x = 315 + speed *= 0.5 + } + ejectAngles = AnglesCompose( ejectAngles, < -5, 0, 0 > ) + + float gravityScale = expect float ( e.player.GetPlayerSettingsField( "gravityscale" ) ) + vector velocity = AnglesToForward( ejectAngles ) * speed * sqrt( gravityScale ) + e.player.SetOrigin( e.player.GetOrigin() ) + e.player.SetVelocity( velocity ) + vector player_look_angles = titan.GetAngles() + player_look_angles.x = 80 //was 35 + e.player.SetAngles( player_look_angles ) + + thread EjectFlightTracker( expect entity( e.player ) ) + + entity rider = expect entity( e.singleRodeoPilot ) + if ( IsAlive( rider ) && e.player.GetTeam() != rider.GetTeam() ) + thread LookAtEachOther( rider, expect entity( e.player ) ) + } + else if ( ejectTitanHasNpcPilot && IsAlive( expect entity( e.npcPilot ) ) ) + { + speed *= 0.6//magic number + vector velocity = < 0, 0, speed > //straight up + e.npcPilot.SetOrigin( titan.GetOrigin() /* + Vector(0,0,100)*/ ) + e.npcPilot.SetAngles( titan.GetAngles() ) + e.npcPilot.Anim_ScriptedPlay( "running_jump_F_float" ) + e.npcPilot.SetVelocity( velocity ) + } + + if ( IsValid( e.player ) ) + TitanEjectVO( expect entity( e.player ), titanOrigin ) + + wait 0.15 + + vector explosionOrigin = titanOrigin + Vector( 0, 0, 200 ) + + if ( nuclearPayload ) + { + thread NuclearCoreExplosion( explosionOrigin, e ) + } + else + { + entity explosionOwner = GetExplosionOwner( e ) + entity inflictor + if ( IsValid( titan ) ) + inflictor = titan + else + inflictor = explosionOwner + + RadiusDamage( + explosionOrigin, // origin + explosionOwner, // owner + inflictor, // inflictor + 1, // normal damage + 1800, // heavy armor damage + 100, // inner radius + 300, // outer radius + SF_ENVEXPLOSION_NO_DAMAGEOWNER, // explosion flags + 0, // distanceFromAttacker + 0, // explosionForce + damageTypes.explosive, // damage flags + eDamageSourceId.titan_explosion // damage source id + ) + + entity shake = CreateEntity( "env_shake" ) + shake.SetOrigin( titanOrigin ) + shake.kv.amplitude = 12 //1-16 + shake.kv.duration = 1 + shake.kv.frequency = 100 //.001 - 255 + shake.kv.radius = 1000 + shake.kv.spawnflags = 4 //in air + DispatchSpawn( shake ) + shake.Fire( "StartShake" ) + shake.Kill_Deprecated_UseDestroyInstead( 1 ) + } + + if ( IsValid( titan ) ) + { + if ( titan.ContextAction_IsBusy() ) + titan.ContextAction_ClearBusy() + } +} + +function TitanEjectVO( entity player, vector titanOrigin ) +{ + array titans = GetTitanArray() + int team = player.GetTeam() + int voEnum + + foreach ( titan in titans ) + { + if ( !titan.IsPlayer() ) + continue + if ( titan == player ) + continue + + if ( team == titan.GetTeam() ) + { + if ( DistanceSqr( titanOrigin, titan.GetOrigin() ) > file.titanVOEjectNotifyDist ) + return + + voEnum = eTitanVO.FRIENDLY_EJECTED + } + else + { + if ( !ShouldCalloutEjection( player, titanOrigin, titan ) ) + return + + voEnum = eTitanVO.ENEMY_EJECTED + } + + Remote_CallFunction_Replay( titan, "SCB_TitanDialogue", voEnum ) + } +} +#endif // SERVER + +bool function ShouldCalloutEjection( entity player, vector titanOrigin, entity titan ) +{ + if ( DistanceSqr( titanOrigin, titan.GetOrigin() ) < file.titanVOEjectNotifyDist ) + return true + + // have they hit each other recently? To catch LTS sniper war ejections + if ( WasRecentlyHitByEntity( player, titan, 6.0 ) ) + return true + + if ( WasRecentlyHitByEntity( titan, player, 6.0 ) ) + return true + + return false +} + + +function TemporarilyNonSolidPlayer( entity rider ) +{ + rider.EndSignal( "OnDeath" ) + + OnThreadEnd( + function () : ( rider ) + { + if ( IsValid( rider ) ) + { + rider.Solid() + } + } + ) + + rider.NotSolid() + wait 1.5 +} + + +#if SERVER +function TitanNonSolidTemp( entity titan ) +{ + if ( !EntityInSolid( titan ) ) + return + + local collisionGroup = titan.kv.CollisionGroup + + // Blocks bullets, projectiles but not players and not AI + titan.kv.CollisionGroup = TRACE_COLLISION_GROUP_BLOCK_WEAPONS + + titan.EndSignal( "OnDeath" ) + + while( EntityInSolid( titan ) ) + { + wait 0.1 + } + + titan.kv.collisionGroup = collisionGroup +} + +function NuclearCoreExplosion( vector origin, e ) +{ + entity titan = expect entity( e.titan ) + + titan.EndSignal( "OnDeath" ) + + e.needToClearNukeFX = false //This thread and NuclearCoreExplosionChainReaction now take responsibility for clearing the FX + + OnThreadEnd( + function() : ( e ) + { + ClearNuclearBlueSunEffect( e ) + } + ) + + wait 1.3 + Assert( IsValid( titan ) ) + titan.s.silentDeath <- true //Don't play normal titan_death_explode in _deathpackage since we're playing titan_nuclear_death_explode + + EmitSoundAtPosition( titan.GetTeam(), origin, "titan_nuclear_death_explode" ) + + titan.s.noLongerCountsForLTS <- true + + thread NuclearCoreExplosionChainReaction( origin, e ) + + if ( IsAlive( titan ) ) + titan.Die( e.attacker, e.inflictor, { scriptType = DF_EXPLOSION, damageType = DMG_REMOVENORAGDOLL, damageSourceId = e.damageSourceId } ) +} + + +void function KillStuckPlayer( entity player ) +{ + if ( IsAlive( player ) ) + player.Die( svGlobal.worldspawn, svGlobal.worldspawn, { scriptType = DF_DISSOLVE, damageSourceId = damagedef_crush } ) +} +#endif // SERVER + +function ClearNuclearBlueSunEffect( e ) +{ + foreach ( fx in e.nukeFX ) + { + if ( IsValid( fx ) ) + fx.Kill_Deprecated_UseDestroyInstead() + } + e.nukeFX.clear() + e.needToClearNukeFX = false +} + +#if SERVER +function NuclearCoreExplosionChainReaction( vector origin, e ) +{ + int explosions + local innerRadius + float time + bool IsNPC + + local heavyArmorDamage = 2500 + local normalDamage = 75 + + switch ( e.nuclearPayload ) + { + case 4: + // npc nuke: the idea is to be the same as the regular nuke - but with less explosion calls + explosions = 3 + innerRadius = 350 + time = 1.5 //1 is the regular nuke time - but we won't be adding an extra explosion and we want 3 explosions over 1s. This will mathematically give us that. + IsNPC = true + + local fraction = 10.0 / explosions //10 is the regular nuke number + heavyArmorDamage = heavyArmorDamage * fraction + normalDamage = normalDamage * fraction + break + + case 3: + // super nuke: PAS_NUCLEAR_CORE + PAS_BUILD_UP_NUCLEAR_CORE + explosions = 20 + innerRadius = 350 + time = 1.7 + IsNPC = false + break + + case 2: + // super nuke: PAS_NUCLEAR_CORE + explosions = 15 + innerRadius = 350 + time = 1.4 + IsNPC = false + break + + case 1: + // regular nuke: PAS_BUILD_UP_NUCLEAR_CORE + explosions = 10 + innerRadius = 350 + time = 1.0 + IsNPC = false + break + + default: + Assert( 0, "e.nuclearPayload value: " + e.nuclearPayload + " not accounted for." ) + break + } + + float waitPerExplosion = time / explosions + + ClearNuclearBlueSunEffect( e ) + + if ( IsValid( e.player ) ) + { + thread __CreateFxInternal( TITAN_NUCLEAR_CORE_FX_1P, null, "", origin, Vector(0,RandomInt(360),0), C_PLAYFX_SINGLE, null, 1, expect entity( e.player ) ) + thread __CreateFxInternal( TITAN_NUCLEAR_CORE_FX_3P, null, "", origin + Vector( 0, 0, -100 ), Vector(0,RandomInt(360),0), C_PLAYFX_SINGLE, null, 6, expect entity( e.player ) ) + } + else + { + PlayFX( TITAN_NUCLEAR_CORE_FX_3P, origin + Vector( 0, 0, -100 ), Vector(0,RandomInt(360),0) ) + } + + // one extra explosion that does damage to physics entities at smaller radius + if ( !IsNPC ) + explosions += 1 + + local outerRadius + + local baseNormalDamage = normalDamage + local baseHeavyArmorDamage = heavyArmorDamage + local baseInnerRadius = innerRadius + local baseOuterRadius = outerRadius + + // all damage must have an inflictor currently + entity inflictor = CreateEntity( "script_ref" ) + inflictor.SetOrigin( origin ) + inflictor.kv.spawnflags = SF_INFOTARGET_ALWAYS_TRANSMIT_TO_CLIENT + DispatchSpawn( inflictor ) + + OnThreadEnd( + function() : ( inflictor ) + { + if ( IsValid( inflictor ) ) + inflictor.Destroy() + } + ) + + for ( int i = 0; i < explosions; i++ ) + { + local normalDamage = baseNormalDamage + local heavyArmorDamage = baseHeavyArmorDamage + local innerRadius = baseInnerRadius + local outerRadius = baseOuterRadius + + if ( i == 0 && !IsNPC ) + { + normalDamage = 75 + heavyArmorDamage = 0 + outerRadius = 600 + } + else + { + outerRadius = 750 + } + + entity explosionOwner = GetExplosionOwner( e ) + + if ( outerRadius < innerRadius ) + outerRadius = innerRadius + + RadiusDamage_DamageDef( damagedef_nuclear_core, + origin, // origin + explosionOwner, // owner + inflictor, // inflictor + normalDamage, // normal damage + heavyArmorDamage, // heavy armor damage + innerRadius, // inner radius + outerRadius, // outer radius + 0 ) // dist from attacker + + wait waitPerExplosion + } +} + +entity function GetExplosionOwner( e ) +{ + if ( IsValid( expect entity( e.overrideAttacker ) ) ) + return expect entity( e.overrideAttacker ) + + if ( IsValid( expect entity( e.player ) ) ) + return expect entity( e.player ) + + if ( IsValid( expect entity( e.titan ) ) ) + return expect entity( e.titan ) + + return GetTeamEnt( expect int( e.team ) ) +} +#endif // SERVER + +function ClearEjectInvulnerability( entity player ) +{ + if ( !IsValid( player ) ) + return + + player.EndSignal( "OnDeath" ) + + OnThreadEnd( + function () : (player) + { + if ( IsValid( player ) ) + player.ClearInvulnerable() + } + ) + + wait 0.35 +} + +function EjectFlightTracker( entity player ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "EjectLand" ) + player.EndSignal( "RodeoStarted" ) + + OnThreadEnd( + function () : (player) + { + player.p.pilotEjecting = false + player.p.pilotEjectEndTime = Time() + } + ) + + player.p.pilotEjecting = true + player.p.pilotEjectStartTime = Time() + + wait 0.1 + for ( ;; ) + { + if ( player.IsOnGround() ) + player.Signal("EjectLand") + + wait 0.1 + } +} + +#if SERVER +function TempAirControl( entity player ) +{ + player.EndSignal( "TempAirControl" ) + player.EndSignal( "OnDeath" ) + + player.kv.airSpeed = 200 + player.kv.airAcceleration = 800 + + wait 1.5 + + player.kv.airSpeed = 100 + + wait 3.5 + + player.kv.airSpeed = player.GetPlayerSettingsField( "airSpeed" ) + player.kv.airAcceleration = player.GetPlayerSettingsField( "airAcceleration" ) +} + + +function TempLossOfAirControl( entity player, float time ) +{ + player.EndSignal( "OnDeath" ) + + player.kv.airSpeed = 0 + player.kv.airAcceleration = 0 // 500 + + wait time + + player.kv.airSpeed = player.GetPlayerSettingsField( "airSpeed" ) + player.kv.airAcceleration = player.GetPlayerSettingsField( "airAcceleration" ) +} + + +bool function TitanStagger( entity titan, damageInfo ) +{ + if ( !IsAlive( titan ) ) + return false + + if ( !titan.IsPlayer() ) + return false + + if ( Time() - titan.s.lastStaggerTime < 1.0 ) + return false + + if ( titan.GetTitanSoul().GetShieldHealth() ) + return false + + if ( DamageInfo_GetDamage( damageInfo ) < 1000 ) + return false + + switch ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) + { + // R1 + // case eDamageSourceId.mp_titanweapon_arc_cannon: + // case eDamageSourceId.titanEmpField: + // case eDamageSourceId.mp_titanweapon_40mm: + // case eDamageSourceId.mp_weapon_rocket_launcher: + // case eDamageSourceId.mp_titanweapon_sniper: + // case eDamageSourceId.mp_titanweapon_shoulder_rockets: + // case eDamageSourceId.mp_titanweapon_homing_rockets: + // case eDamageSourceId.mp_titanweapon_dumbfire_rockets: + // case eDamageSourceId.mp_titanweapon_salvo_rockets: + + // R2 ORDNANCE + case eDamageSourceId.mp_titanweapon_shoulder_rockets: + case eDamageSourceId.mp_titanweapon_tracker_rockets: + // case eDamageSourceId.mp_titanweapon_flame_wall: + case eDamageSourceId.mp_titanweapon_shoulder_rockets: + case eDamageSourceId.mp_titanweapon_laser_lite: + case eDamageSourceId.mp_titanweapon_stun_laser: + case eDamageSourceId.mp_titanweapon_arc_wave: + case eDamageSourceId.mp_titanweapon_dumbfire_rockets: + case eDamageSourceId.mp_titanability_power_shot: + + // R2 PRIMARY WEAPONS + // case eDamageSourceId.mp_titanweapon_xo16_shorty: + case eDamageSourceId.mp_titanweapon_sticky_40mm: + case eDamageSourceId.mp_titanweapon_meteor: + case eDamageSourceId.mp_titanweapon_rocketeer_rocketstream: + case eDamageSourceId.mp_titanweapon_particle_accelerator: + case eDamageSourceId.mp_titanweapon_leadwall: + case eDamageSourceId.mp_titanweapon_sniper: + // case eDamageSourceId.mp_titanweapon_predator_cannon + + // R2 CORES + case eDamageSourceId.mp_titancore_amp_core: + case eDamageSourceId.mp_titancore_salvo_core: + case eDamageSourceId.mp_titancore_flame_wave: + case eDamageSourceId.mp_titanweapon_flightcore_rockets: + case eDamageSourceId.mp_titancore_laser_cannon: + case eDamageSourceId.mp_titancore_shift_core: + case eDamageSourceId.mp_titancore_siege_mode: + + titan.SetStaggering() + titan.s.lastStaggerTime = Time() + return true + + default: + return false + } + + unreachable +} +#endif // SERVER + +function LookAtEachOther( entity rider, entity player ) +{ + rider.EndSignal( "OnDeath" ) + player.EndSignal( "OnDeath" ) + + float endTime = Time() + 0.45 + + for ( ;; ) + { + vector org1 = rider.GetOrigin() + vector org2 = player.GetOrigin() + vector vec1 = org2 - org1 + vector angles1 = VectorToAngles( vec1 ) + vector vec2 = org1 - org2 + vector angles2 = VectorToAngles( vec2 ) + + angles1.x = 0 + angles2.x = 0 + if ( rider.GetParent() == null ) + rider.SetAngles( angles1 ) + if ( player.GetParent() == null ) + player.SetAngles( angles2 ) + + if ( Time() >= endTime ) + return + + WaitFrame() + } +} + +#if SERVER +function EnableTitanExit( entity player ) +{ + if ( CanDisembark( player ) == true ) + return + + Disembark_Allow( player ) + + printt( player, "Titan exit enabled" ) +} + +function DisableTitanExit( entity player ) +{ + if ( !CanDisembark( player ) ) + return + + Disembark_Disallow( player ) + + printt( player, "Titan exit disabled" ) +} + +asset function GetTitanArmBadge( entity soul ) +{ + #if MP + entity soulOwner = soul.GetBossPlayer() + if ( !IsValid( soulOwner ) ) + return $"" + + TitanLoadoutDef loadout = GetActiveTitanLoadout( soulOwner ) + return GetTitanArmBadgeFromLoadoutAndPrimeStatus( loadout ) + #else + return $"" + #endif +} + +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapons/_cloaker.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapons/_cloaker.gnut index 6ec0bc0ac..b4045f3ed 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/weapons/_cloaker.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapons/_cloaker.gnut @@ -97,6 +97,8 @@ function CloakerThink( entity cloaker, float radius, array ents = [ "any void function CloakerCloaksGuy( guy ) { + if( guy.IsNPC() ) + guy.SetCanCloak(true) // if you don't want to cloak specific targets, it should be handled by shouldCloakGuyFunc in CloakerThink guy.SetCloakDuration( 2.0, -1, 0 ) EmitSoundOnEntity( guy, CLOAKED_DRONE_CLOAK_START_SFX ) EmitSoundOnEntity( guy, CLOAKED_DRONE_CLOAK_LOOP_SFX ) @@ -110,6 +112,8 @@ void function CloakerDeCloaksGuy( guy ) StopSoundOnEntity( guy, CLOAKED_DRONE_CLOAK_LOOP_SFX ) guy.Minimap_AlwaysShow( TEAM_IMC, null ) guy.Minimap_AlwaysShow( TEAM_MILITIA, null ) + if( guy.IsNPC() ) + guy.SetCanCloak(false) } bool function CloakerShouldCloakGuy( entity cloaker, entity guy ) @@ -118,4 +122,4 @@ bool function CloakerShouldCloakGuy( entity cloaker, entity guy ) return false return true -} \ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut new file mode 100644 index 000000000..52d07f00f --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_phase_shift.gnut @@ -0,0 +1,774 @@ +untyped +#if CLIENT +#endif + +global function MpAbilityShifter_Init +global function PhaseShift +global function CodeCallback_EnterPhaseShift +global function CodeCallback_ExitPhaseShift +global function CancelPhaseShift + +#if SERVER +global function PlayPhaseShiftDisappearFX +global function UntrackAllToneMarks +#endif + +const SHIFTER_OUTRO_TIME_BEFORE_END = 1.5 + +const SHIFTER_PRE_FX = $"P_warpjump_FP" + +const SHIFTER_APPEAR_FX = $"P_phase_shift_main" +const SHIFTER_APPEAR_FX_TITAN = $"P_phase_shift_main_XO" +const SHIFTER_DISAPPEAR_FX = $"P_phase_shift_main" +const SHIFTER_DISAPPEAR_FX_TITAN = $"P_phase_shift_main_XO" + +const SHIFTER_SCREEN_FX = $"P_phase_shift_screen" +const SHIFTER_PERSONAL_FX = $"P_phase_shift_player" +const SHIFTER_SCREEN_FX_START = $"P_phase_shift_screen_start" +const SHIFTER_COLORCORRECTION = "materials/correction/mp_ability_shifter.raw" + +const SHIFTER_PRE_SOUND_1P = "Pilot_PhaseShift_PreActivate_1P" +const SHIFTER_PRE_SOUND_3P = "Pilot_PhaseShift_PreActivate_3P" +global const SHIFTER_START_SOUND_1P = "Pilot_PhaseShift_Activate_1P" +global const SHIFTER_START_SOUND_3P = "Pilot_PhaseShift_Activate_3P" +const SHIFTER_LOOP_SOUND_1P = "Pilot_PhaseShift_Loop_1P" +const SHIFTER_LOOP_SOUND_3P = "Pilot_PhaseShift_Loop_3P" +const SHIFTER_PRE_END_SOUND_1P = "Pilot_PhaseShift_WarningToEnd_1P" +const SHIFTER_PRE_END_SOUND_3P = "Pilot_PhaseShift_WarningToEnd_3P" +global const SHIFTER_END_SOUND_1P = "Pilot_PhaseShift_End_1P" +global const SHIFTER_END_SOUND_3P = "Pilot_PhaseShift_End_3P" + +const SHIFTER_PRE_SOUND_1P_TITAN = "Pilot_PhaseShift_PreActivate_1P" +const SHIFTER_PRE_SOUND_3P_TITAN = "Pilot_PhaseShift_PreActivate_3P" +global const SHIFTER_START_SOUND_1P_TITAN = "titan_phasedash_activate_1p" +global const SHIFTER_START_SOUND_3P_TITAN = "titan_phasedash_activate_3p" +const SHIFTER_LOOP_SOUND_1P_TITAN = "titan_phasedash_loop_1p" +const SHIFTER_LOOP_SOUND_3P_TITAN = "titan_phasedash_loop_3p" +const SHIFTER_PRE_END_SOUND_1P_TITAN = "titan_phasedash_warningtoend_1p" +const SHIFTER_PRE_END_SOUND_3P_TITAN = "titan_phasedash_warningtoend_3p" +global const SHIFTER_END_SOUND_1P_TITAN = "titan_phasedash_end_1p" +global const SHIFTER_END_SOUND_3P_TITAN = "titan_phasedash_end_3p" + +const int TELEFRAG_DAMAGE = 5000; + +struct +{ +} file; + +void function CodeCallback_EnterPhaseShift( entity ent ) +{ + PhaseShift( ent, 0.0, 999.0 ) +} + +void function CodeCallback_ExitPhaseShift( entity ent ) +{ +#if SERVER + CancelPhaseShift( ent ) +#endif +} + +void function CancelPhaseShift( entity ent ) +{ + ent.PhaseShiftCancel() + +#if SERVER + ent.Signal( "ForceStopPhaseShift" ) + PlayPhaseShiftAppearFX( ent ) +#endif // +} + + +void function MpAbilityShifter_Init() +{ +#if CLIENT + //ColorCorrection_RegisterRemoteTurret( "materials/correction/remote_turret.raw" ) + + ColorCorrection_RegisterPhaseShift( SHIFTER_COLORCORRECTION ) + thread ClientPhaseShiftFirstPersonFXThread() + + thread ClientRemoteTurretFirstPersonFXThread() +#endif // #if CLIENT + + PrecacheParticleSystem( SHIFTER_PRE_FX ) + PrecacheParticleSystem( SHIFTER_APPEAR_FX ) + PrecacheParticleSystem( SHIFTER_APPEAR_FX_TITAN ) + PrecacheParticleSystem( SHIFTER_DISAPPEAR_FX ) + PrecacheParticleSystem( SHIFTER_DISAPPEAR_FX_TITAN ) + PrecacheParticleSystem( SHIFTER_PERSONAL_FX ) + PrecacheParticleSystem( SHIFTER_SCREEN_FX ) + PrecacheParticleSystem( SHIFTER_SCREEN_FX_START ) + + MpAbilityShifterWeapon_Init() + + RegisterSignal( "StartPhaseShift" ) + RegisterSignal( "StopPhaseShift" ) + RegisterSignal( "ForceStopPhaseShift" ) +} + +int function PhaseShift( entity ent, float warmupTime, float duration ) +{ + if ( !IsAlive( ent ) ) + return 0 + + if ( ent.IsPhaseShifted() ) + return 0 + + // PROTO: this should be better eventually + // this is to prevent weirdness if you're already in a context action + if ( ent.IsPlayer() ) + { + entity proxy = ent.GetFirstPersonProxy() + if ( ( ent.ContextAction_IsActive() || (proxy != null && proxy.Anim_IsActive()) ) + && !ent.IsZiplining() + && !ent.ContextAction_IsLeeching() + && ent.GetTitanSoulBeingRodeoed() == null ) + { + return 0 + } + + ent.PhaseShiftBegin( warmupTime, duration ) + + #if SERVER + thread ServerPhaseShiftPlayerThread( ent, warmupTime, duration ) + #else + thread ClientPhaseShiftWarmupThread( ent, warmupTime ) + #endif // #if SERVER + + return 1 + } + else + { + ent.PhaseShiftBegin( warmupTime, duration ) + + #if SERVER + thread ServerPhaseShiftPlayerThread( ent, warmupTime, duration ) + #endif // #if SERVER + + return 1 + } + + unreachable +} + +#if SERVER +void function ServerPhaseShiftPlayerThread( entity ent, float warmupTime, float shiftTime ) +{ + ent.EndSignal( "OnDeath" ) + ent.EndSignal( "ForceStopPhaseShift" ) + + // initialise the two ent.s variables if needed + if ( !( "oldPhaseStateLock" in ent.s ) || !( "oldPhaseState" in ent.s ) ) + { + ent.s.oldPhaseStateLock <- false + ent.s.oldPhaseState <- false + } + + bool keepAnimActive = false + + if ( ent.IsPlayer() ) + { + ent.EndSignal( "player_embarks_titan" ) + + Leech_Disallow( ent ) + // EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_PRE_SOUND_3P ) + + entity proxy = ent.GetFirstPersonProxy() + if ( proxy != null ) + proxy.SetForceVisibleInPhaseShift( true ) + + if ( Rodeo_IsAttached( ent ) ) + { + if ( ent.GetParent() != null && ent.GetParent().IsPhaseShifted() ) + keepAnimActive = true + else + ent.Signal( "RodeoOver" ) + } + + if ( ent.IsTitan() ) + { + UntrackAllToneMarks( ent ) + entity titanSoul = ent.GetTitanSoul() + if ( titanSoul != null ) + { + if ( titanSoul.soul.batteryContainer != null ) + { + titanSoul.soul.batteryContainer.SetForceVisibleInPhaseShift( true ) + } + } + } + + Battery_StopFXAndHideIconForPlayer( ent ) + } + else + { + if ( ent.IsTitan() ) + UntrackAllToneMarks( ent ) + ent.EnableNPCFlag( NPC_IGNORE_ALL ) + EmitSoundOnEntity( ent, SHIFTER_PRE_SOUND_3P ) + } + + // only change the oldPhaseState if it's not locked + if ( !ent.s.oldPhaseStateLock || !GetConVarBool("ns_use_phase_fix") ) + { + ent.s.oldPhaseStateLock <- true + ent.s.oldPhaseState <- ent.GetNoTarget() + } + + OnThreadEnd( + function() : ( ent ) + { + if ( IsValid( ent ) ) + { + ent.Signal( "StopPhaseShift" ) + ent.Solid() + ent.SetNoTarget( ent.s.oldPhaseState ) + // unlock the oldPhaseState + ent.s.oldPhaseStateLock <- false + + StopSoundOnEntity( ent, SHIFTER_PRE_SOUND_3P ) + StopSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P ) + StopSoundOnEntity( ent, SHIFTER_PRE_SOUND_3P_TITAN ) + StopSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P_TITAN ) + + ent.DisablePhaseShiftFlags() + + if ( ent.IsPlayer() ) + { + Leech_Allow( ent ) + UpdatePlayerHighlightsSettings( ent ) + + if ( GetSoulFromPlayer( ent ) != null ) + { + entity soul = GetSoulFromPlayer( ent ) + if ( soul.soul.batteryContainer != null ) + { + soul.soul.batteryContainer.SetForceVisibleInPhaseShift( false ) + } + } + + entity proxy = ent.GetFirstPersonProxy() + if ( proxy != null ) + proxy.SetForceVisibleInPhaseShift( false ) + + if ( PlayerHasBattery( ent ) ) + Battery_StartFX( GetBatteryOnBack( ent ) ) + } + else + { + ent.DisableNPCFlag( NPC_IGNORE_ALL ) + Highlight_ClearEnemyHighlight( ent ) + } + + entity teleFragTarget = ent.GetEntityAtPhaseShiftExitPosition(); + if ( IsValid( teleFragTarget ) ) + { + if ( !IsHumanSized( teleFragTarget ) ) + { + if ( ShouldEntitySelfKill( ent, teleFragTarget ) ) + { + ent.TakeDamage( ent.GetHealth() + 1, teleFragTarget, teleFragTarget, { damageSourceId = eDamageSourceId.phase_shift, scriptType = DF_GIB | DF_BYPASS_SHIELD | DF_SKIPS_DOOMED_STATE } ); + } + else + { + printt( "Pushed players apart" ) + PushPlayersApart( teleFragTarget, ent, 600.0 ) // this will work for NPCs too + } + } + else + { + teleFragTarget.TakeDamage( teleFragTarget.GetHealth() + 1, ent, ent, { damageSourceId = eDamageSourceId.phase_shift, scriptType = DF_GIB | DF_BYPASS_SHIELD | DF_SKIPS_DOOMED_STATE } ); + } + } + } + } + ) + + wait warmupTime + + //thread PROTO_CapVelocity( ent ) + + entity soul + if ( ent.IsTitan() ) + { + soul = ent.GetTitanSoul() + string titanType = GetSoulTitanSubClass( soul ) + entity rider = GetRodeoPilot( ent ) + if ( rider != null && Rodeo_IsAttached( rider ) ) + { + if ( !rider.IsPlayer() ) + rider.Signal( "RodeoOver" ) + else + PhaseShift( rider, 0, shiftTime ) + } + } + + entity fx = PlayPhaseShiftDisappearFX( ent ) + thread PhaseShiftDisappearEffectCleanup( ent, fx, shiftTime ) + + ent.Signal( "StartPhaseShift" ) + if ( !keepAnimActive ) + ent.Signal( "ScriptAnimStop" ) + ent.NotSolid() + ent.SetNoTarget( true ) + ent.EnablePhaseShiftFlags() + ent.Highlight_SetCurrentContext( -1 ) + + if ( ent.IsPlayer() ) + { + PlayerDropsScriptedItems( ent ) + if ( ent.IsTitan() ) + { + EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_START_SOUND_3P_TITAN ) + EmitSoundOnEntityExceptToPlayerNotPredicted( ent, ent, SHIFTER_LOOP_SOUND_3P_TITAN ) + } + else + { + EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_START_SOUND_3P ) + EmitSoundOnEntityExceptToPlayerNotPredicted( ent, ent, SHIFTER_LOOP_SOUND_3P ) + } + + foreach( statusEffect in ent.p.empStatusEffectsToClearForPhaseShift ) //Not great, done to avoid needing code work to get a separate empSlow/empSTurnEffects + { + StatusEffect_Stop( ent, statusEffect ) + } + + ent.p.empStatusEffectsToClearForPhaseShift.clear() + } + else + { + if ( ent.IsTitan() ) + { + EmitSoundOnEntity( ent, SHIFTER_START_SOUND_3P_TITAN ) + EmitSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P_TITAN ) + } + else + { + EmitSoundOnEntity( ent, SHIFTER_START_SOUND_3P ) + EmitSoundOnEntity( ent, SHIFTER_LOOP_SOUND_3P ) + } + } + + float FX_WARMUP_TIME = 0.3 + bool timeAdjusted = false + + if ( shiftTime > FX_WARMUP_TIME ) + { + shiftTime -= FX_WARMUP_TIME // need to play the fx a little earlier so the timing lines up + timeAdjusted = true + } + + if ( shiftTime >= SHIFTER_OUTRO_TIME_BEFORE_END ) + { + wait ( shiftTime - SHIFTER_OUTRO_TIME_BEFORE_END ) + + if ( ent.IsPlayer() ) + { + if ( ent.IsTitan() ) + { + EmitSoundOnEntityOnlyToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_1P_TITAN ) + EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_3P_TITAN ) + } + else + { + EmitSoundOnEntityOnlyToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_1P ) + EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_PRE_END_SOUND_3P ) + } + + } + else + { + if ( ent.IsTitan() ) + EmitSoundOnEntity( ent, SHIFTER_PRE_END_SOUND_3P_TITAN ) + else + EmitSoundOnEntity( ent, SHIFTER_PRE_END_SOUND_3P ) + } + + wait SHIFTER_OUTRO_TIME_BEFORE_END + } + else + { + wait shiftTime + } + + PlayPhaseShiftAppearFX( ent ) + + if ( timeAdjusted ) + wait FX_WARMUP_TIME +} + +// ASSUMES THAT SECOND ENTITY IS NOT HUMAN SIZED +bool function ShouldEntitySelfKill( entity ent, entity largeTelefragTarget ) +{ + if ( IsHumanSized( ent ) ) + return true + + if ( IsSingleplayer() ) + return false + + return ( DistanceSqr( largeTelefragTarget.GetOrigin(), ent.GetOrigin() ) < 4096.0 ) +} + +void function PhaseShiftDisappearEffectCleanup( entity ent, entity fx, float duration ) +{ + fx.EndSignal( "OnDestroy" ) + ent.EndSignal( "ForceStopPhaseShift" ) + + OnThreadEnd( + function() : ( fx ) + { + if ( IsValid( fx ) ) + { + EffectStop( fx ) + } + } + ) + + float bufferTime = 1.4 + if ( ent.IsTitan() ) + bufferTime = 0.0 + + wait max( duration - bufferTime, 0.0 ) +} + +entity function PlayPhaseShiftAppearFX( entity ent ) +{ + asset effect = SHIFTER_APPEAR_FX + if ( !IsHumanSized( ent ) ) + effect = SHIFTER_APPEAR_FX_TITAN + + if ( ent.IsPlayer() ) + { + if ( ent.IsTitan() ) + EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_END_SOUND_3P_TITAN ) + else + EmitSoundOnEntityExceptToPlayer( ent, ent, SHIFTER_END_SOUND_3P ) + + return PlayFXOnEntityForEveryoneExceptPlayer( effect, ent, ent ) + } + else + { + if ( ent.IsTitan() ) + EmitSoundOnEntity( ent, SHIFTER_END_SOUND_3P_TITAN ) + else + EmitSoundOnEntity( ent, SHIFTER_END_SOUND_3P ) + return PlayFXOnEntity( effect, ent ) + } +} + +entity function PlayPhaseShiftDisappearFX( entity ent ) +{ + asset effect = SHIFTER_DISAPPEAR_FX + if ( !IsHumanSized( ent ) ) + effect = SHIFTER_DISAPPEAR_FX_TITAN + + int fxid = GetParticleSystemIndex( effect ) + int attachId = ent.LookupAttachment( "ORIGIN" ) + + return StartParticleEffectOnEntity_ReturnEntity( ent, fxid, FX_PATTACH_POINT_FOLLOW, attachId ) +} + +array function GetAttachedEnts( entity ent ) +{ + array ents = [ ent ] + + if ( HasSoul( ent ) ) + { + entity soul = ent.GetTitanSoul() + if ( IsValid( soul.soul.batteryContainer ) ) + ents.append( soul.soul.batteryContainer ) + } + + entity weapon = ent.GetActiveWeapon() + if ( IsValid( weapon ) ) + ents.append( weapon ) + + return ents +} + +/* +void function PROTO_CapVelocity( player ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "StopPhaseShift" ) + + while( 1 ) + { + local newVel = player.GetVelocity() + local zVel = newVel.z + newVel = Vector( newVel.x, newVel.y, 0 ) + local speed = Length( newVel ) + newVel = Normalize( newVel ) + speed = min( speed, 400 ) + newVel = newVel * speed + player.SetVelocity( Vector(newVel.x,newVel.y,zVel) ) + WaitFrame() + } +} +*/ + +void function UntrackAllToneMarks( entity ent ) +{ + if ( IsSingleplayer() ) //JFS::Probably want to remove this for R3 + return + + array enemyTitans = GetTitanArrayOfEnemies( ent.GetTeam() ) + foreach( titan in enemyTitans ) + { + entity offhand = titan.GetOffhandWeapon( OFFHAND_RIGHT ) + if ( !IsValid( offhand ) ) + return + + if ( offhand.GetWeaponClassName() != "mp_titanweapon_tracker_rockets" ) + continue + + offhand.SmartAmmo_UntrackEntity( ent ) + } +} +#endif // #if SERVER + + +#if CLIENT +void function ClientPhaseShiftWarmupThread( entity player, float warmupTime ) +{ + player.EndSignal( "OnDeath" ) + + if ( player != GetLocalViewPlayer() ) + return + if ( InPrediction() && !IsFirstTimePredicted() ) + return + + if ( warmupTime <= 0 ) + return + + int index = GetParticleSystemIndex( SHIFTER_PRE_FX ) + int fxID = StartParticleEffectInWorldWithHandle( index, ZERO_VECTOR, ZERO_VECTOR ) + + OnThreadEnd( + function() : ( fxID ) + { + EffectStop( fxID, true, true ); + } + ) + + if ( player.IsTitan() ) + EmitSoundOnEntity( player, SHIFTER_PRE_SOUND_1P_TITAN ) + else + EmitSoundOnEntity( player, SHIFTER_PRE_SOUND_1P ) + + wait warmupTime +} + +void function ClientPhaseShiftFirstPersonFXThread() +{ + int effectSparkles; + int effectScreen; + bool effectsAreActive = false; + bool endSoundPlayed = false; + entity ourPlayer = null; + + while( true ) + { + if ( effectsAreActive ) + { + entity localViewPlayer = GetLocalViewPlayer(); + + bool needShutdown = false; + if ( !IsValid( ourPlayer ) || !IsAlive( ourPlayer ) ) + needShutdown = true; + else if ( ourPlayer != localViewPlayer ) + needShutdown = true; + else if ( !ourPlayer.IsPhaseShifted() ) + needShutdown = true; + + if ( needShutdown ) + { + if ( IsValid( ourPlayer ) && (ourPlayer == localViewPlayer) ) + { + // FX + { + int fxIndex = GetParticleSystemIndex( SHIFTER_SCREEN_FX_START ) + StartParticleEffectInWorldWithHandle( fxIndex, ZERO_VECTOR, ZERO_VECTOR ) + } + + // FX + { + int fxIndex = GetParticleSystemIndex( SHIFTER_APPEAR_FX ) + vector viewAngles = ourPlayer.EyeAngles() + vector viewForward = AnglesToForward( viewAngles ) + vector viewForward2d = Normalize( Vector( viewForward.x, viewForward.y, 0.0 ) ) + StartParticleEffectOnEntityWithPos( ourPlayer, fxIndex, FX_PATTACH_ABSORIGIN, -1, (viewForward2d * 30), ZERO_VECTOR ) + } + + if ( ourPlayer.IsTitan() ) + { + EmitSoundOnEntity( ourPlayer, SHIFTER_END_SOUND_1P_TITAN ) + } + else + { + EmitSoundOnEntity( ourPlayer, SHIFTER_END_SOUND_1P ) + } + StopSoundOnEntity( ourPlayer, SHIFTER_LOOP_SOUND_1P ) + StopSoundOnEntity( ourPlayer, SHIFTER_LOOP_SOUND_1P_TITAN ) + } + + ClientPhaseShift_SCRIPT_HACKS_OFF() + + EffectStop( effectSparkles, true, true ) + EffectStop( effectScreen, true, true ) + effectsAreActive = false; + ourPlayer = null; + endSoundPlayed = false; + } + else if ( IsValid( localViewPlayer ) && localViewPlayer.IsPhaseShifted() ) + { + if ( !endSoundPlayed && (localViewPlayer.PhaseShiftTimeRemaining() <= SHIFTER_OUTRO_TIME_BEFORE_END) ) + { + endSoundPlayed = true; + if ( localViewPlayer.IsTitan() ) + EmitSoundOnEntity( localViewPlayer, SHIFTER_PRE_END_SOUND_1P_TITAN ) + else + EmitSoundOnEntity( localViewPlayer, SHIFTER_PRE_END_SOUND_1P ) + } + } + + } + + if ( !effectsAreActive ) + { + entity localViewPlayer = GetLocalViewPlayer(); + + if ( IsValid( localViewPlayer ) && localViewPlayer.IsPhaseShifted() ) + { + // FX + { + int fxIndex = GetParticleSystemIndex( SHIFTER_PERSONAL_FX ) + int attachIdx = localViewPlayer.LookupAttachment( "CHESTFOCUS" ) + effectSparkles = StartParticleEffectOnEntity( localViewPlayer, fxIndex, FX_PATTACH_POINT_FOLLOW, attachIdx ) + } + + // FX + { + int fxIndex = GetParticleSystemIndex( SHIFTER_SCREEN_FX ) + effectScreen = StartParticleEffectInWorldWithHandle( fxIndex, ZERO_VECTOR, ZERO_VECTOR ) + } + + // FX + { + int fxIndex = GetParticleSystemIndex( SHIFTER_SCREEN_FX_START ) + StartParticleEffectInWorldWithHandle( fxIndex, ZERO_VECTOR, ZERO_VECTOR ) + } + + // FX + { + entity viewModelEntity = localViewPlayer.GetViewModelEntity() + entity firstPersonProxy = localViewPlayer.GetPredictedFirstPersonProxy() + + if ( IsValid( viewModelEntity ) ) + { + viewModelEntity.Highlight_HideInside( 0.0 ) + viewModelEntity.Highlight_HideOutline( 0.0 ) + } + + if ( IsValid( firstPersonProxy ) ) + { + firstPersonProxy.Highlight_HideInside( 0.0 ) + firstPersonProxy.Highlight_HideOutline( 0.0 ) + } + } + + ClientPhaseShift_SCRIPT_HACKS_ON() + + if ( localViewPlayer.IsTitan() ) + EmitSoundOnEntity( localViewPlayer, SHIFTER_START_SOUND_1P_TITAN ) + else + EmitSoundOnEntity( localViewPlayer, SHIFTER_START_SOUND_1P ) + + if ( localViewPlayer.IsTitan() ) + EmitSoundOnEntity( localViewPlayer, SHIFTER_LOOP_SOUND_1P_TITAN ) + else + EmitSoundOnEntity( localViewPlayer, SHIFTER_LOOP_SOUND_1P ) + + effectsAreActive = true; + ourPlayer = localViewPlayer; + } + } + + WaitFrame() + } +} + +void function ClientRemoteTurretFirstPersonFXThread() +{ + int effectSparkles; + int effectScreen; + bool effectsAreActive = false; + entity ourPlayer = null; + + const string TURRET_LOOP_SOUND = "Pilot_RemoteTurret_Loop_1P" + + while( true ) + { + if ( effectsAreActive ) + { + entity localViewPlayer = GetLocalViewPlayer(); + + bool needShutdown = false; + if ( !IsValid( ourPlayer ) || !IsAlive( ourPlayer ) ) + needShutdown = true; + else if ( ourPlayer != localViewPlayer ) + needShutdown = true; + else if ( ourPlayer.GetRemoteTurret() == null ) + needShutdown = true; + + if ( needShutdown ) + { + if ( IsValid( ourPlayer ) && (ourPlayer == localViewPlayer) ) + StopSoundOnEntity( ourPlayer, TURRET_LOOP_SOUND ) + + effectsAreActive = false; + ourPlayer = null; + } + } + + if ( !effectsAreActive ) + { + entity localViewPlayer = GetLocalViewPlayer(); + if ( IsValid( localViewPlayer ) && (localViewPlayer.GetRemoteTurret() != null) ) + { + EmitSoundOnEntity( localViewPlayer, TURRET_LOOP_SOUND ) + effectsAreActive = true; + ourPlayer = localViewPlayer; + } + } + + WaitFrame() + } +} + +void function ClientPhaseShift_SCRIPT_HACKS_ON() +{ + entity localViewPlayer = GetLocalViewPlayer(); + + localViewPlayer.Signal( "StartPhaseShift" ) + + if ( localViewPlayer == GetLocalClientPlayer() ) + { + //localViewPlayer.cv.PlayerPetTitanIcon.Hide() + //localViewPlayer.cv.PlayerPetTitanArrow.Hide() + //localViewPlayer.cv.PlayerPetTitanLabel.Hide() + } +} + +void function ClientPhaseShift_SCRIPT_HACKS_OFF() +{ + entity localViewPlayer = GetLocalViewPlayer(); + + if ( localViewPlayer == GetLocalClientPlayer() ) + UpdatePetTitanIcon( localViewPlayer ) + + //It would be great if we could automatically hide icons using SetEntityOverhead if that entity is phased out. + // if ( GameRules_GetGameMode() == SURVIVOR ) + // DisplayScrapCounter( GetLocalClientPlayer(), LIFE_ALIVE, LIFE_ALIVE ) +} + +#endif // #if CLIENT diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_titancore_utility.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_titancore_utility.gnut new file mode 100644 index 000000000..ebb01719d --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapons/sh_titancore_utility.gnut @@ -0,0 +1,620 @@ +untyped + +global function MpTitanabilityFusionCore_Init + +global function OnAbilityCharge_TitanCore + +global function OnAbilityStart_TitanCore + +#if SERVER + global function OnAbilityEnd_TitanCore + global function OnAbilityChargeEnd_TitanCore + + global function SoulTitanCore_SetNextAvailableTime + global function SoulTitanCore_SetExpireTime +#endif + +global function SoulTitanCore_GetNextAvailableTime +global function SoulTitanCore_GetExpireTime +global function IsTitanCoreFiring + +global function CheckCoreAvailable +global function IsCoreAvailable +global function IsCoreChargeAvailable + +global function CoreChargeBegin + +#if SERVER + global function CoreChargeEnd + + global function CoreActivate + global function CoreDeactivate + + global function CoreBegin + global function CoreEnd +#endif + +const EMP_BLAST_EFFECT = $"P_titan_core_atlas_blast" +const EMP_BLAST_CHARGE_EFFECT = $"P_titan_core_atlas_charge" + +#if SERVER + global function SetUsedCoreCallback + global function CreateDefaultChargeEffect + global function SetCoreEffect + global function CreateCoreEffect + global function CleanupCoreEffect + global function HideTitanCoreFX + + global function OnAbilityStart_DashCore + global function OnAbilityEnd_DashCore + + global function LowerEnemyAccuracy +#endif + +#if SERVER +struct +{ + void functionref( entity, entity ) usedCoreCallback +} file +#endif + +function MpTitanabilityFusionCore_Init() +{ + PrecacheParticleSystem( EMP_BLAST_CHARGE_EFFECT ) + PrecacheParticleSystem( EMP_BLAST_EFFECT ) + + LaserCannon_Init() + Shift_Core_Init() + FlightCore_Init() + SalvoCore_Init() + UpgradeCore_Init() + + RegisterSignal( "CoreActivated" ) + RegisterSignal( "CoreBegin" ) + RegisterSignal( "CoreEnd" ) + + #if SERVER + AddCallback_OnPlayerKilled( TitanCore_PlayerKilledCleanup ) + AddDamageCallback( "player", TitanCore_OnDamage ) + #endif +} + +#if SERVER +void function SetUsedCoreCallback( void functionref( entity, entity ) func ) +{ + file.usedCoreCallback = func +} + +void function TitanCore_OnDamage( entity ent, var damageInfo ) +{ + float damageReduction = StatusEffect_Get( ent, eStatusEffect.damage_reduction ) + float damageScale = 1.0 - damageReduction + if ( damageScale != 1.0 ) + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) * damageScale ) +} +#endif + +bool function IsTitanCoreFiring( entity titan ) +{ + if ( !titan.IsTitan() ) + return false + + entity soul = titan.GetTitanSoul() + float time = Time() + return time >= soul.GetCoreChargeStartTime() && time <= soul.GetCoreChargeExpireTime() +} + +bool function OnAbilityCharge_TitanCore( entity weapon ) +{ + if ( !CheckCoreAvailable( weapon ) ) + return false + + entity titan = weapon.GetWeaponOwner() + + if ( !IsValid( titan ) || !titan.IsTitan() ) + return false + + #if CLIENT + if ( IsFirstTimePredicted() ) + { + #endif + // printt( "chargebegin" ) + #if SERVER + CoreActivate( titan ) + #endif + CoreChargeBegin( titan, titan, weapon ) + #if CLIENT + } + #endif + + titan.Signal( "CoreActivated" ) + + return true +} + +bool function OnAbilityStart_TitanCore( entity weapon ) +{ + entity titan = weapon.GetWeaponOwner() + // printt( "abilitybegin" ) + + if ( !IsValid( titan ) || !titan.IsTitan() ) + return false + + titan.Signal( "CoreBegin" ) + + #if SERVER + CoreBegin( titan, titan, weapon ) + #endif + + if ( titan.IsPlayer() ) + { + PlayerUsedOffhand( titan, weapon ) + #if SERVER && MP + PIN_PlayerAbility( titan, "core", weapon.GetWeaponClassName(), {} ) + #endif + } + + return true +} + +#if SERVER +void function OnAbilityChargeEnd_TitanCore( entity weapon ) +{ + // printt( "chargeend" ) + entity titan = weapon.GetWeaponOwner() + + if ( !IsValid( titan ) || !titan.IsTitan() ) + return + + CoreChargeEnd( titan, weapon ) +} + +void function OnAbilityEnd_TitanCore( entity weapon ) +{ + // printt( "abilityend" ) + entity titan = weapon.GetWeaponOwner() + + if ( !IsValid( titan ) || !titan.IsTitan() ) + return + + CoreDeactivate( titan, weapon ) + CoreEnd( titan, titan, weapon ) +} +#endif + +bool function CheckCoreAvailable( entity weapon ) +{ + // printt( "IsCoreAvailable?" ) + entity titan = weapon.GetWeaponOwner() + + if ( !IsValid( titan ) ) + return false + + if ( !titan.IsTitan() ) + return false + + if ( titan.ContextAction_IsActive() ) + return false + + if ( titan.IsPlayer() && IsInExecutionMeleeState( titan ) ) + return false + + if ( titan.GetParent() ) + return false + + entity soul = titan.GetTitanSoul() + + if ( !IsValid( soul ) ) + return false + + if ( soul.IsEjecting() ) + return false + + if ( !IsCoreChargeAvailable( titan, soul ) ) + { + return false + } + + return true +} + +#if SERVER +void function CoreActivate( entity player ) +{ + // printt( "activate" ) + entity soul = player.GetTitanSoul() + + if ( IsValid( soul ) && !player.ContextAction_IsMeleeExecution() ) + { + if ( TitanDamageRewardsTitanCoreTime() ) + SoulTitanCore_SetNextAvailableTime( soul, 0.0 ) + else + SoulTitanCore_SetNextAvailableTime( soul, Time() + 1000 ) + } +} + +void function CoreDeactivate( entity player, entity weapon ) +{ + // printt( "deactivate" ) + entity soul = player.GetTitanSoul() + + if ( IsValid( soul ) && !player.ContextAction_IsMeleeExecution() ) + { + if ( TitanDamageRewardsTitanCoreTime() ) + { + if ( SoulHasPassive( soul, ePassives.PAS_HYPER_CORE ) ) + { + SoulTitanCore_SetNextAvailableTime( soul, 0.20 ) + GiveOffhandElectricSmoke( player ) + } + } + else if ( IsValid( player ) ) + { + SoulTitanCore_SetNextAvailableTime( soul, Time() + GetTitanCoreBuildTimeFromWeapon( weapon ) ) + } + } +} + +bool function CoreBegin( entity player, entity titan, entity weapon ) +{ + entity soul = titan.GetTitanSoul() + + bool marathon = false + + if ( !IsAlive( titan ) ) + return false + + if ( player.IsPlayer() ) + { + marathon = PlayerHasPassive( player, ePassives.PAS_MARATHON_CORE ) + BlastScreenShake( titan ) + + var passive = GetPassiveFromWeapon( weapon ) + + if ( passive != null ) + GivePassive( soul, expect int( passive ) ) + + if ( IsSingleplayer() ) + { + if ( titan.IsPlayer() && weapon.GetWeaponInfoFileKeyField( "damage_protection" ) != 0 ) + { + float duration = weapon.GetCoreDuration() + StatusEffect_AddTimed( soul, eStatusEffect.damage_reduction, 0.75, duration, 0 ) + thread LowerEnemyAccuracy( titan, duration ) + } + else if ( weapon.IsSustainedDischargeWeapon() ) + { + float duration = weapon.GetSustainedDischargeDuration() + thread LowerEnemyAccuracy( titan, duration ) + } + + ResetCoreKillCounter() + } + + #if SERVER && MP + PIN_AddToPlayerCountStat( player, "titan_cores" ) + #endif + } + + if ( marathon ) + EmitSoundOnEntity( titan, "Titan_CoreAbility_Sustain_Long" ) + else + EmitSoundOnEntity( titan, "Titan_CoreAbility_Sustain" ) + + SetCoreEffect( titan, CreateCoreEffect, EMP_BLAST_EFFECT ) + + if ( file.usedCoreCallback != null ) + file.usedCoreCallback( titan, weapon ) + + return true +} + +void function LowerEnemyAccuracy( entity titan, float duration ) +{ + Assert( titan.IsPlayer() ) + + titan.EndSignal( "OnDeath" ) + titan.EndSignal( "TitanEjectionStarted" ) + titan.EndSignal( "CoreEnd" ) + titan.EndSignal( "DisembarkingTitan" ) + titan.EndSignal( "OnSyncedMelee" ) + + OnThreadEnd( + function() : ( titan ) + { + if ( IsValid( titan ) ) + { + print( "Making player titan Shootable\n" ) + titan.kv.EnemyAccuracyMultiplier = 1.0 + } + } + ) + + titan.kv.EnemyAccuracyMultiplier = 0.3 + wait duration +} + +void function CoreEnd( entity player, entity titan, entity weapon ) +{ + entity soul = titan.GetTitanSoul() + + if ( IsValid( soul ) ) + { + var passive = GetPassiveFromWeapon( weapon ) + + if ( passive != null ) + TakePassive( soul, expect int( passive ) ) + + CleanupCoreEffect( soul ) + + if ( IsValid( titan ) ) + { + StopSoundOnEntity( titan, "Titan_CoreAbility_Sustain_Long" ) + StopSoundOnEntity( titan, "Titan_CoreAbility_Sustain" ) + } + } + + if ( IsValid( player ) ) + player.Signal( "CoreEnd" ) +} +#endif // #if SERVER + +bool function CoreChargeBegin( entity player, entity titan, entity weapon ) +{ + entity soul = titan.GetTitanSoul() + +#if CLIENT + thread CoreActivatedVO( player ) +#if HAS_BOSS_AI + if ( titan.IsPlayer() ) + { + BossTitanPlayerUsedCoreAbility( titan, GetTitanCurrentRegenTab( titan ) ) + } +#endif +#else // #if CLIENT + float coreWaitTime = GetTitanCoreDurationFromWeapon( weapon ) + GetTitanCoreChargeTimeFromWeapon( weapon ) + + SoulTitanCore_SetExpireTime( soul, Time() + coreWaitTime ) + soul.SetCoreChargeStartTime( Time() ) + soul.SetCoreUseDuration( coreWaitTime ) + +#if HAS_BOSS_AI + if ( titan.IsNPC() && BossTitanVDUEnabled( titan ) ) + { + entity p = titan.GetEnemy() + if ( p.IsPlayer() ) + Remote_CallFunction_NonReplay( p, "ServerCallback_BossTitanUseCoreAbility", titan.GetEncodedEHandle(), GetTitanCurrentRegenTab( titan ) ) + } +#endif + if ( SoulHasPassive( soul, ePassives.PAS_SHIELDED_CORE ) ) + thread ShieldedCore( soul, coreWaitTime ) +#endif // #else // #if CLIENT + + return true +} + +#if SERVER +void function CoreChargeEnd( entity titan, entity weapon ) +{ + entity soul = titan.GetTitanSoul() + if ( IsValid( soul ) ) + CleanupCoreEffect( soul ) +} +#endif // #if SERVER + +bool function IsCoreChargeAvailable( entity player, entity soul ) +{ + if ( !IsValid( soul ) ) + return false + + if ( TitanDamageRewardsTitanCoreTime() ) + return SoulTitanCore_GetNextAvailableTime( soul ) >= 1.0 + + if ( Time() >= SoulTitanCore_GetNextAvailableTime( soul ) && IsCoreAvailable( player ) ) + return true + + return false +} + +bool function IsCoreAvailable( entity player ) +{ + entity coreWeapon = player.GetOffhandWeapon( OFFHAND_EQUIPMENT ) + + if ( coreWeapon == null ) + return false + + return ( GetDoomedState( player ) == false || CoreAvailableDuringDoomState() ) +} + +var function GetPassiveFromWeapon( entity weapon ) +{ + var passiveName = weapon.GetWeaponInfoFileKeyField( "passive" ) + if ( passiveName == null ) + return null + + switch ( passiveName ) + { + case "PAS_FUSION_CORE": + return ePassives.PAS_FUSION_CORE + case "PAS_SHIELD_BOOST": + return ePassives.PAS_SHIELD_BOOST + case "PAS_BERSERKER": + return ePassives.PAS_BERSERKER + case "PAS_SHIFT_CORE": + return ePassives.PAS_SHIFT_CORE + case "PAS_SMART_CORE": + return ePassives.PAS_SMART_CORE + } + + return null +} + +#if SERVER +void functionref( entity ) function PROTO_CoreStringToFunction( string funcName ) +{ + return null +} + +void functionref( entity ) function GetFuncFromWeaponEntry( weaponName, string field ) +{ + var funcName = GetWeaponInfoFileKeyField_Global( weaponName, field ) + if ( funcName == null ) + return null + + expect string( funcName ) + return PROTO_CoreStringToFunction( funcName ) +} + +//////////////////////////////////////////////////////////////////////// +// Core-start effect functions +//////////////////////////////////////////////////////////////////////// + +void function CreateDefaultChargeEffect( entity titan ) +{ + SetCoreEffect( titan, CreateCoreEffect, EMP_BLAST_CHARGE_EFFECT ) +} + +function BlastScreenShake( entity titan ) +{ + // Screen shake + float amplitude = 16.0 + float frequency = 5.0 + float duration = 2.0 + float radius = 1500.0 + entity shake = CreateShake( titan.GetOrigin(), amplitude, frequency, duration, radius ) + shake.SetParent( titan, "CHESTFOCUS" ) + shake.Kill_Deprecated_UseDestroyInstead( 3.0 ) +} +#endif // #if SERVER + +#if SERVER +void function TitanCore_PlayerKilledCleanup( entity player, entity attacker, var damageInfo ) +{ + ForceTitanSustainedDischargeEnd( player ) +} + +void function CleanupCoreEffect( entity soul ) +{ + if ( "coreEffect" in soul.s && IsValid( soul.s.coreEffect.ent ) ) + { + soul.s.coreEffect.ent.Destroy() + } + + if ( "coreEffect" in soul.s ) + delete soul.s.coreEffect +} + +void function SetCoreEffect( entity titan, entity functionref(entity,asset) func, asset effectName ) +{ + Assert( IsAlive( titan ) ) + Assert( titan.IsTitan() ) + entity soul = titan.GetTitanSoul() + local chargeEffect = func( titan, effectName ) + if ( "coreEffect" in soul.s ) + { + soul.s.coreEffect.ent.Kill_Deprecated_UseDestroyInstead() + } + else + { + soul.s.coreEffect <- null + } + + soul.s.coreEffect = { parameter = effectName, ent = chargeEffect, func = func } +} + +//////////////////////////////////////////////////////////////////////// +// core fx and color correction +//////////////////////////////////////////////////////////////////////// +entity function CreateCoreEffect( entity player, asset effectName ) +{ + Assert( player.IsTitan() ) + + int index = player.LookupAttachment( "hijack" ) + entity chargeEffect = StartParticleEffectOnEntity_ReturnEntity( player, GetParticleSystemIndex( effectName ), FX_PATTACH_POINT_FOLLOW, index ) + + chargeEffect.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) // everyone but owner + chargeEffect.SetOwner( player ) + return chargeEffect + +} + +function HideTitanCoreFX( entity titan, float duration ) +{ + titan.EndSignal( "OnDestroy" ) + + CleanupCoreEffect( titan.GetTitanSoul() ) + + wait duration + + CreateDefaultChargeEffect( titan ) +} + +//////////////////////////////////////////////////////////////////////// +// R1 core functions +//////////////////////////////////////////////////////////////////////// + +void function OnAbilityEnd_DashCore( entity player ) +{ + player.SetDodgePowerDelayScale( 1.0 ) + player.SetPowerRegenRateScale( 1.0 ) +} + +void function OnAbilityStart_DashCore( entity player ) +{ + // Dash recharges fast + player.SetDodgePowerDelayScale( 0.05 ) + player.SetPowerRegenRateScale( 16.0 ) +} + +//PAS_SHIELDED_CORE +void function ShieldedCore( entity soul, float coreDuration ) +{ + soul.EndSignal( "OnDestroy" ) + soul.EndSignal( "OnTitanDeath" ) + + int health = soul.GetShieldHealthMax() + soul.SetShieldHealth( health ) + + OnThreadEnd( + function() : ( soul ) + { + if ( IsValid( soul ) ) + soul.SetShieldHealth( 0 ) + } + ) + + wait max( 3.0, coreDuration ) +} +#endif + +#if SERVER +void function SoulTitanCore_SetNextAvailableTime( entity soul, float time ) +{ + soul.SetTitanSoulNetFloat( "coreAvailableFrac", min( time, 1.0 ) ) + soul.SetNextCoreChargeAvailable( time ) +} + +void function SoulTitanCore_SetExpireTime( entity soul, float expireTime ) +{ + if ( expireTime - Time() > 0 ) + { + soul.SetTitanSoulNetFloat( "coreExpireFrac", 1.0 ) + soul.SetTitanSoulNetFloatOverTime( "coreExpireFrac", 0.0, expireTime - Time() ) + } + else + { + soul.SetTitanSoulNetFloat( "coreExpireFrac", 0.0 ) + } + soul.SetCoreChargeExpireTime( expireTime ) +} +#endif + +float function SoulTitanCore_GetNextAvailableTime( entity soul ) +{ + return soul.GetNextCoreChargeAvailable() +} + +float function SoulTitanCore_GetExpireTime( entity soul ) +{ + return soul.GetCoreChargeExpireTime() +}