aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoyalBlue <11448698+RoyalBlue1@users.noreply.github.com>2023-10-15 02:09:29 +0200
committerRoyalBlue <11448698+RoyalBlue1@users.noreply.github.com>2023-10-15 02:09:29 +0200
commitad70253601a77844347d8aa1989ae5ab4fb4217c (patch)
tree336778ee63ed5bd82a0245dda2eedd8c99e47e83
parent9c13170e72f04050055695c25bc3b0a807d400e3 (diff)
parenta7d40aac072c6725548c2ba6d6a9ab649191594f (diff)
downloadNorthstarMods-ad70253601a77844347d8aa1989ae5ab4fb4217c.tar.gz
NorthstarMods-ad70253601a77844347d8aa1989ae5ab4fb4217c.zip
Merge remote-tracking branch 'upsteam/main' into gamemode_fd
-rw-r--r--.github/nativefuncs.json150
-rw-r--r--.github/workflows/add-to-project.yml19
-rw-r--r--Northstar.Client/mod.json13
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_english.txt24
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_french.txt48
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_german.txt2
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_italian.txt65
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt106
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_russian.txt174
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt103
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt83
-rw-r--r--Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut7
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut56
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut902
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut170
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut98
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut1
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut18
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut44
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut300
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut19
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut5
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut2
-rw-r--r--Northstar.Custom/mod.json10
-rw-r--r--Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdlbin0 -> 1268987 bytes
-rw-r--r--Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdlbin0 -> 743828 bytes
-rw-r--r--Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdlbin0 -> 932128 bytes
-rw-r--r--Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdlbin0 -> 726231 bytes
-rw-r--r--Northstar.Custom/mod/resource/northstar_custom_english.txtbin6446 -> 7376 bytes
-rw-r--r--Northstar.Custom/mod/resource/northstar_custom_portuguese.txtbin5338 -> 6250 bytes
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut4
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut127
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut5
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut1226
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut6
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut1
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut83
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut1051
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut226
-rw-r--r--Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt349
-rw-r--r--Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt405
-rw-r--r--Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpakbin0 -> 264566 bytes
-rw-r--r--Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpakbin0 -> 16539736 bytes
-rw-r--r--Northstar.Custom/paks/rpak.json5
-rw-r--r--Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpkbin86104271 -> 86805541 bytes
-rw-r--r--Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpkbin5374 -> 5905 bytes
-rw-r--r--Northstar.CustomServers/keyvalues/playlists_v2.txt13
-rw-r--r--Northstar.CustomServers/mod.json31
-rw-r--r--Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg6
-rw-r--r--Northstar.CustomServers/mod/maps/mp_complex3_script.ent13234
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut4
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_items.nut20
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut3
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut39
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut13
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut195
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut45
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut3
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut20
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut9
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut12
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut1
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut34
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut4
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut5
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut11
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut1043
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut9
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut4
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut6
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut1117
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut8
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut3
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut5
77 files changed, 21422 insertions, 388 deletions
diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json
index 751b48934..13a7edd3d 100644
--- a/.github/nativefuncs.json
+++ b/.github/nativefuncs.json
@@ -179,6 +179,54 @@
"helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.",
"returnTypeString":"bool",
"argTypes":""
+ },
+ {
+ "name":"NS_InternalLoadFile",
+ "helpText":"Loads a file asynchronously.",
+ "returnTypeString":"int",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSSaveFile",
+ "helpText":"Saves a file.",
+ "returnTypeString":"void",
+ "argTypes":"string file, string data"
+ },
+ {
+ "name":"NSSaveJSONFile",
+ "helpText":"Converts a squirrel table to a json string, then saves it to a file.",
+ "returnTypeString":"void",
+ "argTypes":"string file, table data"
+ },
+ {
+ "name":"NSDoesFileExist",
+ "helpText":"Checks whether or not a file exists.",
+ "returnTypeString":"bool",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSDeleteFile",
+ "helpText":"Deletes a file.",
+ "returnTypeString":"bool",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NS_InternalGetAllFiles",
+ "helpText":"Returns an array of all files in a mod's save folder.",
+ "returnTypeString":"array<string>",
+ "argTypes":"string path"
+ },
+ {
+ "name":"NSGetFileSize",
+ "helpText":"Returns the size of a file, in KB, rounded down.",
+ "returnTypeString":"int",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSIsFolder",
+ "helpText":"Returns whether or not a given path leads to a folder.",
+ "returnTypeString":"bool",
+ "argTypes":"string path"
}
],
"CLIENT":[
@@ -327,6 +375,54 @@
"argTypes":""
},
{
+ "name":"NS_InternalLoadFile",
+ "helpText":"Loads a file asynchronously.",
+ "returnTypeString":"int",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSSaveFile",
+ "helpText":"Saves a file.",
+ "returnTypeString":"void",
+ "argTypes":"string file, string data"
+ },
+ {
+ "name":"NSSaveJSONFile",
+ "helpText":"Converts a squirrel table to a json string, then saves it to a file.",
+ "returnTypeString":"void",
+ "argTypes":"string file, table data"
+ },
+ {
+ "name":"NSDoesFileExist",
+ "helpText":"Checks whether or not a file exists.",
+ "returnTypeString":"bool",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSDeleteFile",
+ "helpText":"Deletes a file.",
+ "returnTypeString":"bool",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NS_InternalGetAllFiles",
+ "helpText":"Returns an array of all files in a mod's save folder.",
+ "returnTypeString":"array<string>",
+ "argTypes":"string path"
+ },
+ {
+ "name":"NSGetFileSize",
+ "helpText":"Returns the size of a file, in KB, rounded down.",
+ "returnTypeString":"int",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSIsFolder",
+ "helpText":"Returns whether or not a given path leads to a folder.",
+ "returnTypeString":"bool",
+ "argTypes":"string path"
+ },
+ {
"name":"NSPushGameStateData",
"helpText":"",
"returnTypeString":"void",
@@ -581,10 +677,64 @@
"argTypes":""
},
{
+ "name":"NS_InternalLoadFile",
+ "helpText":"Loads a file asynchronously.",
+ "returnTypeString":"int",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSSaveFile",
+ "helpText":"Saves a file.",
+ "returnTypeString":"void",
+ "argTypes":"string file, string data"
+ },
+ {
+ "name":"NSSaveJSONFile",
+ "helpText":"Converts a squirrel table to a json string, then saves it to a file.",
+ "returnTypeString":"void",
+ "argTypes":"string file, table data"
+ },
+ {
+ "name":"NSDoesFileExist",
+ "helpText":"Checks whether or not a file exists.",
+ "returnTypeString":"bool",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSDeleteFile",
+ "helpText":"Deletes a file.",
+ "returnTypeString":"bool",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NS_InternalGetAllFiles",
+ "helpText":"Returns an array of all files in a mod's save folder.",
+ "returnTypeString":"array<string>",
+ "argTypes":"string path"
+ },
+ {
+ "name":"NSGetFileSize",
+ "helpText":"Returns the size of a file, in KB, rounded down.",
+ "returnTypeString":"int",
+ "argTypes":"string file"
+ },
+ {
+ "name":"NSIsFolder",
+ "helpText":"Returns whether or not a given path leads to a folder.",
+ "returnTypeString":"bool",
+ "argTypes":"string path"
+ },
+ {
"name":"NSPushUIPresence",
"helpText":"",
"returnTypeString":"void",
"argTypes":"struct presence"
+ },
+ {
+ "name":"NSGetMasterServerAuthResult",
+ "helpText":"",
+ "returnTypeString":"MasterServerAuthResult",
+ "argTypes":""
}
]
} \ No newline at end of file
diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml
new file mode 100644
index 000000000..3a1d1c9a5
--- /dev/null
+++ b/.github/workflows/add-to-project.yml
@@ -0,0 +1,19 @@
+name: add-to-project
+
+on:
+ issues:
+ types:
+ - opened
+ pull_request:
+ types:
+ - opened
+
+jobs:
+ add-to-project:
+ name: Add to project
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/add-to-project@v0.5.0
+ with:
+ project-url: "https://github.com/orgs/R2Northstar/projects/3"
+ github-token: "${{ secrets.ADD_TO_PROJECT_PAT }}"
diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json
index e9536d663..a22f49fdf 100644
--- a/Northstar.Client/mod.json
+++ b/Northstar.Client/mod.json
@@ -1,7 +1,7 @@
{
"Name": "Northstar.Client",
"Description": "Various ui and client changes to fix bugs and add better support for mods",
- "Version": "1.14.0",
+ "Version": "1.19.0",
"LoadPriority": 0,
"InitScript": "cl_northstar_client_init.nut",
"ConVars": [
@@ -36,12 +36,12 @@
{
"Name": "modlist_show_convars",
"DefaultValue": "0",
- "Flags": 16777216
+ "Flags": "ARCHIVE_PLAYERPROFILE"
},
{
"Name": "modlist_reverse",
"DefaultValue": "0",
- "Flags": 16777216
+ "Flags": "ARCHIVE_PLAYERPROFILE"
}
],
"Scripts": [
@@ -128,6 +128,13 @@
{
"Path": "ui/ui_mouse_capture.nut",
"RunOn": "UI"
+ },
+ {
+ "Path": "ui/atlas_auth.nut",
+ "RunOn": "UI",
+ "UICallback": {
+ "After": "AtlasAuthDialog"
+ }
}
],
"Localisation": [
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
index 5dabd5398..c7b25a706 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
@@ -227,6 +227,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"classic_rodeo" "Classic Rodeo"
"oob_timer_enabled" "Out of Bounds Timer"
"riff_instagib" "Instagib Mode"
+ "player_force_respawn" "Forced Respawn"
"riff_player_bleedout" "Pilot Bleedout"
"player_bleedout_forceHolster" "Holster weapons when downed"
@@ -321,6 +322,11 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token"
"JSON_PARSE_ERROR" "Error parsing json response"
"UNSUPPORTED_VERSION" "The version you are using is no longer supported"
+
+ "AUTHENTICATION_FAILED_HEADER" "Authentication Failed"
+ "AUTHENTICATION_FAILED_BODY" "Failed to authenticate with Atlas!"
+ "AUTHENTICATION_FAILED_ERROR_CODE" "Error code: ^DB6F2C00%s1^"
+ "AUTHENTICATION_FAILED_HELP" "Help"
// Mod Settings
"MOD_SETTINGS" "Mod Settings"
@@ -342,5 +348,23 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"MOD_SETTINGS_RESET_ALL" "Reset All"
"NO_RESULTS" "No results."
"NO_MODS" "No settings available! Install more mods at ^5588FF00northstar.thunderstore.io^0."
+
+ // Toggleable progression
+ "TOGGLE_PROGRESSION" "Toggle Progression"
+ "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Toggle Progression"
+
+ "PROGRESSION_TOGGLE_ENABLED_HEADER" "Disable Progression?"
+ "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby."
+
+ "PROGRESSION_TOGGLE_DISABLED_HEADER" "Enable Progression?"
+ "PROGRESSION_TOGGLE_DISABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will need to be unlocked by levelling up, or bought with Merits.\n\nThis can be changed at any time in the multiplayer lobby.\n\n^CC000000Warning: if you have currently equipped any items that you do not have unlocked, they will be reset!"
+
+ "PROGRESSION_ENABLED_HEADER" "Progression Enabled!"
+ "PROGRESSION_ENABLED_BODY" "^CCCC0000Progression has been enabled.^\n\nTitans, Weapons, Factions, Skins, etc. will need to be unlocked by levelling up, or bought with Merits.\n\nThis can be changed at any time in the multiplayer lobby."
+
+ "PROGRESSION_DISABLED_HEADER" "Progression Disabled!"
+ "PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby."
+
+ "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time."
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
index d90cea05f..377f69179 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
@@ -64,7 +64,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"earn_meter_pilot_multiplier" "Multiplicateur de boost pilote"
"earn_meter_titan_multiplier" "Multiplicateur de boost titan"
- "aegis_upgrades" "Aegis Upgrades"
+ "aegis_upgrades" "Upgrades Aegis"
"infinite_doomed_state" "Etat condamné infini"
"titan_shield_regen" "Régénération des boucliers"
@@ -86,13 +86,13 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
// northstar.custom localisation is just deciding not to work, so putting it here for now
"PL_sbox" "Bac à sable"
- "PL_sbox_lobby" "Lobby: Bac à sable"
- "PL_sbox_desc" "GMod, mais en pire..."
+ "PL_sbox_lobby" "Lobby : Bac à sable"
+ "PL_sbox_desc" "GMod, mais en pire"
"PL_sbox_abbr" "SBOX"
"GAMEMODE_SBOX" "Bac à sable"
"PL_gg" "Gun game"
- "PL_gg_lobby" "Lobby: Gun game"
+ "PL_gg_lobby" "Lobby : Gun game"
"PL_gg_desc" "Obtenez une nouvelle arme à chaque frag.\nTuez un pilote avec chaque arme pour gagner."
"PL_gg_hint" "Obtenez une nouvelle arme à chaque frag.\nTuez un pilote avec chaque arme pour gagner."
"PL_gg_abbr" "GG"
@@ -102,21 +102,21 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"gg_execution_reward" "Récompense pourcentage d'exécutions"
"PL_tt" "Titan tag"
- "PL_tt_lobby" "Lobby: Titan tag"
+ "PL_tt_lobby" "Lobby : Titan tag"
"PL_tt_desc" "Gagnez des points lorsque vous êtes dans votre titan.\nDétruisez un titan pour obtenir le vôtre."
"PL_tt_hint" "Gagnez des points lorsque vous êtes dans votre titan.\nDétruisez un titan pour obtenir le vôtre."
"PL_tt_abbr" "TT"
"GAMEMODE_TT" "Titan tag"
"PL_chamber" "Le professionnel"
- "PL_chamber_lobby" "Lobby: Le professionnel"
+ "PL_chamber_lobby" "Lobby : Le professionnel"
"PL_chamber_desc" "Un tir, un mort.\nObtenez une balle en tuant un pilote."
"PL_chamber_hint" "Un tir, un mort.\nObtenez une balle en tuant un pilote."
"PL_chamber_abbr" "CHAMBER"
"GAMEMODE_CHAMBER" "Le professionnel"
"PL_hidden" "Chasse"
- "PL_hidden_lobby" "Lobby: Chasse"
+ "PL_hidden_lobby" "Lobby : Chasse"
"PL_hidden_desc" "Un pilote est invisible et chasse les autres."
"PL_hidden_hint" "Un pilote est invisible et chasse les autres."
"PL_hidden_abbr" "HIDDEN"
@@ -126,7 +126,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"HIDDEN_FIRST_HIDDEN" "%s1 est le chasseur."
"PL_sns" "Sticks and Stones"
- "PL_sns_lobby" "Lobby: Sticks and Stones"
+ "PL_sns_lobby" "Lobby : Sticks and Stones"
"PL_sns_desc" "Chacun pour soi.\nLes exécutions et les lames à impulsions réinitialisent le score de vos ennemis."
"PL_sns_abbr" "SNS"
"GAMEMODE_SNS" "Sticks and Stones"
@@ -144,7 +144,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"sns_softball_enabled" "Softball activé"
"PL_inf" "Infection"
- "PL_inf_lobby" "Lobby: Infection"
+ "PL_inf_lobby" "Lobby : Infection"
"PL_inf_desc" "Les pilotes survivants deviennent infectés lorsque tués."
"PL_inf_hint" "Les pilotes survivants deviennent infectés lorsque tués."
"PL_inf_abbr" "INF"
@@ -158,14 +158,14 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"INFECTION_SURVIVE_LAST_SURVIVOR" "Survivez."
"PL_tffa" "Chacun pour soi (titans)"
- "PL_tffa_lobby" "Lobby: Chacun pour soi (titans)"
+ "PL_tffa_lobby" "Lobby : Chacun pour soi (titans)"
"PL_tffa_desc" "Chacun pour soi.\nDétruisez les titans ennemis."
"PL_tffa_hint" "Chacun pour soi.\nDétruisez les titans ennemis."
"PL_tffa_abbr" "TFFA"
"GAMEMODE_TFFA" "Chacun pour soi (titans)"
"PL_hs" "Cache-cache"
- "PL_hs_lobby" "Lobby: Cache-cache"
+ "PL_hs_lobby" "Lobby : Cache-cache"
"PL_hs_desc" "Les pilotes doivent se cacher pour ne pas être trouvés par l'un d'eux."
"PL_hs_hint" "Les pilotes doivent se cacher pour ne pas être trouvés par l'un d'eux."
"PL_hs_abbr" "HS"
@@ -185,13 +185,13 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
// these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development
"GAMEMODE_fw" "Guerre pour la Frontière"
"PL_fw" "Guerre pour la Frontière"
- "PL_fw_lobby" "Lobby: Guerre pour la Frontière"
+ "PL_fw_lobby" "Lobby : Guerre pour la Frontière"
"PL_fw_desc" "Détruisez le collecteur ennemi et protégez le vôtre."
"PL_fw_abbr" "FW"
"GAMEMODE_kr" "Course aux frags"
"PL_kr" "Course aux frags"
- "PL_kr_lobby" "Lobby: Course aux frags"
+ "PL_kr_lobby" "Lobby : Course aux frags"
"PL_kr_desc" "Capturez le drapeau pour devenir le prédateur.\nFaites des victimes pour établir un nouveau record de frags.\nLe pilote ayant le plus de frags à la fin de la partie l'emporte."
"PL_kr_hint" "Capturez le drapeau pour devenir le prédateur.\nFaites des victimes pour établir un nouveau record de frags.\nLe pilote ayant le plus de frags à la fin de la partie l'emporte."
"PL_kr_abbr" "KR"
@@ -207,12 +207,12 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"GAMEMODE_fastball" "Fastball"
"PL_fastball" "Fastball"
- "PL_fastball_lobby" "Lobby: Fastball"
+ "PL_fastball_lobby" "Lobby : Fastball"
"PL_fastball_desc" "Mort permanente.\nPiratez les panneaux de contrôle pour faire réapparaître vos équipiers."
"PL_fastball_hint" "Mort permanente.\nPiratez les panneaux de contrôle pour faire réapparaître vos équipiers."
"PL_fastball_abbr" "FB"
"FASTBALL_PANEL_CAPTURED" "%s1 a piraté le panneau de contrôle %s2 !"
- "SCOREBOARD_FASTBALL_HACKS" "Panneaux de\ncontrôle capturés"
+ "SCOREBOARD_FASTBALL_HACKS" "Panneaux de contrôle capturés"
"GAMEMODE_ctf_comp" "Capture de drapeau - Compétitif"
@@ -239,7 +239,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
// coop stuff
"PL_sp_coop" "(ALPHA) Campagne (coop)"
- "PL_sp_coop_lobby" "Lobby: Campagne (coop)"
+ "PL_sp_coop_lobby" "Lobby : Campagne (coop)"
"PL_sp_coop_desc" "Jouez la campagne avec des amis."
"PL_sp_coop_hint" "Jouez la campagne avec des amis."
"PL_sp_coop_abbr" "SP"
@@ -337,5 +337,21 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"MOD_SETTINGS_SERVER" "Serveur"
"MOD_SETTINGS_RESET" "Réinitialiser"
"MOD_SETTINGS_RESET_ALL" "Tout réinitialiser"
+ "SHOW_ONLY_REQUIRED" "Afficher les mods requis"
+ "SHOW_ONLY_NOT_REQUIRED" "Uniquement les mods optionnels"
+ "NO_RESULTS" "Aucun résultat."
+ "NO_MODS" "Aucun paramètre trouvé ! Installez d'autres mods depuis ^5588FF00northstar.thunderstore.io^0."
+ "player_force_respawn" "Réapparition forcée"
+ "PROGRESSION_TOGGLE_ENABLED_HEADER" "Désactiver la progression ?"
+ "PROGRESSION_TOGGLE_ENABLED_BODY" "Les Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs."
+ "PROGRESSION_TOGGLE_DISABLED_HEADER" "Activer la progression ?"
+ "PROGRESSION_ENABLED_HEADER" "Progression activée !"
+ "PROGRESSION_DISABLED_HEADER" "Progression désactivée !"
+ "PROGRESSION_DISABLED_BODY" "^CCCC0000La progression a été désactivée.^\n\nLes Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs."
+ "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !"
+ "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs."
+ "TOGGLE_PROGRESSION" "Activer la progression"
+ "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression"
+ "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment."
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt
index 0316bbcf7..f1994a243 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt
@@ -310,5 +310,7 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü
"INVALID_MASTERSERVER_TOKEN" "Ungültiger oder abgelaufener Token vom Masterserver"
"JSON_PARSE_ERROR" "Fehler beim Verarbeiten der JSON-Antwort"
"UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt"
+ "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt"
+ "SNS_BANKRUPT_SUB" "Dein Punkestand wurde von %s1 zurückgesetzt"
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt
index fa84b6a22..38e67dea4 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt
@@ -84,8 +84,8 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
// northstar.custom localisation is just deciding not to work, so putting it here for now
"PL_sbox" "Sandbox"
- "PL_sbox_lobby" "Sandbox Lobby"
- "PL_sbox_desc" "Come gmod ma peggio."
+ "PL_sbox_lobby" "Lobby: Sandbox"
+ "PL_sbox_desc" "Come gmod ma peggio"
"PL_sbox_abbr" "SBOX"
"GAMEMODE_SBOX" "Sandbox"
@@ -170,7 +170,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
"PL_hs_abbr" "NS"
"GAMEMODE_hs" "Nascondino"
"HIDEANDSEEK_YOU_ARE_SEEKER" "TROVA I GIOCATORI NASCOSTI"
- "HIDEANDSEEK_SEEKER_DESC" "Trova ed uccidi tutti i giocatori nascosti. \nRespawnerai in %s1 secondi."
+ "HIDEANDSEEK_SEEKER_DESC" "Trova ed uccidi tutti i giocatori nascosti. \nRespawnerai in %s1 secondi"
"HIDEANDSEEK_YOU_ARE_HIDER" "NASCONDITI"
"HIDEANDSEEK_HIDER_DESC" "Nasconditi e cerca di non farti trovare."
"HIDEANDSEEK_SEEKERS_INCOMING" "HANNO INIZIATO A CERCARTI"
@@ -178,14 +178,14 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
"HIDEANDSEEK_GET_LAST_HIDER" "%s1 è L'ULTIMO CERCATORE"
"HIDEANDSEEK_YOU_ARE_LAST_HIDER" "SEI L'ULTIMO NASCOSTO"
"HIDEANDSEEK_GOT_STIM" "Sei stimolato! Non farti prendere!"
- "hideandseek_balance_teams" "Bilanciamento Squadre..."
+ "hideandseek_balance_teams" "Bilanciamento Squadre"
"hideandseek_hiding_time" "Tempo per Nascondersi"
// these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development
"GAMEMODE_fw" "Guerra di Frontiera"
"PL_fw" "Guerra di Frontiera"
"PL_fw_lobby" "Lobby: Guerra di Frontiera"
- "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo."
+ "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo"
"PL_fw_abbr" "FW"
"GAMEMODE_kr" "Killrace Amplificata"
@@ -198,10 +198,10 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
"KR_NEW_RACER" "%s1 è il killracer amplificato"
"KR_YOU_ARE_NEW_RACER" "Sei il killracer amplificato"
"KR_YOU_SET_NEW_RECORD" "Stabilisci un nuovo record di uccisioni!"
- "KR_FLAG_INCOMING" "Bandiera in Arrivo!"
+ "KR_FLAG_INCOMING" "Bandiera in Arrivo"
"KR_COLLECT_FLAG" "Raccoglila per diventare il killracer!"
- "KR_ENEMY_KILLRACE_OVER" "La killrace di %s1 è finita."
- "KR_YOUR_KILLRACE_OVER" "La tua killrace è finita."
+ "KR_ENEMY_KILLRACE_OVER" "La killrace di %s1 è finita"
+ "KR_YOUR_KILLRACE_OVER" "La tua killrace è finita"
"KR_YOUR_KILLRACE_SCORE" "Hai ottenuto %s1 uccisioni."
"GAMEMODE_fastball" "Fastball"
@@ -222,7 +222,7 @@ 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ºpers."
+ "fp_embark_enabled" "Imbarchi/esecuzioni in 1º persona"
"classic_rodeo" "Rodeo classico"
"oob_timer_enabled" "Timer Fuori dai Limiti"
"riff_instagib" "Modalità Instagib"
@@ -262,7 +262,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
"SP_BEACON_CLASSIC_DESC" "Cooper e BT tentano di informare la flotta rimanente dei piani dell'IMC."
"SP_TDAY" "Prova del fuoco"
- "SP_TDAY_CLASSIC_DESC" "Le abilità del Titan di Cooper vengono messe alla prova in una battaglia senza quartiere per la cattura dell'Arca."
+ "SP_TDAY_CLASSIC_DESC" "Le abilità del Titan di Cooper vengono messe alla prova in una battaglia senza quartiere per la cattura dell'Arca"
"SP_S2S" "L'Arca"
"SP_S2S_CLASSIC_DESC" "Cooper e BT inseguono l'Arca affrontando una nave dopo l'altra."
@@ -333,9 +333,52 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
"SHOULD_RETURN_TO_LOBBY" "Ritorna alla Lobby dopo Fine Partita"
"ARE_YOU_SURE" "Sei sicuro?"
"WILL_RESET_ALL_SETTINGS" "Questo ripristinerà TUTTE le impostazioni che appartengono a questa categoria.\n\nNON può essere annullato."
- "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON può essere annullato" // obviously, don't translate %s1.
+ "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON è reversibile." // obviously, don't translate %s1.
"MOD_SETTINGS_SERVER" "Server"
"MOD_SETTINGS_RESET" "Ripristina"
"MOD_SETTINGS_RESET_ALL" "Ripristina Tutto"
+ "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]"
+ "NO_RESULTS" "Nessun Risultato."
+ "DISABLE" "Disattiva"
+ "DIALOG_AUTHENTICATING_MASTERSERVER" "Autenticazione al master server."
+ "NS_SERVERBROWSER_UNKNOWNMODE" "Modalità sconosciuta"
+ "respawnprotection" "Tempo di protezione al respawn"
+ "NO_MODS" "Nessuna impostazione disponibile! Installa più mods a ^5588FF00northstar.thunderstore.io^0."
+ "gg_assist_reward" "Percentuale ricompensa per assist"
+ "gg_execution_reward" "Percentuale ricompensa per esecuzione"
+ "PL_sns" "Sticks and Stones"
+ "PL_sns_lobby" "Lobby: Sticks and Stones"
+ "PL_sns_abbr" "SNS"
+ "GAMEMODE_SNS" "Sticks and Stones"
+ "SCOREBOARD_BANKRUPTS" "Uccisioni bancarotta"
+ "SNS_LEADER_BANKRUPT" "Leader punteggio in bancarotta!"
+ "SNS_LEADER_BANKRUPT_SUB" "%s1 è stato resettato da %s2"
+ "SNS_BANKRUPT" "Bancarotta!"
+ "sns_softball_kill_value" "Valore per uccisione Softball"
+ "sns_offhand_kill_value" "Valore per uccisione manuale"
+ "sns_melee_kill_value" "Valore per uccisione corpo a corpo"
+ "sns_softball_enabled" "Softball abilitato"
+ "PL_tffa" "Tutti contro tutti Titan"
+ "PL_tffa_lobby" "Lobby: Tutti contro tutti Titan"
+ "PL_tffa_hint" "Ogni pilota per sè, distruggi tutti i titan nemici."
+ "PL_tffa_abbr" "TFFA"
+ "GAMEMODE_TFFA" "Tutti contro tutti Titan"
+ "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Cooldown reset all'uccisione"
+ "SHOW" "Mostra"
+ "SHOW_ALL" "Tutto"
+ "SHOW_ONLY_ENABLED" "Solo Abilitate"
+ "SHOW_ONLY_DISABLED" "Solo Disabilitate"
+ "SHOW_ONLY_NOT_REQUIRED" "Solo Mods opzionali"
+ "SHOW_ONLY_REQUIRED" "Solo Mods richieste"
+ "WARNING" "Attenzione"
+ "CORE_MOD_DISABLE_WARNING" "Disattivare mods di base può rompere il client!"
+ "AUTHENTICATIONAGREEMENT_NO" "Hai scelto di non autenticarti con Northstar. Puoi vedere l'accordo nel menu delle Mods."
+ "aitdm_archer_grunts" "Soldati Archer"
+ "gg_kill_reward" "Percentuale ricompensa per uccisione"
+ "PL_sns_desc" "Tutti contro tutti. Usa la Lama Impulsi e l'esecuzione per resettare il punteggio avversario"
+ "SNS_BANKRUPT_SUB" "Il you punteggio è stato resettato da %s1"
+ "sns_wme_kill_value" "Valore per uccisione Wingman d'Elite"
+ "sns_reset_kill_value" "Valore per uccisione Lama Impulsi/Esecuzione"
+ "PL_tffa_desc" "Ogni pilota per sè, distruggi tutti i titan nemici."
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt
index 51854726b..b6364db4e 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt
@@ -15,14 +15,14 @@
"DIALOG_TITLE_INSTALLED_NORTHSTAR" "Obrigado por instalar Northstar!"
"AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Para o Northstar funcionar é necessário autenticar com o servidor mestre Northstar. Isso requer enviar seu token da Origin para o servidor, ele não será utilizado pra outros propósitos.
Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momento no menu de mods."
- "BACK_AUTHENTICATION_AGREEMENT" "Aceitação de autorização"
- "AUTHENTICATION_AGREEMENT" "Aceitação de autorização"
+ "BACK_AUTHENTICATION_AGREEMENT" "Acordo de Autenticação"
+ "AUTHENTICATION_AGREEMENT" "Acordo de Autenticação"
"AUTHENTICATION_AGREEMENT_RESTART" "Você precisa reiniciar o Titanfall 2 para esta mudança ter efeito."
"DIALOG_AUTHENTICATING_MASTERSERVER" "Autenticando com o servidor mestre."
- "AUTHENTICATIONAGREEMENT_NO" "Você não autorizou a autenticação com Northstar. Troque a configuração no menu de mods."
+ "AUTHENTICATIONAGREEMENT_NO" "Você escolheu não autenticar com Northstar. Você pode ver o acordo no menu de Mods."
- "MENU_TITLE_SERVER_BROWSER" "Servidores"
+ "MENU_TITLE_SERVER_BROWSER" "Lista de Servidores"
"NS_SERVERBROWSER_NOSERVERS" "Nenhum servidor encontrado"
"NS_SERVERBROWSER_UNKNOWNMODE" "Modo desconhecido"
"NS_SERVERBROWSER_WAITINGFORSERVERS" "Aguardando servidores..."
@@ -52,9 +52,9 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"classic_mp" "MP Clássico"
"run_epilogue" "Executar epílogo"
"scorelimit" "Limite de pontos"
- "roundscorelimit" "Limite de pontos (por round)"
+ "roundscorelimit" "Limite de pontos (por rodada)"
"timelimit" "Tempo limite"
- "roundtimelimit" "Tempo limite (por round)"
+ "roundtimelimit" "Tempo limite (por rodada)"
"respawnprotection" "Proteção de reaparecimento"
"pilot_health_multiplier" "Multiplicador de vida"
@@ -64,16 +64,16 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"earn_meter_pilot_multiplier" "Multiplicador de bônus"
"earn_meter_titan_multiplier" "Multiplicador de bônus do titã"
- "aegis_upgrades" "Upgrades Aegis"
+ "aegis_upgrades" "Melhorias de Égide"
"infinite_doomed_state" "Estado condenado infinito"
"titan_shield_regen" "Escudos regeneradores"
- "riff_floorislava" "Deadly Ground"
- "featured_mode_all_holopilot" "The Great Bamboozle"
- "featured_mode_all_grapple" "Attack on Titanfall"
- "featured_mode_all_phase" "The Otherside"
- "featured_mode_all_ticks" "Spicy"
- "featured_mode_tactikill" "Tactikill"
+ "riff_floorislava" "Terreno Mortal"
+ "featured_mode_all_holopilot" "A Grande Enganação"
+ "featured_mode_all_grapple" "Ataque aos Titãs"
+ "featured_mode_all_phase" "O Outro Lado"
+ "featured_mode_all_ticks" "Picante"
+ "featured_mode_tactikill" "Mortático"
"featured_mode_amped_tacticals" "Habilidades táticas melhoradas"
"featured_mode_rocket_arena" "Arena Foguete"
"featured_mode_shotguns_snipers" "Armado e perigoso"
@@ -89,14 +89,14 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"PL_sbox_abbr" "SBOX"
"GAMEMODE_SBOX" "Sandbox"
- "PL_gg" "Gun Game"
- "PL_gg_lobby" "Saguão de Gun Game"
- "PL_gg_desc" "Mate com todas as armas para vencer"
- "PL_gg_hint" "Mate com todas as armas para vencer"
+ "PL_gg" "Jogo de Armas"
+ "PL_gg_lobby" "Saguão de Jogo de Armas"
+ "PL_gg_desc" "Mate com cada arma para vencer."
+ "PL_gg_hint" "Mate com cada arma para vencer."
"PL_gg_abbr" "GG"
- "GAMEMODE_GG" "Gun Game"
+ "GAMEMODE_GG" "Jogo de Armas"
"gg_kill_reward" "% recompensa/morte"
- "gg_assist_reward" "% recompensa/assist"
+ "gg_assist_reward" "% recompensa/assistência"
"gg_execution_reward" "% recompensa/execução"
"PL_tt" "Titan Tag"
@@ -106,20 +106,20 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"PL_tt_abbr" "TT"
"GAMEMODE_TT" "Titan Tag"
- "PL_chamber" "One in the Chamber"
- "PL_chamber_lobby" "Saguão de One in the Chamber"
- "PL_chamber_desc" "Um tiro, uma morte. Ganhe outra munição ao abater um inimigo."
- "PL_chamber_hint" "Um tiro, uma morte. Ganhe outra munição ao abater um inimigo."
- "PL_chamber_abbr" "CHAMBER"
- "GAMEMODE_CHAMBER" "One in the Chamber"
+ "PL_chamber" "Um na Câmara"
+ "PL_chamber_lobby" "Saguão de Um na Câmara"
+ "PL_chamber_desc" "Um tiro, uma morte. Ganhe uma bala no pente ao abater um inimigo."
+ "PL_chamber_hint" "Um tiro, uma morte. Ganhe uma bala no pente ao abater um inimigo."
+ "PL_chamber_abbr" "CÂMARA"
+ "GAMEMODE_CHAMBER" "Um na Câmara"
- "PL_hidden" "O Fantasma"
- "PL_hidden_lobby" "Saguão de O Fantasma"
+ "PL_hidden" "O Oculto"
+ "PL_hidden_lobby" "Saguão de O Oculto"
"PL_hidden_desc" "Um jogador se torna invisível enquanto o resto o caça."
"PL_hidden_hint" "Um jogador se torna invisível enquanto o resto o caça."
"PL_hidden_abbr" "HIDDEN"
- "GAMEMODE_HIDDEN" "The Hidden"
- "HIDDEN_YOU_ARE_HIDDEN" "Você é o fantasma!"
+ "GAMEMODE_HIDDEN" "O Oculto"
+ "HIDDEN_YOU_ARE_HIDDEN" "Você é o ocultado!"
"HIDDEN_KILL_SURVIVORS" "Mate todos os sobreviventes."
"HIDDEN_FIRST_HIDDEN" "%s1 é O Fantasma."
@@ -155,12 +155,12 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"INFECTION_YOU_ARE_LAST_SURVIVOR" "Você é o último sobrevivente!"
"INFECTION_SURVIVE_LAST_SURVIVOR" "Sobreviva."
- "PL_tffa" "Free for All Titã"
- "PL_tffa_lobby" "Saguão de Free for All Titã"
+ "PL_tffa" "Cada Titã por si"
+ "PL_tffa_lobby" "Saguão de Cada Titã por si"
"PL_tffa_desc" "Cada um por si, destrua todos os titãs inimigos."
"PL_tffa_hint" "Cada um por si, destrua todos os titãs inimigos."
"PL_tffa_abbr" "TFFA"
- "GAMEMODE_TFFA" "Free for All Titã"
+ "GAMEMODE_TFFA" "Cada Titã por si"
"PL_hs" "Esconde-esconde"
"PL_hs_lobby" "Saguão de Esconde-esconde"
@@ -168,7 +168,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"PL_hs_hint" "Jogo clássico de esconde-esconde."
"PL_hs_abbr" "HS"
"GAMEMODE_hs" "Esconde-esconde"
- "HIDEANDSEEK_YOU_ARE_SEEKER" "VOCÊ PEGA!"
+ "HIDEANDSEEK_YOU_ARE_SEEKER" "VOCÊ PEGA"
"HIDEANDSEEK_SEEKER_DESC" "Ache os outros e bata neles.\nVocê reaparecerá em %s1 segundos"
"HIDEANDSEEK_YOU_ARE_HIDER" "VOCÊ ESCONDE"
"HIDEANDSEEK_HIDER_DESC" "Esconda-se."
@@ -203,8 +203,8 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"KR_YOUR_KILLRACE_OVER" "Sua matança acabou"
"KR_YOUR_KILLRACE_SCORE" "Você conseguiu %s1 mortes."
- "GAMEMODE_fastball" "Fastball"
- "PL_fastball" "Fastball"
+ "GAMEMODE_fastball" "Travessia Impulsionada"
+ "PL_fastball" "Travessia Impulsionada"
"PL_fastball_lobby" "Saguão de Fastball"
"PL_fastball_desc" "Sem reaparecimento. Invada painéis de controle para ganhar rounds e reaparecer seus aliados."
"PL_fastball_hint" "Sem reaparecimento. Invada painéis de controle para ganhar rounds e reaparecer seus aliados."
@@ -236,8 +236,8 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
"player_bleedout_aiBleedingPlayerMissChance" "Chance de erro da IA ao cair"
// coop stuff
- "PL_sp_coop" "(UNFINISHED) Singleplayer Coop"
- "PL_sp_coop_lobby" "Saguão de Singleplayer em grupo"
+ "PL_sp_coop" "(NÃO-TERMINADO) Campanha Cooperativa"
+ "PL_sp_coop_lobby" "Saguão de Campanha Cooperativa"
"PL_sp_coop_desc" "Jogue através da campanha com seus amigos"
"PL_sp_coop_hint" "Jogue através da campanha com seus amigos"
"PL_sp_coop_abbr" "SP"
@@ -306,5 +306,37 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen
// In-game chat
"HUD_CHAT_WHISPER_PREFIX" "[WHISPER]"
"HUD_CHAT_SERVER_PREFIX" "[SERVER]"
+ "ONLY_HOST_MATCH_SETTINGS" "Somente o Host pode mudar as configurações da Partida Privada"
+ "ONLY_HOST_CAN_START_MATCH" "Somente o Host pode Iniciar a Partida"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Registrar Comandos desconhecidos de Clientes"
+ "DISALLOWED_TACTICALS" "Táticos Proibidos"
+ "TACTICAL_REPLACEMENT" "Tático Substituto"
+ "DISALLOWED_WEAPONS" "Armas Proibidas"
+ "REPLACEMENT_WEAPON" "Armas Substitutas"
+ "ARE_YOU_SURE" "Tem certeza?"
+ "WILL_RESET_ALL_SETTINGS" "Isso irá resetar TODAS as configurações que pertecem a essa categoria.\n\nAção não reversível."
+ "MOD_SETTINGS_SERVER" "Servidor"
+ "MOD_SETTINGS_RESET" "Resetar"
+ "MOD_SETTINGS_RESET_ALL" "Resetar Tudo"
+ "NO_RESULTS" "Sem resultados."
+ "NO_MODS" "Sem configurações disponíveis. Instale mais mods em ^5588FF00northstar.thunderstore.io^0."
+ "SHOW_ONLY_NOT_REQUIRED" "Somente Mods Opcionais"
+ "NO_GAMESERVER_RESPONSE" "Não foi possível alcançar o servidor da partida"
+ "BAD_GAMESERVER_RESPONSE" "Servidor da partida sem resposta válida"
+ "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição"
+ "UNAUTHORIZED_PWD" "Senha inválida"
+ "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador"
+ "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido"
+ "JSON_PARSE_ERROR" "Erro ao ler a resposta json"
+ "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios"
+ "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2"
+ "STRYDER_RESPONSE" "Não foi possível ler a resposta do Stryder"
+ "UNSUPPORTED_VERSION" "A versão que você está usando não é mais suportada"
+ "MOD_SETTINGS" "Configurações de Mod"
+ "NORTHSTAR_BASE_SETTINGS" "Configurações Base do Northstar"
+ "MATCH_COUNTDOWN_LENGTH" "Duração da contagem da Partida Privada"
+ "SHOULD_RETURN_TO_LOBBY" "Retornar ao saguão após término de Partida"
+ "WILL_RESET_SETTING" "Isso irá resetar a configuração %s1 ao valor padrão.\n\nAção não reversível."
+ "aitdm_archer_grunts" "Soldados com Archer"
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt
index 9ce0c2e3e..cf410ff29 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt
@@ -17,7 +17,7 @@
"MENU_TITLE_SERVER_BROWSER" "Список серверов"
"NS_SERVERBROWSER_NOSERVERS" "Серверов не найдено"
"NS_SERVERBROWSER_WAITINGFORSERVERS" "Ожидание серверов..."
- "NS_SERVERBROWSER_CONNECTIONFAILED" "Соединение провалено!"
+ "NS_SERVERBROWSER_CONNECTIONFAILED" "Не удалось подключиться!"
"REFRESH_SERVERS" "Обновить"
"MENU_TITLE_CONNECT_PASSWORD" "Подключиться с помощью пароля"
@@ -41,7 +41,7 @@
"MODE_SETTING_CATEGORY_MATCH" "Матч"
"classic_mp" "Классический мультиплеер"
- "run_epilogue" "Запустить эпилог"
+ "run_epilogue" "Показывать эпилог"
"scorelimit" "Лимит очков"
"roundscorelimit" "Лимит очков (по раундам)"
"timelimit" "Лимит времени"
@@ -58,19 +58,19 @@
"infinite_doomed_state" "Бесконечное обречённое состояние"
"titan_shield_regen" "Регенерация щитов"
- "riff_floorislava" "Смертельная Земля"
+ "riff_floorislava" "Пол это лава"
"featured_mode_all_holopilot" "Великий обманщик"
- "featured_mode_all_grapple" "Зацепщик"
- "featured_mode_all_phase" "Альтернативное пространство"
- "featured_mode_all_ticks" "Острый"
+ "featured_mode_all_grapple" "Зацепер"
+ "featured_mode_all_phase" "Мир иной"
+ "featured_mode_all_ticks" "Крутые перцы"
"featured_mode_tactikill" "Тактический удар"
"featured_mode_amped_tacticals" "Усиленные тактики"
"featured_mode_rocket_arena" "Ракетная Арена"
"featured_mode_shotguns_snipers" "Вооружён и опасен"
"iron_rules" "Правила Железного Титана"
- "cp_amped_capture_points" "Усиленные точки опоры"
- "coliseum_loadouts_enabled" "Выгрузка коллизея"
+ "cp_amped_capture_points" "Усиленные опорные пункты"
+ "coliseum_loadouts_enabled" "Экипировка Колизея"
// northstar.custom localisation is just deciding not to work, so putting it here for now
"PL_sbox" "Песочница"
@@ -81,9 +81,9 @@
"PL_gg" "Гонка вооружений"
"PL_gg_lobby" "Лобби гонки вооружений"
- "PL_gg_desc" "Уничтожьте противника из всех видов оружия чтобы победить."
- "PL_gg_hint" "Уничтожьте противника из всех видов оружия чтобы победить."
- "PL_gg_abbr" "GG"
+ "PL_gg_desc" "Убейте по одному противнику из каждого вида оружия."
+ "PL_gg_hint" "Убейте по одному противнику из каждого вида оружия."
+ "PL_gg_abbr" "ГВ"
"GAMEMODE_GG" "Гонка вооружений"
"PL_tt" "Разборки Титанов"
@@ -99,10 +99,10 @@
"PL_inf_hint" "Переживите инфекцию. Выжившие становятся заражёнными при убийстве."
"PL_inf_abbr" "INF"
"GAMEMODE_INF" "Заражение"
- "INFECTION_YOU_ARE_INFECTED" "Вы были заражены!"
+ "INFECTION_YOU_ARE_INFECTED" "Вас заразили!"
"INFECTION_KILL_SURVIVORS" "Заразите всех оставшихся выживших."
"INFECTION_FIRST_INFECTED" "%s1 был заражён первым."
- "INFECTION_LAST_SURVIVOR" "%s1 выжил последним!"
+ "INFECTION_LAST_SURVIVOR" "%s1 — последний выживший!"
"INFECTION_KILL_LAST_SURVIVOR" "Зарази их, пока время не вышло!"
"INFECTION_YOU_ARE_LAST_SURVIVOR" "Вы последний выживший!"
"INFECTION_SURVIVE_LAST_SURVIVOR" "Выживите."
@@ -116,19 +116,19 @@
"HIDEANDSEEK_YOU_ARE_SEEKER" "ВЫ ИЩЕТЕ"
"HIDEANDSEEK_SEEKER_DESC" "Найдите прячущихся и ударьте их.\nВы появитесь через %s1 секунд(у)"
"HIDEANDSEEK_YOU_ARE_HIDER" "ВЫ ПРЯЧЕТЕСЬ"
- "HIDEANDSEEK_HIDER_DESC" "Спрятайтесь."
+ "HIDEANDSEEK_HIDER_DESC" "Спрячьтесь."
"HIDEANDSEEK_SEEKERS_INCOMING" "ИЩУЩИЕ ВЫДВИГАЮТСЯ"
"HIDEANDSEEK_DONT_GET_FOUND" "Не дайте себя найти!"
"HIDEANDSEEK_GET_LAST_HIDER" "%s1 ПОСЛЕДНИЙ СПРЯТАВШИЙСЯ"
"HIDEANDSEEK_YOU_ARE_LAST_HIDER" "ВЫ ПОСЛЕДНИЙ СПРЯТАВШИЙСЯ"
- "HIDEANDSEEK_GOT_STIM" "Вас остановили! Не попадитесь!"
+ "HIDEANDSEEK_GOT_STIM" "Применён стим! Не попадитесь!"
"hideandseek_balance_teams" "Автобаланс обеих сторон"
"hideandseek_hiding_time" "Время спрятаться"
// these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development
- "GAMEMODE_fw" "Пограничная война"
- "PL_fw" "Пограничная война"
- "PL_fw_lobby" "Лобби пограничной войны"
+ "GAMEMODE_fw" "Война за Фронтир"
+ "PL_fw" "Война за Фронтир"
+ "PL_fw_lobby" "Лобби Войны за Фронтир"
"PL_fw_desc" "Уничтожьте харвестер противника и защитите свой"
"PL_fw_abbr" "FW"
@@ -136,22 +136,22 @@
"PL_kr" "Усиленные гонки убийств"
"PL_kr_lobby" "Лобби усиленных гонок убийств"
- "PL_kr_desc" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать его. Установите рекорд убийств, чтобы победить."
- "PL_kr_hint" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать его. Установите рекорд убийств, чтобы победить."
+ "PL_kr_desc" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать её. Установите рекорд убийств, чтобы победить."
+ "PL_kr_hint" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать её. Установите рекорд убийств, чтобы победить."
"PL_kr_abbr" "KR"
"SCOREBOARD_KR_RECORD" "Рекорд убийств"
"KR_NEW_RACER" "%s1 усиленный гонщик за убийства"
"KR_YOU_ARE_NEW_RACER" "Вы усиленный гонщик за убийства"
"KR_YOU_SET_NEW_RECORD" "Установите новый рекорд убийств!"
"KR_FLAG_INCOMING" "Флаг прибывает"
- "KR_COLLECT_FLAG" "Возьмите его чтобы стать гонщиком за убиства!"
+ "KR_COLLECT_FLAG" "Возьмите его чтобы стать гонщиком за убийства!"
"KR_ENEMY_KILLRACE_OVER" "Гонки убийств у %s1 закончились"
"KR_YOUR_KILLRACE_OVER" "Ваши гонки убийств кончились"
"KR_YOUR_KILLRACE_SCORE" "У вас %s1 убийств."
- "GAMEMODE_fastball" "Фастболл"
- "PL_fastball" "Фастболл"
- "PL_fastball_lobby" "Лобби фастболла"
+ "GAMEMODE_fastball" "Фастбол"
+ "PL_fastball" "Фастбол"
+ "PL_fastball_lobby" "Лобби фастбола"
"PL_fastball_desc" "Перманентная смерть. Взломайте панели управления чтобы побеждать в раундах и возродить своих членов команды."
"PL_fastball_hint" "Перманентная смерть. Взломайте панели управления чтобы побеждать в раундах и возродить своих членов команды."
"PL_fastball_abbr" "FB"
@@ -161,20 +161,20 @@
"GAMEMODE_ctf_comp" "Соревновательное CTF"
// mode settings
- "MODE_SETTING_CATEGORY_PROMODE" "Продвинутое оружие"
+ "MODE_SETTING_CATEGORY_PROMODE" "Режим про"
"MODE_SETTING_CATEGORY_BLEEDOUT" "Кровотечение пилота"
"custom_air_accel_pilot" "Ускорение в воздухе"
- "promode_enable" "Продвинутое оружие"
- "fp_embark_enabled" "Отправления/Казни от первого лица"
+ "promode_enable" "Оружие из режима про"
+ "fp_embark_enabled" "Казни/посадки в титана от первого лица"
"classic_rodeo" "Классическое родео"
"oob_timer_enabled" "Таймер уничтожения за пределами карты"
"riff_instagib" "Моментальная смерть при попадании"
"riff_player_bleedout" "Кровотечение пилота"
- "player_bleedout_forceHolster" "Использовать оружие из кобуры при кровотечении"
+ "player_bleedout_forceHolster" "Убирать оружие при кровотечении"
"player_bleedout_forceDeathOnTeamBleedout" "Смерть при кровотечении во всей команде"
- "player_bleedout_bleedoutTime" "Кремя кровотечения"
+ "player_bleedout_bleedoutTime" "Время кровотечения"
"player_bleedout_firstAidTime" "Время оказания первой помощи"
"player_bleedout_firstAidTimeSelf" "Время оказания помощи самому себе"
"player_bleedout_firstAidHealPercent" "Процент здоровья после лечения"
@@ -187,8 +187,8 @@
"PL_sp_coop_hint" "Сыграть в кампанию с друзьями"
"PL_sp_coop_abbr" "SP"
- "SP_TRAINING" "Тренировачная полоса пилотов"
- "SP_TRAINING_CLASSIC_DESC" "Тренировачная имитация капитана Ластимозы."
+ "SP_TRAINING" "Полоса препятствий"
+ "SP_TRAINING_CLASSIC_DESC" "Симуляция капитана Ластимозы."
"SP_CRASHSITE" "БT-7274"
"SP_CRASHSITE_CLASSIC_DESC" "Джек Купер встречает BT-7274."
@@ -200,7 +200,7 @@
"SP_BOOMTOWN_START_CLASSIC_DESC" "Подземная срезка приводит к неожиданным последствиям."
"SP_HUB_TIMESHIFT" "Следствие и Причина"
- "SP_HUB_TIMESHIFT_CLASSIC_DESC" "Странный феномен был обнаружен на местополжении Майора Андерсена."
+ "SP_HUB_TIMESHIFT_CLASSIC_DESC" "Странный феномен был обнаружен на местоположении Майора Андерсена."
"SP_BEACON" "Маяк"
"SP_BEACON_CLASSIC_DESC" "Купер и БТ пытаются известить оставшийся флот о планах IMC."
@@ -211,7 +211,7 @@
"SP_S2S" "Ковчег"
"SP_S2S_CLASSIC_DESC" "Купер и БТ перемещаются по кораблям, преследуя Ковчег."
- "SP_SKYWAY_V1" "Сложенное оружие"
+ "SP_SKYWAY_V1" "Искажающее орудие"
"SP_SKYWAY_V1_CLASSIC_DESC" "БT и Купер были захвачены Кубеном Блиском."
// Better.Serverbrowser
@@ -229,7 +229,7 @@
"SERVER_DESCRIPTION" "Описание"
"SERVER_MODS" "Моды"
"CLEAR_FILTERS" "ОЧИСТИТЬ"
- "JOIN_BUTTON" "ПРИСОЕДИНИТЬСЯ"
+ "JOIN_BUTTON" "ЗАЙТИ"
"SWITCH_YES" "Да"
"SWITCH_NO" "Нет"
@@ -240,18 +240,110 @@
"TOTAL_SERVERS" "Серверов: ^C46C6C00%s1"
// In-game chat
- "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]"
- "HUD_CHAT_SERVER_PREFIX" "[SERVER]"
+ "HUD_CHAT_WHISPER_PREFIX" "[ЛИЧНОЕ]"
+ "HUD_CHAT_SERVER_PREFIX" "[СЕРВЕР]"
"NO_GAMESERVER_RESPONSE" "Игровой сервер не отвечает"
- "BAD_GAMESERVER_RESPONSE" "Игровой сервер не дал правильного ответа"
+ "BAD_GAMESERVER_RESPONSE" "Игровой сервер вернул некорректный ответ"
"UNAUTHORIZED_GAMESERVER" "Игровой сервер не авторизирован чтобы сделать данный запрос"
- "UNAUTHORIZED_GAME" "Не удалось найти Titanfall 2 на этом аккаунте"
+ "UNAUTHORIZED_GAME" "Stryder не смог найти Titanfall 2 на этом аккаунте"
"UNAUTHORIZED_PWD" "Неправильный пароль"
- "STRYDER_RESPONSE" "Не удалось разобрать ответ stryder"
+ "STRYDER_RESPONSE" "Не удалось разобрать ответ Stryder"
"PLAYER_NOT_FOUND" "Не удалось найти аккаунт игрока"
- "INVALID_MASTERSERVER_TOKEN" "Срок действия жетона главного сервера истек или не является правильным"
- "JSON_PARSE_ERROR" "Ошибка разбора ответа json"
+ "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера"
+ "JSON_PARSE_ERROR" "Ошибка разбора json-ответа"
"UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается"
+ "DISABLE" "Выключить"
+ "DIALOG_AUTHENTICATING_MASTERSERVER" "Аутентификация на главном сервере."
+ "WARNING" "Предупреждение"
+ "CORE_MOD_DISABLE_WARNING" "Выключение основных модов может сломать ваш клиент!"
+ "AUTHENTICATIONAGREEMENT_NO" "Вы выбрали не аутентифицироваться с Northstar-ом. Вы можете посмотреть соглашение в меню модов."
+ "NS_SERVERBROWSER_UNKNOWNMODE" "Неизвестный режим"
+ "SNS_BANKRUPT" "Банкрот!"
+ "MOD_SETTINGS" "Настройки модов"
+ "NORTHSTAR_BASE_SETTINGS" "Основные настройки Northstar"
+ "ONLY_HOST_MATCH_SETTINGS" "Только создатель матча может изменять настройки"
+ "ONLY_HOST_CAN_START_MATCH" "Только создатель матча может его начать"
+ "MATCH_COUNTDOWN_LENGTH" "Длительность обратного отсчёта частного матча"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Записывать в лог неизвестные команды"
+ "DISALLOWED_TACTICALS" "Запрещённое спецоружие"
+ "TACTICAL_REPLACEMENT" "Заменять запрещённое спецоружие на"
+ "DISALLOWED_WEAPONS" "Запрещённое оружие"
+ "REPLACEMENT_WEAPON" "Заменять запрещённое оружие на"
+ "SHOULD_RETURN_TO_LOBBY" "Возвращаться в лобби после матча"
+ "ARE_YOU_SURE" "Вы уверены?"
+ "WILL_RESET_ALL_SETTINGS" "ВСЕ настройки этой категории будут сброшены.\n\nЭто действие нельзя будет откатить."
+ "WILL_RESET_SETTING" "Это сбросит значение настройки %s1.\n\nЭто действие нельзя будет откатить."
+ "MOD_SETTINGS_SERVER" "Сервер"
+ "MOD_SETTINGS_RESET" "Сброс"
+ "MOD_SETTINGS_RESET_ALL" "Сбросить все"
+ "NO_RESULTS" "Нет результатов."
+ "NO_MODS" "Нечего настраивать! Загрузите моды с ^5588FF00northstar.thunderstore.io^0."
+ "respawnprotection" "Длит. защиты после возрождения"
+ "SNS_BANKRUPT_SUB" "Вас обнулил %s1"
+ "PL_hidden" "Невидимка"
+ "PL_hidden_lobby" "Невидимка — лобби"
+ "GAMEMODE_HIDDEN" "Невидимка"
+ "HIDDEN_YOU_ARE_HIDDEN" "Вы — Невидимка!"
+ "HIDDEN_KILL_SURVIVORS" "Убейте всех."
+ "aitdm_archer_grunts" "Пехотинцы со Стрельцами"
+ "PL_chamber" "Последний патрон"
+ "PL_chamber_lobby" "Последний патрон — лобби"
+ "PL_chamber_abbr" "ПАТРОН"
+ "GAMEMODE_CHAMBER" "Последний патрон"
+ "PL_sns" "Камни и палки"
+ "PL_sns_lobby" "Камни и палки — лобби"
+ "PL_sns_desc" "Все против всех. Убийства пульс. клинком и казни сбрасывают очки противника"
+ "PL_sns_abbr" "КИП"
+ "GAMEMODE_SNS" "Камни и палки"
+ "PL_hidden_hint" "Один из игроков невидим."
+ "PL_hidden_abbr" "НЕВИД"
+ "SCOREBOARD_BANKRUPTS" "Врагов обанкрочено"
+ "SNS_LEADER_BANKRUPT" "Лидер обанкрочен!"
+ "SNS_LEADER_BANKRUPT_SUB" "%s1 был обнулён игроком %s2"
+ "gg_kill_reward" "Множитель награды за убийство"
+ "gg_execution_reward" "Множитель награды за казнь"
+ "PL_tffa" "Все против всех на титанах"
+ "PL_tffa_lobby" "Все против всех на титанах — лобби"
+ "PL_tffa_desc" "Каждый пилот сам за себя. Уничтожьте всех вражеских титанов."
+ "PL_tffa_abbr" "ТВПВ"
+ "sns_wme_kill_value" "Очков за убийство Элитным ведомым"
+ "sns_offhand_kill_value" "Очков за убийство спецоружием"
+ "sns_reset_kill_value" "Очков за убийство пульс./казнь"
+ "sns_melee_kill_value" "Очков за убийство врукопашную"
+ "sns_softball_enabled" "Включить Софтбол"
+ "no_pilot_collision" "Столкновения между пилотами"
+ "SHOW" "Показать"
+ "SHOW_ALL" "Все"
+ "SHOW_ONLY_ENABLED" "Только включенные"
+ "SHOW_ONLY_NOT_REQUIRED" "Только необязательные"
+ "SHOW_ONLY_REQUIRED" "Только обязательные"
+ "HIDDEN_FIRST_HIDDEN" "%s1 — Невидимка."
+ "GAMEMODE_TFFA" "Все против всех на титанах"
+ "SHOW_ONLY_DISABLED" "Только выключенные"
+ "HIDE_LOCKED" "Скрыть недоступные"
+ "PL_chamber_desc" "Один выстрел — один труп. Заработайте ещё один патрон, убив врага первым."
+ "PL_chamber_hint" "Один выстрел — один труп. Заработайте ещё один патрон, убив врага первым."
+ "PL_hidden_desc" "Один из игроков невидим."
+ "PL_tffa_hint" "Каждый пилот сам за себя. Уничтожьте всех вражеских титанов."
+ "sns_softball_kill_value" "Очков за убийство Софтболом"
+ "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им"
+ "gg_assist_reward" "Множитель награды за помощь в убийстве"
+ "TOGGLE_PROGRESSION" "Вкл/выкл прогресс"
+ "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Вкл/выкл прогресс"
+ "PROGRESSION_TOGGLE_DISABLED_HEADER" "Включить прогресс?"
+ "PROGRESSION_ENABLED_HEADER" "Прогресс включён!"
+ "PROGRESSION_ENABLED_BODY" "^CCCC0000Прогресс включён.^\n\nНедоступных титанов, оружие, фракции, раскраски, и т.п. теперь нужно разблокировать, или купить за Заслуги.\n\nЭту настройку всегда можно изменить в лобби сетевой игры."
+ "PROGRESSION_DISABLED_HEADER" "Прогресс выключен!"
+ "PROGRESSION_DISABLED_BODY" "^CCCC0000Прогресс выключен.^\n\nВсе титаны, оружие, фракции, раскраски, и т.п. теперь доступны.\n\nЭту настройку всегда можно изменить в лобби сетевой игры."
+ "player_force_respawn" "Принудительное возрождение"
+ "PROGRESSION_TOGGLE_ENABLED_HEADER" "Отключить прогресс?"
+ "PROGRESSION_TOGGLE_ENABLED_BODY" "Все титаны, оружие, фракции, раскраски, и т.п. станут разблокированы.\n\nЭту настройку всегда можно изменить в лобби сетевой игры."
+ "PROGRESSION_TOGGLE_DISABLED_BODY" "Будут доступны только разблокированные или купленные вами титаны, оружие, фракции, раскраски, и т.п.\n\nЭту настройку всегда можно изменить в лобби сетевой игры.\n\n^CC000000Внимание: недоступные предметы в экипировке будут заменены на доступные!"
+ "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Прогресс!^\n\nВ Northstar теперь работает оригинальная система прогресса разблокировок. Титанов, оружие, фракции, раскраски, и т.п. теперь можно разблокировать через получение новых уровней и прохождение испытаний.\n\nПрогресс можно включить с помощью кнопки внизу меню лобби.\n\nЭту настройку всегда можно изменить."
+ "AUTHENTICATION_FAILED_BODY" "Не удалось войти в Atlas!"
+ "AUTHENTICATION_FAILED_ERROR_CODE" "Код ошибки: ^DB6F2C00%s1^"
+ "AUTHENTICATION_FAILED_HELP" "Справка"
+ "AUTHENTICATION_FAILED_HEADER" "Ошибка аутентификации"
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt
index 0dc82570b..3d9ae4c6c 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt
@@ -9,10 +9,10 @@
"MENU_TITLE_MODS" "Mods"
"RELOAD_MODS" "Recargar Mods"
"WARNING" "Advertencia"
- "CORE_MOD_DISABLE_WARNING" "Puedes romper el cliente si deshabilitas los mods principales!"
+ "CORE_MOD_DISABLE_WARNING" "¡Puedes romper el cliente si deshabilitas los mods principales!"
"DISABLE" "Deshabilitar"
- "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Gracias por instalar Northstar!."
+ "DIALOG_TITLE_INSTALLED_NORTHSTAR" "¡Gracias por instalar Northstar!"
"AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Para que Northstar funcione, necesita autentificarse con el servidor maestro Northstar. Esto requiere enviar tu token Origin al servidor maestro, no se guardará ni se usará para cualquier otro fin.
Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mods en cualquier momento."
"BACK_AUTHENTICATION_AGREEMENT" "Acuerdo de autentificación"
@@ -26,7 +26,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"NS_SERVERBROWSER_NOSERVERS" "No se encontraron servidores"
"NS_SERVERBROWSER_UNKNOWNMODE" "Modo desconocido"
"NS_SERVERBROWSER_WAITINGFORSERVERS" "Esperando por servidores..."
- "NS_SERVERBROWSER_CONNECTIONFAILED" "Connexión fallida!"
+ "NS_SERVERBROWSER_CONNECTIONFAILED" "¡Conexión fallida!"
"REFRESH_SERVERS" "Recargar"
"MENU_TITLE_CONNECT_PASSWORD" "Conectar con contraseña"
@@ -36,7 +36,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"PRIVATE_MATCH_PAGE_NEXT" "Página siguiente"
"MENU_MATCH_SETTINGS" "Configuración de partida"
- "MENU_MATCH_SETTINGS_SUBMENU" "%s1 Configuraciones"
+ "MENU_MATCH_SETTINGS_SUBMENU" "Configuración de %s1"
"PRIVATE_MATCH_SINGLEPLAYER_LEVEL" "%s1 (Un jugador)"
@@ -46,16 +46,16 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
// mode settings
"MODE_SETTING_CATEGORY_PILOT" "Piloto"
"MODE_SETTING_CATEGORY_TITAN" "Titán"
- "MODE_SETTING_CATEGORY_RIFF" "Riffs"
+ "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" "Puntaje limite (rondas)"
- "timelimit" "Tiempo limite"
- "roundtimelimit" "Tiempo limite (rondas)"
- "respawnprotection" "Tiempo de proteccion en reaparición"
+ "roundscorelimit" "Límite de punataje (rondas)"
+ "timelimit" "Límite de tiempo"
+ "roundtimelimit" "Límite de tiempo (rondas)"
+ "respawnprotection" "Tiempo de protección en reaparición"
"pilot_health_multiplier" "Multiplicador de salúd"
"respawn_delay" "Retraso de aparición"
@@ -73,7 +73,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"featured_mode_all_grapple" "Ataque a los titanes"
"featured_mode_all_phase" "El otro lado"
"featured_mode_all_ticks" "Picante"
- "featured_mode_tactikill" "Eliminación tactica"
+ "featured_mode_tactikill" "Eliminación con tactica"
"featured_mode_amped_tacticals" "Tacticas mejoradas"
"featured_mode_rocket_arena" "Arena de cohetes"
"featured_mode_shotguns_snipers" "Armado y peligroso"
@@ -85,11 +85,11 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"aitdm_archer_grunts" "Soldado Archer"
// northstar.custom localisation is just deciding not to work, so putting it here for now
- "PL_sbox" "Sandbox"
- "PL_sbox_lobby" "Vestíbulo de Sandbox"
- "PL_sbox_desc" "como gmod pero peor"
+ "PL_sbox" "Custom"
+ "PL_sbox_lobby" "Vestíbulo de juego abierto"
+ "PL_sbox_desc" "Como \"gmod\" pero peor"
"PL_sbox_abbr" "SBOX"
- "GAMEMODE_SBOX" "Sandbox"
+ "GAMEMODE_SBOX" "CUstom"
"PL_gg" "Carrera armamentística"
"PL_gg_lobby" "Vestíbulo de Carrera armamentística"
@@ -103,37 +103,37 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"PL_tt" "Titan Tag"
"PL_tt_lobby" "Vestíbulo de Titan Tag"
- "PL_tt_desc" "Obtén puntos en tu titán. Destruye un titán para obtener el tuyo."
- "PL_tt_hint" "Obtén puntos en tu titán. Destruye un titán para obtener el tuyo."
+ "PL_tt_desc" "Obtén puntos estando en tu titán. Destruye un titán para obtener el tuyo."
+ "PL_tt_hint" "Obtén puntos estando en tu titán. Destruye un titán para obtener el tuyo."
"PL_tt_abbr" "TT"
"GAMEMODE_TT" "Titan Tag"
"PL_chamber" "Uno en la recamara"
"PL_chamber_lobby" "Vestíbulo de uno en la recamara"
- "PL_chamber_desc" "Un disparo, Una eliminación. Obtén otra bala en tu cargador eliminando a alguien."
- "PL_chamber_hint" "Un disparo, Una eliminación. Obtén otra bala en tu cargador eliminando a alguien."
- "PL_chamber_abbr" "CHAMBER"
- "GAMEMODE_CHAMBER" "Uno en la recamara"
+ "PL_chamber_desc" "Un disparo, una eliminación. Obtén otra bala en tu cargador eliminando a alguien."
+ "PL_chamber_hint" "Un disparo, una eliminación. Obtén otra bala en tu cargador eliminando a alguien."
+ "PL_chamber_abbr" "RECÁMARA"
+ "GAMEMODE_CHAMBER" "Uno en la recámara"
"PL_hidden" "El escondido"
"PL_hidden_lobby" "Vestíbulo de El escondido"
"PL_hidden_desc" "Un jugador es invisible. El escondido caza."
"PL_hidden_hint" "Un jugador es invisible. El escondido caza."
- "PL_hidden_abbr" "HIDDEN"
+ "PL_hidden_abbr" "OCULTO"
"GAMEMODE_HIDDEN" "El escondido"
- "HIDDEN_YOU_ARE_HIDDEN" "Eres el escondido!"
+ "HIDDEN_YOU_ARE_HIDDEN" "¡Eres el escondido!"
"HIDDEN_KILL_SURVIVORS" "Mata a todos los supervivientes."
"HIDDEN_FIRST_HIDDEN" "%s1 es El Escondido."
- "PL_sns" "Piedras y palos"
- "PL_sns_lobby" "Vestíbulo de Piedras y palos"
+ "PL_sns" "Palos y Piedras"
+ "PL_sns_lobby" "Vestíbulo de Palos y Piedras"
"PL_sns_desc" "Todos contra todos. Usa cuchillas de pulso y ejecucciones para reestablecer el puntaje del enemigo"
"PL_sns_abbr" "SNS"
- "GAMEMODE_SNS" "Piedras y palos"
+ "GAMEMODE_SNS" "Palos y Piedras"
"SCOREBOARD_BANKRUPTS" "Eliminaciones de bancarrota"
- "SNS_LEADER_BANKRUPT" "Lider de puntaje en bancarrota!"
- "SNS_LEADER_BANKRUPT_SUB" "%s1 Fue reseteado por %s2"
- "SNS_BANKRUPT" "Arruinado!"
+ "SNS_LEADER_BANKRUPT" "¡Lider de puntaje en bancarrota!"
+ "SNS_LEADER_BANKRUPT_SUB" "%s1 fue reseteado por %s2"
+ "SNS_BANKRUPT" "¡Arruinado!"
"SNS_BANKRUPT_SUB" "Tu puntaje fue reseteado por %s1"
"sns_wme_kill_value" "Valor por eliminacion con Wingman Elite"
"sns_softball_kill_value" "Valor por eliminacion con Softball"
@@ -152,7 +152,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"INFECTION_YOU_ARE_INFECTED" "Has sido infectado!"
"INFECTION_KILL_SURVIVORS" "Infecta a todos los supervivientes restantes."
"INFECTION_FIRST_INFECTED" "%s1 es el primer Infectado."
- "INFECTION_LAST_SURVIVOR" "%s1 es el ultimo superviviente!"
+ "INFECTION_LAST_SURVIVOR" "¡%s1 es el ultimo superviviente!"
"INFECTION_KILL_LAST_SURVIVOR" "Infectalo antes de que el tiempo se acabe!"
"INFECTION_YOU_ARE_LAST_SURVIVOR" "Eres el ultimo superviviente!"
"INFECTION_SURVIVE_LAST_SURVIVOR" "Sobrevive."
@@ -186,7 +186,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"GAMEMODE_fw" "Guerra fronteriza"
"PL_fw" "Guerra fronteriza"
"PL_fw_lobby" "Vestíbulo de Guerra fronteriza"
- "PL_fw_desc" "Destruye el cosechador del enemigo y protege el tuyo."
+ "PL_fw_desc" "Destruye el cosechador del enemigo y protege el tuyo"
"PL_fw_abbr" "FW"
"GAMEMODE_kr" "Carrera por muertes"
@@ -205,8 +205,8 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"KR_YOUR_KILLRACE_OVER" "Tu carrera ha acabado"
"KR_YOUR_KILLRACE_SCORE" "Has obtenido %s1 bajas."
- "GAMEMODE_fastball" "Fastball"
- "PL_fastball" "Fastball"
+ "GAMEMODE_fastball" "Lanzamiento"
+ "PL_fastball" "Lanzamiento"
"PL_fastball_lobby" "Vestíbulo de Fastball"
"PL_fastball_desc" "Muerte permanente. Piratea paneles de control para ganar rondas y hacer reaparecer a tus compañeros de equipo."
"PL_fastball_hint" "Muerte permanente. Piratea paneles de control para ganar rondas y hacer reaparecer a tus compañeros de equipo."
@@ -263,7 +263,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"SP_BEACON_CLASSIC_DESC" "Cooper y BT intentan contactar con lo que queda de la flota para alertar de los planes de IMC."
"SP_TDAY" "Prueba de fuego"
- "SP_TDAY_CLASSIC_DESC" "Las habilidades de Cooper al mando de su titán se ponen a prueba en una batalla total para capturar el Arca."
+ "SP_TDAY_CLASSIC_DESC" "Las habilidades de Cooper al mando de su titán se ponen a prueba en una batalla total para capturar el Arca"
"SP_S2S" "El Arca"
"SP_S2S_CLASSIC_DESC" "Cooper y BT van de nave en nave en busca del Arca."
@@ -284,7 +284,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"HIDE_EMPTY_FILTER" "Esconder servidores vacios"
"HIDE_PROT_FILTER" "Esconder servidores protegidos"
"SERVER_DESCRIPTION" "Descripción"
- "SERVER_MODS" "Mods"
+ "SERVER_MODS" "Modificaciones"
"CLEAR_FILTERS" "LIMPIAR"
"JOIN_BUTTON" "UNIR"
@@ -318,6 +318,39 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo
"PLAYER_NOT_FOUND" "No se encontró la cuenta del jugador"
"INVALID_MASTERSERVER_TOKEN" "Token de jugador expirado o invalido"
"JSON_PARSE_ERROR" "Error procesando respuesta json"
- "UNSUPPORTED_VERSION" "La versión que estas usando ya no esta soportada"
+ "UNSUPPORTED_VERSION" "La versión que estás usando ya no está siendo mantenida"
+ "MATCH_COUNTDOWN_LENGTH" "Duración cronometrada de la partida privada"
+ "ONLY_HOST_MATCH_SETTINGS" "Sólo el anfitrión puede cambiar las configuraciones de la partida"
+ "ONLY_HOST_CAN_START_MATCH" "Sólo el anfitrión puede iniciar la partida"
+ "DISALLOWED_WEAPONS" "Armas prohibidas"
+ "REPLACEMENT_WEAPON" "Arma de reemplazo"
+ "MOD_SETTINGS" "Configuración de Mods"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Registrar comandos no reconocidos desde el cliente"
+ "DISALLOWED_TACTICALS" "Tácticas prohibidas"
+ "TACTICAL_REPLACEMENT" "Reemplazo de la táctica"
+ "SHOULD_RETURN_TO_LOBBY" "Regresar a la sala de espera después de la partida"
+ "ARE_YOU_SURE" "¿Segur@?"
+ "WILL_RESET_ALL_SETTINGS" "Esto reiniciará TODAS las opciones de ésta categoría.\n\nNo se podrá revertir el proceso."
+ "NORTHSTAR_BASE_SETTINGS" "Opciones de Northstar por defecto"
+ "NO_RESULTS" "No hay resultados."
+ "MOD_SETTINGS_RESET" "Reiniciar"
+ "SHOW_ONLY_NOT_REQUIRED" "Mostrar sólo mods opcionales"
+ "SHOW_ONLY_REQUIRED" "Mostrar sólo mods obligatorios"
+ "NO_MODS" "¡No hay configuraciones disponibles! Instala más mods desde ^5588FF00northstar.thunderstore.io^0."
+ "PROGRESSION_TOGGLE_DISABLED_HEADER" "¿Habilitar progreso?"
+ "PROGRESSION_TOGGLE_ENABLED_HEADER" "¿Deshabilitar progresión?"
+ "PROGRESSION_ENABLED_HEADER" "¡Progreso habilitado!"
+ "PROGRESSION_DISABLED_HEADER" "¡Progreso deshabilitado!"
+ "TOGGLE_PROGRESSION" "Cambiar modo de progresión"
+ "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Cambiar modo de progresión"
+ "PROGRESSION_TOGGLE_DISABLED_BODY" "Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados sólo al subir de nivel, o a través de Logros.\n\nÉsta opción puede ser cambiada cuando quieras en la sala de espera.\n\n^CC000000Advertencia: ¡Cualquier equipamiento o utensilio será reiniciado si no lo tienes desbloqueado!"
+ "MOD_SETTINGS_SERVER" "Servidor"
+ "MOD_SETTINGS_RESET_ALL" "Reiniciar completamente"
+ "PROGRESSION_TOGGLE_ENABLED_BODY" "Los Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados y permanecerán utilizables.\n\nÉsta opción puede ser cambiada cuando quieras desde la sala de espera."
+ "PROGRESSION_ENABLED_BODY" "^CCCC0000El modo de progreso ha sido habilitado.^\n\nLos Titanes, Armas, Facciones, Aspectos y otros se desbloquearán al subir de nivel o por Logros.\n\nPuedes cambiar ésta opción cuando quieras en la sala de espera."
+ "PROGRESSION_DISABLED_BODY" "^CCCC0000El modo de progreso ha sido deshabilitado.^\n\nLos Titanes, Armas, Facciones, Aspectos y otros están desbloqueados y puedes utilizarlos cuando quieras.\n\nPuedes cambiar ésta opción cuando quieras desde la sala de espera."
+ "WILL_RESET_SETTING" "Ésta acción reiniciará %s1 a su valor por defecto.\n\nNo se podrá revertir el proceso."
+ "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000El progreso puede ser habilitado desde ahora^\n\nNorthstar ahora es compatible con el progreso normal del juego, esto significa que puedes elegir desbloquear Armas, Aspectos, Titanes y otros a través de desafíos y subiendo de nivel.\n\nPuedes habilitar el progreso normal del juego en la opción ubicada al final de la pantalla de la sala de espera.\n\nÉsta opción puede ser cambiada en cualquier momento."
+ "player_force_respawn" "Reaparición Forzada"
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt
index 12b6cad1b..500f8a969 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt
@@ -127,7 +127,7 @@
"PL_sns" "冷兵器"
"PL_sns_lobby" "冷兵器大廳"
- "PL_sns_desc" "模擬十字弓和飛斧的作戰模式。使用脈衝刀及處決擊殺來重置敵人的分數。"
+ "PL_sns_desc" "无规则. 使用脈衝刀及處決擊殺來重置敵人的分數"
"PL_sns_abbr" "SNS"
"GAMEMODE_SNS" "冷兵器"
"SCOREBOARD_BANKRUPTS" "破產次數"
@@ -155,7 +155,7 @@
"INFECTION_LAST_SURVIVOR" "%s1是最後的倖存者!"
"INFECTION_KILL_LAST_SURVIVOR" "在時間用盡前感染他!"
"INFECTION_YOU_ARE_LAST_SURVIVOR" "你是最後的倖存者!"
- "INFECTION_SURVIVE_LAST_SURVIVOR" "倖存"
+ "INFECTION_SURVIVE_LAST_SURVIVOR" "最後幸存者."
"PL_tffa" "泰坦混戰"
"PL_tffa_lobby" "泰坦混戰大廳"
@@ -238,38 +238,38 @@
"player_bleedout_aiBleedingPlayerMissChance" "倒地時AI的失誤率"
// coop stuff
- "PL_sp_coop" "(UNFINISHED) Singleplayer Coop"
- "PL_sp_coop_lobby" "Singleplayer Coop Lobby"
- "PL_sp_coop_desc" "Play through the singleplayer campaign with friends"
- "PL_sp_coop_hint" "Play through the singleplayer campaign with friends"
+ "PL_sp_coop" "(未完成) 單人合作"
+ "PL_sp_coop_lobby" "單人合作模式大廳"
+ "PL_sp_coop_desc" "與朋友一起遊玩單人戰役"
+ "PL_sp_coop_hint" "與朋友一起遊玩單人戰役"
"PL_sp_coop_abbr" "SP"
- "SP_TRAINING" "The Pilot's Gauntlet"
- "SP_TRAINING_CLASSIC_DESC" "Captain Lastimosa's training simulation."
+ "SP_TRAINING" "鐵御的試煉"
+ "SP_TRAINING_CLASSIC_DESC" "拉絲提莫沙上尉的模擬訓練."
"SP_CRASHSITE" "BT-7274"
- "SP_CRASHSITE_CLASSIC_DESC" "Jack Cooper meets BT-7274."
+ "SP_CRASHSITE_CLASSIC_DESC" "傑克庫博預見BT-7274."
- "SP_SEWERS1" "Blood and Rust"
- "SP_SEWERS1_CLASSIC_DESC" "Cooper and BT set out to rendezvous with Major Anderson."
+ "SP_SEWERS1" "鮮血與鐵鏽"
+ "SP_SEWERS1_CLASSIC_DESC" "庫博和BT一起出發前往與安德森上尉回合."
- "SP_BOOMTOWN_START" "Into the Abyss"
- "SP_BOOMTOWN_START_CLASSIC_DESC" "An underground shortcut yields unexpected consequences."
+ "SP_BOOMTOWN_START" "踏入虛空"
+ "SP_BOOMTOWN_START_CLASSIC_DESC" "一個地下捷徑造成了不可預見的後果."
- "SP_HUB_TIMESHIFT" "Effect and Cause"
- "SP_HUB_TIMESHIFT_CLASSIC_DESC" "A strange phenomenon is discovered at Major Anderson's coordinates."
+ "SP_HUB_TIMESHIFT" "因果報應"
+ "SP_HUB_TIMESHIFT_CLASSIC_DESC" "在安德森上尉的坐標處發現了奇異的現象."
- "SP_BEACON" "The Beacon"
- "SP_BEACON_CLASSIC_DESC" "Cooper and BT attempt to inform the remaining fleet of the IMC's plans."
+ "SP_BEACON" "信號台"
+ "SP_BEACON_CLASSIC_DESC" "庫博和BT嘗試將IMC的計劃通知給剩餘反抗軍艦隊."
- "SP_TDAY" "Trial by Fire"
- "SP_TDAY_CLASSIC_DESC" "Cooper's Titan skills are put to the test in an all-out battle to capture the Ark"
+ "SP_TDAY" "烈火審判"
+ "SP_TDAY_CLASSIC_DESC" "庫博驾馭泰坦的技術在爭奪聖櫃的全面戰爭中得到考驗"
- "SP_S2S" "The Ark"
- "SP_S2S_CLASSIC_DESC" "Cooper and BT go ship to ship in pursuit of the Ark."
+ "SP_S2S" "聖櫃"
+ "SP_S2S_CLASSIC_DESC" "庫博和BT在艦艇中穿梭追尋聖櫃."
- "SP_SKYWAY_V1" "The Fold Weapon"
- "SP_SKYWAY_V1_CLASSIC_DESC" "BT and Cooper are captured by Kuben Blisk."
+ "SP_SKYWAY_V1" "折疊時空武器"
+ "SP_SKYWAY_V1_CLASSIC_DESC" "BT和庫博被庫本布里斯克擒拿."
// Better.Serverbrowser
"SERVERS_COLUMN" "伺服器"
@@ -310,8 +310,8 @@
"HUD_CHAT_SERVER_PREFIX" "[伺服器]"
// In-game chat
- "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]"
- "HUD_CHAT_SERVER_PREFIX" "[SERVER]"
+ "HUD_CHAT_WHISPER_PREFIX" "[悄悄話]"
+ "HUD_CHAT_SERVER_PREFIX" "[伺服器]"
"NO_GAMESERVER_RESPONSE" "無法連接到遊戲伺服器'"
"BAD_GAMESERVER_RESPONSE" "遊戲伺服器回應無效"
@@ -323,5 +323,38 @@
"INVALID_MASTERSERVER_TOKEN" "主伺服器token過期或無效"
"JSON_PARSE_ERROR" "讀取json回應時發生錯誤"
"UNSUPPORTED_VERSION" "您的遊戲版本過低"
+ "NORTHSTAR_BASE_SETTINGS" "北极星基础设置"
+ "ONLY_HOST_CAN_START_MATCH" "只有服主可以開始對局"
+ "MATCH_COUNTDOWN_LENGTH" "私人對局倒計時時間"
+ "DISALLOWED_TACTICALS" "禁用的技能"
+ "TACTICAL_REPLACEMENT" "替換的技能"
+ "NO_RESULTS" "無結果."
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "登記未知客戶端指令"
+ "SHOULD_RETURN_TO_LOBBY" "對局結束後返回大廳"
+ "ARE_YOU_SURE" "確定?"
+ "WILL_RESET_SETTING" "這將會重置 %s1 的設置為默認值.\n\n此操作不可復原."
+ "MOD_SETTINGS_SERVER" "服務器"
+ "MOD_SETTINGS_RESET" "重置"
+ "MOD_SETTINGS_RESET_ALL" "重置所有"
+ "SHOW_ONLY_NOT_REQUIRED" "僅展示非必需模組"
+ "SHOW_ONLY_REQUIRED" "僅展示必須模組"
+ "MOD_SETTINGS" "模组设置"
+ "ONLY_HOST_MATCH_SETTINGS" "只有服主可以修改私人對局設置"
+ "DISALLOWED_WEAPONS" "禁用的武器"
+ "REPLACEMENT_WEAPON" "替换的武器"
+ "WILL_RESET_ALL_SETTINGS" "這將會重置所有屬於改條目的設置.\n\n此操作不可復原."
+ "NO_MODS" "無可用模組! 前往 ^5588FF00northstar.thunderstore.io^0 下載更多."
+ "player_force_respawn" "強制重生"
+ "PROGRESSION_TOGGLE_DISABLED_HEADER" "啟用個人進度?"
+ "PROGRESSION_ENABLED_HEADER" "個人進度已開啟!"
+ "PROGRESSION_TOGGLE_DISABLED_BODY" "泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。\n\n^CC000000警告:如果您已經裝備了尚未解鎖的物品,它們將會被重置!"
+ "PROGRESSION_TOGGLE_ENABLED_BODY" "泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品都將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。"
+ "TOGGLE_PROGRESSION" "遊戲進度"
+ "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% 遊戲進度"
+ "PROGRESSION_TOGGLE_ENABLED_HEADER" "停用個人進度?"
+ "PROGRESSION_DISABLED_HEADER" "個人進度已關閉!"
+ "PROGRESSION_DISABLED_BODY" "^CCCC0000個人進度已停用^\n\n泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。"
+ "PROGRESSION_ENABLED_BODY" "^CCCC0000個人進度已啟用^\n\n泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。"
+ "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000現在可以隨時開啟個人進度!^\n\nNorthstar 現在支持類似官服的進度系統, 这意味着你可以选择通过升级和完成挑战来解锁武器、皮肤、泰坦等。\n\n您可以通過多人大廳底部的“遊戲進度”按鈕來進行開啟。\n\n您可以隨時在多人大廳中更改此項。"
}
}
diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut
index 2a2ed3dbe..a844478a2 100644
--- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut
+++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut
@@ -41,3 +41,10 @@ global struct ServerInfo
string region
array< RequiredModInfo > requiredMods
}
+
+global struct MasterServerAuthResult
+{
+ bool success
+ string errorCode
+ string errorMessage
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut b/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut
new file mode 100644
index 000000000..89b7f7196
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut
@@ -0,0 +1,56 @@
+global function AtlasAuthDialog
+
+void function AtlasAuthDialog()
+{
+ thread AtlasAuthDialog_Threaded()
+}
+
+void function AtlasAuthDialog_Threaded()
+{
+ // wait at least 1 frame so that the main menu can be loaded first
+ WaitFrame()
+
+ while ( !NSIsMasterServerAuthenticated() || GetConVarBool( "ns_auth_allow_insecure" ) )
+ WaitFrame()
+
+ if ( GetConVarBool( "ns_auth_allow_insecure" ) )
+ return
+
+ MasterServerAuthResult res = NSGetMasterServerAuthResult()
+
+ // do nothing on successful authentication
+ if ( res.success )
+ return
+
+ EmitUISound( "blackmarket_purchase_fail" )
+
+ DialogData dialogData
+ dialogData.image = $"ui/menu/common/dialog_error"
+ dialogData.header = Localize( "#AUTHENTICATION_FAILED_HEADER" )
+
+ // if we got a special error message from Atlas, display it
+ if ( res.errorMessage != "" )
+ dialogData.message = res.errorMessage
+ else
+ dialogData.message = Localize( "#AUTHENTICATION_FAILED_BODY" )
+
+ if ( res.errorCode != "" )
+ dialogData.message += format( "\n\n%s", Localize( "#AUTHENTICATION_FAILED_ERROR_CODE", res.errorCode ) )
+
+ string link = "https://r2northstar.gitbook.io/r2northstar-wiki/installing-northstar/troubleshooting"
+ // link to generic troubleshooting page if we don't have an error code from Atlas
+ if ( res.errorCode != "" )
+ link = format( "%s#%s", link, res.errorCode )
+
+ CloseAllDialogs()
+ AddDialogButton( dialogData, "#OK" )
+ AddDialogButton( dialogData, Localize( "#AUTHENTICATION_FAILED_HELP" ), void function() : ( dialogData, link )
+ {
+ // todo: get MS to redirect, so i can use an MS link or something?
+ LaunchExternalWebBrowser( link, WEBBROWSER_FLAG_FORCEEXTERNAL )
+ // keep the dialog open
+ OpenDialog( dialogData )
+ } )
+
+ OpenDialog( dialogData )
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut
new file mode 100644
index 000000000..4e98ee8a8
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut
@@ -0,0 +1,902 @@
+untyped
+
+global function Chatroom_GlobalInit
+global function InitChatroom
+global function UpdateChatroomUI
+global function UICodeCallback_ShowUserInfo
+global function UICodeCallback_RemoteMatchInfoUpdated
+global function UICodeCallback_SetChatroomMode
+global function UpdateOpenInvites
+global function HideOpenInvite
+global function ShowOpenInvite
+global function FillInUserInfoPanel
+global function UpdateChatroomThread
+global function IsVoiceChatPushToTalk
+
+global function bsupdate
+
+global const LOBBY_MATERIAL_OWNER = $"rui/menu/common/lobby_icon_owner"
+global const LOBBY_MATERIAL_ADMIN = $"rui/menu/common/lobby_icon_admin"
+
+struct RemoteMatchPlayerInfoRow
+{
+ var playerPanel
+ var name
+ var score
+ var kills
+ var deaths
+}
+
+struct RemoteMatchInfoPanel
+{
+ var panel
+ var PlaylistName
+ var MapName
+ var ModeName
+ var TimeLeft
+ var ScoreLimit
+ var Team1Score
+ var Team2Score
+ array<RemoteMatchPlayerInfoRow> team1Players
+ array<RemoteMatchPlayerInfoRow> team2Players
+}
+
+struct OpenInviteUI
+{
+ var openInviteJoinButton
+ var openInvitePanel
+ var openInviteMessage
+ var openInviteCountdownText
+ array openInvitePlayerSlots
+ array openInvitePlaylistSlots
+}
+
+global struct UserInfoPanel
+{
+ var Panel
+ var Name
+ var Kills
+ var Wins
+ var Losses
+ var Deaths
+ var XP
+ var callsignCard
+ array communityLabels
+ array communityNames
+}
+
+struct ChatroomWidget
+{
+ var chatroomPanel
+ var chatroomWidget
+ var chatroomTextChat
+
+ var chatroomBackground
+ var chatroomDivider
+ var chatroomHappyHour
+ var chatroomMode
+
+ UserInfoPanel userInfoPanel
+
+ RemoteMatchInfoPanel remoteMatchInfoPanelWidgets
+
+ var communityChatroomModeButton
+ var chatroomHintText
+ var happyHourTimeLeft
+
+ OpenInviteUI openInviteUI
+}
+
+struct
+{
+ string userInfoPanel_hardware = ""
+ string userInfoPanel_userId = "0"
+ var communityChatroomMode
+ bool currentUserIsStreaming = false
+ array<ChatroomWidget> chatroomUIs
+ bool hasFocus
+} file
+
+bool function IsVoiceChatPushToTalk()
+{
+ if ( GetPartySize() > 1 )
+ return true
+ return DoesCurrentCommunitySupportChat()
+}
+
+void function UICodeCallback_SetChatroomMode( string mode )
+{
+ file.communityChatroomMode = mode
+ UpdateChatroomUI()
+}
+
+void function UpdateChatroomUI()
+{
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ if ( file.communityChatroomMode == "chatroom" )
+ {
+ int communityId = GetCurrentCommunityId()
+ CommunitySettings ornull communitySettings = GetCommunitySettings( communityId )
+
+ string communityName
+ if ( communitySettings != null )
+ {
+ expect CommunitySettings( communitySettings )
+ communityName = GetCurrentCommunityName() + " [" + communitySettings.clanTag + "]"
+ }
+ else
+ {
+ communityName = expect string( GetCurrentCommunityName() )
+ }
+
+ if ( IsChatroomMuted() )
+ SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_CHATROOM_MUTED", communityName ) )
+ else
+ SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_CHATROOM", communityName ) )
+ }
+ else if ( file.communityChatroomMode == "party" )
+ {
+ SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_PARTY", GetPartyLeaderName() ) )
+ }
+ else
+ {
+ SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( file.communityChatroomMode ) )
+ }
+
+ int meritsLeft = GetHappyHourMeritsLeft()
+ if ( meritsLeft == 0 )
+ {
+ SetLabelRuiText( chatroomUI.happyHourTimeLeft, Localize( "#HAPPYHOUR_NOMERITSLEFT", meritsLeft ) )
+ SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", "" )
+ //SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", Localize( "#HAPPYHOUR_HINT_ACTIVE_01" ) )
+ }
+ else if ( meritsLeft >= 1 )
+ {
+ SetLabelRuiText( chatroomUI.happyHourTimeLeft, Localize( GetHappyHourStatus() ) )
+ SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", Localize( "#HAPPYHOUR_HINT_MERITS", 5 ) )
+ }
+ UICodeCallback_ShowUserInfo( file.userInfoPanel_hardware, file.userInfoPanel_userId )
+ }
+
+ UpdateFooterOptions()
+}
+
+bool function FillInCommunityMembership( UserInfoPanel userInfoPanel, CommunityMembership membershipData, int communityIndex )
+{
+ if ( userInfoPanel.communityNames.len() <= communityIndex )
+ return false;
+
+ string title
+ title = "[" + membershipData.communityClantag + "] " + Localize( membershipData.communityName );
+
+ if ( membershipData.membershipLevel == "owner" )
+ Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_OWNER" )
+ else if ( membershipData.membershipLevel == "admin" )
+ Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_ADMIN" )
+ else if ( membershipData.membershipLevel == "member" )
+ Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_MEMBER" )
+ else
+ Assert( false, "Unknown membership level " + membershipData.membershipLevel + " in FillInCommunityMembership" )
+
+ Hud_SetText( userInfoPanel.communityNames[communityIndex], title )
+ Hud_Show( userInfoPanel.communityLabels[communityIndex] );
+ Hud_Show( userInfoPanel.communityNames[communityIndex] );
+
+ return true
+}
+
+void function FillInUserInfoPanel( UserInfoPanel userInfoPanel, CommunityUserInfo userInfo )
+{
+ file.currentUserIsStreaming = userInfo.isLivestreaming
+
+ Hud_SetText( userInfoPanel.Name, userInfo.name )
+ string killsText = "" + userInfo.kills
+ Hud_SetText( userInfoPanel.Kills, killsText )
+ string winsText = "" + userInfo.wins
+ Hud_SetText( userInfoPanel.Wins, winsText )
+ string lossesText = "" + userInfo.losses
+ Hud_SetText( userInfoPanel.Losses, lossesText )
+ string deathsText = "" + userInfo.deaths
+ Hud_SetText( userInfoPanel.Deaths, deathsText )
+ string xpText = ShortenNumber( userInfo.xp )
+ Hud_EnableKeyBindingIcons( userInfoPanel.XP )
+ Hud_SetText( userInfoPanel.XP, Localize( "#CREDITSIGN_N", xpText ) )
+
+ CallingCard callingCard = CallingCard_GetByIndex( userInfo.callingCardIdx )
+ CallsignIcon callsignIcon = CallsignIcon_GetByIndex( userInfo.callSignIdx )
+
+ var card = userInfoPanel.callsignCard
+ var rui = Hud_GetRui( userInfoPanel.callsignCard )
+ RuiSetImage( rui, "cardImage", callingCard.image )
+ RuiSetImage( rui, "iconImage", callsignIcon.image )
+ RuiSetInt( rui, "layoutType", callingCard.layoutType )
+ RuiSetImage( rui, "cardGenImage", GetGenIcon( userInfo.gen, userInfo.lvl ) )
+ RuiSetString( rui, "playerLevel", PlayerXPDisplayGenAndLevel( userInfo.gen, userInfo.lvl ) )
+ RuiSetString( rui, "playerName", userInfo.name )
+
+ array<CommunityMembership> ownerCommunities
+ array<CommunityMembership> adminCommunities
+ array<CommunityMembership> memberCommunities
+
+ for ( int i = 0; i < userInfo.numCommunities; i++ )
+ {
+ CommunityMembership ornull communityInfo = GetCommunityUserMembershipInfo( userInfo.hardware, userInfo.uid, i )
+ if ( !communityInfo )
+ continue;
+ expect CommunityMembership( communityInfo )
+ string membershipLevel = communityInfo.membershipLevel
+ if ( membershipLevel == "owner" )
+ {
+ ownerCommunities.append( communityInfo )
+ }
+ else if ( membershipLevel == "admin" )
+ {
+ adminCommunities.append( communityInfo )
+ }
+ else if ( membershipLevel == "member" )
+ {
+ memberCommunities.append( communityInfo )
+ }
+ else
+ {
+ printt( "Unknown membershipLevel " + membershipLevel )
+ Assert( false, "Unknown membershipLevel" )
+ }
+ }
+
+ array<CommunityMembership> allCommunities
+ for ( int i = 0; i < ownerCommunities.len(); i++ )
+ allCommunities.append( ownerCommunities[i] )
+ for ( int i = 0; i < adminCommunities.len(); i++ )
+ allCommunities.append( adminCommunities[i] )
+ for ( int i = 0; i < memberCommunities.len(); i++ )
+ allCommunities.append( memberCommunities[i] )
+
+ int currentCommunityIndex = 0
+ for ( ; currentCommunityIndex < allCommunities.len(); currentCommunityIndex++ )
+ {
+ if ( !FillInCommunityMembership( userInfoPanel, allCommunities[currentCommunityIndex], currentCommunityIndex ) )
+ break;
+ }
+
+ for ( ; currentCommunityIndex < userInfoPanel.communityNames.len(); currentCommunityIndex++ )
+ {
+ Hud_Hide( userInfoPanel.communityLabels[currentCommunityIndex] );
+ Hud_Hide( userInfoPanel.communityNames[currentCommunityIndex] );
+ }
+
+ UpdateFooterOptions()
+}
+
+void function GetUserInfoThread( string hardware, string userId )
+{
+ EndSignal( uiGlobal.signalDummy, "StopUserInfoLookups" )
+
+ printt( "getting userinfo for user " + userId )
+
+ CommunityUserInfo fakeSettings
+ fakeSettings.name = Localize( "#COMMUNITY_FETCHING" )
+ foreach ( chatroomUI in file.chatroomUIs )
+ FillInUserInfoPanel( chatroomUI.userInfoPanel, fakeSettings )
+
+ while ( true )
+ {
+ printt( "asking for userinfo for " + hardware + "=" + userId )
+
+ CommunityUserInfo ornull userInfo = GetCommunityUserInfo( hardware, userId )
+ if ( !userInfo )
+ {
+ wait 0.05
+ }
+ else
+ {
+ printt( "Got user info for user " + userId + " on hardware " + hardware )
+ expect CommunityUserInfo( userInfo )
+
+ printt( "User " + userId + " is in " + userInfo.numCommunities + " communities" )
+
+ foreach ( chatroomUI in file.chatroomUIs )
+ FillInUserInfoPanel( chatroomUI.userInfoPanel, userInfo )
+ break
+ }
+ }
+}
+
+
+void function UICodeCallback_ShowUserInfo( string hardware, string userId )
+{
+ Signal( uiGlobal.signalDummy, "StopUserInfoLookups" )
+
+ // printt( "Showing user info for UID " + userId + " on hardware " + hardware )
+
+ file.userInfoPanel_userId = userId
+ file.userInfoPanel_hardware = hardware
+
+ if ( hardware == "" && userId == "0" )
+ {
+ foreach ( chatroomUI in file.chatroomUIs )
+ Hud_Hide( chatroomUI.userInfoPanel.Panel )
+
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ // Hud_SetWidth( chatrooUI.chatroomWidget, Hud_GetBaseWidth( chatrooUI.chatroomWidget ) )
+ Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) )
+ Hud_Show( chatroomUI.chatroomDivider )
+ // Hud_SetWidth( chatrooUI.chatroomHeader, Hud_GetBaseWidth( chatrooUI.chatroomHeader ) )
+ // Hud_SetWidth( chatrooUI.chatroomMode, Hud_GetBaseWidth( chatrooUI.chatroomBackground ) )
+ #if CONSOLE_PROG
+ Hud_Show( chatroomUI.chatroomHintText )
+ #else
+ Hud_Show( chatroomUI.chatroomTextChat )
+ #endif
+ }
+ }
+ else
+ {
+ foreach ( chatroomUI in file.chatroomUIs )
+ Hud_Show( chatroomUI.userInfoPanel.Panel )
+
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ // Hud_SetWidth( chatroomUI.chatroomWidget, Hud_GetBaseWidth( chatroomUI.chatroomWidget ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 )
+ Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 )
+ Hud_Hide( chatroomUI.chatroomDivider )
+ // Hud_SetWidth( chatroomUI.chatroomHeader, Hud_GetBaseWidth( chatroomUI.chatroomHeader ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 )
+ // Hud_SetWidth( chatroomUI.chatroomMode, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 )
+ #if CONSOLE_PROG
+ Hud_Hide( chatroomUI.chatroomHintText )
+ #else
+ Hud_Hide( chatroomUI.chatroomTextChat )
+ #endif
+ }
+
+ thread GetUserInfoThread( hardware, userId )
+ }
+}
+
+void function FindRemoteMatchInfoWidgetsInPanel( RemoteMatchInfoPanel infostruct, var panel )
+{
+ infostruct.PlaylistName = Hud_GetChild( panel, "PlaylistName" )
+ infostruct.MapName = Hud_GetChild( panel, "MapName" )
+ infostruct.ModeName = Hud_GetChild( panel, "ModeName" )
+ infostruct.TimeLeft = Hud_GetChild( panel, "TimeLeft" )
+ infostruct.ScoreLimit = Hud_GetChild( panel, "ScoreLimit" )
+ infostruct.Team1Score = Hud_GetChild( panel, "Team1Score" )
+ infostruct.Team2Score = Hud_GetChild( panel, "Team2Score" )
+ for ( int i = 1; i <= 2; i++ )
+ {
+ array<RemoteMatchPlayerInfoRow> teamPlayers
+ if ( i == 1 )
+ teamPlayers = infostruct.team1Players
+ else
+ teamPlayers = infostruct.team2Players
+
+ for ( int j = 1; j <= 8; j++ )
+ {
+ RemoteMatchPlayerInfoRow teamPlayer
+ string key = "Team" + i + "Player" + j
+ teamPlayer.playerPanel = Hud_GetChild( panel, key )
+ teamPlayer.name = Hud_GetChild( teamPlayer.playerPanel, "Name" )
+ teamPlayer.score = Hud_GetChild( teamPlayer.playerPanel, "Score" )
+ teamPlayer.kills = Hud_GetChild( teamPlayer.playerPanel, "Kills" )
+ teamPlayer.deaths = Hud_GetChild( teamPlayer.playerPanel, "Deaths" )
+ teamPlayers.append( teamPlayer )
+ }
+ }
+}
+
+int function RemoteMatchInfoPlayerSort( RemoteClientInfoFromMatchInfo a, RemoteClientInfoFromMatchInfo b )
+{
+ return ( b.score - a.score )
+}
+
+void function FillInRemoteMatchInfoPanel( RemoteMatchInfo info, RemoteMatchInfoPanel panel )
+{
+ Hud_Show( panel.panel )
+
+ Hud_SetText( panel.PlaylistName, GetPlaylistDisplayName( info.playlist ) )
+ Hud_SetText( panel.MapName, Localize( "#" + info.map ) )
+
+ string modeName
+
+ if ( IsFDMode( info.gamemode ) )
+ {
+ modeName = "#GAMEMODE_COOP"
+ // HACK because fd has multiple gamemodes in playlists
+ }
+ else
+ {
+ modeName = GAMETYPE_TEXT[ info.gamemode ]
+ }
+
+ if ( IsFullyConnected() )
+ modeName = GetGameModeDisplayName( info.gamemode )
+
+ Hud_SetText( panel.ModeName, modeName )
+ int minsLeft = info.timeLeftSecs / 60
+ int secsLeft = info.timeLeftSecs % 60
+ string timeLeft = "" + minsLeft
+ if ( secsLeft < 10 )
+ timeLeft = timeLeft + ":0" + secsLeft
+ else
+ timeLeft = timeLeft + ":" + secsLeft
+ Hud_SetText( panel.TimeLeft, timeLeft )
+ string scoreLimit = "" + info.maxScore
+ Hud_SetText( panel.ScoreLimit, scoreLimit )
+ string imcScore = "" + info.teamScores[TEAM_IMC]
+ string milScore = "" + info.teamScores[TEAM_MILITIA]
+ Hud_SetText( panel.Team1Score, imcScore )
+ Hud_SetText( panel.Team2Score, milScore )
+
+ int team1PlayerCount = 0
+ int team2PlayerCount = 0
+
+ info.clients.sort( RemoteMatchInfoPlayerSort )
+
+ for ( int i = 0; i < info.clients.len(); i++ )
+ {
+ RemoteMatchPlayerInfoRow teamPlayer
+ if ( info.clients[i].teamNum == TEAM_IMC )
+ {
+ if ( team1PlayerCount >= panel.team1Players.len() )
+ {
+ printt( "too many team players" )
+ continue
+ }
+
+ teamPlayer = panel.team1Players[team1PlayerCount]
+ team1PlayerCount++
+ }
+ else if ( info.clients[i].teamNum == TEAM_MILITIA )
+ {
+ if ( team2PlayerCount >= panel.team2Players.len() )
+ {
+ printt( "too many team players" )
+ continue
+ }
+
+ teamPlayer = panel.team2Players[team2PlayerCount]
+ team2PlayerCount++
+ }
+ else
+ {
+ printt( "Unhandled player team " + info.clients[i].teamNum )
+ continue
+ }
+ string score = "" + info.clients[i].score
+ string kills = "" + info.clients[i].kills
+ string deaths = "" + info.clients[i].deaths
+
+ Hud_Hide( teamPlayer.playerPanel ) // not enough room for these
+ Hud_SetText( teamPlayer.name, info.clients[i].name )
+ Hud_SetText( teamPlayer.score, score )
+ Hud_SetText( teamPlayer.kills, kills )
+ Hud_SetText( teamPlayer.deaths, deaths )
+ }
+ for ( int i = team1PlayerCount; i < panel.team1Players.len(); i++ )
+ Hud_Hide( panel.team1Players[i].playerPanel )
+ for ( int i = team2PlayerCount; i < panel.team2Players.len(); i++ )
+ Hud_Hide( panel.team2Players[i].playerPanel )
+
+}
+
+void function RemoteMatchInfoVisibilityThread()
+{
+ EndSignal( uiGlobal.signalDummy, "StopRemoteMatchInfoThread" )
+ wait 2
+ foreach ( chatroomUI in file.chatroomUIs )
+ Hud_Hide( chatroomUI.remoteMatchInfoPanelWidgets.panel )
+}
+
+void function UICodeCallback_RemoteMatchInfoUpdated()
+{
+ printt( "Remote Match Info Updated!" )
+
+ RemoteMatchInfo info = GetRemoteMatchInfo()
+ foreach ( chatroomUI in file.chatroomUIs )
+ FillInRemoteMatchInfoPanel( info, chatroomUI.remoteMatchInfoPanelWidgets )
+
+ Signal( uiGlobal.signalDummy, "StopRemoteMatchInfoThread" )
+ thread RemoteMatchInfoVisibilityThread()
+}
+
+void function Chatroom_GlobalInit()
+{
+ RegisterSignal( "StopRemoteMatchInfoThread" )
+}
+
+bool function IsSelectedUserStreaming()
+{
+ if ( !ChatroomHasFocus() )
+ return false
+ return file.currentUserIsStreaming
+}
+
+void function InitChatroom( var parentMenu )
+{
+ RegisterSignal( "StopUserInfoLookups" )
+
+ file.communityChatroomMode = "chatroom"
+
+ var menu = Hud_GetChild( parentMenu, "ChatroomPanel" )
+
+ ChatroomWidget chatroomUI
+ file.chatroomUIs.append( chatroomUI )
+
+ chatroomUI.chatroomPanel = menu
+ chatroomUI.chatroomWidget = Hud_GetChild( menu, "ChatRoom" )
+ chatroomUI.chatroomTextChat = Hud_GetChild( menu, "ChatRoomTextChat" )
+ chatroomUI.chatroomBackground = Hud_GetChild( menu, "ChatbarBackground" )
+ chatroomUI.chatroomDivider = Hud_GetChild( menu, "ChatroomHeaderBackground" )
+ chatroomUI.chatroomHappyHour = Hud_GetChild( menu, "HappyHourTimeLeft" )
+ chatroomUI.chatroomMode = Hud_GetChild( menu, "CommunityChatRoomMode" )
+
+ var remoteMatchInfoPanel = Hud_GetChild( parentMenu, "MatchDetails" )
+ chatroomUI.remoteMatchInfoPanelWidgets.panel = remoteMatchInfoPanel
+ FindRemoteMatchInfoWidgetsInPanel( chatroomUI.remoteMatchInfoPanelWidgets, remoteMatchInfoPanel )
+
+ chatroomUI.userInfoPanel.Panel = Hud_GetChild( parentMenu, "UserInfo" )
+ chatroomUI.userInfoPanel.Name = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Name" )
+ chatroomUI.userInfoPanel.Kills = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Kills" )
+ chatroomUI.userInfoPanel.Wins = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Wins" )
+ chatroomUI.userInfoPanel.Losses = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Losses" )
+ chatroomUI.userInfoPanel.Deaths = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Deaths" )
+ chatroomUI.userInfoPanel.XP = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "XP" )
+ chatroomUI.userInfoPanel.callsignCard = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "CallsignCard" )
+
+ // chatroomUI.userInfoPanel.ViewUserCardButton = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "ViewUserCard" )
+
+ for ( int i = 0; i < 6; i++ )
+ {
+ if ( !Hud_HasChild( chatroomUI.userInfoPanel.Panel, "Community" + i + "Label" ) )
+ break;
+ var communityLabel = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Community" + i + "Label" )
+ var communityName = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Community" + i )
+ Assert( communityName, "found Community" + i + "Label, but no Community" + i + " in userInfo panel" );
+ chatroomUI.userInfoPanel.communityLabels.append( communityLabel )
+ chatroomUI.userInfoPanel.communityNames.append( communityName )
+ }
+
+ chatroomUI.communityChatroomModeButton = Hud_GetChild( menu, "CommunityChatRoomMode" )
+#if CONSOLE_PROG
+ chatroomUI.chatroomHintText = Hud_GetChild( menu, "TextChatHintForConsole" )
+#endif
+ chatroomUI.happyHourTimeLeft = Hud_GetChild( menu, "HappyHourTimeLeft" )
+ // Hud_EnableKeyBindingIcons( chatroomUI.communityChatroomModeButton )
+
+ OpenInviteUI openInviteUI = chatroomUI.openInviteUI
+ openInviteUI.openInvitePanel = Hud_GetChild( parentMenu, "OpenInvitePanel" )
+ openInviteUI.openInviteMessage = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteMessage" )
+ openInviteUI.openInviteCountdownText = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteCountdownText" )
+
+ var openInviteBackground = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteBox" )
+ RuiSetColorAlpha( Hud_GetRui( openInviteBackground ), "backgroundColor", <0, 0, 0>, 0.9 )
+
+ int i = 0;
+ while ( i < 8 )
+ {
+ int count = i + 1
+ var widget = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInvitePlayer" + count )
+ if ( !widget )
+ break
+ openInviteUI.openInvitePlayerSlots.append( widget )
+ i++
+ }
+ for ( int idx = 0; idx < 9; ++idx )
+ {
+ string widgetName = ("OpenInvitePlaylist" + format( "%02d", idx ))
+ var widget = Hud_GetChild( openInviteUI.openInvitePanel, widgetName )
+ openInviteUI.openInvitePlaylistSlots.append( widget )
+ i++
+ }
+
+ openInviteUI.openInviteJoinButton = Hud_GetChild( openInviteUI.openInvitePanel, "JoinOpenInviteButton" )
+ Hud_EnableKeyBindingIcons( openInviteUI.openInviteJoinButton )
+
+ AddEventHandlerToButton( openInviteUI.openInvitePanel, "JoinOpenInviteButton", UIE_CLICK, JoinOpenInvite_OnClick )
+ AddEventHandlerToButton( openInviteUI.openInvitePanel, "OpenInviteCountdownText", UIE_CLICK, JoinOpenInvite_OnClick )
+ AddEventHandlerToButton( openInviteUI.openInvitePanel, "OpenInviteMessageButtonOverlay", UIE_CLICK, JoinOpenInvite_OnClick )
+
+ AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_LEFT, "#LB_MUTEROOM", "#MUTEROOM", MuteRoom, ChatroomIsNotMuted )
+ AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_LEFT, "#LB_UNMUTEROOM", "#UNMUTEROOM", UnmuteRoom, ChatroomIsMuted )
+ AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_DESTROY_FOOTER", "#OPENINVITE_DESTROY", LeaveOpenInviteButton, CanDestroyOpenInvite )
+ AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_JOIN_FOOTER", "#OPENINVITE_JOIN", JoinOpenInvite, CanJoinOpenInvite )
+ AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_LEAVE_FOOTER", "#OPENINVITE_LEAVE", LeaveOpenInviteButton, CanLeaveOpenInvite )
+ AddMenuFooterOption( parentMenu, BUTTON_A, "#BUTTON_VIEW_PLAYER_PROFILE", "#MOUSE1_VIEW_PROFILE", null, IsChatroomViewProfileValid )
+ AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_RIGHT, "#COMMUNITY_RB_CHATROOM_VIEWSTREAM", "#COMMUNITY_CHATROOM_VIEWSTREAM", null, IsSelectedUserStreaming )
+ AddMenuFooterOption( parentMenu, BUTTON_X, "#BUTTON_MUTE", "#MOUSE2_MUTE", null, ChatroomHasFocus )
+
+ UpdateChatroomUI()
+
+ Hud_AddEventHandler( chatroomUI.chatroomWidget, UIE_LOSE_FOCUS, LostFocus )
+ Hud_AddEventHandler( chatroomUI.chatroomWidget, UIE_GET_FOCUS, GotFocus )
+}
+
+void function bsupdate()
+{
+ ShowOpenInvite()
+
+ OpenInvite openInvite
+ openInvite.amILeader = false
+ openInvite.amIInThis = false
+ openInvite.numSlots = 5
+ openInvite.numClaimedSlots = 1
+
+ string inviteString = openInvite.amILeader ? "#OPENINVITE_SENDER_PLAYLIST" : "#OPENINVITE_PLAYLIST"
+
+ float endTime = Time() + 10.0
+ while ( Time() < endTime )
+ {
+ openInvite.timeLeft = endTime - Time()
+
+ int remainingTime = int( ceil( endTime - Time() ) )
+ UpdateOpenInvites( openInvite, inviteString, "scriptacus", "Bounty Hunt", remainingTime )
+
+ if ( remainingTime == 8 )
+ openInvite.numClaimedSlots = 2
+
+ if ( remainingTime == 6 )
+ openInvite.numClaimedSlots = 4
+
+ //if ( remainingTime == 5 )
+ // openInvite.numClaimedSlots = 5
+ //
+ //if ( remainingTime == 4 )
+ // openInvite.numClaimedSlots = 6
+
+ WaitFrame()
+ }
+}
+
+void function UpdateOpenInvites( OpenInvite openInvite, string message, string param1, string ornull param2, int countdown )
+{
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ if ( param2 )
+ Hud_SetText( chatroomUI.openInviteUI.openInviteMessage, message, param1, param2 );
+ else
+ Hud_SetText( chatroomUI.openInviteUI.openInviteMessage, message, param1 );
+
+ string countdownText = "" + countdown
+// Hud_SetText( chatroomUI.openInviteUI.openInviteCountdownText, "#OPENINVITE_COUNTDOWN", countdownText )
+ var countdownRui = Hud_GetRui( chatroomUI.openInviteUI.openInviteCountdownText )
+ RuiSetFloat( countdownRui, "timeLeft", openInvite.timeLeft )
+ RuiSetFloat( countdownRui, "maxTime", GetConVarFloat( "openinvite_duration_default" ) )
+
+ bool started = openInvite.timeLeft <= 0 || openInvite.numFreeSlots == 0
+
+ if ( started )
+ {
+ Hud_Hide( chatroomUI.openInviteUI.openInviteJoinButton )
+ }
+ else if ( CanDestroyOpenInvite() )
+ {
+ Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton )
+ if ( IsControllerModeActive() )
+ SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_DESTROY" )
+ else
+ SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_DESTROY" )
+ }
+ else if ( CanLeaveOpenInvite() )
+ {
+ Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton )
+ if ( IsControllerModeActive() )
+ SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_LEAVE" )
+ else
+ SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_LEAVE" )
+ }
+ else if ( CanJoinOpenInvite() )
+ {
+ Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton )
+ if ( IsControllerModeActive() )
+ SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_JOIN" )
+ else
+ SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_JOIN" )
+ }
+
+ string myUID = GetPlayerUID()
+ int i = 0
+ foreach ( player in chatroomUI.openInviteUI.openInvitePlayerSlots )
+ {
+ var rui = Hud_GetRui( player )
+ Hud_Show( player )
+
+ if ( i >= openInvite.numSlots )
+ {
+ //Hud_Hide( player )
+ RuiSetBool( rui, "isEnabled", false )
+ RuiSetBool( rui, "hasPlayer", false )
+ }
+ else
+ {
+ CallsignIcon callsignIcon
+ bool isMe = false
+ // asset playerImage
+
+ if ( i < openInvite.numClaimedSlots )
+ {
+ PartyMember member = openInvite.members[i]
+ isMe = ( member.uid == myUID )
+ if ( isMe )
+ {
+ if ( GetUIPlayer() != null ) // this can happen sometimes after a resolution/windowed mode change
+ callsignIcon = PlayerCallsignIcon_GetActive( GetUIPlayer() )
+ else
+ callsignIcon = CallsignIcon_GetByRef( "gc_icon_happyface" )
+ }
+ else
+ {
+ callsignIcon = CallsignIcon_GetByIndex( member.callsignIdx )
+ }
+ }
+ else
+ {
+ callsignIcon = CallsignIcon_GetByRef( "gc_icon_happyface" )
+ }
+
+ Hud_Show( player )
+ RuiSetBool( rui, "isEnabled", true )
+
+ RuiSetBool( rui, "hasPlayer", i < openInvite.numClaimedSlots )
+ RuiSetBool( rui, "isViewPlayer", isMe )
+ RuiSetImage( rui, "playerImage", callsignIcon.image )
+
+ //if ( i < openInvite.numClaimedSlots )
+ // Hud_SetImage( player, $"ui/menu/main_menu/openinvite_occupiedslot" )
+ //else
+ // Hud_SetImage( player, $"ui/menu/main_menu/openinvite_emptyslot" )
+ }
+ i++
+ }
+
+ array<string> checklistPlaylists = GetChecklistPlaylistsArray()
+
+ if ( Lobby_IsFDMode() )
+ checklistPlaylists = GetFDDifficultyArray()
+
+ array<string> invitePlaylists = split( openInvite.playlistName, "," )
+ bool shouldShowCheckboxPlaylists = true
+ if ( !MixtapeMatchmakingIsEnabled() )
+ shouldShowCheckboxPlaylists = false
+ else if ( invitePlaylists.len() == 0 )
+ shouldShowCheckboxPlaylists = false
+ else if ( (invitePlaylists.len() == 1) && (!checklistPlaylists.contains( invitePlaylists[0] )) )
+ shouldShowCheckboxPlaylists = false
+
+ int playlistSlotCount = chatroomUI.openInviteUI.openInvitePlaylistSlots.len()
+ for( int idx = 0; idx < playlistSlotCount; ++idx )
+ {
+ var slot = chatroomUI.openInviteUI.openInvitePlaylistSlots[idx]
+
+ string thisPlaylistName = idx < checklistPlaylists.len() ? checklistPlaylists[idx] : ""
+ if ( (thisPlaylistName == "") || !shouldShowCheckboxPlaylists )
+ {
+ Hud_Hide( slot )
+ continue
+ }
+
+ Hud_Show( slot )
+ var slotRui = Hud_GetRui( slot )
+ asset playlistThumbnail = GetPlaylistThumbnailImage( thisPlaylistName )
+ RuiSetImage( slotRui, "checkImage", playlistThumbnail )
+
+ bool isChecked = invitePlaylists.contains( thisPlaylistName )
+ RuiSetBool( slotRui, "isChecked", isChecked )
+
+ string abbr = GetPlaylistVarOrUseValue( thisPlaylistName, "abbreviation", "" )
+ RuiSetString( slotRui, "abbreviation", Localize( abbr ) )
+ }
+ }
+}
+
+
+void function HideOpenInvite()
+{
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ Hud_Hide( chatroomUI.openInviteUI.openInvitePanel )
+ }
+}
+
+void function ShowOpenInvite()
+{
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ Hud_Show( chatroomUI.openInviteUI.openInvitePanel )
+ }
+}
+
+
+void function LostFocus( panel )
+{
+ Signal( uiGlobal.signalDummy, "StopUserInfoLookups" )
+ printt( "Chatroom lost focus" )
+ foreach ( chatroomUI in file.chatroomUIs )
+ Hud_Hide( chatroomUI.userInfoPanel.Panel )
+ file.hasFocus = false
+
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ // Hud_SetWidth( chatrooUI.chatroomWidget, Hud_GetBaseWidth( chatrooUI.chatroomWidget ) )
+ Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) )
+ Hud_Show( chatroomUI.chatroomDivider )
+ // Hud_SetWidth( chatrooUI.chatroomMode, Hud_GetBaseWidth( chatrooUI.chatroomBackground ) )
+ Hud_Show( chatroomUI.chatroomTextChat )
+ }
+}
+
+
+void function OnChatroomWidgetGetFocus( var widget )
+{
+}
+
+void function OnChatroomWidgetLoseFocus( var widget )
+{
+}
+
+void function GotFocus( panel )
+{
+ printt( "Chatroom got focus" )
+ file.hasFocus = true
+
+ foreach ( chatroomUI in file.chatroomUIs )
+ {
+ // Hud_SetWidth( chatroomUI.chatroomWidget, Hud_GetBaseWidth( chatroomUI.chatroomWidget ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 )
+ Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 )
+ Hud_Hide( chatroomUI.chatroomDivider )
+ // Hud_SetWidth( chatroomUI.chatroomMode, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 )
+ Hud_Hide( chatroomUI.chatroomTextChat )
+ }
+}
+
+bool function IsChatroomViewProfileValid()
+{
+ #if PC_PROG
+ if ( !Origin_IsOverlayAvailable() )
+ return false
+ #endif // PC_PROG
+
+ return ChatroomHasFocus()
+}
+
+bool function ChatroomHasFocus()
+{
+ return file.hasFocus
+}
+
+bool function ChatroomIsMuted()
+{
+ if ( IsControllerModeActive() )
+ return ChatroomHasFocus() && IsChatroomMuted()
+ return IsChatroomMuted()
+}
+
+bool function ChatroomIsNotMuted()
+{
+ if ( IsControllerModeActive() )
+ return ChatroomHasFocus() && !IsChatroomMuted()
+ return !IsChatroomMuted()
+}
+
+void function MuteRoom( var button )
+{
+ printt( "muting the room" )
+ ClientCommand( "muteroom" )
+}
+
+void function UnmuteRoom( var button )
+{
+ printt( "unmuting the room" )
+ ClientCommand( "unmuteroom" )
+}
+
+void function UpdateChatroomThread()
+{
+ EndSignal( uiGlobal.signalDummy, "OnCloseLobbyMenu" )
+ while ( true )
+ {
+ UpdateChatroomUI()
+ wait 30
+ }
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut
new file mode 100644
index 000000000..89479a76c
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut
@@ -0,0 +1,170 @@
+untyped
+
+global function InitEditPilotLoadoutsMenu
+
+struct
+{
+ var menu
+ var loadoutPanel
+ var[NUM_PERSISTENT_PILOT_LOADOUTS] loadoutHeaders
+ var[NUM_PERSISTENT_PILOT_LOADOUTS] activateButtons
+ bool enteringEdit = false
+ var unlockReq
+} file
+
+void function InitEditPilotLoadoutsMenu()
+{
+ file.menu = GetMenu( "EditPilotLoadoutsMenu" )
+ var menu = file.menu
+
+ AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnPilotLoadoutsMenu_Open )
+ AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnPilotLoadoutsMenu_Close )
+ AddMenuEventHandler( menu, eUIEvent.MENU_INPUT_MODE_CHANGED, OnPilotLoadoutsMenu_InputModeChanged )
+
+ for ( int i = 0; i < NUM_PERSISTENT_PILOT_LOADOUTS; i++ )
+ {
+ var activateButton = Hud_GetChild( menu, "Button" + i )
+ activateButton.s.rowIndex <- i
+ Hud_SetVisible( activateButton, true )
+ Hud_AddEventHandler( activateButton, UIE_CLICK, OnLoadoutButton_Activate )
+ Hud_AddEventHandler( activateButton, UIE_GET_FOCUS, OnLoadoutButton_Focused )
+ Hud_AddEventHandler( activateButton, UIE_LOSE_FOCUS, OnLoadoutButton_LostFocus )
+ file.activateButtons[i] = activateButton
+ }
+
+ Hud_SetFocused( file.activateButtons[0] )
+
+ file.loadoutPanel = Hud_GetChild( menu, "PilotLoadoutDisplay" )
+ file.unlockReq = Hud_GetChild( menu, "UnlockReq" )
+
+ AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" )
+ AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" )
+}
+
+void function OnPilotLoadoutsMenu_Open()
+{
+ entity player = GetUIPlayer()
+ if ( player == null )
+ return
+
+ RunMenuClientFunction( "ClearEditingPilotLoadoutIndex" )
+
+ int loadoutIndex = uiGlobal.pilotSpawnLoadoutIndex
+ UpdatePilotLoadoutButtons( loadoutIndex, file.activateButtons )
+ UpdatePilotLoadoutPanel( file.loadoutPanel, GetCachedPilotLoadout( loadoutIndex ) )
+ UI_SetPresentationType( ePresentationType.PILOT )
+
+ RefreshCreditsAvailable()
+}
+
+void function OnPilotLoadoutsMenu_Close()
+{
+ entity player = GetUIPlayer()
+ if ( player == null )
+ return
+
+ foreach ( i, button in file.activateButtons )
+ {
+ string pilotLoadoutRef = "pilot_loadout_" + ( i + 1 )
+ if ( !IsItemNew( player, pilotLoadoutRef ) )
+ continue
+
+ ClearNewStatus( button, pilotLoadoutRef )
+ }
+}
+
+void function OnPilotLoadoutsMenu_InputModeChanged()
+{
+ UpdatePilotLoadoutPanelBinds( file.loadoutPanel )
+}
+
+void function OnLoadoutButton_Focused( var button )
+{
+ int index = expect int( button.s.rowIndex )
+
+ // update the editingLoadoutIndex on focus so that it always matches
+ // with the pilot loadout panel
+ uiGlobal.editingLoadoutIndex = index
+ uiGlobal.editingLoadoutType = "pilot"
+
+ UpdatePilotLoadout( index )
+
+ string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 )
+ string unlockReq = GetItemUnlockReqText( pilotLoadoutRef )
+ RHud_SetText( file.unlockReq, unlockReq )
+}
+
+void function UpdatePilotLoadout( int loadoutIndex )
+{
+ PilotLoadoutDef loadout = GetCachedPilotLoadout( loadoutIndex )
+
+ UpdatePilotLoadoutPanel( file.loadoutPanel, loadout )
+ RunMenuClientFunction( "UpdatePilotModel", loadoutIndex )
+}
+
+void function OnLoadoutButton_Activate( var button )
+{
+ if ( !IsFullyConnected() )
+ return
+
+ if ( Hud_IsLocked( button ) )
+ {
+ int index = expect int ( button.s.rowIndex )
+ string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 )
+
+ array<var> buttons
+ foreach ( button in file.activateButtons )
+ {
+ buttons.append( button )
+ }
+
+ OpenBuyItemDialog( buttons, button, GetItemName( pilotLoadoutRef ), pilotLoadoutRef )
+ return
+ }
+
+ int loadoutIndex = expect int ( button.s.rowIndex )
+ SetEditLoadout( "pilot", loadoutIndex )
+
+ if ( EDIT_LOADOUT_SELECTS )
+ {
+ bool indexChanged = loadoutIndex != uiGlobal.pilotSpawnLoadoutIndex
+
+ if ( indexChanged )
+ {
+ EmitUISound( "Menu_LoadOut_Pilot_Select" )
+
+ if ( !IsLobby() )
+ uiGlobal.updatePilotSpawnLoadout = true
+ }
+
+ uiGlobal.pilotSpawnLoadoutIndex = loadoutIndex
+ ClientCommand( "RequestPilotLoadout " + loadoutIndex )
+ }
+
+ if ( PRE_RELEASE_DEMO && loadoutIndex < 3 )
+ {
+ UpdatePilotLoadoutButtons( loadoutIndex, file.activateButtons )
+ return
+ }
+
+ RunMenuClientFunction( "SetEditingPilotLoadoutIndex", loadoutIndex )
+ AdvanceMenu( GetMenu( "EditPilotLoadoutMenu" ) )
+}
+
+void function OnLoadoutButton_LostFocus( var button )
+{
+ entity player = GetUIPlayer()
+ if ( !IsValid( player ) )
+ return
+
+ int loadoutIndex = expect int ( button.s.rowIndex )
+ string pilotLoadoutRef = "pilot_loadout_" + ( loadoutIndex + 1 )
+ ClearNewStatus( button, pilotLoadoutRef )
+
+ if ( IsItemLocked( player, pilotLoadoutRef ) )
+ return
+
+ PilotLoadoutDef loadout = GetCachedPilotLoadout( loadoutIndex )
+ if ( (RefHasAnyNewSubitem( player, loadout.primary ) || RefHasAnyNewSubitem( player, loadout.secondary ) || RefHasAnyNewSubitem( player, loadout.weapon3 )) )
+ Hud_SetNew( button, true )
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut
index 2bef0e205..23dae99d5 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut
@@ -178,6 +178,8 @@ void function InitLobbyMenu()
AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" )
AddMenuFooterOption( menu, BUTTON_BACK, "#BACK_BUTTON_POSTGAME_REPORT", "#POSTGAME_REPORT", OpenPostGameMenu, IsPostGameMenuValid )
AddMenuFooterOption( menu, BUTTON_TRIGGER_RIGHT, "#R_TRIGGER_CHAT", "", null, IsVoiceChatPushToTalk )
+ // Client side progression toggle
+ AddMenuFooterOption( menu, BUTTON_Y, "#Y_BUTTON_TOGGLE_PROGRESSION", "#TOGGLE_PROGRESSION", ShowToggleProgressionDialog )
InitChatroom( menu )
@@ -226,6 +228,57 @@ void function InitLobbyMenu()
RegisterSignal( "LeaveParty" )
}
+void function ShowToggleProgressionDialog( var button )
+{
+ bool enabled = Progression_GetPreference()
+
+ DialogData dialogData
+ dialogData.menu = GetMenu( "AnnouncementDialog" )
+ dialogData.header = enabled ? "#PROGRESSION_TOGGLE_ENABLED_HEADER" : "#PROGRESSION_TOGGLE_DISABLED_HEADER"
+ dialogData.message = enabled ? "#PROGRESSION_TOGGLE_ENABLED_BODY" : "#PROGRESSION_TOGGLE_DISABLED_BODY"
+ dialogData.image = $"ui/menu/common/dialog_announcement_1"
+
+ AddDialogButton( dialogData, "#NO" )
+ AddDialogButton( dialogData, "#YES", enabled ? DisableProgression : EnableProgression )
+
+ OpenDialog( dialogData )
+}
+
+void function EnableProgression()
+{
+ Progression_SetPreference( true )
+
+ // update the cache just in case something changed
+ UpdateCachedLoadouts_Delayed()
+
+ DialogData dialogData
+ dialogData.menu = GetMenu( "AnnouncementDialog" )
+ dialogData.header = "#PROGRESSION_ENABLED_HEADER"
+ dialogData.message = "#PROGRESSION_ENABLED_BODY"
+ dialogData.image = $"ui/menu/common/dialog_announcement_1"
+
+ AddDialogButton( dialogData, "#OK" )
+
+ EmitUISound( "UI_Menu_Item_Purchased_Stinger" )
+
+ OpenDialog( dialogData )
+}
+
+void function DisableProgression()
+{
+ Progression_SetPreference( false )
+
+ DialogData dialogData
+ dialogData.menu = GetMenu( "AnnouncementDialog" )
+ dialogData.header = "#PROGRESSION_DISABLED_HEADER"
+ dialogData.message = "#PROGRESSION_DISABLED_BODY"
+ dialogData.image = $"ui/menu/common/dialog_announcement_1"
+
+ AddDialogButton( dialogData, "#OK" )
+
+ OpenDialog( dialogData )
+}
+
void function SetupComboButtonTest( var menu )
{
ComboStruct comboStruct = ComboButtons_Create( menu )
@@ -235,44 +288,21 @@ void function SetupComboButtonTest( var menu )
int buttonIndex = 0
file.playHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PLAY" )
- bool isModded = IsNorthstarServer()
-
-
- // this will be the server browser
- if ( isModded )
- {
- file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" )
- file.lobbyButtons.append( file.findGameButton )
- Hud_SetLocked( file.findGameButton, true )
- Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser )
- }
- else
- {
- file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" )
- file.lobbyButtons.append( file.findGameButton )
- Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate )
- }
+ // server browser
+ file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" )
+ file.lobbyButtons.append( file.findGameButton )
+ Hud_SetLocked( file.findGameButton, true )
+ Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser )
- // this is used for launching private matches now
- if ( isModded )
- {
- file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" )
- Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch )
- }
- else
- {
- file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" )
- Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed )
- }
+ // private match
+ file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" )
+ Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch )
file.inviteFriendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" )
Hud_AddEventHandler( file.inviteFriendsButton, UIE_CLICK, InviteFriendsIfAllowed )
-
- if ( isModded )
- {
- Hud_SetEnabled( file.inviteFriendsButton, false )
- Hud_SetVisible( file.inviteFriendsButton, false )
- }
+
+ Hud_SetEnabled( file.inviteFriendsButton, false )
+ Hud_SetVisible( file.inviteFriendsButton, false )
// file.toggleMenuModeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LOBBY_SWITCH_FD" )
// Hud_AddEventHandler( file.toggleMenuModeButton, UIE_CLICK, ToggleLobbyMode )
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut
index a45082c71..8c13955cc 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut
@@ -949,6 +949,7 @@ void function SendTextPanelChanges( var textPanel )
ThrowInvalidValue( "This setting is an integer, and only accepts whole numbers." )
Hud_SetText( textPanel, GetConVarString( c.conVar ) )
}
+ break
case "bool":
if ( newSetting != "0" && newSetting != "1" )
{
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 b757d089b..3d1cc15f8 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut
@@ -18,8 +18,8 @@ void function InitModesMenu()
AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" )
AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" )
- AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack, IsNorthstarServer )
- AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward, IsNorthstarServer )
+ AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack )
+ AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward )
}
void function OnOpenModesMenu()
@@ -58,13 +58,7 @@ void function UpdateVisibleModes()
else if( IsFDMode( modesArray[ i ] ) )
Hud_SetLocked( buttons[ i ], false )
else
- Hud_SetLocked( buttons[ i ], true )
-
- if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeIndex ] ) && !IsNorthstarServer() )
- {
- Hud_SetLocked( buttons[ i ], true )
- SetButtonRuiText( buttons[ i ], Localize( "#PRIVATE_MATCH_UNAVAILABLE", Localize( GetGameModeDisplayName( modesArray[ modeIndex ] ) ) ) )
- }
+ Hud_SetLocked( buttons[ i ], true )
}
}
@@ -92,9 +86,7 @@ void function ModeButton_GetFocus( var button )
string mapName = PrivateMatch_GetSelectedMap()
bool mapSupportsMode = PrivateMatch_IsValidMapModeCombo( mapName, modeName )
- if ( !mapSupportsMode && !IsNorthstarServer() )
- Hud_SetText( nextModeDesc, Localize( "#PRIVATE_MATCH_MODE_NO_MAP_SUPPORT", Localize( GetGameModeDisplayName( modeName ) ), Localize( GetMapDisplayName( mapName ) ) ) )
- else if ( IsFDMode( modeName ) ) // HACK!
+ if ( IsFDMode( modeName ) ) // HACK!
Hud_SetText( nextModeDesc, Localize( "#FD_PLAYERS_DESC", Localize( GetGameModeDisplayHint( modeName ) ) ) )
else
Hud_SetText( nextModeDesc, GetGameModeDisplayHint( modeName ) )
@@ -116,7 +108,7 @@ void function ModeButton_Click( var button )
// on modded servers set us to the first map for that mode automatically
// need this for coliseum mainly which is literally impossible to select without this
- if ( IsNorthstarServer() && !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeID ] ) )
+ if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeID ] ) )
ClientCommand( "SetCustomMap " + GetPrivateMatchMapsForMode( modeName )[ 0 ] )
// set it
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 7ea8134a8..efc8d66ce 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
@@ -1059,15 +1059,39 @@ void function ThreadedAuthAndConnectToServer( string password = "" )
if ( NSWasAuthSuccessful() )
{
- bool modsChanged
+ bool modsChanged = false
- // unload mods we don't need, load necessary ones and reload mods before connecting
+ // disable all RequiredOnClient mods that are not required by the server and are currently enabled
+ foreach ( string modName in NSGetModNames() )
+ {
+ if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) )
+ {
+ // find the mod name in the list of server required mods
+ bool found = false
+ foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods )
+ {
+ if (mod.name == modName)
+ {
+ found = true
+ break
+ }
+ }
+ // if we didnt find the mod name, disable the mod
+ if (!found)
+ {
+ modsChanged = true
+ NSSetModEnabled( modName, false )
+ }
+ }
+ }
+
+ // enable all RequiredOnClient mods that are required by the server and are currently disabled
foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods )
{
- if ( NSIsModRequiredOnClient( mod.name ) )
+ if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name ))
{
- modsChanged = modsChanged || NSIsModEnabled( mod.name ) != file.lastSelectedServer.requiredMods.contains( mod )
- NSSetModEnabled( mod.name, file.lastSelectedServer.requiredMods.contains( mod ) )
+ modsChanged = true
+ NSSetModEnabled( mod.name, true )
}
}
@@ -1250,10 +1274,16 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call
file.connectCallbacks.fastremovebyvalue( callback )
}
-void function TriggerConnectToServerCallbacks()
+void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null )
{
+ ServerInfo server;
+ if (targetServer == null)
+ {
+ targetServer = file.lastSelectedServer
+ }
+
foreach( callback in file.connectCallbacks )
{
- callback( file.lastSelectedServer )
+ callback( expect ServerInfo( targetServer ) )
}
}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut
new file mode 100644
index 000000000..f0139e04e
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut
@@ -0,0 +1,300 @@
+
+global function UpdatePilotLoadoutPanel
+global function UpdatePilotLoadoutPanelBinds
+global function UpdatePilotLoadoutButtons
+global function UpdatePilotItemButton
+
+void function UpdatePilotLoadoutButtons( int selectedIndex, var[NUM_PERSISTENT_PILOT_LOADOUTS] buttons, bool focusSelected = true )
+{
+ entity player = GetUIPlayer()
+ if ( player == null )
+ return
+
+ int numLoadouts = GetAllCachedPilotLoadouts().len()
+
+ // HACK: num_pilot_loadouts is just used to disable certain loadouts for FNF
+ int numLoadoutsForPlaylist = GetCurrentPlaylistVarInt( "num_pilot_loadouts", 0 )
+ if ( numLoadoutsForPlaylist > 0 )
+ numLoadouts = numLoadoutsForPlaylist
+
+ foreach ( index, button in buttons )
+ {
+ PilotLoadoutDef loadout = GetCachedPilotLoadout( index )
+ RHud_SetText( button, GetPilotLoadoutName( loadout ) )
+ Hud_SetPanelAlpha( button, 0 )
+
+ bool isSelected = ( index == selectedIndex ) ? true : false
+ Hud_SetSelected( button, isSelected )
+
+ string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 )
+ Hud_SetLocked( button, IsItemLocked( player, pilotLoadoutRef ) )
+
+ bool shouldShowNew = ButtonShouldShowNew( eItemTypes.FEATURE, pilotLoadoutRef )
+ if ( !shouldShowNew && (RefHasAnyNewSubitem( player, loadout.primary ) || RefHasAnyNewSubitem( player, loadout.secondary ) || RefHasAnyNewSubitem( player, loadout.weapon3 )) )
+ shouldShowNew = true
+
+ if ( IsItemLocked( player, pilotLoadoutRef ) )
+ shouldShowNew = false
+
+ Hud_SetNew( button, shouldShowNew )
+
+ RefreshButtonCost( button, pilotLoadoutRef )
+ }
+
+ if ( focusSelected )
+ Hud_SetFocused( buttons[ selectedIndex ] )
+}
+
+void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout )
+{
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalName" ), Localize( GetItemName( loadout.special ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryName" ), Localize( GetItemName( loadout.primary ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryName" ), Localize( GetItemName( loadout.secondary ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Name" ), Localize( GetItemName( loadout.weapon3 ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceName" ), Localize( GetItemName( loadout.ordnance ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "Kit1Name" ), Localize( GetItemName( loadout.passive1 ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "Kit2Name" ), Localize( GetItemName( loadout.passive2 ) ) )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "ExecutionName" ), Localize( GetItemName( loadout.execution ) ) )
+
+ UpdatePilotLoadoutPanelBinds( loadoutPanel )
+
+ var menu = Hud_GetParent( loadoutPanel )
+ array<var> buttons = GetElementsByClassname( menu, "PilotLoadoutPanelButtonClass" )
+
+ /*if ( button )
+ {
+ // TEMP disabled since Hud_GetChild( menu, "ButtonTooltip" ) will fail
+ //if ( HandleLockedMenuItem( menu, button ) )
+ // return
+ }*/
+ bool isEdit
+ if ( Hud_GetHudName( loadoutPanel ) == "PilotLoadoutButtons" ) // Edit menu
+ isEdit = true
+ else // Select menu
+ isEdit = false
+
+ foreach ( button in buttons )
+ UpdatePilotItemButton( button, loadout, isEdit )
+
+ var renameEditBox = Hud_GetChild( loadoutPanel, "RenameEditBox" )
+
+ asset pilotAppearanceImage = loadout.camoIndex > 0 ? CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.camoIndex ) ) : $"rui/menu/common/appearance_button_swatch"
+
+ asset primaryAppearanceImage
+ if ( loadout.primarySkinIndex == 0 ) // default skin
+ primaryAppearanceImage = $"rui/menu/common/appearance_button_swatch"
+ else if ( loadout.primarySkinIndex == 1 ) // camo
+ primaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.primaryCamoIndex ) )
+ else // warpaint skin
+ primaryAppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex, "primarySkinIndex" )
+
+ asset secondaryAppearanceImage
+ if ( loadout.secondarySkinIndex == 0 ) // default skin
+ secondaryAppearanceImage = $"rui/menu/common/appearance_button_swatch"
+ else if ( loadout.secondarySkinIndex == 1 ) // camo
+ secondaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.secondaryCamoIndex ) )
+ else // warpaint skin
+ secondaryAppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex, "secondarySkinIndex" )
+
+ asset weapon3AppearanceImage
+ if ( loadout.weapon3SkinIndex == 0 ) // default skin
+ weapon3AppearanceImage = $"rui/menu/common/appearance_button_swatch"
+ else if ( loadout.weapon3SkinIndex == 1 ) // camo
+ weapon3AppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.weapon3CamoIndex ) )
+ else // warpaint skin
+ weapon3AppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex, "weapon3SkinIndex" )
+
+ RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ), "camoImage", pilotAppearanceImage )
+ RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ), "camoImage", primaryAppearanceImage )
+ RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonSecondarySkin" ) ), "camoImage", secondaryAppearanceImage )
+ RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonWeapon3Skin" ) ), "camoImage", weapon3AppearanceImage )
+
+ array<var> nonItemElements
+ nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) )
+ nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonGender" ) )
+ nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) )
+ nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonSecondarySkin" ) )
+ nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonWeapon3Skin" ) )
+ nonItemElements.append( renameEditBox )
+
+ foreach ( elem in nonItemElements )
+ {
+ if ( isEdit )
+ Hud_Show( elem )
+ else
+ Hud_Hide( elem )
+ }
+ Hud_SetEnabled( renameEditBox, isEdit )
+}
+
+void function UpdatePilotItemButton( var button, PilotLoadoutDef loadout, bool isEdit )
+{
+ string propertyName = Hud_GetScriptID( button )
+ string itemRef = GetPilotLoadoutValue( loadout, propertyName )
+ int itemType = GetItemTypeFromPilotLoadoutProperty( propertyName )
+ asset image
+
+ ItemDisplayData parentItem
+
+ if ( itemType == eItemTypes.PILOT_PRIMARY_ATTACHMENT || itemType == eItemTypes.PILOT_PRIMARY_MOD || itemType == eItemTypes.PILOT_SECONDARY_MOD || itemType == eItemTypes.PILOT_WEAPON_MOD3 )
+ {
+ string parentProperty = GetParentLoadoutProperty( "pilot", propertyName )
+ Assert( parentProperty == "primary" || parentProperty == "secondary" || parentProperty == "weapon3" )
+
+ if ( parentProperty == "primary" )
+ parentItem = GetItemDisplayData( loadout.primary )
+ else if ( parentProperty == "secondary" )
+ parentItem = GetItemDisplayData( loadout.secondary )
+ else
+ parentItem = GetItemDisplayData( loadout.weapon3 )
+
+ bool isHiddenAttachment = false
+
+ if ( itemType == eItemTypes.PILOT_PRIMARY_ATTACHMENT )
+ {
+ // Disable attachment option for "special" primary weapons
+ if ( "menuCategory" in parentItem.i && ( expect int( parentItem.i.menuCategory ) == ePrimaryWeaponCategory.SPECIAL || expect int( parentItem.i.menuCategory ) == ePrimaryWeaponCategory.HANDGUN ) )
+ {
+ isHiddenAttachment = true
+
+ Hud_SetWidth( button, 0 )
+ Hud_SetPos( button, 0, 0 ) // Clear sibling offset
+ }
+ else
+ {
+ int defaultButtonWidth = int( ContentScaledX( 72 ) )
+ int defaultOffsetX = int( ContentScaledX( 6 ) )
+
+ Hud_SetWidth( button, defaultButtonWidth )
+ Hud_SetPos( button, defaultOffsetX, 0 )
+ }
+ }
+
+ if ( !isHiddenAttachment )
+ image = GetImage( itemType, parentItem.ref, itemRef )
+ }
+ else
+ {
+ image = GetImage( itemType, itemRef )
+ }
+
+ if ( itemType == eItemTypes.PILOT_PRIMARY || itemType == eItemTypes.PILOT_SECONDARY )
+ {
+ //if ( isEdit )
+ //{
+ // RuiSetString( Hud_GetRui( button ), "subText", "" )
+ // RuiSetFloat( Hud_GetRui( button ), "numSegments", 0 )
+ // RuiSetFloat( Hud_GetRui( button ), "filledSegments", 0 )
+ //}
+ //else
+ {
+ int currentXP = WeaponGetXP( GetLocalClientPlayer(), itemRef )
+ int numPips = WeaponGetNumPipsForXP( itemRef, currentXP )
+ int filledPips = WeaponGetFilledPipsForXP( itemRef, currentXP )
+ RuiSetString( Hud_GetRui( button ), "subText", WeaponGetDisplayGenAndLevelForXP( itemRef, currentXP ) )
+ RuiSetFloat( Hud_GetRui( button ), "numSegments", float( numPips ) )
+ RuiSetFloat( Hud_GetRui( button ), "filledSegments", float( filledPips ) )
+ }
+ }
+
+ var rui = Hud_GetRui( button )
+
+ if ( image == $"" )
+ {
+ RuiSetBool( rui, "isVisible", false )
+ Hud_SetEnabled( button, false )
+ }
+ else
+ {
+ RuiSetBool( rui, "isVisible", true )
+ RuiSetImage( rui, "buttonImage", image )
+
+ Hud_SetEnabled( button, true )
+ }
+
+ bool isLocked = false
+ bool shouldShowNew = false
+
+ // For unlock and subitem checks below, treat weapon3 as secondary
+ if ( propertyName == "weapon3Mod1" )
+ propertyName = "secondaryMod1"
+ else if ( propertyName == "weapon3Mod2" )
+ propertyName = "secondaryMod2"
+ else if ( propertyName == "weapon3Mod3" )
+ propertyName = "secondaryMod3"
+
+ string propertyRef = propertyName.tolower()
+
+ if ( !IsSubItemType( itemType ) )
+ {
+ if ( IsUnlockValid( propertyRef ) && IsItemLocked( GetUIPlayer(), propertyRef ) )
+ {
+ RefreshButtonCost( button, propertyRef )
+ isLocked = true
+ }
+ shouldShowNew = ButtonShouldShowNew( itemType, itemRef )
+ }
+ else
+ {
+ if ( IsUnlockValid( propertyRef, parentItem.ref ) && IsSubItemLocked( GetUIPlayer(), propertyRef, parentItem.ref ) )
+ {
+ RefreshButtonCost( button, propertyRef )
+ isLocked = true
+ }
+ shouldShowNew = ButtonShouldShowNew( itemType, itemRef, parentItem.ref )
+ }
+
+ Hud_SetLocked( button, isLocked )
+
+ if ( !shouldShowNew && IsUnlockValid( propertyRef, parentItem.ref ) )
+ shouldShowNew = ButtonShouldShowNew( GetSubitemType( parentItem.ref, propertyRef ), propertyRef, parentItem.ref )
+ Hud_SetNew( button, shouldShowNew )
+
+#if HAS_THREAT_SCOPE_SLOT_LOCK
+ if ( propertyName == "primaryMod2" )
+ {
+ string attatchmentRef = GetPilotLoadoutValue( loadout, "primaryAttachment" )
+ if ( attatchmentRef == "threat_scope" )
+ {
+ Hud_SetLocked( button, true )
+ RefreshButtonCost( button, propertyRef, "", 0, 0 )
+ Hud_SetNew( button, false )
+ }
+ }
+#endif
+}
+
+void function UpdatePilotLoadoutPanelBinds( var loadoutPanel )
+{
+ if ( IsControllerModeActive() )
+ {
+ //SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryBind" ), "%weaponCycle%" )
+ //SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryBind" ), "%weaponCycle%" )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Bind" ), Localize( "#WEAPON3_HOLD_HINT" ) )
+ }
+ else
+ {
+ //SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryBind" ), "%weaponSelectPrimary0%" )
+ //SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryBind" ), "%weaponSelectPrimary1%" )
+ SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Bind" ), Localize( "#WEAPON3_PRESS_HINT" ) )
+ }
+
+ //SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalBind" ), Localize( "%offhand1%" ) )
+ //SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceBind" ), Localize( "%offhand0%" ) )
+}
+
+asset function GetItemImageFromWeaponRefAndPersistenceValue(string weaponRef, int persistenceValue, string loadoutProperty)
+{
+ string skinRef = GetSkinRefFromWeaponRefAndPersistenceValue( weaponRef, persistenceValue )
+ if (!IsRefValid(skinRef))
+ {
+ if (uiGlobal.editingLoadoutIndex != -1)
+ {
+ printt( "Resetting invalid " + loadoutProperty + " for weapon " + weaponRef )
+ SetCachedLoadoutValue(GetUIPlayer(), "pilot", uiGlobal.editingLoadoutIndex, loadoutProperty, "0")
+ }
+ return $"rui/menu/common/appearance_button_swatch"
+ }
+
+ return GetItemImage( skinRef )
+}
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 d7c7442f4..e3c1f268e 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut
@@ -247,10 +247,7 @@ void function OnSelectMatchSettings_Activate( var button )
if ( Hud_IsLocked( button ) )
return
- if ( !IsNorthstarServer() )
- AdvanceMenu( GetMenu( "MatchSettingsMenu" ) )
- else
- AdvanceMenu( GetMenu( "CustomMatchSettingsCategoryMenu" ) )
+ AdvanceMenu( GetMenu( "CustomMatchSettingsCategoryMenu" ) )
}
void function SetupComboButtons( var menu, var navUpButton, var navDownButton )
@@ -274,13 +271,6 @@ void function SetupComboButtons( var menu, var navUpButton, var navDownButton )
file.matchSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_MATCH_SETTINGS" )
Hud_AddEventHandler( file.matchSettingsButton, UIE_CLICK, OnSelectMatchSettings_Activate )
- if ( !IsNorthstarServer() )
- {
- var friendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" )
- file.inviteFriendsButton = friendsButton
- Hud_AddEventHandler( friendsButton, UIE_CLICK, InviteFriendsIfAllowed )
- }
-
headerIndex++
buttonIndex = 0
file.customizeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_LOADOUTS" )
@@ -575,17 +565,12 @@ function UpdatePrivateMatchButtons()
Hud_SetLocked( file.selectMapButton, true )
Hud_SetLocked( file.selectModeButton, true )
Hud_SetLocked( file.matchSettingsButton, true )
-
- if ( !IsNorthstarServer() )
- Hud_SetLocked( file.inviteFriendsButton, true )
}
else
{
RHud_SetText( file.startMatchButton, "#START_MATCH" )
Hud_SetLocked( file.selectMapButton, false )
Hud_SetLocked( file.selectModeButton, false )
- if ( !IsNorthstarServer() )
- Hud_SetLocked( file.inviteFriendsButton, false )
string modeName = PrivateMatch_GetSelectedMode()
bool settingsLocked = IsFDMode( modeName )
@@ -648,7 +633,7 @@ function UpdateLobby()
{
float varOrigVal = float( GetCurrentPlaylistGamemodeByIndexVar( gamemodeIdx, varName, false ) )
float varOverrideVal = float( GetCurrentPlaylistGamemodeByIndexVar( gamemodeIdx, varName, true ) )
- if ( varOrigVal == varOverrideVal && !IsNorthstarServer() ) // stuff seems to break outside of northstar servers since we dont always use private_match playlist
+ if ( varOrigVal == varOverrideVal ) // stuff seems to break outside of northstar servers since we dont always use private_match playlist
continue
string label = Localize( MatchSettings_PlaylistVarLabels[varName] ) + ": "
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut b/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut
index 4b3d0f55e..f91231b6b 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut
@@ -202,7 +202,10 @@ void function UpdateOpenInvite_Thread()
void function UICodeCallback_OpenInviteUpdated()
{
- if ( file.openInviteVisible || IsNorthstarServer() )
+ // don't support on northstar
+ return
+
+ if ( file.openInviteVisible )
return
int currentPartySize = GetPartySize()
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
index eef19b5ee..c97c8cdce 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
@@ -531,7 +531,6 @@ void function OnPlayFDButton_Activate( var button ) // repurposed for launching
{
if ( !Hud_IsLocked( button ) )
{
- SetConVarBool( "ns_is_modded_server", true )
SetConVarString( "communities_hostname", "" ) // disable communities due to crash exploits that are still possible through it
NSTryAuthWithLocalServer()
thread TryAuthWithLocalServer()
@@ -601,7 +600,6 @@ void function OnPlayMPButton_Activate( var button )
{
Lobby_SetAutoFDOpen( false )
// Lobby_SetFDMode( false )
- SetConVarBool( "ns_is_modded_server", false )
thread file.mpButtonActivateFunc()
}
}
diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json
index f3f73fde3..93f371bd0 100644
--- a/Northstar.Custom/mod.json
+++ b/Northstar.Custom/mod.json
@@ -1,7 +1,7 @@
{
"Name": "Northstar.Custom",
"Description": "Custom content for Northstar: extra weapons, gamemodes, etc.",
- "Version": "1.14.0",
+ "Version": "1.19.0",
"LoadPriority": 1,
"RequiredOnClient": true,
"ConVars": [
@@ -39,6 +39,10 @@
"RunOn": "( CLIENT || SERVER ) && MP"
},
{
+ "Path": "weapons/mp_titanweapon_arc_cannon.nut",
+ "RunOn": "( CLIENT || SERVER ) && MP"
+ },
+ {
"Path": "gamemodes/sh_gamemode_chamber.nut",
"RunOn": "( CLIENT || SERVER ) && MP",
"ClientCallback": {
@@ -426,6 +430,10 @@
{
"Path": "sh_northstar_http_requests.gnut",
"RunOn": "CLIENT || SERVER || UI"
+ },
+ {
+ "Path": "sh_northstar_safe_io.gnut",
+ "RunOn": "CLIENT || SERVER || UI"
}
],
diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl
new file mode 100644
index 000000000..2fcc34390
--- /dev/null
+++ b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl
Binary files differ
diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl
new file mode 100644
index 000000000..137d985d6
--- /dev/null
+++ b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl
Binary files differ
diff --git a/Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl
new file mode 100644
index 000000000..ec9203182
--- /dev/null
+++ b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl
Binary files differ
diff --git a/Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl
new file mode 100644
index 000000000..498cf0e87
--- /dev/null
+++ b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl
Binary files differ
diff --git a/Northstar.Custom/mod/resource/northstar_custom_english.txt b/Northstar.Custom/mod/resource/northstar_custom_english.txt
index dbd3b106c..56f56e8df 100644
--- a/Northstar.Custom/mod/resource/northstar_custom_english.txt
+++ b/Northstar.Custom/mod/resource/northstar_custom_english.txt
Binary files differ
diff --git a/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt b/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt
index 0a7b19d23..85e915f69 100644
--- a/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt
+++ b/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt
Binary files differ
diff --git a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut
index ac9ffab37..37d4356f0 100644
--- a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut
@@ -188,7 +188,7 @@ BurnReward function BurnReward_GetRandom()
string ref = burn.allowedCards.getrandom().ref
#if SERVER || CLIENT
- if ( !EarnMeterMP_IsTitanEarnGametype() )
+ if ( Riff_TitanAvailability() == eTitanAvailability.Never )
ref = BurnMeter_GetNoTitansReplacement( ref )
if ( GetCurrentPlaylistVarInt( "featured_mode_all_ticks", 0 ) >= 1 )
@@ -211,7 +211,7 @@ string function GetSelectedBurnCardRef( entity player )
#endif
#if SERVER || CLIENT
- if ( !EarnMeterMP_IsTitanEarnGametype() )
+ if ( Riff_TitanAvailability() == eTitanAvailability.Never )
ref = BurnMeter_GetNoTitansReplacement( ref )
if ( GetCurrentPlaylistVarInt( "featured_mode_all_ticks", 0 ) >= 1 )
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut
index 850aa7b37..fa66c2f71 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut
@@ -13,8 +13,12 @@ global function FW_ReplaceMegaTurret
global function FW_IsPlayerInFriendlyTerritory
global function FW_IsPlayerInEnemyTerritory
+// Callbacks for mods to reduce harvester damage of modded weapons
+global function FW_AddHarvesterDamageSourceModifier
+global function FW_RemoveHarvesterDamageSourceModifier
+
// you need to deal this much damage to trigger "FortWarTowerDamage" score event
-const int FW_HARVESTER_DAMAGE_SEGMENT = 1500
+const int FW_HARVESTER_DAMAGE_SEGMENT = 5250
// basically needs to match "waves count - bosswaves count"
const int FW_MAX_LEVELS = 3
@@ -85,6 +89,9 @@ struct CampSpawnStruct
struct
{
array<HarvesterStruct> harvesters
+
+ // Stores damage source IDs and the modifier applied to them when they damage a harvester
+ table< int, float > harvesterDamageSourceMods
// save camp's info_target, we spawn camps after game starts, or player's first life won't show up correct camp icons
array<entity> camps
@@ -1738,13 +1745,14 @@ void function FW_createHarvester()
{
// imc havester spawn
fw_harvesterImc = SpawnHarvester( file.harvesterImc_info.GetOrigin(), file.harvesterImc_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_IMC )
+ fw_harvesterImc.harvester.SetArmorType( ARMOR_TYPE_HEAVY )
fw_harvesterImc.harvester.Minimap_SetAlignUpright( true )
fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_IMC, null )
fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null )
fw_harvesterImc.harvester.Minimap_SetHeightTracking( true )
fw_harvesterImc.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT )
fw_harvesterImc.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER )
- AddEntityCallback_OnDamaged( fw_harvesterImc.harvester, OnHarvesterDamaged )
+ AddEntityCallback_OnFinalDamaged( fw_harvesterImc.harvester, OnHarvesterDamaged )
AddEntityCallback_OnPostDamaged( fw_harvesterImc.harvester, OnHarvesterPostDamaged )
// imc havester settings
@@ -1763,13 +1771,14 @@ void function FW_createHarvester()
// mlt havester spawn
fw_harvesterMlt = SpawnHarvester( file.harvesterMlt_info.GetOrigin(), file.harvesterMlt_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_MILITIA )
+ fw_harvesterMlt.harvester.SetArmorType( ARMOR_TYPE_HEAVY )
fw_harvesterMlt.harvester.Minimap_SetAlignUpright( true )
fw_harvesterMlt.harvester.Minimap_AlwaysShow( TEAM_IMC, null )
fw_harvesterMlt.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null )
fw_harvesterMlt.harvester.Minimap_SetHeightTracking( true )
fw_harvesterMlt.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT )
fw_harvesterMlt.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER )
- AddEntityCallback_OnDamaged( fw_harvesterMlt.harvester, OnHarvesterDamaged )
+ AddEntityCallback_OnFinalDamaged( fw_harvesterMlt.harvester, OnHarvesterDamaged )
AddEntityCallback_OnPostDamaged( fw_harvesterMlt.harvester, OnHarvesterPostDamaged )
// mlt havester settings
@@ -1784,6 +1793,53 @@ void function FW_createHarvester()
// scores starts from 100, TeamScore means harvester health; TeamScore2 means shield bar
GameRules_SetTeamScore( TEAM_IMC , 100 )
GameRules_SetTeamScore2( TEAM_IMC , 100 )
+
+ InitHarvesterDamageMods()
+}
+
+void function FW_AddHarvesterDamageSourceModifier( int id, float mod )
+{
+ if ( !( id in file.harvesterDamageSourceMods ) )
+ file.harvesterDamageSourceMods[id] <- 1.0
+
+ file.harvesterDamageSourceMods[id] *= mod
+}
+
+void function FW_RemoveHarvesterDamageSourceModifier( int id, float mod )
+{
+ if ( !( id in file.harvesterDamageSourceMods ) )
+ return
+
+ file.harvesterDamageSourceMods[id] /= mod
+
+ if ( file.harvesterDamageSourceMods[id] == 1.0 )
+ delete file.harvesterDamageSourceMods[id]
+}
+
+void function InitHarvesterDamageMods()
+{
+ // Damage balancing
+ const float CORE_DAMAGE_FRAC = 0.67
+ const float NUKE_EJECT_DAMAGE_FRAC = 0.25
+ const float DOT_DAMAGE_FRAC = 0.5
+
+ // Core balancing
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_laser_cannon, CORE_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_salvo_core, CORE_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_flightcore_rockets, CORE_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_shift_core, CORE_DAMAGE_FRAC )
+ // Flame Core is not included since its single target damage is low compared to the others
+
+ // Nuke eject balancing
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.damagedef_nuclear_core, NUKE_EJECT_DAMAGE_FRAC )
+
+ // Damage over time balancing
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_dumbfire_rockets, DOT_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_meteor_thermite, DOT_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_flame_wall, DOT_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanability_slow_trap, DOT_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_flame_wave_secondary, DOT_DAMAGE_FRAC )
+ FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_heat_shield, DOT_DAMAGE_FRAC )
}
// this function can't handle specific damageSourceID, such as plasma railgun, but is the best to scale both shield and health damage
@@ -1792,6 +1848,21 @@ void function OnHarvesterDamaged( entity harvester, var damageInfo )
if ( !IsValid( harvester ) )
return
+ // Entities (non-Players and non-NPCs) don't consider damaged entity lists, which makes ground attacks (e.g. Arc Wave) and thermite hit more than they should
+ entity inflictor = DamageInfo_GetInflictor( damageInfo )
+ if ( IsValid( inflictor ) && ( inflictor.e.onlyDamageEntitiesOnce || inflictor.e.onlyDamageEntitiesOncePerTick ) )
+ {
+ if ( inflictor.e.damagedEntities.contains( harvester ) )
+ {
+ DamageInfo_SetDamage( damageInfo, 0 )
+ return
+ }
+ else
+ {
+ inflictor.e.damagedEntities.append( harvester )
+ }
+ }
+
int friendlyTeam = harvester.GetTeam()
int enemyTeam = GetOtherTeam( friendlyTeam )
int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo )
@@ -1816,52 +1887,9 @@ void function OnHarvesterDamaged( entity harvester, var damageInfo )
// always reset harvester's recharge delay
harvesterstruct.lastDamage = Time()
-
- // done damage adjustments here, since harvester prop's health is setting manually through damageAmount
- if ( damageSourceID == eDamageSourceId.mp_titancore_laser_cannon )
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 50 ) // laser core shreds super well for some reason
-
- // plasma railgun can always do no-charge shots and deal same damage
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_sniper ) // nerf northstar
- {
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 )
- entity inflictor = DamageInfo_GetInflictor( damageInfo )
- if( IsValid( inflictor ) && inflictor.IsProjectile() )
- {
- inflictor.s.extraDamagePerBullet = expect int( inflictor.s.extraDamagePerBullet ) / 3
- }
- }
-
- // leadwall have high pilot damage so works really well aginst harvester
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_leadwall ) // nerf ronin
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 )
-
- // missiles mostly have high pilot damage so works really well aginst harvester
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_salvo_rockets ||
- damageSourceID == eDamageSourceId.mp_titanweapon_shoulder_rockets ||
- damageSourceID == eDamageSourceId.mp_titancore_salvo_core
- ) // titan missiles
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 )
-
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_sticky_40mm ) // 40mm trakcer cannon
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 )
-
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_flightcore_rockets ) // flight core shreds well
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 )
-
- // cluster missle is very effective against non-moving targets
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_dumbfire_rockets ) // cluster missile shreds super well
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 10 )
-
- // scorch's thermites is very effective against non-moving targets
- if ( damageSourceID == eDamageSourceId.mp_titanweapon_heat_shield ||
- damageSourceID == eDamageSourceId.mp_titanweapon_meteor_thermite ||
- damageSourceID == eDamageSourceId.mp_titanweapon_flame_wall ||
- damageSourceID == eDamageSourceId.mp_titanability_slow_trap ||
- damageSourceID == eDamageSourceId.mp_titancore_flame_wave_secondary
- ) // scorch's thermite damages, nerf scorch
- DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 )
-
+ // Should be moved to a final damage callback once those are added
+ if ( damageSourceID in file.harvesterDamageSourceMods )
+ DamageInfo_ScaleDamage( damageInfo, file.harvesterDamageSourceMods[ damageSourceID ] )
}
void function OnHarvesterPostDamaged( entity harvester, var damageInfo )
{
@@ -1977,7 +2005,6 @@ void function OnHarvesterPostDamaged( entity harvester, var damageInfo )
}
}
-
// harvester down!
if ( harvester.GetHealth() == 0 )
{
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut
index d999bb4c5..c295d596d 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut
@@ -7,8 +7,8 @@ global function SHCreateGamemodeFW_Init
// object settings, changable through playlist vars
// default havester settings
-global const int FW_DEFAULT_HARVESTER_HEALTH = 25000
-global const int FW_DEFAULT_HARVESTER_SHIELD = 5000
+global const int FW_DEFAULT_HARVESTER_HEALTH = 87500
+global const int FW_DEFAULT_HARVESTER_SHIELD = 17500
global const float FW_DEFAULT_HARVESTER_REGEN_DELAY = 12.0
global const float FW_DEFAULT_HARVESTER_REGEN_TIME = 10.0
// default turret settings
@@ -69,6 +69,7 @@ void function CreateGamemodeFW()
GameMode_AddClientInit( FORT_WAR, CLGamemodeFW_Init )
#endif
#if !UI
+ GameMode_SetScoreCompareFunc( FORT_WAR, CompareAssaultScore )
GameMode_AddSharedInit( FORT_WAR, SHGamemodeFW_Init )
#endif
}
diff --git a/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut
new file mode 100644
index 000000000..95ab39158
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut
@@ -0,0 +1,1226 @@
+untyped
+
+global function MeleeShared_Init
+
+global function CodeCallback_OnMeleePressed
+//global function CodeCallback_OnMeleeHeld
+//global function CodeCallback_OnMeleeReleased
+global function CodeCallback_IsValidMeleeExecutionTarget
+global function CodeCallback_IsValidMeleeAttackTarget
+global function CodeCallback_OnMeleeAttackAnimEvent
+global function AddSyncedMeleeServerCallback
+global function AddSyncedMeleeServerThink
+
+global function GetSyncedMeleeChooser
+global function CreateSyncedMeleeChooser
+global function PlayerTriesSyncedMelee
+global function FindBestSyncedMelee
+global function GetSyncedMeleeChooserForPlayerVsTarget
+global function AddSyncedMelee
+global function GetEyeOrigin
+global function SetObjectCanBeMeleed
+global function ObjectCanBeMeleed
+global function ShouldClampTargetVelocity
+global function ClampVerticalVelocity
+global function IsInExecutionMeleeState
+
+global function GetLungeTargetForPlayer
+global function Melee_IsAllowed
+global function IsAttackerRef
+global function AddCallback_IsValidMeleeExecutionTarget
+
+#if SERVER
+ global function Melee_Enable
+ global function Melee_Disable
+ global function SyncedMelee_Enable
+ global function SyncedMelee_Disable
+ global function InitMeleeAnimEventCallbacks
+ global function GetRefAnglesBetweenEnts
+ global function CreateMeleeScriptMoverBetweenEnts
+ global function ShouldHolsterWeaponForMelee
+ global function ShouldHolsterWeaponForSyncedMelee
+ global function NPCTriesSyncedMeleeVsPlayer
+#endif
+
+const SMOOTH_TIME = 0.2
+const INSTA_KILL_TIME_THRESHOLD = 0.35
+const BUG_REPRO_MOVEMELEE = 19114
+
+global struct SyncedMelee
+{
+ string ref
+ bool enabled = true
+ vector direction = < 1, 0, 0 >
+ float distance
+ float distanceSqr
+ string attackerAnimation1p
+ string attackerAnimation3p
+// void function AddAnimEvent( entity ent, string eventName, void functionref( entity ent ) func, var optionalVar = null )
+ array<AnimEventData> attacker3pAnimEvents
+ array<AnimEventData> target3pAnimEvents
+ string targetAnimation1p
+ string targetAnimation3p
+ string thirdPersonCameraAttachment
+ asset attachModel1p
+ string attachTag1p
+ float minDot = -1.0 // always happens
+ string animRefPos = "target"
+ bool canTargetNPCs = true
+ float percentDamageDealtPerHit = 1.0
+ bool usableByPlayers = true
+
+ float targetMinHealthRatio = 0.0 // target health ratio must be at least this high
+ float targetMaxHealthRatio = 1.0 // target health ratio must be at or below this
+ bool onlyIfLethal // only if the strike would be lethal
+ bool isAttackerRef = true
+
+}
+
+global struct SyncedMeleeChooser
+{
+ vector functionref( entity ) attackerOriginFunc
+ vector functionref( entity ) targetOriginFunc
+ array<SyncedMelee> syncedMelees
+ bool displayMeleePrompt = true
+}
+
+struct
+{
+ table<string, table<string,SyncedMeleeChooser> > syncedMeleeChoosers
+ table<SyncedMeleeChooser, array<void functionref( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target )> > syncedMeleeServerCallbacks
+ table<SyncedMeleeChooser, bool functionref( SyncedMelee action, entity player, entity target ) > syncedMeleeServerThink
+ array<bool functionref(entity attacker, entity target)> isValidMeleeExecutionTargetCallBacks
+ string lastExecutionUsed = ""
+} file
+
+function MeleeShared_Init()
+{
+ FlagInit( "ForceSyncedMelee" )
+
+ level.HUMAN_VS_TITAN_MELEE <- 1
+ level.titan_attack_anim_event_count <- 0
+ level.titan_attack_push_button_count <- 0
+
+ MeleeHumanShared_Init()
+ MeleeTitanShared_Init()
+ MeleeSyncedHumanShared_Init()
+ MeleeSyncedTitanShared_Init()
+
+ #if SERVER
+ VerifySyncedMelee()
+ MeleeSyncedServer_Init()
+ #endif
+
+ RegisterSignal( "SyncedMeleeComplete" )
+ RegisterSignal( "OnSyncedMelee" )
+ RegisterSignal( "OnSyncedMeleeVictim" )
+ RegisterSignal( "OnSyncedMeleeAttacker" )
+}
+
+int function GetPlayerMeleeDamage( entity player )
+{
+ Assert( player.IsPlayer() )
+ foreach ( weapon in player.GetMainWeapons() )
+ {
+ switch ( weapon.GetWeaponInfoFileKeyField( "fire_mode" ) )
+ {
+ case "offhand_melee":
+ return expect int( weapon.GetWeaponInfoFileKeyField( "melee_damage" ) )
+ }
+ }
+
+ return 0
+}
+
+void function AddSyncedMeleeServerCallback( SyncedMeleeChooser chooser, void functionref( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target ) func )
+{
+ if ( !( chooser in file.syncedMeleeServerCallbacks ) )
+ file.syncedMeleeServerCallbacks[ chooser ] <- []
+
+ file.syncedMeleeServerCallbacks[ chooser ].append( func )
+}
+
+void function AddSyncedMeleeServerThink( SyncedMeleeChooser chooser, bool functionref( SyncedMelee action, entity player, entity target ) func )
+{
+ file.syncedMeleeServerThink[ chooser ] <- func
+}
+
+
+function VerifySyncedMelee()
+{
+ foreach ( attackerChoosers in file.syncedMeleeChoosers )
+ {
+ foreach ( chooser in attackerChoosers )
+ {
+ //Assert( chooser in file.syncedMeleeServerCallbacks, "Need to add synced server melee callback for synced melee chooser" )
+ //Assert( file.syncedMeleeServerCallbacks[ chooser ].len() > 0, "Need to create a callback for chooser" )
+ Assert( chooser in file.syncedMeleeServerThink, "Need to add synced server melee callback for synced melee chooser" )
+ }
+ }
+}
+
+SyncedMeleeChooser function GetSyncedMeleeChooser( string attackerType, string victimType )
+{
+ return file.syncedMeleeChoosers[ attackerType ][ victimType ]
+}
+
+SyncedMeleeChooser function CreateSyncedMeleeChooser( string attackerType, string victimType )
+{
+ SyncedMeleeChooser chooser
+
+ chooser.attackerOriginFunc = GetEyeOrigin
+ chooser.targetOriginFunc = GetEyeOrigin
+
+ if ( !( attackerType in file.syncedMeleeChoosers ) )
+ file.syncedMeleeChoosers[ attackerType ] <- {}
+
+ Assert( !( victimType in file.syncedMeleeChoosers[ attackerType ] ), "Already has " + victimType )
+ file.syncedMeleeChoosers[ attackerType ][ victimType ] <- chooser
+ return chooser
+}
+
+vector function GetEyeOrigin( entity ent )
+{
+ return ent.EyePosition()
+}
+
+void function AddCallback_IsValidMeleeExecutionTarget( bool functionref( entity attacker, entity target ) callbackFunc )
+{
+ file.isValidMeleeExecutionTargetCallBacks.append( callbackFunc )
+}
+
+//Called after pressing the melee button to recheck for targets
+bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity target )
+{
+ if ( attacker == target )
+ return false
+
+ if ( !ShouldPlayerExecuteTarget( attacker, target ) )
+ return false
+
+ if ( !attacker.IsOnGround() && attacker.IsHuman() )
+ return false
+
+ if ( !IsAlive( target ) )
+ return false
+
+ if ( target.IsInvulnerable() )
+ return false
+
+ if ( !CanBeMeleed( target ) )
+ return false
+
+ if ( target.IsNPC() && !target.CanBeMeleeExecuted() )
+ return false
+
+ // Disallow executing someone that is already in execution. That road leads to script errors and asserts.
+ if ( target.ContextAction_IsMeleeExecution() )
+ return false
+
+ if ( attacker.IsTitan() && target.IsTitan() )
+ {
+ // no melee execute for berserker
+ if ( PlayerHasPassive( attacker, ePassives.PAS_BERSERKER ) )
+ return false
+
+ if ( PlayerHasPassive( attacker, ePassives.PAS_SHIFT_CORE ) )
+ return false
+
+ if ( HasSoul( target ) && target.GetTitanSoul().IsEjecting() )
+ return false
+
+ if ( attacker.ContextAction_IsActive() )
+ return false
+
+ if ( target.ContextAction_IsActive() )
+ return false
+
+ if ( GetCurrentPlaylistVarInt( "vortex_blocks_melee", 0 ) == 1 )
+ {
+ vector traceStartPos = attacker.EyePosition()
+ vector traceEndPos = target.EyePosition()
+ VortexBulletHit ornull vortexHit = VortexBulletHitCheck( attacker, traceStartPos, traceEndPos )
+ if ( vortexHit != null )
+ {
+ return false
+ }
+ }
+ }
+
+ if ( !CheckVerticallyCloseEnough( attacker, target ) )
+ return false
+
+ //No necksnaps while wall running or mantling
+ if ( attacker.IsWallRunning() )
+ 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() )
+ return false
+
+ if ( target.IsTraversing() )
+ return false
+
+ if ( !target.IsOnGround() ) //disallow mid-air necksnaps. Can't really do that for Titan executions since dash puts them in mid air... will have visual glitches unfortunately.
+ return false
+
+ if ( target.IsCrouched() )
+ return false
+
+ if ( Rodeo_IsAttached( target ) )
+ return false
+ }
+ }
+
+ if ( target.IsPhaseShifted() )
+ return false
+
+ //Disallow executions on contextActions marked Busy. Note that this allows
+ //execution on melee and leeching context actions!
+ if ( target.ContextAction_IsBusy() )
+ return false
+
+ if ( target.IsNPC() ) //NPC only checks
+ {
+ if ( target.ContextAction_IsActive() )
+ return false
+
+ if ( !target.IsInterruptable() )
+ return false
+ }
+
+ if ( attacker.GetTeam() == target.GetTeam() )
+ return false
+
+#if SERVER
+ if ( "syncedMeleeAttacker" in target.s ) //Don't allow necksnap on a guy who'se already getting necksnapped
+ return false
+#endif // #if SERVER
+
+ SyncedMeleeChooser ornull actions = GetSyncedMeleeChooserForPlayerVsTarget( attacker, target )
+ if ( actions == null )
+ return false
+ expect SyncedMeleeChooser( actions )
+
+ SyncedMelee ornull action = FindBestSyncedMelee( attacker, target, actions )
+ if ( action == null )
+ return false
+
+ if ( !PlayerMelee_IsExecutionReachable( attacker, target, 0.3 ) )
+ return false
+
+ foreach ( callbackFunc in file.isValidMeleeExecutionTargetCallBacks )
+ {
+ if ( !callbackFunc( attacker, target ) )
+ {
+ return false
+ }
+ }
+
+ return true
+}
+
+bool function CodeCallback_IsValidMeleeAttackTarget( entity attacker, entity target )
+{
+ if ( attacker == target )
+ return false
+
+ if ( target.IsBreakableGlass() )
+ return true
+
+ if ( !CanBeMeleed( target ) )
+ return false
+
+ if ( attacker.GetTeam() == target.GetTeam() )
+ return false
+
+#if SERVER
+ if ( target.IsPlayer() )
+ {
+ //Make titans not able to melee the pilot who is doing the embark animation
+ if ( GetTitanBeingRodeoed( target ) == attacker )
+ return false
+ }
+#endif // #if SERVER
+
+ if ( target.IsPhaseShifted() )
+ return false
+
+ if ( target.GetParent() == attacker )
+ return false
+
+ #if SERVER //Awkward, needed because it's CBaseCombatCharacter on server and C_BaseCombatCharacter on client, and because we allow melee on non BaseCombatCharacters like props that don't have ContextActions defined
+ if ( target instanceof CBaseCombatCharacter && target.ContextAction_IsMeleeExecutionTarget() ) //Don't lunge towards a victim that is already being executed )
+ return false
+ #elseif CLIENT
+ if ( target instanceof C_BaseCombatCharacter && target.ContextAction_IsMeleeExecutionTarget() ) //Don't lunge towards a victim that is already being executed )
+ return false
+ #endif
+
+ entity meleeWeapon = attacker.GetMeleeWeapon()
+ if ( !IsValid( meleeWeapon ) )
+ return false;
+
+ if ( !meleeWeapon.GetMeleeCanHitHumanSized() && IsHumanSized( target ) )
+ return false;
+ if ( !meleeWeapon.GetMeleeCanHitTitans() && target.IsTitan() )
+ return false;
+
+ return true
+}
+
+void function CodeCallback_OnMeleePressed( entity player )
+{
+#if SERVER
+ print( "SERVER: " + player + " pressed melee\n" )
+#else
+ print( "CLIENT: " + player + " pressed melee\n" )
+#endif
+
+ if ( !Melee_IsAllowed( player ) )
+ {
+#if SERVER
+ print( "SERVER: Melee_IsAllowed() for " + player + " is false\n" )
+#else
+ print( "CLIENT: Melee_IsAllowed() for " + player + " is false\n" )
+#endif
+ return
+ }
+
+#if SERVER
+ if ( svGlobal.cloakBreaksOnMelee && IsCloaked( player ) )
+ player.SetCloakFlicker( 1.0, 2.0 )
+#endif // #if SERVER
+
+ if ( player.IsWeaponDisabled() )
+ {
+#if SERVER
+ print( "SERVER: IsWeaponDisabled() for " + player + " is true\n" )
+#else
+ print( "CLIENT: IsWeaponDisabled() for " + player + " is true\n" )
+#endif
+ return
+ }
+
+ if ( player.PlayerMelee_GetState() != PLAYER_MELEE_STATE_NONE )
+ {
+#if SERVER
+ print( "SERVER: PlayerMelee_GetState() for " + player + " is " + player.PlayerMelee_GetState() + "\n" )
+#else
+ print( "CLIENT: PlayerMelee_GetState() for " + player + " is " + player.PlayerMelee_GetState() + "\n" )
+#endif
+ return
+ }
+
+ if ( !IsAlive( player ) )
+ {
+#if SERVER
+ print( "SERVER: " + player + " is dead\n" )
+#else
+ print( "CLIENT: " + player + " is dead\n" )
+#endif
+ return
+ }
+
+ thread CodeCallback_OnMeleePressed_InternalThread( player )
+}
+
+void function CodeCallback_OnMeleePressed_InternalThread( entity player )
+{
+ if ( player.IsTitan() )
+ {
+ TitanUnsyncedMelee( player )
+ }
+ else if ( player.IsHuman() )
+ {
+ const float STUN_EFFECT_CUTOFF = 0.05
+ float movestunEffect = StatusEffect_Get( player, eStatusEffect.move_slow )
+ bool movestunBlocked = (movestunEffect > STUN_EFFECT_CUTOFF)
+
+ HumanUnsyncedMelee( player, movestunBlocked )
+ }
+}
+
+//void function CodeCallback_OnMeleeHeld( entity player )
+//{
+//}
+
+//void function CodeCallback_OnMeleeReleased( entity player )
+//{
+//}
+
+bool function ShouldHolsterWeaponForSyncedMelee( entity player )
+{
+ if ( player.GetPlayerSettings() == "titan_ogre_minigun" )
+ return false
+
+ return ShouldHolsterWeaponForMelee( player )
+}
+
+bool function ShouldHolsterWeaponForMelee( entity player )
+{
+ #if !SERVER
+ return true
+ #endif
+
+ if ( !player.IsTitan() )
+ return true
+
+ return Time() - player.s.startDashMeleeTime > 1.0 //Fix issue with gun being out when it shouldn't, according to Mackey...
+}
+
+#if SERVER
+bool function NPCTriesSyncedMeleeVsPlayer( entity npc, entity player )
+{
+ Assert( npc.IsNPC() )
+ Assert( player.IsPlayer() )
+ Assert( IsAlive( player ) )
+ Assert( player.IsPlayer() )
+ Assert( IsPilot( player ) )
+ if ( player.ContextAction_IsBusy() )
+ return false
+
+ //#if SERVER
+ //player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION )
+ //#else
+ //player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED )
+ //#endif
+
+ return DoSyncedMelee( npc, player )
+}
+#endif
+
+
+
+bool function PlayerTriesSyncedMelee( entity player, entity target )
+{
+ if ( !target )
+ return false
+ if ( !IsAlive( target ) )
+ return false
+
+ if ( target.ContextAction_IsBusy() )
+ return false
+
+ if ( player.IsTitan() )
+ {
+#if SERVER
+ player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION )
+#else
+ player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION_PREDICTED )
+#endif
+ }
+ else
+ {
+#if SERVER
+ player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION )
+#else
+ 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 SERVER
+ print( "SERVER: " + player + " is calling Lunge_SetTargetEntity() from PlayerTriesSyncedMelee()\n" )
+#else
+ print( "CLIENT: " + player + " is calling Lunge_SetTargetEntity() from PlayerTriesSyncedMelee()\n" )
+#endif
+ player.Lunge_SetTargetEntity( target, false )
+ }
+
+#if SERVER
+ OnThreadEnd(
+ function() : ( player, target )
+ {
+ if ( IsValid( player ) && player.IsPlayer() )
+ {
+ RemoveCinematicFlag( player, CE_FLAG_TITAN_3P_CAM )
+ RemoveCinematicFlag( player, CE_FLAG_EXECUTION )
+ }
+ if ( IsValid( target ) && target.IsPlayer() )
+ {
+ RemoveCinematicFlag( target, CE_FLAG_TITAN_3P_CAM )
+ RemoveCinematicFlag( target, CE_FLAG_EXECUTION )
+ }
+ }
+ )
+
+ if ( player.IsTitan() )
+ TransferDamageHistoryToTarget( target )
+ if ( player.IsPlayer() )
+ {
+ AddCinematicFlag( player, CE_FLAG_TITAN_3P_CAM )
+ AddCinematicFlag( player, CE_FLAG_EXECUTION )
+ }
+ if ( IsValid( target ) && target.IsPlayer() )
+ {
+ AddCinematicFlag( target, CE_FLAG_TITAN_3P_CAM )
+ AddCinematicFlag( player, CE_FLAG_EXECUTION )
+ }
+#endif
+
+ bool success = DoSyncedMelee( player, target )
+ if ( !success )
+ {
+ player.Lunge_ClearTarget()
+ }
+
+ return success
+}
+
+function TransferDamageHistoryToTarget( entity target )
+{
+ entity titanSoul = target.GetTitanSoul()
+ target.e.recentDamageHistory = titanSoul.e.recentDamageHistory
+}
+
+bool function DoSyncedMelee( entity player, entity target )
+{
+ SyncedMeleeChooser ornull actions = GetSyncedMeleeChooserForPlayerVsTarget( player, target )
+
+ Assert( actions != null, "No melee action for " + player + " vs " + target )
+ expect SyncedMeleeChooser( actions )
+
+#if SERVER
+ if ( player.IsPlayer() )
+ {
+ PlayerMelee_StartLagCompensateTargetForLunge( player, target )
+ }
+#endif // #if SERVER
+
+ SyncedMelee ornull action = FindBestSyncedMelee( player, target, actions )
+
+#if SERVER
+ if ( player.IsPlayer() )
+ {
+
+ player.ForceStand()
+ player.UnforceStand()
+ PlayerMelee_FinishLagCompensateTarget( player )
+ }
+#endif // #if SERVER
+
+ if ( action == null )
+ return false
+
+ expect SyncedMelee( action )
+
+
+
+ player.Signal( "OnSyncedMelee" )
+ target.Signal( "OnSyncedMelee" )
+ player.Signal( "OnSyncedMeleeAttacker" )
+ target.Signal( "OnSyncedMeleeVictim" )
+
+#if SERVER
+ player.p.lastExecutionUsed = action.ref
+
+ if ( actions in file.syncedMeleeServerCallbacks )
+ thread SyncedMeleeServerCallbacks( actions, action, player, target )
+ bool functionref( SyncedMelee action, entity player, entity target ) think = file.syncedMeleeServerThink[ actions ]
+ return think( action, player, target )
+#endif // #if SERVER
+
+ return true
+}
+
+void function SyncedMeleeServerCallbacks( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target )
+{
+ // Added via AddSyncedMeleeServerCallback
+ foreach ( index, _ in file.syncedMeleeServerCallbacks[ actions ] )
+ {
+ void functionref( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target ) item = file.syncedMeleeServerCallbacks[ actions ][ index ]
+ item( actions, action, player, target )
+ }
+}
+
+/*
+void function CodeCallback_OnMeleeReleased( entity player )
+{
+}
+*/
+
+function TextDebug( string msg )
+{
+ wait 0.5
+ printt( msg )
+}
+
+bool function ShouldClampTargetVelocity( vector targetVelocity, vector pushBackVelocity, float clampRatio )
+{
+ float dot = DotProduct( targetVelocity, pushBackVelocity )
+ if ( dot < 0 )
+ return true
+
+ if ( dot <= 0 )
+ return false
+
+ float velRatio = LengthSqr( targetVelocity ) / LengthSqr( pushBackVelocity )
+
+ return velRatio < clampRatio
+}
+
+bool function CanBeMeleed( entity target )
+{
+ if ( target.IsPlayer() )
+ return true
+ if ( target.IsNPC() )
+ return true
+
+ if ( ObjectCanBeMeleed( target ) )
+ return true
+
+ return false
+}
+
+// IMPORTANT: Only used for non-player, non-living special cases like prop_dynamics we want to be able to melee (drones, etc)
+bool function ObjectCanBeMeleed( entity ent )
+{
+ if ( !( "canBeMeleed" in ent.s ) )
+ return false
+
+ return expect bool( ent.s.canBeMeleed )
+}
+
+// IMPORTANT: Only used for non-player, non-living special cases like prop_dynamics we want to be able to melee (drones, etc)
+function SetObjectCanBeMeleed( entity ent, bool value )
+{
+ Assert( !ent.IsPlayer(), ent + " should not be a player. This is for non-player, non-NPC entities.")
+ Assert( !ent.IsNPC(), ent + " should not be an NPC. This is for non-player, non-NPC entities.")
+
+ if ( !( "canBeMeleed" in ent.s ) )
+ ent.s.canBeMeleed <- false
+
+ ent.s.canBeMeleed = value
+}
+
+//function TitanExposionDeath( entity titan, entity attacker )
+//{
+// if ( !IsAlive( titan ) )
+// return
+//
+// ExplodeTitanBits( titan )
+// // and your pretty titan too!
+//
+// //TitanEjectExplosion
+// table deathTable = { scriptType = damageTypes.titanMelee, forceKill = true, damageType = DMG_MELEE_EXECUTION, damageSourceId = eDamageSourceId.titan_execution }
+// titan.TakeDamage( titan.GetMaxHealth() + 1, attacker, attacker, deathTable )
+//}
+
+#if SERVER
+vector function GetRefAnglesBetweenEnts( entity attacker, entity target )
+{
+ vector endOrigin = target.GetOrigin()
+ vector startOrigin = attacker.GetOrigin()
+ vector refVec = endOrigin - startOrigin
+ vector refAng = VectorToAngles( refVec )
+ if ( fabs( AngleNormalize( refAng.x ) ) > 35 ) //If pitch is too much, use angles from either attacker or target
+ {
+ if ( attacker.IsTitan() )
+ refAng = attacker.GetAngles() //Doing titan synced kill from front, so use attacker's origin
+ else
+ refAng = target.GetAngles() // Doing rear necksnap, so use target's angles
+ }
+ return refAng
+}
+
+entity function CreateMeleeScriptMoverBetweenEnts( entity attacker, entity target )
+{
+ vector refAng = GetRefAnglesBetweenEnts( attacker, target )
+
+ vector endOrigin = target.GetOrigin()
+ vector startOrigin = attacker.GetOrigin()
+ vector refVec = endOrigin - startOrigin
+ vector refPos = endOrigin - refVec * 0.5
+
+ entity ref = CreateOwnedScriptMover( attacker )
+ ref.SetOrigin( refPos )
+ ref.SetAngles( refAng )
+
+ return ref
+}
+#endif // SERVER
+
+void function AddSyncedMelee( SyncedMeleeChooser chooser, SyncedMelee melee )
+{
+ // sqr the distance
+ melee.distanceSqr = melee.distance * melee.distance
+
+ chooser.syncedMelees.append( melee )
+}
+
+SyncedMelee ornull function FindBestSyncedMelee( entity attacker, entity target, SyncedMeleeChooser actions )
+{
+ #if CLIENT
+ Assert( attacker == GetLocalViewPlayer() )
+ #endif // CLIENT
+
+ vector absTargetToPlayerDir
+ if ( attacker.IsPlayer() && attacker.Lunge_IsActive() && (attacker.Lunge_GetTargetEntity() == target) )
+ {
+ absTargetToPlayerDir = attacker.Lunge_GetStartPositionOffset()
+ absTargetToPlayerDir = Normalize( absTargetToPlayerDir )
+ }
+ else
+ {
+ vector attackerPos = actions.attackerOriginFunc( attacker ) // + ( attacker.GetVelocity() * SMOOTH_TIME )
+ vector targetPos = actions.targetOriginFunc( target )
+
+ if ( attackerPos == targetPos )
+ {
+ absTargetToPlayerDir = < 1, 0, 0 >
+ }
+ else
+ {
+ absTargetToPlayerDir = Normalize( attackerPos - targetPos )
+ }
+ }
+
+ vector angles = attacker.EyeAngles()
+ vector forward = AnglesToForward( angles )
+
+ vector relTargetToPlayerDir = CalcRelativeVector( < 0, target.EyeAngles().y, 0 >, absTargetToPlayerDir )
+
+ array<SyncedMelee> bestActions
+ float bestDot = -2.0
+ float distSqr = LengthSqr( actions.attackerOriginFunc( attacker ) - actions.targetOriginFunc( target ) )
+
+ bool npcTarget = target.IsNPC()
+ bool playerAttacker = attacker.IsPlayer()
+
+ int health = target.GetHealth()
+ float healthRatio = HealthRatio( target )
+ int meleeDamage
+ if ( attacker.IsNPC() )
+ {
+ meleeDamage = attacker.GetMeleeDamageMaxForTarget( target )
+ }
+ else if ( attacker.IsPlayer() )
+ {
+ meleeDamage = GetPlayerMeleeDamage( attacker )
+ }
+
+ SyncedMelee ornull returnVal = null
+
+#if MP
+ if ( IsPilot( attacker ) )
+ {
+ PilotLoadoutDef loadout = GetActivePilotLoadout( attacker )
+
+ foreach ( action in actions.syncedMelees )
+ {
+ if ( action.ref != loadout.execution )
+ continue
+
+ if ( npcTarget && !action.canTargetNPCs )
+ break
+
+ if ( playerAttacker && !action.usableByPlayers )
+ break
+
+ if ( healthRatio < action.targetMinHealthRatio )
+ break
+
+ if ( healthRatio > action.targetMaxHealthRatio )
+ break
+
+ if ( action.onlyIfLethal && health > meleeDamage )
+ break
+
+ if ( distSqr > action.distanceSqr )
+ break
+
+ float dot = relTargetToPlayerDir.Dot( action.direction )
+ if ( dot < action.minDot )
+ break
+
+#if SERVER
+ //Random Execution
+ if ( string( attacker.GetPersistentVar( "activePilotLoadout.execution" )) == "execution_random")
+ {
+ returnVal = PickRandomExecution(actions, attacker)
+ break
+ }
+#endif
+
+ returnVal = action
+ break
+ }
+ }
+ else
+ {
+#endif
+ foreach ( action in actions.syncedMelees )
+ {
+ if ( !action.enabled )
+ continue
+
+ if ( npcTarget && !action.canTargetNPCs )
+ continue
+
+ if ( playerAttacker && !action.usableByPlayers )
+ continue
+
+ if ( healthRatio < action.targetMinHealthRatio )
+ continue
+
+ if ( healthRatio > action.targetMaxHealthRatio )
+ continue
+
+ if ( action.onlyIfLethal && health > meleeDamage )
+ continue
+
+ if ( distSqr > action.distanceSqr )
+ continue
+
+ float dot = relTargetToPlayerDir.Dot( action.direction )
+
+ //printt( "Dot: " + dot )
+
+ if ( dot < action.minDot )
+ continue
+
+ if ( dot == bestDot )
+ {
+ bestActions.append( action )
+ continue
+ }
+
+ if ( dot > bestDot )
+ {
+ // found new best dot
+ bestActions.clear()
+ bestDot = dot
+ bestActions.append( action )
+ }
+ }
+
+ if ( bestActions.len() )
+ returnVal = bestActions.getrandom()
+#if MP
+ }
+#endif
+
+ return returnVal
+}
+
+string function GetAttackerSyncedMelee( entity ent )
+{
+ if ( ent.IsPlayer() )
+ {
+ // TODO: for MP, change this to be based on loadout choice
+ string bodyType = GetPlayerBodyType( ent )
+ if ( bodyType == "human" )
+ {
+ entity weapon = ent.GetActiveWeapon()
+ var weaponSyncedMelee
+
+ if ( IsValid( weapon ) )
+ weaponSyncedMelee = weapon.GetWeaponInfoFileKeyField( "synced_melee_action" )
+
+ if ( weaponSyncedMelee )
+ return string( weaponSyncedMelee )
+ }
+
+ return bodyType
+
+ }
+ else if ( IsProwler( ent ) )
+ {
+ return "prowler"
+ }
+ else if ( IsPilotElite( ent ) )
+ {
+ return "pilotelite"
+ }
+ else if ( IsSpectre( ent ) )
+ {
+ return "spectre"
+ }
+ else if ( ent.IsNPC() )
+ {
+ return ent.GetBodyType()
+ }
+ else if ( ent.IsTitan() )
+ {
+ return "titan"
+ }
+
+ unreachable
+}
+
+string function GetVictimSyncedMeleeTargetType( entity ent )
+{
+ string targetType
+
+ if ( ent.IsPlayer() && GetPlayerBodyType( ent ) == "human" )
+ {
+ targetType = "human"
+ }
+ else if ( IsProwler( ent ) )
+ {
+ targetType = "prowler"
+ }
+ else if ( IsPilotElite( ent ) )
+ {
+ targetType = "pilotelite"
+ }
+ else if ( ent.IsNPC() )
+ {
+ targetType = ent.GetBodyType()
+ }
+ else if ( ent.IsTitan() )
+ {
+ targetType = "titan"
+ }
+ else
+ {
+ Assert( 0, "Unknown ent type" )
+ }
+
+ return targetType
+}
+
+SyncedMeleeChooser ornull function GetSyncedMeleeChooserForPlayerVsTarget( entity attacker, entity target )
+{
+ string attackerType = GetAttackerSyncedMelee( attacker )
+ string targetType = GetVictimSyncedMeleeTargetType( target )
+
+ if ( !( attackerType in file.syncedMeleeChoosers ) )
+ return null
+
+ if ( !( targetType in file.syncedMeleeChoosers[ attackerType ] ) )
+ return null
+
+ return file.syncedMeleeChoosers[ attackerType ][ targetType ]
+}
+
+void function CodeCallback_OnMeleeAttackAnimEvent( entity player )
+{
+ Assert( IsValid( player ) )
+#if SERVER
+ print( "SERVER: " + player + " is calling CodeCallback_OnMeleeAttackAnimEvent()\n" )
+#else
+ print( "CLIENT: " + player + " is calling CodeCallback_OnMeleeAttackAnimEvent()\n" )
+#endif
+ if ( player.PlayerMelee_IsAttackActive() )
+ {
+ if ( player.IsTitan() )
+ TitanMeleeAttack( player )
+ else if ( player.IsHuman() )
+ HumanMeleeAttack( player )
+ }
+}
+
+bool function IsInExecutionMeleeState( entity player )
+{
+ local meleeState = player.PlayerMelee_GetState()
+ switch ( meleeState )
+ {
+ case PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED:
+ case PLAYER_MELEE_STATE_HUMAN_EXECUTION:
+ case PLAYER_MELEE_STATE_TITAN_EXECUTION_PREDICTED:
+ case PLAYER_MELEE_STATE_TITAN_EXECUTION:
+ return true
+
+ default:
+ return false
+ }
+
+ unreachable
+}
+
+#if SERVER
+void function InitMeleeAnimEventCallbacks( entity player )
+{
+ AddAnimEvent( player, "screen_blackout", MeleeBlackoutScreen_AE )
+}
+
+void function MeleeBlackoutScreen_AE( entity player )
+{
+ ScreenFadeToBlack( player, 0.7, 1.2 )
+}
+#endif
+
+bool function ShouldPlayerExecuteTarget( entity player, entity target )
+{
+ if ( player.IsTitan() )
+ {
+ if ( !target.IsTitan() )
+ return false
+
+ if ( Flag( "ForceSyncedMelee" ) )
+ return true
+
+ if ( !GetDoomedState( target ) )
+ return false
+
+ entity soul = target.GetTitanSoul()
+ if ( soul != null )
+ {
+ if ( soul.GetShieldHealth() > 0 && GetCurrentPlaylistVarInt( "titan_shield_blocks_execution", 0 ) != 0 )
+ return false
+ }
+
+ if ( !SyncedMelee_IsAllowed( player ) )
+ return false
+
+ return true
+ }
+
+ if ( player.IsHuman() )
+ {
+ if ( !IsHumanSized( target ) )
+ return false
+
+#if SERVER
+ if ( Flag( "ForceSyncedMelee" ) )
+ return true
+#endif // #if SERVER
+
+ if ( !SyncedMelee_IsAllowed( player ) )
+ return false
+ }
+
+ return true
+}
+
+vector function ClampVerticalVelocity( vector targetVelocity, float maxVerticalVelocity )
+{
+ vector clampedVelocity = targetVelocity
+ if ( clampedVelocity.z > maxVerticalVelocity )
+ {
+ printt( "clampedVelocity.z: " + clampedVelocity.z +", maxVerticalVelocity:" + maxVerticalVelocity )
+ clampedVelocity = Vector( targetVelocity.x, targetVelocity.y, maxVerticalVelocity )
+ }
+
+ return clampedVelocity
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool function CheckVerticallyCloseEnough( entity attacker, entity target )
+{
+ vector attackerOrigin = attacker.GetOrigin()
+ vector targetOrigin = target.GetOrigin()
+
+ float verticalDistance = fabs( attackerOrigin.z - targetOrigin.z )
+ float halfHeight = 0
+
+ if ( attacker.IsTitan() )
+ halfHeight = 92.5
+ else if ( attacker.IsHuman() )
+ halfHeight = 30
+
+ Assert( halfHeight, "Attacker is neither Titan nor Human" )
+
+ //printt( "vertical distance: " + verticalDistance )
+ return verticalDistance < halfHeight
+}
+
+
+entity function GetLungeTargetForPlayer( entity player )
+{
+ // Titan melee does not lunge
+ if ( player.IsTitan() )
+ return null
+
+ if ( player.IsPhaseShifted() )
+ return null
+
+ entity lungeTarget = PlayerMelee_LungeConeTrace( player, SHARED_CB_IS_VALID_MELEE_ATTACK_TARGET )
+ return lungeTarget
+}
+
+#if SERVER
+void function Melee_Enable( entity player )
+{
+ player.SetPlayerNetBool( "playerAllowedToMelee", true )
+}
+
+void function Melee_Disable( entity player )
+{
+ player.SetPlayerNetBool( "playerAllowedToMelee", false )
+}
+
+void function SyncedMelee_Enable( entity player )
+{
+ player.SetPlayerNetBool( "playerAllowedToSyncedMelee", true )
+}
+
+void function SyncedMelee_Disable( entity player )
+{
+ player.SetPlayerNetBool( "playerAllowedToSyncedMelee", false )
+}
+#endif
+
+bool function Melee_IsAllowed( entity player )
+{
+ return player.GetPlayerNetBool( "playerAllowedToMelee" )
+}
+
+bool function SyncedMelee_IsAllowed( entity player )
+{
+ return player.GetPlayerNetBool( "playerAllowedToSyncedMelee" )
+}
+
+bool function IsAttackerRef( SyncedMelee ornull action, entity target )
+{
+ if ( action != null )
+ {
+ expect SyncedMelee( action )
+ if ( action.isAttackerRef )
+ {
+ return true
+ }
+ }
+
+ if ( !target )
+ return true
+
+ if ( !IsValid( target ) )
+ return true
+
+ if ( !target.IsPlayer() )
+ return true
+
+ return false
+}
+
+#if MP
+#if SERVER
+SyncedMelee ornull function PickRandomExecution( SyncedMeleeChooser actions, entity attacker )
+{
+ array<SyncedMelee> possibleExecutions = []
+
+ SyncedMelee neckSnap
+
+ foreach ( action in actions.syncedMelees )
+ {
+ if (action.ref == "execution_neck_snap")
+ neckSnap = action
+
+ if(!IsItemLocked( attacker, action.ref ) && action.ref != "execution_random" && action.ref != attacker.p.lastExecutionUsed)
+
+ possibleExecutions.append(action)
+ }
+
+ if (possibleExecutions.len() == 0)
+ return neckSnap
+
+ possibleExecutions.randomize()
+
+ return possibleExecutions[0]
+}
+#endif
+#endif \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut
index c66fc8579..4987ee015 100644
--- a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut
+++ b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut
@@ -630,7 +630,9 @@ void function DamageTypes_Init()
[ eDamageSourceId.melee_titan_punch_fighter ] = "#DEATH_TITAN_MELEE",
[ eDamageSourceId.melee_titan_punch_vanguard ] = "#DEATH_TITAN_MELEE",
[ eDamageSourceId.melee_titan_sword ] = "#DEATH_TITAN_SWORD",
- [ eDamageSourceId.melee_titan_sword_aoe ] = "#DEATH_TITAN_SWORD"
+ [ eDamageSourceId.melee_titan_sword_aoe ] = "#DEATH_TITAN_SWORD",
+ [ eDamageSourceId.mp_titanweapon_arc_cannon ] = "#WPN_TITAN_ARC_CANNON_SHORT",
+ [ eDamageSourceId.mp_weapon_shotgun_doublebarrel ] = "#WPN_SHOTGUN_DBLBARREL_SHORT"
}
#if DEV
@@ -773,4 +775,4 @@ void function ReceiveNewDamageSourceIDs( array<string> args )
for ( int i = 0; i < args.len(); i += 3 )
RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " " ) )
}
-#endif \ No newline at end of file
+#endif
diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut
index 79e64684e..b8d4b1ba2 100644
--- a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut
@@ -4,6 +4,7 @@ void function NorthstarCustomPrecache()
{
PrecacheWeapon( "mp_weapon_peacekraber" )
PrecacheWeapon( "mp_titanweapon_triplethreat" )
+ PrecacheWeapon( "mp_titanweapon_arc_cannon" )
PrecacheWeapon( "melee_pilot_kunai" )
RegisterWeaponDamageSources(
diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut
new file mode 100644
index 000000000..f7b31cc21
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut
@@ -0,0 +1,83 @@
+globalize_all_functions
+
+table< int, void functionref( string ) > pendingCallbacks
+table< int, void functionref( table ) > pendingJSONCallbacks
+table< int, void functionref() > failedCallbacks
+
+
+void function NSLoadFile( string file, void functionref( string ) onSuccess, void functionref() onFailure = null )
+{
+ int handle = NS_InternalLoadFile( file )
+
+ pendingCallbacks[handle] <- onSuccess
+ if (onFailure != null)
+ failedCallbacks[handle] <- onFailure
+}
+
+void function NSLoadJSONFile( string file, void functionref( table ) onSuccess, void functionref() onFailure = null )
+{
+ int handle = NS_InternalLoadFile( file )
+
+ pendingJSONCallbacks[handle] <- onSuccess
+ if (onFailure != null)
+ failedCallbacks[handle] <- onFailure
+}
+
+void function NSHandleLoadResult( int handle, bool success, string result )
+{
+ bool hasFailedCallback = handle in failedCallbacks
+ bool isJSONRequest = handle in pendingJSONCallbacks
+ bool isValid = isJSONRequest || handle in pendingCallbacks
+
+ if (!isValid)
+ throw "Invalid IO callback handle"
+
+ if (success)
+ {
+ if (isJSONRequest)
+ {
+ try
+ {
+ table result = DecodeJSON(result, true)
+ pendingJSONCallbacks[handle](result)
+ }
+ catch (ex)
+ {
+ print(ex)
+ // parsing failed, setting 'success' to false, since we
+ // consider this a failure.
+ success = false
+ }
+ }
+ else
+ {
+ pendingCallbacks[handle](result)
+ }
+ }
+ // don't use 'else', json might fail parsing and set 'success' to false.
+ if (!success)
+ {
+ if (hasFailedCallback)
+ failedCallbacks[handle]()
+ else
+ {
+ if (isJSONRequest)
+ pendingJSONCallbacks[handle]({})
+ else
+ pendingCallbacks[handle]("")
+ }
+ }
+
+ if (isJSONRequest)
+ delete pendingJSONCallbacks[handle]
+ else
+ delete pendingCallbacks[handle]
+
+ if (hasFailedCallback)
+ delete failedCallbacks[handle]
+}
+
+array<string> function NSGetAllFiles( string path = "" )
+{
+ return NS_InternalGetAllFiles(path)
+}
diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
new file mode 100644
index 000000000..011389670
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
@@ -0,0 +1,1051 @@
+untyped
+
+global function ArcCannon_Init
+
+global function ArcCannon_PrecacheFX
+global function ArcCannon_Start
+global function ArcCannon_Stop
+global function ArcCannon_ChargeBegin
+global function ArcCannon_ChargeEnd
+global function FireArcCannon
+global function ArcCannon_HideIdleEffect
+#if SERVER
+ global function AddToArcCannonTargets
+ global function RemoveArcCannonTarget
+ global function ConvertTitanShieldIntoBonusCharge
+#endif
+global function GetArcCannonChargeFraction
+
+global function IsEntANeutralMegaTurret
+global function CreateArcCannonBeam
+
+
+// Aiming & Range
+global const DEFAULT_ARC_CANNON_FOVDOT = 0.98 // First target must be within this dot to be zapped and start a chain
+global const DEFAULT_ARC_CANNON_FOVDOT_MISSILE = 0.95 // First target must be within this dot to be zapped and start a chain ( if it's a missile, we allow more leaniency )
+global const ARC_CANNON_RANGE_CHAIN = 400 // Max distance we can arc from one target to another
+global const ARC_CANNON_TITAN_RANGE_CHAIN = 900 // Max distance we can arc from one target to another
+global const ARC_CANNON_CHAIN_COUNT_MIN = 5 // Max number of chains at no charge
+global const ARC_CANNON_CHAIN_COUNT_MAX = 5 // Max number of chains at full charge
+global const ARC_CANNON_CHAIN_COUNT_NPC = 2 // Number of chains when an NPC fires the weapon
+global const ARC_CANNON_FORK_COUNT_MAX = 1 // Number of forks that can come out of one target to other targets
+global const ARC_CANNON_FORK_DELAY = 0.1
+
+global const ARC_CANNON_RANGE_CHAIN_BURN = 400
+global const ARC_CANNON_TITAN_RANGE_CHAIN_BURN = 900
+global const ARC_CANNON_CHAIN_COUNT_MIN_BURN = 100 // Max number of chains at no charge
+global const ARC_CANNON_CHAIN_COUNT_MAX_BURN = 100 // Max number of chains at full charge
+global const ARC_CANNON_CHAIN_COUNT_NPC_BURN = 10 // Number of chains when an NPC fires the weapon
+global const ARC_CANNON_FORK_COUNT_MAX_BURN = 10 // Number of forks that can come out of one target to other targets
+global const ARC_CANNON_BEAM_LIFETIME_BURN = 1
+
+// Visual settings
+global const ARC_CANNON_BOLT_RADIUS_MIN = 32 // Bolt radius at no charge ( not actually sure what this does to the beam lol )
+global const ARC_CANNON_BOLT_RADIUS_MAX = 640 // Bold radius at full charge ( not actually sure what this does to the beam lol )
+global const ARC_CANNON_BOLT_WIDTH_MIN = 1 // Bolt width at no charge
+global const ARC_CANNON_BOLT_WIDTH_MAX = 26 // Bolt width at full charge
+global const ARC_CANNON_BOLT_WIDTH_NPC = 8 // Bolt width when used by NPC
+global const ARC_CANNON_BEAM_COLOR = "150 190 255"
+global const ARC_CANNON_BEAM_LIFETIME = 0.75
+
+// Player Effects
+global const ARC_CANNON_TITAN_SCREEN_SFX = "Null_Remove_SoundHook"
+global const ARC_CANNON_PILOT_SCREEN_SFX = "Null_Remove_SoundHook"
+global const ARC_CANNON_EMP_DURATION_MIN = 0.1
+global const ARC_CANNON_EMP_DURATION_MAX = 1.8
+global const ARC_CANNON_EMP_FADEOUT_DURATION = 0.4
+global const ARC_CANNON_SCREEN_EFFECTS_MIN = 0.01
+global const ARC_CANNON_SCREEN_EFFECTS_MAX = 0.02
+global const ARC_CANNON_SCREEN_THRESHOLD = 0.3385
+global const ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION = 0.2
+
+// Damage
+global const ARC_CANNON_DAMAGE_FALLOFF_SCALER = 0.75 // Amount of damage carried on to the next target in the chain lightning. If 0.75, then a target that would normally take 100 damage will take 75 damage if they are one chain deep, or 56 damage if 2 levels deep
+global const ARC_CANNON_DAMAGE_CHARGE_RATIO = 0.85 // What amount of charge is required for full damage.
+global const ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN = 0.676 // What amount of charge is required for full damage.
+global const ARC_CANNON_CAPACITOR_CHARGE_RATIO = 1.0
+
+// Options
+global const ARC_CANNON_TARGETS_MISSILES = 1 // 1 = arc cannon zaps missiles that are active, 0 = missiles are ignored by arc cannon
+
+//Mods
+global const OVERCHARGE_MAX_SHIELD_DECAY = 0.2
+global const OVERCHARGE_SHIELD_DECAY_MULTIPLIER = 0.04
+global const OVERCHARGE_BONUS_CHARGE_FRACTION = 0.05
+
+global const SPLITTER_DAMAGE_FALLOFF_SCALER = 0.6
+global const SPLITTER_FORK_COUNT_MAX = 10
+
+global const ARC_CANNON_SIGNAL_DEACTIVATED = "ArcCannonDeactivated"
+global const ARC_CANNON_SIGNAL_CHARGEEND = "ArcCannonChargeEnd"
+
+global const ARC_CANNON_BEAM_EFFECT = $"wpn_arc_cannon_beam"
+global const ARC_CANNON_BEAM_EFFECT_MOD = $"wpn_arc_cannon_beam_mod"
+
+global const ARC_CANNON_FX_TABLE = "exp_arc_cannon"
+
+global const ArcCannonTargetClassnames = {
+ [ "npc_drone" ] = true,
+ [ "npc_dropship" ] = true,
+ [ "npc_marvin" ] = true,
+ [ "npc_prowler" ] = true,
+ [ "npc_soldier" ] = true,
+ [ "npc_soldier_heavy" ] = true,
+ [ "npc_soldier_shield" ] = true,
+ [ "npc_spectre" ] = true,
+ [ "npc_stalker" ] = true,
+ [ "npc_super_spectre" ] = true,
+ [ "npc_titan" ] = true,
+ [ "npc_turret_floor" ] = true,
+ [ "npc_turret_mega" ] = true,
+ [ "npc_turret_sentry" ] = true,
+ [ "npc_frag_drone" ] = true,
+ [ "player" ] = true,
+ [ "prop_dynamic" ] = true,
+ [ "prop_script" ] = true,
+ [ "grenade_frag" ] = true,
+ [ "rpg_missile" ] = true,
+ [ "script_mover" ] = true,
+ [ "turret" ] = true,
+}
+
+struct {
+ array<string> missileCheckTargetnames = [
+ // "Arc Pylon",
+ "Arc Ball"
+ ]
+} file;
+
+function ArcCannon_Init()
+{
+ RegisterSignal( ARC_CANNON_SIGNAL_DEACTIVATED )
+ RegisterSignal( ARC_CANNON_SIGNAL_CHARGEEND )
+ PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT )
+ PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT_MOD )
+ PrecacheImpactEffectTable( ARC_CANNON_FX_TABLE )
+
+ #if CLIENT
+ AddDestroyCallback( "mp_titanweapon_arc_cannon", ClientDestroyCallback_ArcCannon_Stop )
+ #else
+ level._arcCannonTargetsArrayID <- CreateScriptManagedEntArray()
+ #endif
+
+ PrecacheParticleSystem( $"impact_arc_cannon_titan" )
+}
+
+function ArcCannon_PrecacheFX()
+{
+ PrecacheParticleSystem( $"wpn_arc_cannon_electricity_fp" )
+ PrecacheParticleSystem( $"wpn_arc_cannon_electricity" )
+
+ PrecacheParticleSystem( $"wpn_muzzleflash_arc_cannon_fp" )
+ PrecacheParticleSystem( $"wpn_muzzleflash_arc_cannon" )
+}
+
+function ArcCannon_Start( weapon )
+{
+ expect entity( weapon )
+ if ( !IsPilot( weapon.GetWeaponOwner() ) )
+ {
+ weapon.PlayWeaponEffectNoCull( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity", "muzzle_flash" )
+ weapon.EmitWeaponSound( "arc_cannon_charged_loop" )
+ }
+ else
+ {
+ weapon.EmitWeaponSound_1p3p( "Arc_Rifle_charged_Loop_1P", "Arc_Rifle_charged_Loop_3P" )
+ }
+}
+
+function ArcCannon_Stop( weapon, player = null )
+{
+ expect entity( weapon )
+ weapon.Signal( ARC_CANNON_SIGNAL_DEACTIVATED )
+
+ weapon.StopWeaponEffect( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity" )
+ weapon.StopWeaponSound( "arc_cannon_charged_loop" )
+}
+
+function ArcCannon_ChargeBegin( entity weapon )
+{
+ #if SERVER
+ if ( weapon.HasMod( "overcharge" ) )
+ {
+ entity weaponOwner = weapon.GetWeaponOwner()
+ if ( weaponOwner.IsTitan() )
+ {
+ entity soul = weaponOwner.GetTitanSoul()
+ thread ConvertTitanShieldIntoBonusCharge( soul, weapon )
+ }
+ }
+ #endif
+
+ #if CLIENT
+ if ( !weapon.ShouldPredictProjectiles() )
+ return
+
+ entity weaponOwner = weapon.GetWeaponOwner()
+ Assert( weaponOwner.IsPlayer() )
+ weaponOwner.StartArcCannon();
+ #endif
+}
+
+function ArcCannon_ChargeEnd( entity weapon, entity player = null )
+{
+ #if SERVER
+ if ( IsValid( weapon ) )
+ weapon.Signal( ARC_CANNON_SIGNAL_CHARGEEND )
+ #endif
+
+ #if CLIENT
+ if ( weapon.GetWeaponOwner() == GetLocalViewPlayer() )
+ {
+ entity weaponOwner
+ if ( player != null )
+ weaponOwner = player
+ else
+ weaponOwner = weapon.GetWeaponOwner()
+
+ if ( IsValid( weaponOwner ) && weaponOwner.IsPlayer() )
+ weaponOwner.StopArcCannon()
+ }
+ #endif
+}
+
+#if SERVER
+function ConvertTitanShieldIntoBonusCharge( entity soul, entity weapon )
+{
+ weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND )
+ weapon.EndSignal( "OnDestroy" )
+
+ local maxShieldDecay = OVERCHARGE_MAX_SHIELD_DECAY
+ local bonusChargeFraction = OVERCHARGE_BONUS_CHARGE_FRACTION
+ local shieldDecayMultiplier = OVERCHARGE_SHIELD_DECAY_MULTIPLIER
+ int shieldHealthMax = soul.GetShieldHealthMax()
+ local chargeRatio = GetArcCannonChargeFraction( weapon )
+
+ while( 1 )
+ {
+ if ( !IsValid( soul ) || !IsValid( weapon ) )
+ break
+
+ local baseCharge = GetWeaponChargeFrac( weapon ) // + GetOverchargeBonusChargeFraction()
+ local charge = clamp ( baseCharge * ( 1 / chargeRatio ), 0.0, 1.0 )
+ if ( charge < 1.0 || maxShieldDecay > 0)
+ {
+ int shieldHealth = soul.GetShieldHealth()
+
+ //Slight inconsistency in server updates, this ensures it never takes too much.
+ if ( shieldDecayMultiplier > maxShieldDecay )
+ shieldDecayMultiplier = maxShieldDecay
+ maxShieldDecay -= shieldDecayMultiplier
+
+ local shieldDecayAmount = shieldHealthMax * shieldDecayMultiplier
+ local newShieldAmount = shieldHealth - shieldDecayAmount
+ soul.SetShieldHealth( max( newShieldAmount, 0 ) )
+ soul.nextRegenTime = Time() + GetShieldRegenTime( soul )
+
+ if ( shieldDecayAmount > shieldHealth )
+ bonusChargeFraction = bonusChargeFraction * ( shieldHealth / shieldDecayAmount )
+ weapon.SetWeaponChargeFraction( baseCharge + bonusChargeFraction )
+ }
+ wait 0.1
+ }
+}
+#endif
+
+function FireArcCannon( entity weapon, WeaponPrimaryAttackParams attackParams )
+{
+ local weaponScriptScope = weapon.GetScriptScope()
+ local baseCharge = GetWeaponChargeFrac( weapon ) // + GetOverchargeBonusChargeFraction()
+ local charge = clamp( baseCharge * ( 1 / GetArcCannonChargeFraction( weapon ) ), 0.0, 1.0 )
+ float newVolume = GraphCapped( charge, 0.25, 1.0, 0.0, 1.0 )
+
+ weapon.EmitWeaponNpcSound( LOUD_WEAPON_AI_SOUND_RADIUS_MP, 0.2 )
+
+ weapon.PlayWeaponEffect( $"wpn_muzzleflash_arc_cannon_fp", $"wpn_muzzleflash_arc_cannon", "muzzle_flash" )
+
+ local attachmentName = "muzzle_flash"
+ local attachmentIndex = weapon.LookupAttachment( attachmentName )
+ Assert( attachmentIndex >= 0 )
+ local muzzleOrigin = weapon.GetAttachmentOrigin( attachmentIndex )
+
+ //printt( "-------- FIRING ARC CANNON --------" )
+
+ table firstTargetInfo = GetFirstArcCannonTarget( weapon, attackParams )
+ if ( !IsValid( firstTargetInfo.target ) )
+ FireArcNoTargets( weapon, attackParams, muzzleOrigin )
+ else
+ FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin )
+
+ return 1
+}
+
+table function GetFirstArcCannonTarget( entity weapon, WeaponPrimaryAttackParams attackParams )
+{
+ entity owner = weapon.GetWeaponOwner()
+ local coneHeight = weapon.GetMaxDamageFarDist()
+
+ local angleToAxis = 2 // set this too high and auto-titans using it will error on FindVisibleEntitiesInCone
+ array<entity> ignoredEntities = [ owner, weapon ]
+ int traceMask = TRACE_MASK_SHOT
+ int flags = VIS_CONE_ENTS_TEST_HITBOXES
+ local antilagPlayer = null
+ if ( owner.IsPlayer() )
+ {
+ angleToAxis = owner.GetAttackSpreadAngle() * 0.11
+ antilagPlayer = owner
+ }
+
+ int ownerTeam = owner.GetTeam()
+
+ // Get a missile target and a non-missile target in the cone that the player can zap
+ // We do this in a separate check so we can use a wider cone to be more forgiving for targeting missiles
+ table firstTargetInfo = {}
+ firstTargetInfo.target <- null
+ firstTargetInfo.hitLocation <- null
+
+ for ( int i = 0; i < 2; i++ )
+ {
+ local missileCheck = i == 0
+ local coneAngle = angleToAxis
+ if ( missileCheck && owner.IsPlayer() ) // missile check only if owner is player
+ coneAngle *= 8.0
+
+ coneAngle = clamp( coneAngle, 0.1, 89.9 )
+
+ array<VisibleEntityInCone> results = FindVisibleEntitiesInCone( attackParams.pos, attackParams.dir, coneHeight, coneAngle, ignoredEntities, traceMask, flags, antilagPlayer )
+ foreach ( result in results )
+ {
+ entity visibleEnt = result.ent
+
+ if ( !IsValid( visibleEnt ) )
+ continue
+
+ if ( visibleEnt.IsPhaseShifted() )
+ continue
+
+ local classname = IsServer() ? visibleEnt.GetClassName() : visibleEnt.GetSignifierName()
+
+ if ( !( classname in ArcCannonTargetClassnames ) )
+ continue
+
+ if ( "GetTeam" in visibleEnt )
+ {
+ int visibleEntTeam = visibleEnt.GetTeam()
+ if ( visibleEntTeam == ownerTeam )
+ continue
+ if ( IsEntANeutralMegaTurret( visibleEnt, ownerTeam ) )
+ continue
+ }
+
+ expect string( classname )
+ string targetname = visibleEnt.GetTargetName()
+
+ if ( missileCheck && ( classname != "rpg_missile" && !file.missileCheckTargetnames.contains( targetname ) ) )
+ continue
+
+ if ( !missileCheck && ( classname == "rpg_missile" || file.missileCheckTargetnames.contains( targetname ) ) )
+ continue
+
+ firstTargetInfo.target = visibleEnt
+ firstTargetInfo.hitLocation = result.visiblePosition
+ break
+ }
+ }
+ //Creating a whiz-by sound.
+ weapon.FireWeaponBullet_Special( attackParams.pos, attackParams.dir, 1, 0, true, true, true, true, true, false, false )
+
+ return firstTargetInfo
+}
+
+function FireArcNoTargets( entity weapon, WeaponPrimaryAttackParams attackParams, muzzleOrigin )
+{
+ Assert( IsValid( weapon ) )
+ entity player = weapon.GetWeaponOwner()
+ local chargeFrac = GetWeaponChargeFrac( weapon )
+ local beamVec = attackParams.dir * weapon.GetMaxDamageFarDist()
+ local playerEyePos = player.EyePosition()
+ TraceResults traceResults = TraceLineHighDetail( playerEyePos, (playerEyePos + beamVec), weapon, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+ local beamEnd = traceResults.endPos
+
+ VortexBulletHit ornull vortexHit = VortexBulletHitCheck( player, playerEyePos, beamEnd )
+ if ( vortexHit )
+ {
+ expect VortexBulletHit( vortexHit )
+ #if SERVER
+ entity vortexWeapon = vortexHit.vortex.GetOwnerWeapon()
+ string className = IsValid( vortexWeapon ) ? vortexWeapon.GetWeaponClassName() : ""
+ if ( vortexWeapon && ( className == "mp_titanweapon_vortex_shield" || className == "mp_titanweapon_vortex_shield_ion" ) )
+ {
+ float amount = expect float ( chargeFrac ) * weapon.GetWeaponSettingFloat( eWeaponVar.vortex_drain )
+ if ( amount <= 0.0 )
+ return
+
+ if ( vortexWeapon.GetWeaponClassName() == "mp_titanweapon_vortex_shield_ion" )
+ {
+ entity owner = vortexWeapon.GetWeaponOwner()
+ int totalEnergy = owner.GetSharedEnergyTotal()
+ owner.TakeSharedEnergy( int( float( totalEnergy ) * amount ) )
+ }
+ else
+ {
+ float frac = min ( vortexWeapon.GetWeaponChargeFraction() + amount, 1.0 )
+ vortexWeapon.SetWeaponChargeFraction( frac )
+ }
+ }
+ else if ( IsVortexSphere( vortexHit.vortex ) )
+ {
+ // do damage to vortex_sphere entities that isn't the titan "vortex shield"
+ local damageNear = weapon.GetWeaponInfoFileKeyField( "damage_near_value" )
+ local damage = damageNear * GraphCapped( chargeFrac, 0, 1, 0.0, 1.0 ) * 10 // do more damage the more charged the weapon is.
+ VortexSphereDrainHealthForDamage( vortexHit.vortex, damage )
+ if ( IsValid( player ) && player.IsPlayer() )
+ player.NotifyDidDamage( vortexHit.vortex, 0, vortexHit.hitPos, 0, damage, DF_NO_HITBEEP, 0, null, 0 )
+ }
+ #endif
+ beamEnd = vortexHit.hitPos
+ }
+
+ float radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX )
+ local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX )
+ if ( player.IsNPC() )
+ boltWidth = ARC_CANNON_BOLT_WIDTH_NPC
+ thread CreateArcCannonBeam( weapon, null, muzzleOrigin, beamEnd, player, ARC_CANNON_BEAM_LIFETIME, radius, boltWidth, 2, false, true )
+
+ #if SERVER
+ PlayImpactFXTable( expect vector( beamEnd ), player, ARC_CANNON_FX_TABLE, SF_ENVEXPLOSION_INCLUDE_ENTITIES )
+ #endif
+}
+
+function FireArcWithTargets( entity weapon, table firstTargetInfo, WeaponPrimaryAttackParams attackParams, muzzleOrigin )
+{
+ local beamStart = muzzleOrigin
+ local beamEnd
+ entity player = weapon.GetWeaponOwner()
+ local chargeFrac = GetWeaponChargeFrac( weapon )
+ float radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX )
+ float boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX )
+ local maxChains
+ local minChains
+
+ if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
+ {
+ if ( player.IsNPC() )
+ maxChains = ARC_CANNON_CHAIN_COUNT_NPC_BURN
+ else
+ maxChains = ARC_CANNON_CHAIN_COUNT_MAX_BURN
+
+ minChains = ARC_CANNON_CHAIN_COUNT_MIN_BURN
+ }
+ else
+ {
+ if ( player.IsNPC() )
+ maxChains = ARC_CANNON_CHAIN_COUNT_NPC
+ else
+ maxChains = ARC_CANNON_CHAIN_COUNT_MAX
+
+ minChains = ARC_CANNON_CHAIN_COUNT_MIN
+ }
+
+ if ( !player.IsNPC() )
+ maxChains = Graph( chargeFrac, 0, 1, minChains, maxChains )
+
+ table zapInfo = {}
+ zapInfo.weapon <- weapon
+ zapInfo.player <- player
+ zapInfo.muzzleOrigin <- muzzleOrigin
+ zapInfo.radius <- radius
+ zapInfo.boltWidth <- boltWidth
+ zapInfo.maxChains <- maxChains
+ zapInfo.chargeFrac <- chargeFrac
+ zapInfo.zappedTargets <- {}
+ zapInfo.zappedTargets[ firstTargetInfo.target ] <- true
+ zapInfo.dmgSourceID <- weapon.GetDamageSourceID()
+ local chainNum = 1
+ thread ZapTargetRecursive( expect entity( firstTargetInfo.target), zapInfo, zapInfo.muzzleOrigin, expect vector( firstTargetInfo.hitLocation ), chainNum )
+}
+
+function ZapTargetRecursive( entity target, table zapInfo, beamStartPos, vector ornull firstTargetBeamEndPos = null, chainNum = 1 )
+{
+ if ( !IsValid( target ) )
+ return
+
+ if ( !IsValid( zapInfo.weapon ) )
+ return
+
+ Assert( target in zapInfo.zappedTargets )
+ if ( chainNum > zapInfo.maxChains )
+ return
+ vector beamEndPos
+ if ( firstTargetBeamEndPos == null )
+ beamEndPos = target.GetWorldSpaceCenter()
+ else
+ beamEndPos = expect vector( firstTargetBeamEndPos )
+
+ waitthread ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum )
+
+ // Get other nearby targets we can chain to
+ #if SERVER
+ if ( !IsValid( zapInfo.weapon ) )
+ return
+
+ var noArcing = expect entity( zapInfo.weapon ).GetWeaponInfoFileKeyField( "disable_arc" )
+
+ if ( noArcing != null && noArcing == 1 )
+ return // no chaining on new arc cannon
+
+ // NOTE: 'target' could be invalid at this point (no corpse)
+ array<entity> chainTargets = GetArcCannonChainTargets( beamEndPos, target, zapInfo )
+ foreach( entity chainTarget in chainTargets )
+ {
+ local newChainNum = chainNum
+ if ( chainTarget.GetClassName() != "rpg_missile" )
+ newChainNum++
+ zapInfo.zappedTargets[ chainTarget ] <- true
+ thread ZapTargetRecursive( chainTarget, zapInfo, beamEndPos, null, newChainNum )
+ }
+
+ if ( IsValid( zapInfo.player ) && zapInfo.player.IsPlayer() && zapInfo.zappedTargets.len() >= 5 )
+ {
+ #if HAS_STATS
+ if ( chainNum == 5 )
+ UpdatePlayerStat( expect entity( zapInfo.player ), "misc_stats", "arcCannonMultiKills", 1 )
+ #endif
+ }
+ #endif
+}
+
+function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
+{
+ expect entity( target )
+ expect vector( beamStartPos )
+ expect vector( beamEndPos )
+
+ //DebugDrawLine( beamStartPos, beamEndPos, 255, 0, 0, true, 5.0 )
+ local boltWidth = zapInfo.boltWidth
+ if ( zapInfo.player.IsNPC() )
+ boltWidth = ARC_CANNON_BOLT_WIDTH_NPC
+ local firstBeam = ( chainNum == 1 )
+ #if SERVER
+ if ( firstBeam )
+ {
+ PlayImpactFXTable( beamEndPos, expect entity( zapInfo.player ), ARC_CANNON_FX_TABLE, SF_ENVEXPLOSION_INCLUDE_ENTITIES )
+ }
+ #endif
+
+ thread CreateArcCannonBeam( zapInfo.weapon, target, beamStartPos, beamEndPos, zapInfo.player, ARC_CANNON_BEAM_LIFETIME, zapInfo.radius, boltWidth, 5, true, firstBeam )
+
+ #if SERVER
+ local isMissile = ( target.GetClassName() == "rpg_missile" )
+ if ( !isMissile )
+ wait ARC_CANNON_FORK_DELAY
+ else
+ wait 0.05
+
+ local deathPackage = damageTypes.arcCannon
+
+ float damageAmount
+ int damageMin
+ int damageMax
+
+ int damageFarValue = eWeaponVar.damage_far_value
+ int damageNearValue = eWeaponVar.damage_near_value
+ int damageFarValueTitanArmor = eWeaponVar.damage_far_value_titanarmor
+ int damageNearValueTitanArmor = eWeaponVar.damage_near_value_titanarmor
+ int damageFarDistance = eWeaponVar.damage_far_distance
+ int damageNearDistance = eWeaponVar.damage_near_distance
+ if ( zapInfo.player.IsNPC() )
+ {
+ damageFarValue = eWeaponVar.npc_damage_far_value
+ damageNearValue = eWeaponVar.npc_damage_near_value
+ damageFarValueTitanArmor = eWeaponVar.npc_damage_far_value_titanarmor
+ damageNearValueTitanArmor = eWeaponVar.npc_damage_near_value_titanarmor
+ damageFarDistance = eWeaponVar.npc_damage_far_distance
+ damageNearDistance = eWeaponVar.npc_damage_near_distance
+ }
+
+ if ( IsValid( target ) && IsValid( zapInfo.player ) )
+ {
+ bool hasFastPacitor = false
+ bool noArcing = false
+
+ if ( IsValid( zapInfo.weapon ) )
+ {
+ entity weap = expect entity( zapInfo.weapon )
+ hasFastPacitor = weap.GetWeaponInfoFileKeyField( "push_apart" ) != null && weap.GetWeaponInfoFileKeyField( "push_apart" ) == 1
+ noArcing = weap.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weap.GetWeaponInfoFileKeyField( "no_arcing" ) == 1
+ }
+
+ if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
+ {
+ if ( IsValid( zapInfo.weapon ) )
+ {
+ entity weapon = expect entity( zapInfo.weapon )
+ damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor )
+ damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor )
+ }
+ else
+ {
+ damageMin = 100
+ damageMax = zapInfo.player.IsNPC() ? 1200 : 800
+ }
+ }
+ else
+ {
+ if ( IsValid( zapInfo.weapon ) )
+ {
+ entity weapon = expect entity( zapInfo.weapon )
+ damageMin = weapon.GetWeaponSettingInt( damageFarValue )
+ damageMax = weapon.GetWeaponSettingInt( damageNearValue )
+ }
+ else
+ {
+ damageMin = 120
+ damageMax = zapInfo.player.IsNPC() ? 140 : 275
+ }
+
+ if ( target.IsNPC() )
+ {
+ damageMin *= 3 // more powerful against NPC humans so they die easy
+ damageMax *= 3
+ }
+ }
+
+
+ local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon )
+ if ( IsValid( zapInfo.weapon ) && !zapInfo.weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) )
+ {
+ // use distance for damage if the weapon auto-fires
+ entity weapon = expect entity( zapInfo.weapon )
+ float nearDist = weapon.GetWeaponSettingFloat( damageNearDistance )
+ float farDist = weapon.GetWeaponSettingFloat( damageFarDistance )
+
+ float dist = Distance( weapon.GetOrigin(), target.GetOrigin() )
+ damageAmount = GraphCapped( dist, farDist, nearDist, damageMin, damageMax )
+ }
+ else
+ {
+ // Scale damage amount based on how many chains deep we are
+ damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax )
+ }
+ local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER
+ if ( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) )
+ damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER
+ damageAmount *= pow( damageFalloff, chainNum - 1 )
+
+ local dmgSourceID = zapInfo.dmgSourceID
+
+ // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target
+ // move to Damaged callback instead
+ if ( damageAmount > 0 )
+ {
+ float empDuration = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_EMP_DURATION_MIN, ARC_CANNON_EMP_DURATION_MAX )
+
+ if ( target.IsPlayer() && target.IsTitan() && !hasFastPacitor && !noArcing )
+ {
+ float empViewStrength = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SCREEN_EFFECTS_MIN, ARC_CANNON_SCREEN_EFFECTS_MAX )
+
+ if ( target.IsTitan() && zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD )
+ {
+ Remote_CallFunction_Replay( target, "ServerCallback_TitanEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION )
+ EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_TITAN_SCREEN_SFX )
+ }
+ else if ( zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD )
+ {
+ StatusEffect_AddTimed( target, eStatusEffect.emp, empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION )
+ EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_PILOT_SCREEN_SFX )
+ }
+ }
+
+ // Do 3rd person effect on the body
+ asset effect
+ string tag
+ target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = zapInfo.weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale ) } )
+ //vector dir = Normalize( beamEndPos - beamStartPos )
+ //vector velocity = dir * 600
+ //PushPlayerAway( target, velocity )
+ //PushPlayerAway( expect entity( zapInfo.player ), -velocity )
+
+ if ( IsValid( zapInfo.weapon ) && hasFastPacitor )
+ {
+ if ( IsAlive( target ) && IsAlive( expect entity( zapInfo.player ) ) && target.IsTitan() )
+ {
+ float pushPercent = GraphCapped( damageAmount, damageMin, damageMax, 0.0, 1.0 )
+
+ if ( pushPercent > 0.6 )
+ PushPlayersApart( target, expect entity( zapInfo.player ), pushPercent * 400.0 )
+ }
+ }
+
+ if ( zapInfo.chargeFrac < ARC_CANNON_SCREEN_THRESHOLD )
+ empDuration = ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION
+ else
+ empDuration += ARC_CANNON_EMP_FADEOUT_DURATION
+
+ if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
+ {
+ effect = $"impact_arc_cannon_titan"
+ tag = "exp_torso_front"
+ }
+ else
+ {
+ effect = $"P_emp_body_human"
+ tag = "CHESTFOCUS"
+ }
+
+ if ( target.IsPlayer() )
+ {
+ if ( target.LookupAttachment( tag ) != 0 )
+ ClientStylePlayFXOnEntity( effect, target, tag, empDuration )
+ }
+
+ if ( target.IsPlayer() )
+ EmitSoundOnEntityExceptToPlayer( target, target, "Titan_Blue_Electricity_Cloud" )
+ else
+ EmitSoundOnEntity( target, "Titan_Blue_Electricity_Cloud" )
+
+ thread FadeOutSoundOnEntityAfterDelay( target, "Titan_Blue_Electricity_Cloud", empDuration * 0.6666, empDuration * 0.3333 )
+ }
+ else
+ {
+ //Don't bounce if the beam is set to do 0 damage.
+ chainNum = zapInfo.maxChains
+ }
+
+ if ( isMissile )
+ {
+ if ( IsValid( zapInfo.player ) )
+ target.SetOwner( zapInfo.player )
+ target.MissileExplode()
+ }
+ }
+ #endif // SERVER
+}
+
+
+#if SERVER
+
+void function PushEntForTime( entity ent, vector velocity, float time )
+{
+ ent.EndSignal( "OnDeath" )
+ float endTime = Time() + time
+ float startTime = Time()
+ for ( ;; )
+ {
+ if ( Time() >= endTime )
+ break
+ float multiplier = Graph( Time(), startTime, endTime, 1.0, 0.0 )
+ vector currentVel = ent.GetVelocity()
+ currentVel += velocity * multiplier
+ ent.SetVelocity( currentVel )
+ WaitFrame()
+ }
+}
+
+array<entity> function GetArcCannonChainTargets( vector fromOrigin, entity fromTarget, table zapInfo )
+{
+ // NOTE: fromTarget could be null/invalid if it was a drone
+ array<entity> results = []
+ if ( !IsValid( zapInfo.player ) )
+ return results
+
+ int playerTeam = expect entity( zapInfo.player ).GetTeam()
+ array<entity> allTargets = GetArcCannonTargetsInRange( fromOrigin, playerTeam, expect entity( zapInfo.weapon ) )
+ allTargets = ArrayClosest( allTargets, fromOrigin )
+
+ local viewVector
+ if ( zapInfo.player.IsPlayer() )
+ viewVector = zapInfo.player.GetViewVector()
+ else
+ viewVector = AnglesToForward( zapInfo.player.EyeAngles() )
+
+ local eyePosition = zapInfo.player.EyePosition()
+
+ foreach ( ent in allTargets )
+ {
+ local forkCount = ARC_CANNON_FORK_COUNT_MAX
+ if ( zapInfo.weapon.HasMod( "splitter" ) )
+ forkCount = SPLITTER_FORK_COUNT_MAX
+ else if ( zapInfo.weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
+ forkCount = ARC_CANNON_FORK_COUNT_MAX_BURN
+
+ if ( results.len() >= forkCount )
+ break
+
+ if ( ent.IsPhaseShifted() )
+ continue
+
+ if ( ent.IsPlayer() )
+ {
+ // Ignore players that are passing damage to their parent. This is to address zapping a friendly rodeo player
+ local entParent = ent.GetParent()
+ if ( IsValid( entParent ) && ent.kv.PassDamageToParent.tointeger() )
+ continue
+
+ // only chains to other titan players for now
+ if ( !ent.IsTitan() )
+ continue
+ }
+
+ if ( ent.GetClassName() == "script_mover" )
+ continue
+
+ if ( IsEntANeutralMegaTurret( ent, playerTeam ) )
+ continue
+
+ if ( !IsAlive( ent ) )
+ continue
+
+ // Don't consider targets that already got zapped
+ if ( ent in zapInfo.zappedTargets )
+ continue
+
+ //Preventing the arc-cannon from firing behind.
+ local vecToEnt = ( ent.GetWorldSpaceCenter() - eyePosition )
+ vecToEnt.Norm()
+ local dotVal = DotProduct( vecToEnt, viewVector )
+ if ( dotVal < 0 )
+ continue
+
+ // Check if we can see them, they aren't behind a wall or something
+ local ignoreEnts = []
+ ignoreEnts.append( zapInfo.player )
+ ignoreEnts.append( ent )
+
+ foreach( zappedTarget, val in zapInfo.zappedTargets )
+ {
+ if ( IsValid( zappedTarget ) )
+ ignoreEnts.append( zappedTarget )
+ }
+
+ TraceResults traceResult = TraceLineHighDetail( fromOrigin, ent.GetWorldSpaceCenter(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+
+ // Trace failed, lets try an eye to eye trace
+ if ( traceResult.fraction < 1 )
+ {
+ // 'fromTarget' may be invalid
+ if ( IsValid( fromTarget ) )
+ traceResult = TraceLineHighDetail( fromTarget.EyePosition(), ent.EyePosition(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+ }
+
+ if ( traceResult.fraction < 1 )
+ continue
+
+ // Enemy is in visible, and within range.
+ if ( !results.contains( ent ) )
+ results.append( ent )
+ }
+
+ //printt( "NEARBY TARGETS VALID AND VISIBLE:", results.len() )
+
+ return results
+}
+#endif // SERVER
+
+bool function IsEntANeutralMegaTurret( ent, int playerTeam )
+{
+ expect entity( ent )
+
+ if ( ent.GetClassName() != "npc_turret_mega" )
+ return false
+ int entTeam = ent.GetTeam()
+ if ( entTeam == playerTeam )
+ return false
+ if ( !IsEnemyTeam( playerTeam, entTeam ) )
+ return true
+
+ return false
+}
+
+function ArcCannon_HideIdleEffect( entity weapon, delay )
+{
+ bool weaponOwnerIsPilot = IsPilot( weapon.GetWeaponOwner() )
+ weapon.EndSignal( ARC_CANNON_SIGNAL_DEACTIVATED )
+ if ( weaponOwnerIsPilot == false )
+ {
+ weapon.StopWeaponEffect( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity" )
+ weapon.StopWeaponSound( "arc_cannon_charged_loop" )
+ }
+ wait delay
+
+ if ( !IsValid( weapon ) )
+ return
+
+ entity weaponOwner = weapon.GetWeaponOwner()
+ //The weapon can be valid, but the player isn't a Titan during melee execute.
+ // JFS: threads with waits should just end on "OnDestroy"
+ if ( !IsValid( weaponOwner ) )
+ return
+
+ if ( weapon != weaponOwner.GetActiveWeapon() )
+ return
+
+ if ( weaponOwnerIsPilot == false )
+ {
+ weapon.PlayWeaponEffectNoCull( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity", "muzzle_flash" )
+ weapon.EmitWeaponSound( "arc_cannon_charged_loop" )
+ }
+ else
+ {
+ weapon.EmitWeaponSound_1p3p( "Arc_Rifle_charged_Loop_1P", "Arc_Rifle_charged_Loop_3P" )
+ }
+}
+
+#if SERVER
+void function AddToArcCannonTargets( entity ent )
+{
+ AddToScriptManagedEntArray( level._arcCannonTargetsArrayID, ent );
+}
+
+function RemoveArcCannonTarget( ent )
+{
+ RemoveFromScriptManagedEntArray( level._arcCannonTargetsArrayID, ent )
+}
+
+array<entity> function GetArcCannonTargets( vector origin, int team, entity weapon )
+{
+ array<entity> targets = GetScriptManagedEntArrayWithinCenter( level._arcCannonTargetsArrayID, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN )
+
+ if ( ARC_CANNON_TARGETS_MISSILES && weapon.GetWeaponChargeFraction() == 1.0 )
+ targets.extend( GetProjectileArrayEx( "rpg_missile", TEAM_ANY, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) )
+
+ return targets
+}
+
+array<entity> function GetArcCannonTargetsInRange( vector origin, int team, entity weapon )
+{
+ array<entity> allTargets = GetArcCannonTargets( origin, team, weapon )
+ array<entity> targetsInRange
+
+ float titanDistSq
+ float distSq
+ if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
+ {
+ titanDistSq = ARC_CANNON_TITAN_RANGE_CHAIN_BURN * ARC_CANNON_TITAN_RANGE_CHAIN_BURN
+ distSq = ARC_CANNON_RANGE_CHAIN_BURN * ARC_CANNON_RANGE_CHAIN_BURN
+ }
+ else
+ {
+ titanDistSq = ARC_CANNON_TITAN_RANGE_CHAIN * ARC_CANNON_TITAN_RANGE_CHAIN
+ distSq = ARC_CANNON_RANGE_CHAIN * ARC_CANNON_RANGE_CHAIN
+ }
+
+ foreach( target in allTargets )
+ {
+ float d = DistanceSqr( target.GetOrigin(), origin )
+ float validDist = target.IsTitan() ? titanDistSq : distSq
+ if ( d <= validDist )
+ targetsInRange.append( target )
+ }
+
+ return targetsInRange
+}
+#endif // SERVER
+
+function CreateArcCannonBeam( weapon, target, startPos, endPos, player, lifeDuration = ARC_CANNON_BEAM_LIFETIME, radius = 256, boltWidth = 4, noiseAmplitude = 5, hasTarget = true, firstBeam = false )
+{
+ Assert( startPos )
+ Assert( endPos )
+
+ //**************************
+ // LIGHTNING BEAM EFFECT
+ //**************************
+ if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
+ lifeDuration = ARC_CANNON_BEAM_LIFETIME_BURN
+ // If it's the first beam and on client we do a special beam so it's lined up with the muzzle origin
+ #if CLIENT
+ if ( firstBeam )
+ thread CreateClientArcBeam( weapon, endPos, lifeDuration, target )
+ #endif
+
+ #if SERVER
+ // Control point sets the end position of the effect
+ entity cpEnd = CreateEntity( "info_placement_helper" )
+ SetTargetName( cpEnd, UniqueString( "arc_cannon_beam_cpEnd" ) )
+ cpEnd.SetOrigin( endPos )
+ DispatchSpawn( cpEnd )
+
+ entity zapBeam = CreateEntity( "info_particle_system" )
+ zapBeam.kv.cpoint1 = cpEnd.GetTargetName()
+
+ zapBeam.SetValueForEffectNameKey( GetBeamEffect( weapon ) )
+
+ zapBeam.kv.start_active = 0
+ zapBeam.SetOwner( player )
+ zapBeam.SetOrigin( startPos )
+ if ( firstBeam )
+ {
+ zapBeam.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) // everyone but owner
+ zapBeam.SetParent( player.GetActiveWeapon(), "muzzle_flash", false, 0.0 )
+ }
+ DispatchSpawn( zapBeam )
+
+ zapBeam.Fire( "Start" )
+ zapBeam.Fire( "StopPlayEndCap", "", lifeDuration )
+ zapBeam.Kill_Deprecated_UseDestroyInstead( lifeDuration )
+ cpEnd.Kill_Deprecated_UseDestroyInstead( lifeDuration )
+ #endif
+}
+
+function GetBeamEffect( weapon )
+{
+ if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
+ return ARC_CANNON_BEAM_EFFECT_MOD
+
+ return ARC_CANNON_BEAM_EFFECT
+}
+
+#if CLIENT
+function CreateClientArcBeam( weapon, endPos, lifeDuration, target )
+{
+ Assert( IsClient() )
+
+ local beamEffect = GetBeamEffect( weapon )
+
+ // HACK HACK HACK HACK
+ string tag = "muzzle_flash"
+ if ( weapon.GetWeaponInfoFileKeyField( "client_tag_override" ) != null )
+ tag = expect string( weapon.GetWeaponInfoFileKeyField( "client_tag_override" ) )
+
+ local handle = weapon.PlayWeaponEffectReturnViewEffectHandle( beamEffect, $"", tag )
+ if ( !EffectDoesExist( handle ) )
+ return
+
+ EffectSetControlPointVector( handle, 1, endPos )
+
+ if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
+ lifeDuration = ARC_CANNON_BEAM_LIFETIME_BURN
+
+ wait( lifeDuration )
+
+ if ( IsValid( weapon ) )
+ weapon.StopWeaponEffect( beamEffect, $"" )
+}
+
+void function ClientDestroyCallback_ArcCannon_Stop( entity ent )
+{
+ ArcCannon_Stop( ent )
+}
+#endif // CLIENT
+
+function GetArcCannonChargeFraction( weapon )
+{
+ if ( IsValid( weapon ) )
+ {
+ local chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO
+ if ( weapon.HasMod( "capacitor" ) )
+ chargeRatio = ARC_CANNON_CAPACITOR_CHARGE_RATIO
+ if ( weapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
+ chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN
+ return chargeRatio
+ }
+
+ return 0
+}
+
+function GetWeaponChargeFrac( weapon )
+{
+ if ( weapon.IsChargeWeapon() )
+ return weapon.GetWeaponChargeFraction()
+ return 1.0
+}
diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut
new file mode 100644
index 000000000..788793932
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut
@@ -0,0 +1,226 @@
+untyped
+
+global function MpTitanweaponArcCannon_Init
+
+global function OnWeaponActivate_titanweapon_arc_cannon
+global function OnWeaponDeactivate_titanweapon_arc_cannon
+global function OnWeaponReload_titanweapon_arc_cannon
+global function OnWeaponOwnerChanged_titanweapon_arc_cannon
+global function OnWeaponChargeBegin_titanweapon_arc_cannon
+global function OnWeaponChargeEnd_titanweapon_arc_cannon
+global function OnWeaponPrimaryAttack_titanweapon_arc_cannon
+
+const FX_EMP_BODY_HUMAN = $"P_emp_body_human"
+const FX_EMP_BODY_TITAN = $"P_emp_body_titan"
+
+#if SERVER
+global function OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon
+#endif // #if SERVER
+
+void function MpTitanweaponArcCannon_Init()
+{
+ ArcCannon_PrecacheFX()
+
+ #if SERVER
+ AddDamageCallbackSourceID( eDamageSourceId.mp_titanweapon_arc_cannon, ArcRifleOnDamage )
+ #endif
+}
+
+void function OnWeaponActivate_titanweapon_arc_cannon( entity weapon )
+{
+ entity weaponOwner = weapon.GetWeaponOwner()
+ thread DelayedArcCannonStart( weapon, weaponOwner )
+ if( !("weaponOwner" in weapon.s) )
+ weapon.s.weaponOwner <- weaponOwner
+}
+
+function DelayedArcCannonStart( entity weapon, entity weaponOwner )
+{
+ weapon.EndSignal( "WeaponDeactivateEvent" )
+
+ WaitFrame()
+
+ if ( IsValid( weapon ) && IsValid( weaponOwner ) && weapon == weaponOwner.GetActiveWeapon() )
+ {
+ if( weaponOwner.IsPlayer() )
+ {
+ entity modelEnt = weaponOwner.GetViewModelEntity()
+ if( IsValid( modelEnt ) && EntHasModelSet( modelEnt ) )
+ ArcCannon_Start( weapon )
+ }
+ else
+ {
+ ArcCannon_Start( weapon )
+ }
+ }
+}
+
+void function OnWeaponDeactivate_titanweapon_arc_cannon( entity weapon )
+{
+ ArcCannon_ChargeEnd( weapon, expect entity( weapon.s.weaponOwner ) )
+ ArcCannon_Stop( weapon )
+}
+
+void function OnWeaponReload_titanweapon_arc_cannon( entity weapon, int milestoneIndex )
+{
+ local reloadTime = weapon.GetWeaponInfoFileKeyField( "reload_time" )
+ thread ArcCannon_HideIdleEffect( weapon, reloadTime ) //constant seems to help it sync up better
+}
+
+void function OnWeaponOwnerChanged_titanweapon_arc_cannon( entity weapon, WeaponOwnerChangedParams changeParams )
+{
+ #if CLIENT
+ entity viewPlayer = GetLocalViewPlayer()
+ if ( changeParams.oldOwner != null && changeParams.oldOwner == viewPlayer )
+ {
+ ArcCannon_ChargeEnd( weapon, changeParams.oldOwner )
+ ArcCannon_Stop( weapon)
+ }
+
+ if ( changeParams.newOwner != null && changeParams.newOwner == viewPlayer )
+ thread ArcCannon_HideIdleEffect( weapon, 0.25 )
+ #else
+ if ( changeParams.oldOwner != null )
+ {
+ ArcCannon_ChargeEnd( weapon, changeParams.oldOwner )
+ ArcCannon_Stop( weapon )
+ }
+
+ if ( changeParams.newOwner != null )
+ thread ArcCannon_HideIdleEffect( weapon, 0.25 )
+ #endif
+}
+
+bool function OnWeaponChargeBegin_titanweapon_arc_cannon( entity weapon )
+{
+ local stub = "this is here to suppress the untyped message. This can go away when the .s. usage is removed from this file."
+ #if SERVER
+ //if ( weapon.HasMod( "fastpacitor_push_apart" ) )
+ // weapon.GetWeaponOwner().StunMovementBegin( weapon.GetWeaponSettingFloat( eWeaponVar.charge_time ) )
+ #endif
+
+ ArcCannon_ChargeBegin( weapon )
+
+ return true
+}
+
+void function OnWeaponChargeEnd_titanweapon_arc_cannon( entity weapon )
+{
+ ArcCannon_ChargeEnd( weapon, weapon )
+}
+
+var function OnWeaponPrimaryAttack_titanweapon_arc_cannon( entity weapon, WeaponPrimaryAttackParams attackParams )
+{
+ if ( weapon.HasMod( "capacitor" ) && weapon.GetWeaponChargeFraction() < GetArcCannonChargeFraction( weapon ) )
+ return 0
+
+ if ( !attackParams.firstTimePredicted )
+ return
+
+ local fireRate = weapon.GetWeaponInfoFileKeyField( "fire_rate" )
+ thread ArcCannon_HideIdleEffect( weapon, (1 / fireRate) )
+
+ return FireArcCannon( weapon, attackParams )
+}
+
+#if SERVER
+var function OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon( entity weapon, WeaponPrimaryAttackParams attackParams )
+{
+ local fireRate = weapon.GetWeaponInfoFileKeyField( "fire_rate" )
+ thread ArcCannon_HideIdleEffect( weapon, fireRate )
+
+ return FireArcCannon( weapon, attackParams )
+}
+
+void function ArcRifleOnDamage( entity ent, var damageInfo )
+{
+ vector pos = DamageInfo_GetDamagePosition( damageInfo )
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
+
+ EmitSoundOnEntity( ent, ARC_CANNON_TITAN_SCREEN_SFX )
+
+ if ( ent.IsPlayer() || ent.IsNPC() )
+ {
+ entity entToSlow = ent
+ entity soul = ent.GetTitanSoul()
+
+ if ( soul != null )
+ entToSlow = soul
+
+ StatusEffect_AddTimed( entToSlow, eStatusEffect.move_slow, 0.5, 2.0, 1.0 )
+ StatusEffect_AddTimed( entToSlow, eStatusEffect.dodge_speed_slow, 0.5, 2.0, 1.0 )
+ }
+
+ string tag = ""
+ asset effect
+
+ if ( ent.IsTitan() )
+ {
+ tag = "exp_torso_front"
+ effect = FX_EMP_BODY_TITAN
+ }
+ else if ( ChestFocusTarget( ent ) )
+ {
+ tag = "CHESTFOCUS"
+ effect = FX_EMP_BODY_HUMAN
+ }
+ else if ( IsAirDrone( ent ) )
+ {
+ tag = "HEADSHOT"
+ effect = FX_EMP_BODY_HUMAN
+ }
+ else if ( IsGunship( ent ) )
+ {
+ tag = "ORIGIN"
+ effect = FX_EMP_BODY_TITAN
+ }
+
+ if ( tag != "" )
+ {
+ float duration = 2.0
+ //thread EMP_FX( effect, ent, tag, duration )
+ }
+
+ if ( ent.IsTitan() )
+ {
+ if ( ent.IsPlayer() )
+ {
+ EmitSoundOnEntityOnlyToPlayer( ent, ent, "titan_energy_bulletimpact_3p_vs_1p" )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, "titan_energy_bulletimpact_3p_vs_3p" )
+ }
+ else
+ {
+ EmitSoundOnEntity( ent, "titan_energy_bulletimpact_3p_vs_3p" )
+ }
+ }
+ else
+ {
+ if ( ent.IsPlayer() )
+ {
+ EmitSoundOnEntityOnlyToPlayer( ent, ent, "flesh_lavafog_deathzap_3p" )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, "flesh_lavafog_deathzap_1p" )
+ }
+ else
+ {
+ EmitSoundOnEntity( ent, "flesh_lavafog_deathzap_1p" )
+ }
+ }
+
+}
+
+bool function ChestFocusTarget( entity ent )
+{
+ if ( IsSpectre( ent ) )
+ return true
+ if ( IsStalker( ent ) )
+ return true
+ if ( IsSuperSpectre( ent ) )
+ return true
+ if ( IsGrunt( ent ) )
+ return true
+ if ( IsPilot( ent ) )
+ return true
+
+ return false
+}
+#endif // #if SERVER
diff --git a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt
new file mode 100644
index 000000000..2672dca9c
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt
@@ -0,0 +1,349 @@
+WeaponData
+{
+ // General
+ "printname" "#WPN_TITAN_ARC_CANNON"
+ "shortprintname" "#WPN_TITAN_ARC_CANNON_SHORT"
+ "description" "#WPN_TITAN_ARC_CANNON_DESC"
+ "longdesc" "#WPN_TITAN_ARC_CANNON_LONGDESC"
+ "weaponClass" "titan"
+ "fire_mode" "semi-auto"
+ "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]"
+ "pickup_press_prompt" "[USE] [WEAPONNAME]"
+ "minimap_reveal_distance" "32000"
+
+ // Menu Stats
+ "stat_damage" "85"
+ "stat_range" "35"
+ "stat_accuracy" "80"
+ "stat_rof" "20"
+
+ // Models
+ "viewmodel" "models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl"
+ "playermodel" "models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl"
+ "anim_prefix" "ar2"
+
+
+ "OnWeaponActivate" "OnWeaponActivate_titanweapon_arc_cannon"
+ "OnWeaponDeactivate" "OnWeaponDeactivate_titanweapon_arc_cannon"
+ "OnWeaponReload" "OnWeaponReload_titanweapon_arc_cannon"
+ "OnWeaponOwnerChanged" "OnWeaponOwnerChanged_titanweapon_arc_cannon"
+ "OnWeaponChargeBegin" "OnWeaponChargeBegin_titanweapon_arc_cannon"
+ "OnWeaponChargeEnd" "OnWeaponChargeEnd_titanweapon_arc_cannon"
+ "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_titanweapon_arc_cannon"
+ "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon"
+// "OnWeaponCooldown" "OnWeaponCooldown_titanweapon_particle_accelerator"
+
+
+
+ // Effects
+ //"tracer_effect" "weapon_tracers_xo16"
+ //Impact Table used for visuals at the top of arc_cannon.nut
+ "tracer_effect" "P_wpn_arcball_beam"
+ "tracer_effect_first_person" "P_wpn_arcball_beam"
+ "impact_effect_table" "exp_arc_cannon"
+ "adjust_to_gun_barrel" "1"
+ "fx_muzzle_flash_view" "wpn_arc_cannon_electricity_fp"
+ "fx_muzzle_flash_world" "wpn_arc_cannon_electricity"
+ "fx_muzzle_flash_attach" "muzzle_flash"
+
+ // Damage - When Used by Players
+ "damage_type" "bullet"
+ "damage_near_distance" "200"
+ "damage_far_distance" "2500"
+ "damage_near_value" "220"
+ "damage_far_value" "170"
+ "damage_near_value_titanarmor" "1800"
+ "damage_far_value_titanarmor" "100"
+
+ // Damage - When Used by NPCs
+ "npc_damage_near_distance" "200"
+ "npc_damage_far_distance" "2500"
+ "npc_damage_near_value" "220"
+ "npc_damage_far_value" "170"
+ "npc_damage_near_value_titanarmor" "1800"
+ "npc_damage_far_value_titanarmor" "100"
+
+ "critical_hit" "0"
+ "critical_hit_damage_scale" "1.5"
+
+ // Ammo
+ "ammo_min_to_fire" "1"
+ "ammo_no_remove_from_stockpile" "1"
+
+ // Behavior
+ "fire_rate" "1"
+// "rechamber_time" "0.25" //"1.30"
+ "cooldown_time" "0.6"
+ "reloadempty_time" "6.03"
+ "reloadempty_time_late1" "4.7"
+ "reloadempty_time_late2" "3.5"
+ "reloadempty_time_late3" "2.5"
+ "reloadempty_time_late4" "1.43"
+ "reloadempty_time_late5" "0.56"
+ "zoom_time_in" "0.1"
+ "zoom_time_out" "0.1"
+ "zoom_fov" "33"
+ "reload_time" "3.5"
+ "reloadempty_time" "3.5"
+ "holster_time" ".45"
+ "deploy_time" ".85"
+ "lower_time" ".1"
+ "raise_time" ".4"
+ "charge_time" "3.7"
+ "charge_cooldown_time" "1.0"
+ "charge_end_forces_fire" "0"
+ "allow_empty_fire" "1"
+ "reload_enabled" "0"
+ "allow_empty_click" "1"
+ "empty_reload_only" "0"
+ "trigger_snipercam" "1"
+ "allow_headshots" "0"
+ "bypass_semiauto_hold_protection" "1"
+ "vortex_drain" ".15"
+ "charge_effect_1p" "wpn_arc_cannon_charge_fp"
+ "charge_effect_3p" "wpn_arc_cannon_charge"
+ "charge_effect_attachment" "muzzle_flash"
+
+
+
+ // Spread
+ "spread_stand_hip" "10"
+ "spread_npc" "2"
+
+ "ammo_suck_behavior" "primary_weapons"
+
+ // View Kick
+ "viewkick_spring" "titan_arc"
+
+ "viewkick_pitch_base" "-1"
+ "viewkick_pitch_random" "0.5"
+ "viewkick_pitch_softScale" "1"
+ "viewkick_pitch_hardScale" "0"
+
+ "viewkick_yaw_base" "0"
+ "viewkick_yaw_random" "0.5"
+ "viewkick_yaw_softScale" "1"
+ "viewkick_yaw_hardScale" "0"
+
+ "viewkick_roll_base" "0.0"
+ "viewkick_roll_randomMin" "0.3"
+ "viewkick_roll_randomMax" "0.45"
+ "viewkick_roll_softScale" "0.2"
+ "viewkick_roll_hardScale" "1.5"
+
+ "viewkick_hipfire_weaponFraction" "0.5"
+ "viewkick_hipfire_weaponFraction_vmScale" "0.75"
+ "viewkick_ads_weaponFraction" "0.6"
+ "viewkick_ads_weaponFraction_vmScale" "0.2"
+
+
+ // Bob
+ "bob_cycle_time" "0.7"
+ "bob_vert_dist" "0.5"
+ "bob_horz_dist" "1"
+ "bob_max_speed" "150"
+ "bob_pitch" "1"
+ "bob_yaw" "1"
+ "bob_roll" "-0.75"
+
+ // View Drift
+
+ // Rumble
+ "fire_rumble" "titan_arc_cannon"
+
+ // Sway
+ "sway_rotate_attach" "SWAY_ROTATE"
+ "sway_min_x" "-0.3"
+ "sway_min_y" "-0.5"
+ "sway_min_z" "-0.5"
+ "sway_max_x" "0.3"
+ "sway_max_y" "0.5"
+ "sway_max_z" "0.1"
+ "sway_min_pitch" "-3"
+ "sway_min_yaw" "-3.5"
+ "sway_min_roll" "-1"
+ "sway_max_pitch" "3"
+ "sway_max_yaw" "3.5"
+ "sway_max_roll" "2"
+ "sway_translate_gain" "10"
+ "sway_rotate_gain" "12"
+ "sway_move_forward_translate_x" "0"
+ "sway_move_forward_translate_z" "-0.5"
+ "sway_move_back_translate_x" "-2"
+ "sway_move_back_translate_z" "-1"
+ "sway_move_left_translate_y" "-1"
+ "sway_move_left_translate_z" "-0.5"
+ "sway_move_left_rotate_roll" "-1"
+ "sway_move_right_translate_y" "1"
+ "sway_move_right_translate_z" "-0.5"
+ "sway_move_right_rotate_roll" "2"
+ "sway_move_up_translate_z" "-1"
+ "sway_move_down_translate_z" "1"
+ "sway_turn_left_rotate_yaw" "-1"
+ "sway_turn_right_rotate_yaw" "1"
+ "sway_turn_up_rotate_pitch" "1"
+ "sway_turn_down_rotate_pitch" "-1"
+
+ // NPC
+ "proficiency_poor_spreadscale" "5.0"
+ "proficiency_poor_bias" "1.0"
+ "proficiency_average_spreadscale" "4.0"
+ "proficiency_average_bias" "1.0"
+ "proficiency_good_spreadscale" "3.0"
+ "proficiency_good_bias" "1.0"
+ "proficiency_very_good_spreadscale" "2.3"
+ "proficiency_very_good_bias" "1.0"
+ "proficiency_perfect_spreadscale" "1.7"
+ "proficiency_perfect_bias" "1.0"
+
+ "npc_min_range" "0"
+ "npc_max_range" "2500"
+ "npc_min_range_secondary" "0"
+ "npc_max_range_secondary" "2500"
+ "npc_min_burst" "1"
+ "npc_max_burst" "1"
+ "rest_time_between_bursts_min" "2.5"
+ "rest_time_between_bursts_max" "3.0"
+
+ // WeaponED Unhandled Key/Values and custom script Key/Values
+ "sound_dryfire" "titan_dryfire"
+ "viewdrift_hipfire_stand_scale_pitch" "0.1"
+ "viewdrift_hipfire_crouch_scale_pitch" "0.1"
+ "viewdrift_hipfire_air_scale_pitch" "0.1"
+ "viewdrift_hipfire_stand_scale_yaw" "0.075"
+ "viewdrift_hipfire_crouch_scale_yaw" "0.075"
+ "viewdrift_hipfire_air_scale_yaw" "0.075"
+ "viewdrift_hipfire_speed_pitch" "0.6"
+ "viewdrift_hipfire_speed_yaw" "1.22"
+ "viewdrift_ads_stand_scale_pitch" "0.05"
+ "viewdrift_ads_crouch_scale_pitch" "0.05"
+ "viewdrift_ads_air_scale_pitch" "0.05"
+ "viewdrift_ads_stand_scale_yaw" "0.037"
+ "viewdrift_ads_crouch_scale_yaw" "0.037"
+ "viewdrift_ads_air_scale_yaw" "0.037"
+ "viewdrift_ads_speed_pitch" "0.6"
+ "viewdrift_ads_speed_yaw" "1.22"
+ "npc_reload_enabled" "0"
+ "npc_vortex_block" "1"
+
+ // Crosshair
+ "red_crosshair_range" "2500"
+
+ Mods
+ {
+ overcharge
+ {
+ //overcharge
+ }
+ capacitor
+ {
+ "charge_time" "2.5" //for reference was 3 in 10/15 evening playtest
+ "charge_cooldown_time" "1.0"
+ "charge_cooldown_delay" "0.0"
+ //"crosshair_index" "1"
+ "spread_stand_hip" "15"
+ "damage_far_distance" "2700"
+ "damage_near_value_titanarmor" "2000"
+ }
+ splitter
+ {
+ "damage_near_value_titanarmor" "1900"
+ "damage_far_value_titanarmor" "100"
+ }
+ burn_mod_titan_arc_cannon
+ {
+ //"crosshair_index" "2"
+ "tracer_effect" "wpn_arc_cannon_beam_mod"
+ "tracer_effect_first_person" "wpn_arc_cannon_beam_mod"
+ "damage_near_value" "*1.1"
+ "damage_far_value" "*1.1"
+ "damage_near_value_titanarmor" "*1.1"
+ "damage_far_value_titanarmor" "*1.1"
+ "is_burn_mod" "1"
+ }
+ }
+
+ active_crosshair_count "2"
+// rui_crosshair_index "1"
+ "ui1_enable" "1"
+ "ui1_draw_cloaked" "0"
+ UiData1
+ {
+ "ui" "ui/crosshair_charge_rifle"
+ "mesh" "models/weapons/attachments/alternator_rui_upper"
+ Args
+ {
+ adjustedSpread weapon_spread
+ adsFrac player_zoomFrac
+ isSprinting player_is_sprinting
+ isReloading weapon_is_reloading
+ readyFrac progress_ready_to_fire_frac
+ teamColor crosshair_team_color
+ isAmped weapon_is_amped
+ chargeFrac player_chargeFrac
+ crosshairMovementX crosshair_movement_x
+ crosshairMovementY crosshair_movement_y
+ }
+ }
+ RUI_CrosshairData
+ {
+ DefaultArgs
+ {
+ adjustedSpread weapon_spread
+ adsFrac player_zoomFrac
+ isSprinting player_is_sprinting
+ isReloading weapon_is_reloading
+ readyFrac progress_ready_to_fire_frac
+ teamColor crosshair_team_color
+ isAmped weapon_is_amped
+ chargeFrac player_chargeFrac
+ crosshairMovementX crosshair_movement_x
+ crosshairMovementY crosshair_movement_y
+ }
+
+ Crosshair_1
+ {
+ "ui" "ui/crosshair_charge_rifle"
+// "ui" "ui/alternator_reticle"
+ "base_spread" "10.0"
+ Args
+ {
+ isFiring weapon_is_firing
+ }
+ Element0
+ {
+ "fade_while_sprinting" "1"
+ "fade_while_reloading" "1"
+ "stationary" "1"
+ "default_color" "246 134 40 255"
+ "type" "static"
+ "material" $"vgui/hud/arc_cannon_charge/arc_cannon_charge"
+ "size_x" "80"
+ "size_y" "80"
+ "scale_ads" "1.5"
+ }
+ Element1
+ {
+ "fade_while_sprinting" "1"
+ "fade_while_reloading" "1"
+ "stationary" "1"
+ "default_color" "246 134 40 255"
+ "type" "static"
+ "material" "vgui/hud/arc_cannon_charge/arc_cannon_shadow_horizontal"
+ "size_x" "80"
+ "size_y" "80"
+ "scale_ads" "1.5"
+ }
+ }
+
+ Crosshair_2
+ {
+ "ui" "ui/crosshair_circle2"
+ "base_spread" "0.0"
+ Args
+ {
+ isFiring weapon_is_firing
+ }
+ }
+ }
+}
diff --git a/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt b/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt
new file mode 100644
index 000000000..2bc8b0945
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt
@@ -0,0 +1,405 @@
+WeaponData
+{
+ // General
+ "printname" "#WPN_SHOTGUN_DBLBARREL"
+ "shortprintname" "#WPN_SHOTGUN_DBLBARREL_SHORT"
+ "description" "#WPN_SHOTGUN_DBLBARREL_DESC"
+ "longdesc" "#WPN_SHOTGUN_DBLBARREL_LONGDESC"
+ "menu_icon" "rui/weapon_icons/mp_weapon_shotgun_doublebarrel"
+ "hud_icon" "rui/weapon_icons/mp_weapon_shotgun_doublebarrel"
+ "viewmodel_offset_hip" "2 -2 -2"
+ "weaponClass" "human"
+ "weaponSubClass" "shotgun"
+ "body_type" "light"
+ "fire_mode" "semi-auto"
+ "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]"
+ "pickup_press_prompt" "[USE] [WEAPONNAME]"
+ "aimassist_adspull_weaponclass" "broad"
+ "minimap_reveal_distance" "32000"
+ "leveled_pickup" "0"
+
+ // Models
+ "viewmodel" "models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl"
+ "playermodel" "models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl"
+
+ "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_weapon_shotgun"
+ "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_weapon_shotgun"
+
+
+ "viewmodel_offset_ads" "0 0 0"
+ "dof_zoom_nearDepthStart" "2.000"
+ "dof_zoom_nearDepthEnd" "4.750"
+ "dof_nearDepthStart" "3.683"
+ "dof_nearDepthEnd" "5.300"
+
+ // Menu
+ "menu_category" "shotgun"
+ "menu_anim_class" "large"
+ "stat_damage" "50"
+ "stat_range" "70"
+ "stat_accuracy" "65"
+ "stat_rof" "30"
+
+ "impulse_force" "800"
+
+ "impact_effect_table" "inc_bullet"
+
+ // Spread
+ "spread_stand_hip" "8.5"
+ "spread_stand_hip_run" "8.5"
+ "spread_stand_hip_sprint" "8.5"
+ "spread_crouch_hip" "8.5"
+ "spread_air_hip" "8.5"
+ "spread_stand_ads" "8.5"
+ "spread_crouch_ads" "8.5"
+ "spread_air_ads" "8.5"
+ "spread_wallrunning" "8.5"
+ "spread_wallhanging" "8.5"
+
+ // Damage - When Used by Players
+ "damage_type" "bullet"
+ "damage_near_distance" "300"
+ "damage_far_distance" "700"
+ "damage_near_value" "220"
+ "damage_far_value" "25"
+ "damage_near_value_titanarmor" "130"
+ "damage_far_value_titanarmor" "10"
+
+ "damage_rodeo" "700"
+ "damage_falloff_type" "inverse"
+ "damage_inverse_distance" "130"
+ "damage_falloff_type" "inverse"
+ "damage_inverse_distance" "100"
+ "damage_flags" "DF_SHOTGUN | DF_BULLET | DF_KNOCK_BACK | DF_DISMEMBERMENT"
+
+ "damage_headshot_scale" "1.25"
+
+ "red_crosshair_range" "750"
+
+ // Damage - When Used by NPCs
+ "npc_damage_near_value" "25"
+ "npc_damage_far_value" "13"
+ "npc_damage_near_value_titanarmor" "40"
+ "npc_damage_far_value_titanarmor" "0"
+
+ "enable_highlight_networking_on_creation" "1"
+
+ "damage_heavyarmor_nontitan_scale" "0.35"
+
+
+ // Ammo
+ "ammo_stockpile_max" "40"
+ "ammo_default_total" "40"
+ "ammo_clip_size" "2"
+ "ammo_no_remove_from_stockpile" "1"
+ "ammo_min_to_fire" "1"
+
+ "reload_time" "1.85"
+ "reload_time_late1" "1.15"
+ "reloadempty_time" "1.85"
+ "reloadempty_time_late1" "1.15"
+
+
+ // Effects
+ "tracer_effect" "weapon_tracers_shotgun"
+ "vortex_absorb_effect" "wpn_vortex_projectile_shotgun_FP"
+ "vortex_absorb_effect_third_person" "wpn_vortex_projectile_shotgun"
+ "vortex_absorb_sound" "Vortex_Shield_AbsorbBulletSmall"
+ "vortex_absorb_sound_1p_vs_3p" "Vortex_Shield_AbsorbBulletSmall_1P_VS_3P"
+ "projectile_adjust_to_gun_barrel" "1"
+
+ "sound_dryfire" "shotgun_dryfire"
+ "sound_pickup" "wpn_pickup_Rifle_1P"
+ "fire_sound_1_player_1p" "Weapon_EVA8_AutoFire_1P"
+ "fire_sound_1_player_3p" "Weapon_EVA8_AutoFire_3P"
+ "fire_sound_1_npc" "Weapon_EVA8_AutoFire_NPC"
+ "sound_zoom_in" "Weapon_EVA8_ADS_In"
+ "sound_zoom_out" "Weapon_EVA8_ADS_Out"
+
+ "low_ammo_sound_name_1" "EVA8_LowAmmo_Shot1"
+ "low_ammo_sound_name_2" "EVA8_LowAmmo_Shot2"
+ "low_ammo_sound_name_3" "EVA8_LowAmmo_Shot3"
+
+ "fx_shell_eject_view" "wpn_shelleject_shotshell_FP"
+ "fx_shell_eject_world" "wpn_shelleject_shotshell"
+ "fx_shell_eject_attach" "shell"
+
+ "fx_muzzle_flash_view" "mflash_shotgun_fp_FULL"
+ "fx_muzzle_flash_world" "mflash_shotgun_FULL"
+ "fx_muzzle_flash_attach" "muzzle_flash"
+
+
+
+ "critical_hit_damage_scale" "1"
+ "critical_hit" "1"
+
+ dof_zoom_focusArea_horizontal 0.036
+ dof_zoom_focusArea_top 0.070
+ dof_zoom_focusArea_bottom -0.023
+
+
+ "titanarmor_critical_hit_required" "1"
+
+
+ // Behavior
+ "fire_rate" "2.75"
+ "zoom_time_in" "0.25"
+ "zoom_time_out" "0.2"
+ "zoom_fov" "55"
+ "holster_time" "0.5"
+ "deploy_time" "0.66"
+ "lower_time" "0.25"
+ "raise_time" "0.3"
+ "vortex_refire_behavior" "bullet"
+ "allow_empty_fire" "0"
+ "reload_enabled" "1"
+ "allow_empty_click" "1"
+ "empty_reload_only" "0"
+ "trigger_snipercam" "0"
+ "allow_headshots" "1"
+ "primary_fire_does_not_block_sprint" "0"
+ "ads_move_speed_scale" "0.75"
+ "aimassist_disable_hipfire" "0"
+ "aimassist_disable_ads" "0"
+ "aimassist_disable_hipfire_titansonly" "1"
+ "aimassist_disable_ads_titansonly" "1"
+ "headshot_distance" "500"
+
+
+ "sprint_fractional_anims" "0"
+
+
+
+ "ammo_suck_behavior" "primary_weapons"
+
+ // View Kick
+ "viewkick_spring" "shotgun"
+
+ "viewkick_pitch_base" "-1.75"
+ "viewkick_pitch_random" "0.75"
+ "viewkick_pitch_softScale" "0.3"
+ "viewkick_pitch_hardScale" "1.5"
+
+ "viewkick_yaw_base" "-0.65"
+ "viewkick_yaw_random" "0.38"
+ "viewkick_yaw_softScale" "0.38"
+ "viewkick_yaw_hardScale" "1.5"
+
+ "viewkick_roll_base" "0"
+ "viewkick_roll_randomMin" "0.6"
+ "viewkick_roll_randomMax" "0.8"
+ "viewkick_roll_softScale" "0.2"
+ "viewkick_roll_hardScale" "2.75"
+
+ "viewkick_hipfire_weaponFraction" "0.1"
+ "viewkick_hipfire_weaponFraction_vmScale" "0.0"
+ "viewkick_ads_weaponFraction" "0.35"
+ "viewkick_ads_weaponFraction_vmScale" "0.25"
+
+ "viewkick_perm_pitch_base" "-0.5"
+ "viewkick_perm_pitch_random" "1.1"
+ "viewkick_perm_pitch_random_innerexclude" "0.5"
+ "viewkick_perm_yaw_base" "0.0"
+ "viewkick_perm_yaw_random" "1.5"
+ "viewkick_perm_yaw_random_innerexclude" "0.5"
+
+ //
+ "viewmodel_shake_forward" "0.5"
+ "viewmodel_shake_up" "0.2"
+ "viewmodel_shake_right" "0.0"
+
+ // Bob
+ "bob_cycle_time" "0.45"
+ "bob_vert_dist" "0.1"
+ "bob_horz_dist" "0.1"
+ "bob_max_speed" "150"
+ "bob_pitch" "0.75"
+ "bob_yaw" "0.5"
+ "bob_roll" "-0.75"
+
+ // Bob_Zoomed
+ "bob_cycle_time_zoomed" "0.4"
+ "bob_vert_dist_zoomed" "0.01"
+ "bob_horz_dist_zoomed" "0.01"
+ "bob_max_speed_zoomed" "150"
+ //"bob_pitch_zoomed" "0.002"
+ //"bob_yaw_zoomed" "-.002"
+ //"bob_roll_zoomed" ".002"
+
+ // Rumble
+ "fire_rumble" "rumble_shotgun"
+
+ // Sway
+ "sway_rotate_attach" "SWAY_ROTATE"
+ "sway_min_x" "-0.5"
+ "sway_min_y" "-0.5"
+ "sway_min_z" "-0.6"
+ "sway_max_x" "0.5"
+ "sway_max_y" "0.5"
+ "sway_max_z" "0.6"
+ "sway_min_pitch" "-3"
+ "sway_min_yaw" "-2.5"
+ "sway_min_roll" "-4"
+ "sway_max_pitch" "3"
+ "sway_max_yaw" "2.5"
+ "sway_max_roll" "4"
+ "sway_translate_gain" "2.5"
+ "sway_rotate_gain" "7"
+ "sway_move_forward_translate_x" "-0.1"
+ "sway_move_forward_translate_z" "-0.5"
+ "sway_move_back_translate_x" "0.2"
+ "sway_move_back_translate_z" "-0.2"
+ "sway_move_left_translate_y" "-1"
+ "sway_move_left_translate_z" "-0.5"
+ "sway_move_left_rotate_roll" "-4"
+ "sway_move_right_translate_y" "1"
+ "sway_move_right_translate_z" "-0.5"
+ "sway_move_right_rotate_roll" "4"
+ "sway_move_up_translate_z" "-1"
+ "sway_move_down_translate_z" "1"
+ "sway_turn_left_rotate_yaw" "-2.5"
+ "sway_turn_right_rotate_yaw" "2.5"
+
+ "sway_turn_left_translate_y" ".5"
+ "sway_turn_right_translate_y" "-.5"
+ "sway_turn_up_translate_z" ".2"
+ "sway_turn_down_translate_z" "-.2"
+ "sway_turn_up_translate_x" ".1"
+ "sway_turn_down_translate_x" "-.1"
+
+ "sway_turn_left_rotate_roll" "4"
+ "sway_turn_right_rotate_roll" "-4"
+ "sway_turn_up_rotate_pitch" "3"
+ "sway_turn_down_rotate_pitch" "-3"
+ "sway_turn_up_rotate_roll" "-0.8"
+ "sway_turn_down_rotate_roll" "0.8"
+
+ // Zoomed Sway
+ "sway_rotate_attach_zoomed" "SWAY_ROTATE_ZOOMED"
+ "sway_rotate_attach_blend_time_zoomed" "0.2"
+ "sway_rotate_gain_zoomed" "5"
+
+ "sway_min_yaw_zoomed" "-0.045"
+ "sway_max_yaw_zoomed" "0.045"
+ "sway_turn_left_rotate_yaw_zoomed" "-0.085"
+ "sway_turn_right_rotate_yaw_zoomed" "0.085"
+
+ "sway_min_roll_zoomed" "-4"
+ "sway_max_roll_zoomed" "4"
+ "sway_turn_left_rotate_roll_zoomed" "0"
+ "sway_turn_right_rotate_roll_zoomed" "0"
+
+ "sway_move_right_rotate_roll_zoomed" "0.2"
+ "sway_move_left_rotate_roll_zoomed" "-0.2"
+
+ "sway_min_pitch_zoomed" "-0.03"
+ "sway_max_pitch_zoomed" "0.03"
+ "sway_turn_up_rotate_pitch_zoomed" "0.07"
+ "sway_turn_down_rotate_pitch_zoomed" "-0.07"
+
+ // NPC
+ "proficiency_poor_spreadscale" "7.0"
+ "proficiency_average_spreadscale" "5.0"
+ "proficiency_good_spreadscale" "4.5"
+ "proficiency_very_good_spreadscale" "3.7"
+
+ "npc_min_engage_range" "0"
+ "npc_max_engage_range" "800"
+ "npc_min_engage_range_heavy_armor" "500"
+ "npc_max_engage_range_heavy_armor" "800"
+ "npc_min_range" "0"
+ "npc_max_range" "800"
+
+ "npc_min_burst" "1"
+ "npc_max_burst" "1"
+ "npc_rest_time_between_bursts_min" "0.5"
+ "npc_rest_time_between_bursts_max" "0.7"
+
+ // WeaponED Unhandled Key/Values and custom script Key/Values
+ "bob_tilt_angle" "0.5"
+ "sway_turn_angle_factor" "-0.5"
+ "sway_turn_origin_factor" "0"
+ "sway_turn_angle_factor_zoomed" "0"
+ "sway_turn_origin_factor_zoomed" "0.05"
+ "sway_move_angle_factor" "0.15"
+ "sway_move_origin_factor" "0.15"
+ "sway_move_angle_factor_zoomed" "0"
+ "sway_move_origin_factor_zoomed" "0.03"
+ "sway_gain" "10.0"
+ "deployfirst_time" "1.25"
+ "deploycatch_time" "1.33"
+ "sprintcycle_time" ".55"
+
+
+ "clip_bodygroup" "twinbshotgun_magazine"
+ "clip_bodygroup_index_shown" "0"
+ "clip_bodygroup_index_hidden" "1"
+ "clip_bodygroup_show_for_milestone_0" "1"
+ "clip_bodygroup_show_for_milestone_1" "0"
+ "clip_bodygroup_show_for_milestone_2" "1"
+ "clip_bodygroup_show_for_milestone_3" "1"
+ Mods
+ {
+ iron_sights
+ {
+ }
+ pas_run_and_gun
+ {
+ "primary_fire_does_not_block_sprint" "1"
+ "crosshair_force_sprint_fade_disabled" "1"
+ }
+ pas_fast_ads
+ {
+ //Fast ADS
+ "zoom_time_in" "*0.5"
+ "zoom_time_out" "*0.6"
+ }
+ pas_fast_swap
+ {
+ //Fast Swap
+ "fast_swap_to" "1"
+ }
+ burn_mod_shotgun
+ {
+ "is_burn_mod" "1"
+ "fx_muzzle_flash_view" "P_wpn_muz_shotgun_amp_FP"
+ "fx_muzzle_flash_world" "P_wpn_muz_shotgun_amp"
+ "fx_muzzle_flash_attach" "muzzle_flash"
+ "tracer_effect" "P_wpn_tracer_shotgun_BC"
+
+ "damage_near_value" "250"
+ "damage_far_value" "20"
+ "damage_near_value_titanarmor" "400"
+ "damage_far_value_titanarmor" "20"
+ }
+ }
+
+
+ active_crosshair_count "1"
+ rui_crosshair_index "0"
+
+ RUI_CrosshairData
+ {
+ DefaultArgs
+ {
+ adjustedSpread weapon_spread
+ adsFrac player_zoomFrac
+ isSprinting player_is_sprinting
+ isReloading weapon_is_reloading
+ teamColor crosshair_team_color
+ isAmped weapon_is_amped
+ crosshairMovementX crosshair_movement_x
+ crosshairMovementY crosshair_movement_y
+ }
+
+ Crosshair_1
+ {
+ "ui" "ui/crosshair_shotgun"
+ "base_spread" "-4.0"
+ Args
+ {
+ isFiring weapon_is_firing
+ }
+ }
+ }
+}
diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak
new file mode 100644
index 000000000..3a714d3b6
--- /dev/null
+++ b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak
Binary files differ
diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak
new file mode 100644
index 000000000..3bd344679
--- /dev/null
+++ b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak
Binary files differ
diff --git a/Northstar.Custom/paks/rpak.json b/Northstar.Custom/paks/rpak.json
new file mode 100644
index 000000000..743468b4f
--- /dev/null
+++ b/Northstar.Custom/paks/rpak.json
@@ -0,0 +1,5 @@
+{
+ "Postload": {
+ "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak"
+ }
+} \ No newline at end of file
diff --git a/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk b/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk
index 036dd8abf..dd8fe7d0c 100644
--- a/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk
+++ b/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk
Binary files differ
diff --git a/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk b/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk
index 4c36af3e6..1aff9ac33 100644
--- a/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk
+++ b/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk
Binary files differ
diff --git a/Northstar.CustomServers/keyvalues/playlists_v2.txt b/Northstar.CustomServers/keyvalues/playlists_v2.txt
new file mode 100644
index 000000000..c49fb0e9c
--- /dev/null
+++ b/Northstar.CustomServers/keyvalues/playlists_v2.txt
@@ -0,0 +1,13 @@
+playlists
+{
+ Gamemodes
+ {
+ defaults
+ {
+ vars
+ {
+ player_force_respawn 5
+ }
+ }
+ }
+}
diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json
index 93fc89328..d3740a12e 100644
--- a/Northstar.CustomServers/mod.json
+++ b/Northstar.CustomServers/mod.json
@@ -1,26 +1,17 @@
{
"Name": "Northstar.CustomServers",
"Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods",
- "Version": "1.14.0",
+ "Version": "1.19.0",
"LoadPriority": 0,
"ConVars": [
{
- "Name": "ns_lobby_type",
- "DefaultValue": "0"
- },
- {
- "Name": "ns_is_modded_server",
- "DefaultValue": "1",
- "Flags": 8192
- },
- {
"Name": "ns_should_return_to_lobby",
"DefaultValue": "1"
},
{
"Name": "ns_allow_spectators",
"DefaultValue": "0",
- "Flags": 8192
+ "Flags": "REPLICATED"
},
{
"Name": "ns_private_match_last_mode",
@@ -57,6 +48,11 @@
{
"Name": "ns_use_phase_fix",
"DefaultValue": "1"
+ },
+ {
+ "Name": "ns_progression_enabled",
+ "DefaultValue": "0",
+ "Flags": "ARCHIVE_PLAYERPROFILE"
}
],
"Scripts": [
@@ -155,6 +151,19 @@
"After": "AiTurretSentry_Init"
}
},
+ {
+ "Path": "sh_progression.nut",
+ "RunOn": "UI || SERVER || CLIENT",
+ "ServerCallback": {
+ "Before": "Progression_Init"
+ },
+ "ClientCallback": {
+ "Before": "Progression_Init"
+ },
+ "UICallback": {
+ "Before": "Progression_Init"
+ }
+ },
{
"Path": "gamemodes/_gamemode_fd_events.nut",
diff --git a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg
index d92ca3ec1..bd4227835 100644
--- a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg
+++ b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg
@@ -6,7 +6,6 @@ ns_report_sp_server_to_masterserver 0 // whether this server should report itsel
ns_auth_allow_insecure 0 // keep this to 0 unless you want to allow people to join without masterserver auth/persistence
ns_erase_auth_info 1 // keep this to 1 unless you're testing and crashing alot, so you don't have to go through the northstar lobby to reauth
-ns_player_auth_port 8081 // this can be whatever, make sure it's portforwarded over tcp
ns_masterserver_hostname "https://northstar.tf" // masterserver hostname
everything_unlocked 1 // unlock everything
@@ -22,4 +21,7 @@ sv_updaterate_mp 20 // default updaterate: 20 tick
sv_minupdaterate 20 // unsure if this actually works, but if it does, should set minimum client updaterate
sv_max_snapshots_multiplayer 300 // this needs to be updaterate * 15, or clients will dc in killreplay
net_data_block_enabled 0 // not really sure on this, have heard datablock could have security issues? doesn't seem to have any adverse effects being disabled
-host_skip_client_dll_crc 1 // allow people to run modded client dlls, this is mainly so people running pilot visor colour mods can keep those, since they use a client.dll edit \ No newline at end of file
+host_skip_client_dll_crc 1 // allow people to run modded client dlls, this is mainly so people running pilot visor colour mods can keep those, since they use a client.dll edit
+
+announcementVersion 1
+announcement #PROGRESSION_ANNOUNCEMENT_BODY \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/maps/mp_complex3_script.ent b/Northstar.CustomServers/mod/maps/mp_complex3_script.ent
new file mode 100644
index 000000000..df26fd80c
--- /dev/null
+++ b/Northstar.CustomServers/mod/maps/mp_complex3_script.ent
@@ -0,0 +1,13234 @@
+ENTITIES01
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0 -12.363 0"
+"origin" "-3966.17 -2563 748"
+"targetname" "info_player_start_7"
+"classname" "info_player_start"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_at" "0"
+"origin" "-6248 -1288 520"
+"link_to_guid_0" "3148974f"
+"link_guid" "e2596db6"
+"hardpointGroup" "p"
+"gamemode_tday" "1"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_at" "0"
+"origin" "-3688 -2288 720"
+"link_to_guid_0" "5bdcb1bf"
+"link_guid" "9ef44891"
+"hardpointGroup" "p"
+"gamemode_tday" "1"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_at" "0"
+"origin" "-896 -2880 520"
+"link_to_guid_0" "a6716741"
+"link_guid" "f137536f"
+"hardpointGroup" "p"
+"gamemode_tday" "1"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_at" "0"
+"origin" "-3624 -4216 640"
+"link_to_guid_0" "c9c2695"
+"link_guid" "24221b55"
+"hardpointGroup" "p"
+"gamemode_tday" "1"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_at" "0"
+"origin" "-3752 -96 560"
+"link_to_guid_0" "17679895"
+"link_guid" "bf771060"
+"hardpointGroup" "p"
+"gamemode_tday" "1"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"classname" "info_hardpoint"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 69.653 0"
+"origin" "-8484.94 -2690.44 603.359"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 74.349 0"
+"origin" "-8474.32 -2693.28 603.359"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8442.56 -2694.55 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 35.353 0"
+"origin" "-8428.26 -2695.27 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 140.285 0"
+"origin" "-8435.99 -2693.2 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 162.106 0"
+"origin" "-8448.62 -2693.96 585.359"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -95.139 0"
+"origin" "-8445.15 -2704.21 585.359"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8432.59 -2707.57 585.359"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -13.747 0"
+"origin" "-8477.69 -2690.31 651.359"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8472.39 -2693.8 585.359"
+"targetname" "func_model_242"
+"model" "models/containers/styrofoam_box_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -30.172 0"
+"origin" "-8446.78 -2698.6 651.359"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8461.88 -2689.37 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 35.353 0"
+"origin" "-8447.58 -2690.1 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 140.285 0"
+"origin" "-8455.31 -2688.02 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8485.06 -2683.16 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 35.353 0"
+"origin" "-8470.76 -2683.88 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 140.285 0"
+"origin" "-8478.49 -2681.81 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8434.97 -2704.86 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -15 0"
+"origin" "-8465.88 -2696.58 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 140.285 0"
+"origin" "-8455.45 -2696.27 627.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 35.353 0"
+"origin" "-8472.83 -2691.61 627.359"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -13.747 0"
+"origin" "-8439.05 -2700.67 603.359"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "-2.2039e-006 140.285 1.12504e-006"
+"origin" "-8454.93 -2694.34 603.639"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "2.4724e-006 -15 0"
+"origin" "-8452.22 -2691.96 603.639"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 89.4372 0"
+"origin" "-8463.43 -2695.17 603.359"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 119.849 0"
+"origin" "-8397.44 -2748.86 585.86"
+"targetname" "func_model_287"
+"model" "models/containers/crate_blue_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -60.1509 0"
+"origin" "-8380.52 -2778.35 585.86"
+"targetname" "func_model_287"
+"model" "models/containers/crate_blue_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 116.955 0"
+"origin" "-8384.52 -2763.35 628.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -151.236 0"
+"origin" "-8370.71 -2785.4 628.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -151.236 0"
+"origin" "-8384.12 -2778.11 628.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 120.523 0"
+"origin" "-8397.78 -2735.22 652.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 121.152 0"
+"origin" "-8408.19 -2741.19 652.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 121.152 0"
+"origin" "-8401.72 -2752.46 652.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 120.523 0"
+"origin" "-8391.31 -2746.49 652.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 120.523 0"
+"origin" "-8384.34 -2758.63 652.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 94.0521 0"
+"origin" "-8381.52 -2776.61 652.36"
+"targetname" "func_model_224"
+"spawnflags" "4"
+"model" "models/hardware/paint_container_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -19.5849 0"
+"origin" "-8398.65 -2766.85 580.86"
+"targetname" "func_model_297"
+"model" "models/containers/styrofoam_lid_dirty.mdl"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 119.849 0"
+"origin" "-8382.2 -2776.43 604.36"
+"targetname" "prop_static_3"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/box_mini_plastic.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1200"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "-0.6507 -21.8879 -90"
+"origin" "-8346.46 -2848.61 607.86"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -150.802 0"
+"origin" "-8357.11 -2814.72 604.36"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -155.498 0"
+"origin" "-8351.13 -2825.12 604.36"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 31.4211 0"
+"origin" "-8336.32 -2856.97 604.36"
+"targetname" "prop_static_83"
+"spawnflags" "4"
+"solid" "6"
+"model" "models/containers/gas_tank.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.8"
+"angles" "0 119.849 180"
+"origin" "-8357.91 -2816.33 662.235"
+"targetname" "func_model_287"
+"model" "models/containers/crate_blue_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 122.844 0"
+"origin" "-8359.79 -2822.08 627.36"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 130.405 0"
+"origin" "-8357.34 -2822.34 586.36"
+"targetname" "prop_static_3"
+"solid" "6"
+"model" "models/hardware/paint_container_metal.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -83.9714 0"
+"origin" "-8336.39 -2847.8 586.36"
+"targetname" "prop_static_3"
+"solid" "6"
+"model" "models/hardware/paint_container_metal.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -150.151 0"
+"origin" "-8361.71 -2808.71 586.36"
+"targetname" "prop_static_3"
+"solid" "6"
+"model" "models/hardware/paint_container_metal.mdl"
+"luxelsize" "16"
+"lightingMethod" "0"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -69.2394 0"
+"origin" "-8342.32 -2848.36 627.36"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 28.2831 0"
+"origin" "-8322.86 -2875.99 586.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -61.7169 0"
+"origin" "-8313.16 -2888.88 586.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -151.717 0"
+"origin" "-8304.44 -2908.08 586.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -137.524 0"
+"origin" "-8296.97 -2921.09 586.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 31.9871 0"
+"origin" "-8321.86 -2877.73 604.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 27.1071 0"
+"origin" "-8314.89 -2889.87 604.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -80.9149 0"
+"origin" "-8303.94 -2908.95 604.36"
+"targetname" "func_model_895"
+"spawnflags" "4"
+"model" "models/containers/crate_orange_plastic.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 114.489 0"
+"origin" "-8317.92 -2884.58 652.36"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -59.5809 0"
+"origin" "-8297.61 -2917.99 628.36"
+"targetname" "func_model_225"
+"spawnflags" "4"
+"model" "models/containers/styrofoam_box_short_dirty.mdl"
+"forcetoenablemotion" "10"
+"fadedist" "1500"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 20.8021 0"
+"origin" "-8300.88 -2922.38 604.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -82.5729 0"
+"origin" "-8294.08 -2926.26 604.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -99.5309 0"
+"origin" "-8315.2 -2901.47 604.36"
+"targetname" "func_model_240"
+"spawnflags" "4"
+"model" "models/hardware/paint_spraycan_closed.mdl"
+"forcetoenablemotion" "5"
+"fadedist" "1000"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 119.849 0"
+"origin" "-8302.32 -2913.79 652.36"
+"targetname" "func_model_218"
+"model" "models/containers/styrofoam_box_long_dirty.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "4.26799e-006 -145.253 6.43766e-008"
+"origin" "-4448.12 -4514.19 666.181"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "4.26799e-006 64.3103 6.43766e-008"
+"origin" "-6668.7 -636.537 545.181"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "-2.53273e-006 -107.57 -1.67088e-006"
+"origin" "-6664.16 -937.235 545.181"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "4.26799e-006 32.1242 6.43766e-008"
+"origin" "-5892.35 775.76 872.583"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "4.26799e-006 32.1242 6.43766e-008"
+"origin" "-5615.16 -881.698 600.583"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 32.8045 2.59711e-006"
+"origin" "-8307.97 -1570.87 872.582"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 149.842 0"
+"origin" "-8655.45 -2144.56 586"
+"targetname" "func_static_1"
+"physicsmode" "1"
+"model" "models/containers/barrel.mdl"
+"forcetoenablemotion" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -135 0"
+"origin" "-8631.4 -2171.43 586"
+"targetname" "func_static_1"
+"physicsmode" "1"
+"model" "models/containers/barrel.mdl"
+"forcetoenablemotion" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -78.0148 0"
+"origin" "-8600.29 -2114.86 586"
+"targetname" "func_static_1"
+"physicsmode" "1"
+"model" "models/containers/barrel.mdl"
+"forcetoenablemotion" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -135 0"
+"origin" "-8638.48 -2161.53 656"
+"targetname" "func_static_1"
+"solid" "6"
+"model" "models/containers/box_large_plastic.mdl"
+"forcetoenablemotion" "1"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -135 0"
+"origin" "-8596.76 -2119.81 656"
+"targetname" "func_static_1"
+"solid" "6"
+"model" "models/containers/box_large_plastic.mdl"
+"forcetoenablemotion" "1"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -45 0"
+"origin" "-8516.15 -2300.83 586"
+"targetname" "func_static_1"
+"solid" "6"
+"model" "models/containers/box_large_plastic.mdl"
+"forcetoenablemotion" "1"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -45 0"
+"origin" "-8570.59 -2246.38 586"
+"targetname" "func_static_1"
+"solid" "6"
+"model" "models/containers/box_large_plastic.mdl"
+"forcetoenablemotion" "1"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "0 -45 0"
+"origin" "-8594.63 -2222.34 586"
+"targetname" "func_static_1"
+"solid" "6"
+"model" "models/containers/box_large_plastic.mdl"
+"forcetoenablemotion" "1"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "1.40406e-006 59.3433 -2.16305e-006"
+"origin" "-7348.92 -477.003 596.582"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.98919"
+"angles" "89.9558 0 -36.2377"
+"origin" "-7993.88 -1240.76 576.988"
+"targetname" "prop_physics_1"
+"spawnflags" "4"
+"model" "models/containers/can_red_soda.mdl"
+"collide_titan" "0"
+"collide_sight" "0"
+"collide_human" "0"
+"collide_bullet" "0"
+"collide_ai" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.98919"
+"angles" "89.9558 0 -126.238"
+"origin" "-7996 -1194.28 577.489"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.876748"
+"angles" "89.9558 0 -134.246"
+"origin" "-7463.83 -1274.32 588.877"
+"targetname" "prop_physics_1"
+"spawnflags" "4"
+"model" "models/containers/can_red_soda.mdl"
+"collide_titan" "0"
+"collide_sight" "0"
+"collide_human" "0"
+"collide_bullet" "0"
+"collide_ai" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.876748"
+"angles" "89.9558 0 135.754"
+"origin" "-7504.36 -1281.92 589.321"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1.19801"
+"angles" "89.9558 0 -128.72"
+"origin" "-6799.69 -346.635 581.197"
+"targetname" "prop_physics_1"
+"spawnflags" "4"
+"model" "models/containers/can_red_soda.mdl"
+"collide_titan" "0"
+"collide_sight" "0"
+"collide_human" "0"
+"collide_bullet" "0"
+"collide_ai" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1.19801"
+"angles" "89.9558 0 141.28"
+"origin" "-6855.82 -351.639 581.804"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.892666"
+"angles" "89.9558 0 94.2158"
+"origin" "-7214.96 -435.646 576.893"
+"targetname" "prop_physics_1"
+"spawnflags" "4"
+"model" "models/containers/can_red_soda.mdl"
+"collide_titan" "0"
+"collide_sight" "0"
+"collide_human" "0"
+"collide_bullet" "0"
+"collide_ai" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "0.892666"
+"angles" "89.9558 0 4.2156"
+"origin" "-7181.8 -461.404 577.346"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "89.9558 0 -70.039"
+"origin" "-6909.78 -873.816 524.998"
+"targetname" "prop_physics_1"
+"spawnflags" "4"
+"model" "models/containers/can_red_soda.mdl"
+"collide_titan" "0"
+"collide_sight" "0"
+"collide_human" "0"
+"collide_bullet" "0"
+"collide_ai" "0"
+"classname" "prop_physics"
+}
+{
+"spawnflags" "1"
+"skin" "0"
+"shadowcastdist" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"pressuredelay" "0"
+"physicsmode" "0"
+"physdamagescale" "0.1"
+"PerformanceMode" "0"
+"nodamageforces" "0"
+"minhealthdmg" "0"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"massScale" "0"
+"inertiaScale" "1.0"
+"forcetoenablemotion" "0"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"Damagetype" "0"
+"damagetoenablemotion" "0"
+"allowfunnel" "1"
+"scale" "1"
+"angles" "89.9558 0 -160.039"
+"origin" "-6937.7 -835.964 525.505"
+"targetname" "func_static_1428"
+"model" "models/containers/can_blue_soda.mdl"
+"classname" "prop_physics"
+}
+{
+"editorclass" "trigger_fw_territory"
+"origin" "-6879.19 -581.853 796"
+"wait" "0"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "1"
+"StartDisabled" "0"
+"spawnflags" "64"
+"triggerFilterUseNew" "1"
+"link_guid" "25060c9d8d9"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 -223.44238"
+"*trigger_brush_0_plane_1" "1 0 0 2033.6353"
+"*trigger_brush_0_plane_2" "0 -1 0 -114.55118"
+"*trigger_brush_0_plane_3" "0 1 0 2275.4695"
+"*trigger_brush_0_plane_4" "0 0 -1 296"
+"*trigger_brush_0_plane_5" "0 0 1 296"
+"*trigger_brush_0_plane_6" "0.70710683 0.70710671 0 2026.9972"
+"*trigger_brush_0_plane_7" "0.99972111 -0.023614977 0 2013.3975"
+"*trigger_brush_0_plane_8" "-0.70710683 -0.70710677 -0 -1506.9976"
+"*trigger_brush_0_plane_9" "-0.70710701 0.70710653 0 1191.0017"
+"*trigger_brush_0_plane_10" "0.70710689 0.70710677 0 2026.9973"
+"*trigger_brush_0_plane_11" "0.99972117 -0.023614977 0 2013.3977"
+"*trigger_brush_0_plane_12" "-0.70710683 -0.70710683 0 -1506.9976"
+"*trigger_brush_0_plane_13" "-0.70710707 0.70710659 0 1191.0018"
+"*trigger_brush_0_plane_14" "0.92833394 0.37174723 0 2197.5474"
+"*trigger_brush_0_plane_15" "0.37174726 -0.92833406 0 643.34802"
+"*trigger_brush_1_plane_0" "-1 -0 -0 -591.1377"
+"*trigger_brush_1_plane_1" "1 0 0 2361.7329"
+"*trigger_brush_1_plane_2" "-0 -1 -0 -889.54016"
+"*trigger_brush_1_plane_3" "0 1 0 2660.1355"
+"*trigger_brush_1_plane_4" "0 0 -1 296"
+"*trigger_brush_1_plane_5" "0 0 1 296"
+"*trigger_brush_1_plane_6" "-0.70710683 -0.70710671 -0 -2026.9973"
+"*trigger_brush_1_plane_7" "0.70710683 -0.70710671 0 768.99762"
+"*trigger_brush_1_plane_8" "0.70710677 0.70710677 0 2570.9971"
+"*trigger_brush_1_plane_9" "-0.70710677 0.70710677 0 1191.0024"
+"*trigger_brush_1_plane_10" "0.70710689 -0.70710671 0 768.99786"
+"*trigger_brush_1_plane_11" "0.70710683 0.70710683 0 2570.9976"
+"*trigger_brush_1_plane_12" "-0.70710665 0.70710689 0 1191.0029"
+"*trigger_brush_2_plane_0" "-1 -0 -0 1043.6934"
+"*trigger_brush_2_plane_1" "1 -0 -0 -446.89502"
+"*trigger_brush_2_plane_2" "0 -1 0 2660.1357"
+"*trigger_brush_2_plane_3" "0 1 0 -2094.4504"
+"*trigger_brush_2_plane_4" "0 0 -1 296"
+"*trigger_brush_2_plane_5" "0 0 1 296"
+"*trigger_brush_2_plane_6" "-0.26079348 -0.96539462 -0 2684.6282"
+"*trigger_brush_2_plane_7" "0.9750666 0.22191244 -0 -1026.0696"
+"*trigger_brush_2_plane_8" "0.35897923 0.93334556 0 -2293.9731"
+"*trigger_brush_2_plane_9" "-0.97132921 0.23773833 0 419.68182"
+"*trigger_brush_2_plane_10" "-0.26079351 -0.96539462 -0 2684.6282"
+"*trigger_brush_2_plane_11" "0.9750666 0.22191243 0 -1026.0696"
+"*trigger_brush_2_plane_12" "-0.97132933 0.23773836 0 419.68188"
+"*trigger_brush_2_plane_13" "-0.86105388 -0.50851375 0 2169.4092"
+"*trigger_brush_2_plane_14" "0.69279945 -0.72113037 -0 1608.696"
+"*trigger_brush_2_plane_15" "0.75594574 0.65463442 0 -1881.3237"
+"*trigger_brush_2_plane_16" "-0.46336862 0.88616568 0 -1418.2866"
+"*trigger_brush_3_plane_0" "-1 0 0 2361.7397"
+"*trigger_brush_3_plane_1" "1 0 0 1920.4985"
+"*trigger_brush_3_plane_2" "0 -1 0 2250.0139"
+"*trigger_brush_3_plane_3" "0 1 0 1907.7739"
+"*trigger_brush_3_plane_4" "0 0 -1 296"
+"*trigger_brush_3_plane_5" "0 0 1 296"
+"*trigger_brush_3_plane_6" "-0.35897923 -0.93334556 -0 2293.9731"
+"*trigger_brush_3_plane_7" "0.70710677 0.70710677 -0 1506.9974"
+"*trigger_brush_3_plane_8" "0.70710677 -0.70710683 0 1208.9976"
+"*trigger_brush_3_plane_9" "-0.70710689 -0.70710665 0 2149.0024"
+"*trigger_brush_3_plane_10" "-0.70710683 0.70710677 0 1191.0022"
+"*trigger_brush_3_plane_11" "0.70710683 0.70710683 0 1506.9976"
+"*trigger_brush_3_plane_12" "0.70710671 -0.70710683 0 1208.9976"
+"*trigger_brush_3_plane_13" "-0.70710695 -0.70710671 0 2149.0027"
+"*trigger_brush_3_plane_14" "-0.70710689 0.70710677 0 1191.0023"
+"*trigger_brush_3_plane_15" "0.2075914 -0.97821563 0 2088.8511"
+"*trigger_bounds_mins" "-2361.7397 -2660.1357 -296"
+"*trigger_bounds_maxs" "2361.7329 2660.1355 296"
+}
+{
+"model" "*1"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-7273.76 -262.241 830"
+"startDisconnected" "0"
+"link_guid" "250c09f3be6"
+"classname" "func_brush"
+}
+{
+"editorclass" "info_fw_team_tower"
+"teamnumber" "3"
+"spawnflags" "0"
+"model" "models/props/generator_coop/generator_coop_medium.mdl"
+"scale" "1"
+"angles" "0 45.1013 0"
+"origin" "-7274.49 -264.029 640"
+"radius" "1"
+"link_to_guid_1" "250c09f3be6"
+"link_to_guid_0" "25060c9d8d9"
+"link_guid" "250f840be54"
+"classname" "info_target"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "16.3574 55.7916 -1.02973e-015"
+"origin" "-9592.83 -5363.1 1083.69"
+"targetname" "spec_cam2"
+"target" "escape_node2"
+"classname" "info_target"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0 32.194 0"
+"origin" "-9424.58 -4026.32 688"
+"targetname" "escape_node2"
+"classname" "info_target"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-640 1856 704"
+"targetname" "escape_node3"
+"classname" "info_target"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0.0015841 -78.187 0.31054"
+"origin" "-1510.63 2845.77 1260.03"
+"targetname" "spec_cam3"
+"target" "escape_node3"
+"classname" "info_target"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0 129.018 0"
+"origin" "-1449.94 395.183 680"
+"targetname" "escape_node1"
+"classname" "info_target"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0 -50.606 0"
+"origin" "-2105.68 1100.57 1024"
+"targetname" "spec_cam1"
+"target" "escape_node1"
+"classname" "info_target"
+}
+{
+"origin" "-8108 -3596 784"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "nonphaseshift"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "3"
+"triggerFilterUseNew" "1"
+"targetname" "trigger_hardpoint_A1"
+"classname" "trigger_capture_point"
+"*trigger_brush_0_plane_0" "-1 0 0 948"
+"*trigger_brush_0_plane_1" "1 0 0 948"
+"*trigger_brush_0_plane_2" "0 -1 0 764"
+"*trigger_brush_0_plane_3" "0 1 0 764"
+"*trigger_brush_0_plane_4" "-0 0 -1 304"
+"*trigger_brush_0_plane_5" "-0 -0 1 304"
+"*trigger_brush_0_plane_6" "-0.86514002 -0.50153041 -0 757.96295"
+"*trigger_brush_0_plane_7" "0.95562351 -0.29459071 0 817.55389"
+"*trigger_brush_0_plane_8" "0.26159054 0.96517897 0 537.5415"
+"*trigger_brush_0_plane_9" "-0.25997347 -0.96561575 -0 576.54688"
+"*trigger_brush_0_plane_10" "-0.96106929 0.27630743 0 945.35583"
+"*trigger_brush_0_plane_11" "-0.86513996 -0.50153041 0 757.96295"
+"*trigger_brush_0_plane_12" "-0.2599735 -0.96561587 -0 576.54694"
+"*trigger_brush_0_plane_13" "-0.96106935 0.27630743 0 945.3559"
+"*trigger_brush_0_plane_14" "0.48327103 -0.87547076 0 968.48773"
+"*trigger_brush_0_plane_15" "0.87587523 0.48253766 0 975.091"
+"*trigger_brush_0_plane_16" "-0.49087024 0.87123269 0 1040.6466"
+"*trigger_bounds_mins" "-948 -764 -304"
+"*trigger_bounds_maxs" "948 763.99994 304"
+}
+{
+"origin" "-1056 184 832"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "nonphaseshift"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "3"
+"triggerFilterUseNew" "1"
+"targetname" "trigger_hardpoint_C1"
+"classname" "trigger_capture_point"
+"*trigger_brush_0_plane_0" "-1 -0 -0 704"
+"*trigger_brush_0_plane_1" "1 -0 -0 704"
+"*trigger_brush_0_plane_2" "-0 -1 -0 824"
+"*trigger_brush_0_plane_3" "0 1 0 824"
+"*trigger_brush_0_plane_4" "0 0 -1 384"
+"*trigger_brush_0_plane_5" "0 0 1 384"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 1080.4592"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 1080.4592"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 1080.4592"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 1080.4592"
+"*trigger_bounds_mins" "-704 -824 -384"
+"*trigger_bounds_maxs" "704 824 384"
+}
+{
+"origin" "-4552 -1864 768"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "nonphaseshift"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "3"
+"triggerFilterUseNew" "1"
+"targetname" "trigger_hardpoint_B1"
+"classname" "trigger_capture_point"
+"*trigger_brush_0_plane_0" "-1 -0 -0 376"
+"*trigger_brush_0_plane_1" "1 0 0 376"
+"*trigger_brush_0_plane_2" "-0 -1 -0 520"
+"*trigger_brush_0_plane_3" "0 1 0 520"
+"*trigger_brush_0_plane_4" "-0 0 -1 96"
+"*trigger_brush_0_plane_5" "-0 -0 1 96"
+"*trigger_brush_0_plane_6" "0 -0.0033803894 -0.99999428 94.241646"
+"*trigger_brush_0_plane_7" "-0.70710677 0.70710677 0 633.56763"
+"*trigger_brush_0_plane_8" "-0.70710677 -0.70710677 -0 633.56763"
+"*trigger_brush_0_plane_9" "0.70710677 -0.70710677 0 633.56763"
+"*trigger_brush_0_plane_10" "0.70710677 0.70710677 0 633.56763"
+"*trigger_bounds_mins" "-376 -520 -96"
+"*trigger_bounds_maxs" "376 520 96"
+}
+{
+"editorclass" "info_bomb_mode_pilot_defuse_point"
+"spawnflags" "0"
+"origin" "-6258.77 -506.916 588"
+"teamnumber" "3"
+"classname" "info_target"
+}
+{
+"editorclass" "info_bomb_mode_pilot_defuse_point"
+"spawnflags" "0"
+"origin" "-16 -2528 528"
+"teamnumber" "2"
+"classname" "info_target"
+}
+{
+"editorclass" "info_bomb_mode_bomb"
+"spawnflags" "0"
+"origin" "-3733.81 -73.9383 553.108"
+"classname" "info_target"
+}
+{
+"editorclass" "info_bomb_mode_bomb"
+"spawnflags" "0"
+"origin" "-4263.48 -4642.26 652.991"
+"classname" "info_target"
+}
+{
+"editorclass" "info_bomb_mode_base"
+"spawnflags" "0"
+"origin" "-759.944 -2094.34 519.999"
+"teamnumber" "2"
+"classname" "info_target"
+}
+{
+"editorclass" "info_bomb_mode_base"
+"spawnflags" "0"
+"origin" "-6937.51 -1231.18 523.996"
+"teamnumber" "3"
+"classname" "info_target"
+}
+{
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-11520 10880 10536"
+"script_name" "menu_camera_target"
+"classname" "info_target_clientside"
+}
+{
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-11520 11136 10496"
+"script_name" "menu_scene_ref"
+"classname" "info_target_clientside"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-6576 -6864 -104"
+"targetname" "at_hardpoint_blackbox"
+"link_to_guid_0" "27528a1afab"
+"link_guid" "2758215f435"
+"hardpointGroup" "p"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"origin" "-6576 -6864 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "27528a1afab"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 128"
+"*trigger_brush_0_plane_1" "1 -0 -0 128"
+"*trigger_brush_0_plane_2" "-0 -1 -0 128"
+"*trigger_brush_0_plane_3" "0 1 0 128"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933"
+"*trigger_bounds_mins" "-128 -128 -128"
+"*trigger_bounds_maxs" "128 128 128"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-6256 -6864 -104"
+"targetname" "at_hardpoint_blackbox1"
+"link_to_guid_0" "2759b6c10ad"
+"link_guid" "275ca0c34a7"
+"hardpointGroup" "p"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"origin" "-6256 -6864 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "2759b6c10ad"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 128"
+"*trigger_brush_0_plane_1" "1 -0 -0 128"
+"*trigger_brush_0_plane_2" "-0 -1 -0 128"
+"*trigger_brush_0_plane_3" "0 1 0 128"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933"
+"*trigger_bounds_mins" "-128 -128 -128"
+"*trigger_bounds_maxs" "128 128 128"
+}
+{
+"origin" "-6256 -7184 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "275da28a532"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 128"
+"*trigger_brush_0_plane_1" "1 -0 -0 128"
+"*trigger_brush_0_plane_2" "-0 -1 -0 128"
+"*trigger_brush_0_plane_3" "0 1 0 128"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933"
+"*trigger_bounds_mins" "-128 -128 -128"
+"*trigger_bounds_maxs" "128 128 128"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-6256 -7184 -104"
+"targetname" "at_hardpoint_blackbox2"
+"link_to_guid_0" "275da28a532"
+"link_guid" "275edb69c4d"
+"hardpointGroup" "p"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-6576 -7184 -104"
+"targetname" "at_hardpoint_blackbox3"
+"link_to_guid_0" "275cd46eda5"
+"link_guid" "2751884002b"
+"hardpointGroup" "p"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"origin" "-6576 -7184 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "275cd46eda5"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 128"
+"*trigger_brush_0_plane_1" "1 -0 -0 128"
+"*trigger_brush_0_plane_2" "-0 -1 -0 128"
+"*trigger_brush_0_plane_3" "0 1 0 128"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933"
+"*trigger_bounds_mins" "-128 -128 -128"
+"*trigger_bounds_maxs" "128 128 128"
+}
+{
+"origin" "-5840 -6864 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "275e36af485"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 192"
+"*trigger_brush_0_plane_1" "1 -0 0 192"
+"*trigger_brush_0_plane_2" "-0 -1 -0 192"
+"*trigger_brush_0_plane_3" "0 1 0 192"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899"
+"*trigger_bounds_mins" "-192 -192 -128"
+"*trigger_bounds_maxs" "192 192 128"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-5840 -6864 -104"
+"targetname" "at_hardpoint_blackbox4"
+"link_to_guid_0" "275e36af485"
+"link_guid" "275fa2f4f04"
+"hardpointGroup" "s"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-5392 -6864 -104"
+"targetname" "at_hardpoint_blackbox5"
+"link_to_guid_0" "275ddde673b"
+"link_guid" "2753df97a78"
+"hardpointGroup" "s"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"origin" "-5392 -6864 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "275ddde673b"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 192"
+"*trigger_brush_0_plane_1" "1 -0 0 192"
+"*trigger_brush_0_plane_2" "-0 -1 -0 192"
+"*trigger_brush_0_plane_3" "0 1 0 192"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899"
+"*trigger_bounds_mins" "-192 -192 -128"
+"*trigger_bounds_maxs" "192 192 128"
+}
+{
+"origin" "-5392 -7312 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "275ac23c51f"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 192"
+"*trigger_brush_0_plane_1" "1 -0 0 192"
+"*trigger_brush_0_plane_2" "-0 -1 -0 192"
+"*trigger_brush_0_plane_3" "0 1 0 192"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899"
+"*trigger_bounds_mins" "-192 -192 -128"
+"*trigger_bounds_maxs" "192 192 128"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-5392 -7312 -104"
+"targetname" "at_hardpoint_blackbox6"
+"link_to_guid_0" "275ac23c51f"
+"link_guid" "275cbcacf82"
+"hardpointGroup" "s"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"model" "models/communication/terminal_com_station_tall.mdl"
+"hardpointName" "random"
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"origin" "-5840 -7312 -104"
+"targetname" "at_hardpoint_blackbox7"
+"link_to_guid_0" "2759e570221"
+"link_guid" "27590ba1b72"
+"hardpointGroup" "s"
+"gamemode_sur" "0"
+"gamemode_lh" "0"
+"gamemode_cp" "0"
+"gamemode_at" "1"
+"classname" "info_hardpoint"
+}
+{
+"origin" "-5840 -7312 -40"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"triggerFilterUseNew" "1"
+"link_guid" "2759e570221"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 192"
+"*trigger_brush_0_plane_1" "1 -0 0 192"
+"*trigger_brush_0_plane_2" "-0 -1 -0 192"
+"*trigger_brush_0_plane_3" "0 1 0 192"
+"*trigger_brush_0_plane_4" "0 0 -1 128"
+"*trigger_brush_0_plane_5" "-0 -0 1 128"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899"
+"*trigger_bounds_mins" "-192 -192 -128"
+"*trigger_bounds_maxs" "192 192 128"
+}
+{
+"origin" "-5009.8 -4210.14 671.526"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_1_easy" "1"
+"damagemodel" "0"
+"damagecap" "20"
+"triggerFilterUseNew" "1"
+"mobility_2_normal" "0"
+"damageSourceName" "burn"
+"damage" "10"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 21.77832"
+"*trigger_brush_0_plane_1" "1 0 0 21.771973"
+"*trigger_brush_0_plane_2" "0 -1 0 20.042969"
+"*trigger_brush_0_plane_3" "0 1 0 20.052246"
+"*trigger_brush_0_plane_4" "0.00016665296 6.251569e-005 -1 18.119028"
+"*trigger_brush_0_plane_5" "-0.00016378085 -5.835561e-005 1 18.118982"
+"*trigger_brush_0_plane_6" "0.17627637 -0.98434073 -4.0189021e-005 19.384438"
+"*trigger_brush_0_plane_7" "0.98433661 0.17629911 0.00015777189 20.173597"
+"*trigger_brush_0_plane_8" "-0.17627142 0.98434162 2.4551438e-005 19.05201"
+"*trigger_brush_0_plane_9" "-0.98956627 0.14407825 -0.00013696289 20.649738"
+"*trigger_brush_0_plane_10" "0.82067442 -0.57139605 9.4199539e-005 21.93189"
+"*trigger_brush_0_plane_11" "-0.57138246 -0.8206839 -0.0001399785 17.561274"
+"*trigger_brush_0_plane_12" "-0.82069337 0.57136887 -0.00010190317 20.345854"
+"*trigger_brush_0_plane_13" "0.57139683 0.82067388 0.00014767883 18.677172"
+"*trigger_brush_0_plane_14" "0.17627637 -0.98434073 0 19.385166"
+"*trigger_brush_0_plane_15" "0.17627141 -0.98434162 0 19.383736"
+"*trigger_brush_0_plane_16" "0.98433489 0.17630903 0 20.170713"
+"*trigger_brush_0_plane_17" "0.98433667 0.17629911 -0 20.176456"
+"*trigger_brush_0_plane_18" "-0.17626645 0.98434252 0 19.052406"
+"*trigger_brush_0_plane_19" "-0.17627141 0.98434162 0 19.051565"
+"*trigger_brush_0_plane_20" "-0.98956412 0.14409372 0 20.647114"
+"*trigger_brush_0_plane_21" "-0.98956639 0.14407825 0 20.652224"
+"*trigger_brush_0_plane_22" "0.8206687 -0.57140434 0 21.930241"
+"*trigger_brush_0_plane_23" "0.82067454 -0.57139611 0 21.933601"
+"*trigger_brush_0_plane_24" "-0.57138246 -0.82068402 -0 17.563808"
+"*trigger_brush_0_plane_25" "-0.82070088 0.57135814 0 20.343922"
+"*trigger_brush_0_plane_26" "-0.82069343 0.57136881 0 20.3477"
+"*trigger_brush_0_plane_27" "0.57139134 0.82067776 -0 18.679781"
+"*trigger_brush_0_plane_28" "0.57140237 0.82067001 0 18.674438"
+"*trigger_brush_0_plane_29" "-0.91751391 -0.39770368 -0.00016278407 22.460146"
+"*trigger_bounds_mins" "-21.77832 -20.042969 -18.123047"
+"*trigger_bounds_maxs" "21.771973 20.052345 18.12262"
+}
+{
+"origin" "-4979.47 -4239.79 669.121"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_1_easy" "1"
+"damagemodel" "0"
+"damagecap" "20"
+"triggerFilterUseNew" "1"
+"mobility_2_normal" "0"
+"damageSourceName" "burn"
+"damage" "10"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 22.675781"
+"*trigger_brush_0_plane_1" "1 0 0 22.670898"
+"*trigger_brush_0_plane_2" "0 -1 0 21.022461"
+"*trigger_brush_0_plane_3" "0 1 0 21.017578"
+"*trigger_brush_0_plane_4" "0 0 -1 19.994141"
+"*trigger_brush_0_plane_5" "0 0 1 19.994568"
+"*trigger_brush_0_plane_6" "-0.79023558 0.61255193 -0.017547544 19.368935"
+"*trigger_brush_0_plane_7" "-0.61217505 -0.7877965 0.067958973 19.915857"
+"*trigger_brush_0_plane_8" "0.79024911 -0.61253446 0.017546039 19.839951"
+"*trigger_brush_0_plane_9" "0.83065367 0.55366367 -0.058915287 21.821468"
+"*trigger_brush_0_plane_10" "0.0277991 0.064444266 0.99753404 18.568161"
+"*trigger_brush_0_plane_11" "-0.12590383 0.99019819 -0.060462583 18.096422"
+"*trigger_brush_0_plane_12" "0.9916538 0.12390357 -0.035645492 21.509848"
+"*trigger_brush_0_plane_13" "-0.027795117 -0.064435109 -0.99753475 18.398573"
+"*trigger_brush_0_plane_14" "0.12591469 -0.99019766 0.060449135 18.870047"
+"*trigger_brush_0_plane_15" "-0.99164891 -0.12394232 0.035647802 21.617529"
+"*trigger_brush_0_plane_16" "-0.11031668 0 -0.99389642 20.323952"
+"*trigger_brush_0_plane_17" "0 0.085939594 0.99630034 19.237625"
+"*trigger_brush_0_plane_18" "-0.78962427 0.61359054 0 19.692518"
+"*trigger_brush_0_plane_19" "-0.99961174 0 0.027862126 22.167356"
+"*trigger_brush_0_plane_20" "0 0.028639561 0.99958974 19.452505"
+"*trigger_brush_0_plane_21" "-0.02220404 0 0.99975342 20.130083"
+"*trigger_brush_0_plane_22" "0 -0.99792051 0.064456455 19.89064"
+"*trigger_brush_0_plane_23" "-0.61264962 -0.79035473 0 21.120331"
+"*trigger_brush_0_plane_24" "0 -0.085925035 -0.99630165 19.084589"
+"*trigger_brush_0_plane_25" "0.78964102 -0.61356914 0 20.160496"
+"*trigger_brush_0_plane_26" "0.11033292 0 0.9938947 20.542135"
+"*trigger_brush_0_plane_27" "0.99961174 0 -0.027862221 22.156351"
+"*trigger_brush_0_plane_28" "0 -0.045882083 -0.99894691 19.118061"
+"*trigger_brush_0_plane_29" "0.068414442 0 -0.99765694 20.797762"
+"*trigger_brush_0_plane_30" "0.83084786 0.5564996 0 22.878237"
+"*trigger_brush_0_plane_31" "0 0.99791962 -0.064470463 19.885517"
+"*trigger_brush_0_plane_32" "-0 0.060945805 0.99814111 19.166637"
+"*trigger_brush_0_plane_33" "-0.1239908 0.99228328 0 19.186661"
+"*trigger_brush_0_plane_34" "0.99201429 0.12612571 -0 22.159206"
+"*trigger_brush_0_plane_35" "0.035918012 -0 0.99935478 19.754478"
+"*trigger_brush_0_plane_36" "-0.035910171 0 -0.99935496 19.534838"
+"*trigger_brush_0_plane_37" "0 -0.060938403 -0.99814153 18.994009"
+"*trigger_brush_0_plane_38" "-0.99200934 -0.12616478 -0 22.260799"
+"*trigger_brush_0_plane_39" "0.12399895 -0.99228233 0 19.948387"
+"*trigger_brush_0_plane_40" "0.41424116 0.90745842 -0.070168488 23.463116"
+"*trigger_bounds_mins" "-22.675793 -21.022488 -19.994152"
+"*trigger_bounds_maxs" "22.67091 21.017591 19.994577"
+}
+{
+"origin" "-6630.51 -3874.89 545.789"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_1_easy" "1"
+"damagemodel" "0"
+"damagecap" "20"
+"triggerFilterUseNew" "1"
+"mobility_2_normal" "0"
+"damageSourceName" "burn"
+"damage" "10"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 23.161621"
+"*trigger_brush_0_plane_1" "1 0 0 23.152832"
+"*trigger_brush_0_plane_2" "0 -1 0 18.999268"
+"*trigger_brush_0_plane_3" "0 1 0 18.994873"
+"*trigger_brush_0_plane_4" "0 0 -1 20.728516"
+"*trigger_brush_0_plane_5" "0 0 1 20.728699"
+"*trigger_brush_0_plane_6" "0.072347663 -0.99576795 -0.056674022 18.008764"
+"*trigger_brush_0_plane_7" "0.97601706 0.082389019 -0.20150122 19.375139"
+"*trigger_brush_0_plane_8" "-0.07234402 0.99576789 0.05668062 17.779463"
+"*trigger_brush_0_plane_9" "-0.94880831 0.23674069 0.20908532 18.678394"
+"*trigger_brush_0_plane_10" "0.20531863 -0.040751129 0.97784638 17.118582"
+"*trigger_brush_0_plane_11" "-0.63899124 -0.76236641 0.10240906 15.904586"
+"*trigger_brush_0_plane_12" "-0.74129868 0.64586955 0.1825617 18.554268"
+"*trigger_brush_0_plane_13" "-0.20530531 0.040738355 -0.97784972 16.622938"
+"*trigger_brush_0_plane_14" "0.63898653 0.76237053 -0.10240788 17.836845"
+"*trigger_brush_0_plane_15" "0.74129188 -0.6458807 -0.18254977 20.810663"
+"*trigger_brush_0_plane_16" "-0.20217523 -0 -0.97934932 17.345173"
+"*trigger_brush_0_plane_17" "0 -0.99913335 -0.041623548 18.290937"
+"*trigger_brush_0_plane_18" "0.084106304 -0.99645674 0 18.969072"
+"*trigger_brush_0_plane_19" "0.97865915 0 -0.20549038 20.138351"
+"*trigger_brush_0_plane_20" "0.99737042 0.072472855 0 22.431414"
+"*trigger_brush_0_plane_21" "0 0.05682518 -0.99838412 20.255196"
+"*trigger_brush_0_plane_22" "-0.084103674 0.99645692 0 18.711605"
+"*trigger_brush_0_plane_23" "0 0.99913311 0.041630547 18.28121"
+"*trigger_brush_0_plane_24" "0.20219001 -0 0.97934633 17.831245"
+"*trigger_brush_0_plane_25" "-0.97865975 0 0.20548709 20.146931"
+"*trigger_brush_0_plane_26" "-0.9707675 0.24002215 0 21.741335"
+"*trigger_brush_0_plane_27" "0 -0.27201349 0.96229345 21.163248"
+"*trigger_brush_0_plane_28" "-0 0.13312577 0.99109912 21.450081"
+"*trigger_brush_0_plane_29" "0.15823317 0 0.98740178 18.252949"
+"*trigger_brush_0_plane_30" "0.23913115 0 0.97098726 18.046215"
+"*trigger_brush_0_plane_31" "0.65689623 0.75398088 -0 19.52286"
+"*trigger_brush_0_plane_32" "0.7663759 -0.6423924 0 23.598701"
+"*trigger_brush_0_plane_33" "-0.23910885 -0 -0.97099274 17.447922"
+"*trigger_brush_0_plane_34" "-0.65690094 -0.75397676 0 17.549532"
+"*trigger_brush_0_plane_35" "-0.76638836 0.64237756 0 21.289915"
+"*trigger_brush_0_plane_36" "-0 -0.13313271 -0.99109828 21.574442"
+"*trigger_brush_0_plane_37" "-0.15824135 0 -0.98740047 17.899864"
+"*trigger_brush_0_plane_38" "0 0.27198976 -0.96230012 21.282295"
+"*trigger_brush_0_plane_39" "-0.93328655 -0.30895549 0.18309207 20.327454"
+"*trigger_bounds_mins" "-23.161669 -18.999268 -20.728502"
+"*trigger_bounds_maxs" "23.152775 18.994848 20.728708"
+}
+{
+"origin" "-6752.38 -3850.29 591.335"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_1_easy" "1"
+"damagemodel" "0"
+"damagecap" "20"
+"triggerFilterUseNew" "1"
+"mobility_2_normal" "0"
+"damageSourceName" "burn"
+"damage" "10"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 29.717285"
+"*trigger_brush_0_plane_1" "1 0 0 29.714844"
+"*trigger_brush_0_plane_2" "0 -1 0 27.994873"
+"*trigger_brush_0_plane_3" "0 1 0 27.990967"
+"*trigger_brush_0_plane_4" "0 0 -1 28.347107"
+"*trigger_brush_0_plane_5" "0 0 1 28.34668"
+"*trigger_brush_0_plane_6" "-0.35651442 0.88672775 0.29429817 22.655819"
+"*trigger_brush_0_plane_7" "-0.90868795 -0.40231937 0.11146893 22.658901"
+"*trigger_brush_0_plane_8" "0.35651633 -0.88672686 -0.29429838 22.658344"
+"*trigger_brush_0_plane_9" "0.97479039 0.10128918 -0.19880684 25.473263"
+"*trigger_brush_0_plane_10" "0.21724674 -0.22769055 0.9491896 21.361078"
+"*trigger_brush_0_plane_11" "0.39044589 0.91150326 0.129282 21.358908"
+"*trigger_brush_0_plane_12" "0.89463139 -0.34251106 -0.28691611 24.921045"
+"*trigger_brush_0_plane_13" "-0.21725486 0.22769006 -0.94918787 21.361015"
+"*trigger_brush_0_plane_14" "-0.3904449 -0.9115029 -0.1292876 21.363583"
+"*trigger_brush_0_plane_15" "-0.89462113 0.3425425 0.2869105 24.921858"
+"*trigger_brush_0_plane_16" "-0.40486702 0.9143756 0 27.965538"
+"*trigger_brush_0_plane_17" "0 0.97241479 0.23325837 23.848343"
+"*trigger_brush_0_plane_18" "0.12175279 -0 0.99256045 26.3246"
+"*trigger_brush_0_plane_19" "-0.92782265 -0.37302157 0 24.995735"
+"*trigger_brush_0_plane_20" "-0.97479403 0 0.22310717 25.834534"
+"*trigger_brush_0_plane_21" "0 -0.31499946 0.94909179 26.044333"
+"*trigger_brush_0_plane_22" "-0.12176256 -0 -0.99255919 26.325142"
+"*trigger_brush_0_plane_23" "0 -0.97241485 -0.23325837 23.8522"
+"*trigger_brush_0_plane_24" "0.40485916 -0.91437912 0 27.967974"
+"*trigger_brush_0_plane_25" "0.97479415 0 -0.22310589 25.83219"
+"*trigger_brush_0_plane_26" "0.99862283 0.052462563 0 29.311333"
+"*trigger_brush_0_plane_27" "0 0.2442729 -0.96970654 26.390877"
+"*trigger_brush_0_plane_28" "-0.35755318 -0.93389279 0 24.051094"
+"*trigger_brush_0_plane_29" "0 -0.14042859 0.99009079 26.638908"
+"*trigger_brush_0_plane_30" "0.30539426 0 0.95222604 25.900644"
+"*trigger_brush_0_plane_31" "0.91922188 -0.39373985 0 30.03582"
+"*trigger_brush_0_plane_32" "0.35755575 0.93389171 -0 24.04635"
+"*trigger_brush_0_plane_33" "0 0.14043257 -0.99009031 26.638762"
+"*trigger_brush_0_plane_34" "-0.3053968 0 -0.95222515 25.901608"
+"*trigger_brush_0_plane_35" "-0.91921216 0.39376283 0 30.036396"
+"*trigger_brush_0_plane_36" "0.80246222 0.59530187 -0.040865496 27.527145"
+"*trigger_bounds_mins" "-29.717148 -27.994802 -28.347107"
+"*trigger_bounds_maxs" "29.714777 27.990847 28.34668"
+}
+{
+"origin" "-6863.43 -3565.73 649.505"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_1_easy" "1"
+"damagemodel" "0"
+"damagecap" "20"
+"triggerFilterUseNew" "1"
+"mobility_2_normal" "0"
+"damageSourceName" "burn"
+"damage" "10"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 22.392578"
+"*trigger_brush_0_plane_1" "1 0 0 22.38623"
+"*trigger_brush_0_plane_2" "0 -1 0 23.695801"
+"*trigger_brush_0_plane_3" "0 1 0 23.701904"
+"*trigger_brush_0_plane_4" "0 0 -1 22.756958"
+"*trigger_brush_0_plane_5" "0 0 1 22.756592"
+"*trigger_brush_0_plane_6" "-0.79363966 0.59335631 0.13440391 19.363192"
+"*trigger_brush_0_plane_7" "-0.60828322 -0.76986647 -0.19312474 19.924692"
+"*trigger_brush_0_plane_8" "0.79365343 -0.59333885 -0.13439952 19.84547"
+"*trigger_brush_0_plane_9" "0.82803267 0.54273474 0.14071582 21.814674"
+"*trigger_brush_0_plane_10" "-0.011122293 -0.23502477 0.97192574 18.448565"
+"*trigger_brush_0_plane_11" "-0.13108115 0.96393937 0.23160015 18.086199"
+"*trigger_brush_0_plane_12" "0.99130905 0.12482663 0.041529257 21.507544"
+"*trigger_brush_0_plane_13" "0.011131484 0.23503047 -0.97192425 18.517982"
+"*trigger_brush_0_plane_14" "0.13107763 -0.96394128 -0.23159409 18.880201"
+"*trigger_brush_0_plane_15" "-0.99130905 -0.12482665 -0.04152919 21.619696"
+"*trigger_brush_0_plane_16" "-0.78463531 0.61995769 0 21.717289"
+"*trigger_brush_0_plane_17" "-0.3026042 0 0.9531163 24.282679"
+"*trigger_brush_0_plane_18" "0 0.22091037 -0.97529411 18.879345"
+"*trigger_brush_0_plane_19" "-0.16696684 -0 -0.98596251 23.528826"
+"*trigger_brush_0_plane_20" "-0.59878683 -0.80090845 -0 23.1381"
+"*trigger_brush_0_plane_21" "-0 -0.97198671 -0.23503631 19.936106"
+"*trigger_brush_0_plane_22" "0.78464919 -0.61994004 0 22.185463"
+"*trigger_brush_0_plane_23" "0.30263686 0 -0.95310599 24.525101"
+"*trigger_brush_0_plane_24" "0.31883568 -0 0.94781005 25.59812"
+"*trigger_brush_0_plane_25" "-0 0.97198439 0.23504555 19.941891"
+"*trigger_brush_0_plane_26" "0.82108754 0.57080221 -0 24.242928"
+"*trigger_brush_0_plane_27" "-0.99087983 -0.13474874 0 22.387548"
+"*trigger_brush_0_plane_28" "-0.041856475 0 0.99912369 22.207701"
+"*trigger_brush_0_plane_29" "0.12492958 -0.99216563 0 22.642241"
+"*trigger_brush_0_plane_30" "-0.12493286 0.99216515 0 21.886036"
+"*trigger_brush_0_plane_31" "0.99087977 0.13474873 -0 22.278454"
+"*trigger_brush_0_plane_32" "0.04186533 0 -0.99912328 22.463369"
+"*trigger_brush_0_plane_33" "0.40965781 0.88560075 0.21884184 23.453144"
+"*trigger_bounds_mins" "-22.392578 -23.695826 -22.756931"
+"*trigger_bounds_maxs" "22.38623 23.701887 22.756578"
+}
+{
+"origin" "-5083.35 -3813.92 658.865"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_1_easy" "1"
+"damagemodel" "0"
+"damagecap" "20"
+"triggerFilterUseNew" "1"
+"mobility_2_normal" "0"
+"damageSourceName" "burn"
+"damage" "10"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 22.353027"
+"*trigger_brush_0_plane_1" "1 0 0 22.356445"
+"*trigger_brush_0_plane_2" "0 -1 0 20.129639"
+"*trigger_brush_0_plane_3" "0 1 0 20.134277"
+"*trigger_brush_0_plane_4" "0 0 -1 20.002502"
+"*trigger_brush_0_plane_5" "0 0 1 20.002197"
+"*trigger_brush_0_plane_6" "0.092027478 -0.99034268 -0.10369346 18.011898"
+"*trigger_brush_0_plane_7" "0.98560303 0.075766191 0.15114939 19.300398"
+"*trigger_brush_0_plane_8" "-0.092014894 0.99034363 0.10369541 17.776217"
+"*trigger_brush_0_plane_9" "-0.96412814 0.24129748 -0.11060037 18.7479"
+"*trigger_brush_0_plane_10" "-0.14183062 -0.11611505 0.98305714 16.76276"
+"*trigger_brush_0_plane_11" "-0.63186896 -0.75383621 -0.18020141 15.959561"
+"*trigger_brush_0_plane_12" "-0.76200849 0.64669693 -0.03355841 18.604645"
+"*trigger_brush_0_plane_13" "0.14184251 0.11611181 -0.98305583 16.9785"
+"*trigger_brush_0_plane_14" "0.63186169 0.75384116 0.18020649 17.781702"
+"*trigger_brush_0_plane_15" "0.76199979 -0.6467073 0.033555906 20.760326"
+"*trigger_brush_0_plane_16" "0 -0.99309695 -0.11729673 18.357685"
+"*trigger_brush_0_plane_17" "0.07664188 -0.99705875 0 19.670906"
+"*trigger_brush_0_plane_18" "0.15159363 0 -0.9884429 18.960403"
+"*trigger_brush_0_plane_19" "0.9897514 -0 0.14280061 20.011522"
+"*trigger_brush_0_plane_20" "0 -0.10413853 0.9945628 19.340891"
+"*trigger_brush_0_plane_21" "0.99570972 0.092532285 -0 21.656448"
+"*trigger_brush_0_plane_22" "-0.076628812 0.9970597 0 19.459202"
+"*trigger_brush_0_plane_23" "0 0.99309695 0.11729673 18.384413"
+"*trigger_brush_0_plane_24" "-0.15158319 0 0.98844451 18.718756"
+"*trigger_brush_0_plane_25" "-0.98975176 0 -0.14279857 20.243675"
+"*trigger_brush_0_plane_26" "0 0.14999454 -0.9886868 19.526537"
+"*trigger_brush_0_plane_27" "-0.97394067 0.22680272 0 20.504448"
+"*trigger_brush_0_plane_28" "-0.6470865 -0.7624166 0 18.720362"
+"*trigger_brush_0_plane_29" "-0.27426073 0 0.96165532 19.786783"
+"*trigger_brush_0_plane_30" "-0.76640385 0.6423589 0 19.165703"
+"*trigger_brush_0_plane_31" "0 0.051804371 0.99865729 20.25021"
+"*trigger_brush_0_plane_32" "-0.043983713 0 0.9990322 19.274397"
+"*trigger_brush_0_plane_33" "0 -0.23249318 0.97259808 20.278576"
+"*trigger_brush_0_plane_34" "-0 -0.05182166 -0.99865639 20.061886"
+"*trigger_brush_0_plane_35" "0.043999169 0 -0.99903154 19.21018"
+"*trigger_brush_0_plane_36" "0 0.23250006 -0.97259635 20.0965"
+"*trigger_brush_0_plane_37" "0.27426839 0 -0.96165317 20.379969"
+"*trigger_brush_0_plane_38" "0.76639473 -0.64236981 0 21.327457"
+"*trigger_brush_0_plane_39" "0.64707154 0.76242924 0 20.551546"
+"*trigger_brush_0_plane_40" "-0.93809688 -0.30126056 -0.17092778 20.400368"
+"*trigger_bounds_mins" "-22.353048 -20.129639 -20.002504"
+"*trigger_bounds_maxs" "22.356396 20.134279 20.002209"
+}
+{
+"SuppressAnimSounds" "0"
+"StartDisabled" "0"
+"spawnflags" "0"
+"solid" "6"
+"skin" "0"
+"SetBodyGroup" "0"
+"rendermode" "0"
+"renderfx" "0"
+"rendercolor" "255 255 255"
+"renderamt" "255"
+"RandomAnimation" "0"
+"pressuredelay" "0"
+"PerformanceMode" "0"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"mingpulevel" "0"
+"mincpulevel" "0"
+"MinAnimTime" "5"
+"maxgpulevel" "0"
+"maxcpulevel" "0"
+"MaxAnimTime" "10"
+"HoldAnimation" "0"
+"gamemode_tdm" "1"
+"gamemode_sur" "1"
+"gamemode_lts" "1"
+"gamemode_lh" "1"
+"gamemode_fd" "1"
+"gamemode_ctf" "1"
+"gamemode_cp" "1"
+"fadedist" "-1"
+"ExplodeRadius" "0"
+"ExplodeDamage" "0"
+"drawinfastreflection" "0"
+"disableX360" "0"
+"disableshadows" "0"
+"disablereceiveshadows" "0"
+"DisableBoneFollowers" "0"
+"collide_titan" "1"
+"collide_ai" "1"
+"ClientSide" "0"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-784 7760 2304"
+"script_name" "rings_pristine"
+"model" "models/props/timeshift_rings_animated.mdl"
+"classname" "prop_dynamic"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-1270.75 -1694.72 647.999"
+"targetname" "intermission"
+"classname" "info_target"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -44.724 0"
+"origin" "-5903.3 1066.05 724.634"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -44.724 0"
+"origin" "-5943.3 1026.05 724.634"
+"classname" "info_node_cover_stand"
+}
+{
+"origin" "-1692.96 -828.384 1487"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"triggerFilterUseNew" "1"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamBeast" "1"
+"targetname" "trigger_nessy"
+"classname" "trigger_once"
+"*trigger_brush_0_plane_0" "-1 0 0 22.049438"
+"*trigger_brush_0_plane_1" "1 0 0 22.049194"
+"*trigger_brush_0_plane_2" "0 -1 0 22.049194"
+"*trigger_brush_0_plane_3" "0 1 0 22.049255"
+"*trigger_brush_0_plane_4" "6.4687615e-006 -4.0451205e-006 -1 16"
+"*trigger_brush_0_plane_5" "-6.4687406e-006 4.0451073e-006 1 16"
+"*trigger_brush_0_plane_6" "0.84787196 -0.53020108 8.4913063e-006 15.999903"
+"*trigger_brush_0_plane_7" "-0.53020018 -0.8478725 -8.1072972e-007 16.000036"
+"*trigger_brush_0_plane_8" "-0.84787196 0.53020108 -8.4913063e-006 16.000143"
+"*trigger_brush_0_plane_9" "0.53020018 0.8478725 8.1072972e-007 15.99996"
+"*trigger_brush_0_plane_10" "0.84787196 -0.53020108 0 15.999767"
+"*trigger_brush_0_plane_11" "-0.53020018 -0.8478725 -0 16.00005"
+"*trigger_brush_0_plane_12" "-0.84787196 0.53020108 0 16.000006"
+"*trigger_brush_0_plane_13" "0.53020018 0.8478725 -0 15.99997"
+"*trigger_brush_0_plane_14" "0.22462773 -0.97444457 5.4309844e-006 22.627359"
+"*trigger_brush_0_plane_15" "0.97444463 0.22462772 6.5775362e-006 22.627329"
+"*trigger_brush_0_plane_16" "-0.97444463 -0.22462772 -6.5775362e-006 22.627554"
+"*trigger_brush_0_plane_17" "-0.22462773 0.97444457 -5.4309844e-006 22.627476"
+"*trigger_bounds_mins" "-22.049438 -22.049194 -16.000122"
+"*trigger_bounds_maxs" "22.049194 22.049255 16.000122"
+}
+{
+"origin" "-3680 -4240 1320"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 -0 -0 -256"
+"*trigger_brush_0_plane_1" "1 -0 -0 1504"
+"*trigger_brush_0_plane_2" "-0 -1 -0 1712"
+"*trigger_brush_0_plane_3" "0 1 0 -152"
+"*trigger_brush_0_plane_4" "0 -0 -1 80"
+"*trigger_brush_0_plane_5" "0 0 1 80"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 -288.49957"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 1029.5475"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 2274.0552"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 956.0083"
+"*trigger_brush_1_plane_0" "-1 -0 -0 2096"
+"*trigger_brush_1_plane_1" "1 0 0 256"
+"*trigger_brush_1_plane_2" "-0 -1 -0 1712"
+"*trigger_brush_1_plane_3" "0 1 0 -1544"
+"*trigger_brush_1_plane_4" "0 -0 -1 80"
+"*trigger_brush_1_plane_5" "0 0 1 80"
+"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 0 390.323"
+"*trigger_brush_1_plane_7" "-0.70710677 -0.70710677 0 2692.6626"
+"*trigger_brush_1_plane_8" "0.70710677 -0.70710677 0 1391.5861"
+"*trigger_brush_1_plane_9" "0.70710677 0.70710677 0 -910.75348"
+"*trigger_brush_2_plane_0" "-1 0 0 -1504"
+"*trigger_brush_2_plane_1" "1 -0 0 2096"
+"*trigger_brush_2_plane_2" "-0 -1 -0 1712"
+"*trigger_brush_2_plane_3" "-0 1 -0 624"
+"*trigger_brush_2_plane_4" "0 -0 -1 80"
+"*trigger_brush_2_plane_5" "0 0 1 80"
+"*trigger_brush_2_plane_6" "-0.70710677 0.70710677 0 -622.25391"
+"*trigger_brush_2_plane_7" "-0.70710677 -0.70710677 0 147.07825"
+"*trigger_brush_2_plane_8" "0.70710677 -0.70710677 0 2692.6626"
+"*trigger_brush_2_plane_9" "0.70710677 0.70710677 0 1923.3304"
+"*trigger_brush_3_plane_0" "-1 -0 -0 -256"
+"*trigger_brush_3_plane_1" "1 -0 -0 1504"
+"*trigger_brush_3_plane_2" "0 -1 0 20"
+"*trigger_brush_3_plane_3" "0 1 0 1712"
+"*trigger_brush_3_plane_4" "0 -0 -1 80"
+"*trigger_brush_3_plane_5" "0 0 1 80"
+"*trigger_brush_3_plane_6" "-0.70710677 0.70710677 0 1029.5475"
+"*trigger_brush_3_plane_7" "-0.70710677 -0.70710677 0 -166.8772"
+"*trigger_brush_3_plane_8" "0.70710677 -0.70710677 0 1077.6306"
+"*trigger_brush_3_plane_9" "0.70710677 0.70710677 0 2274.0552"
+"*trigger_brush_4_plane_0" "-1 -0 -0 -256"
+"*trigger_brush_4_plane_1" "1 -0 -0 1504"
+"*trigger_brush_4_plane_2" "-0 -1 -0 152"
+"*trigger_brush_4_plane_3" "-0 1 -0 -20"
+"*trigger_brush_4_plane_4" "0 -0 -1 80"
+"*trigger_brush_4_plane_5" "0 0 1 80"
+"*trigger_brush_4_plane_6" "-0.7288481 0.68467546 0 -290.65579"
+"*trigger_brush_4_plane_7" "0.70710677 -0.70710677 -0 1170.9688"
+"*trigger_brush_4_plane_8" "0.70710677 0.70710677 -0 1049.3464"
+"*trigger_brush_4_plane_9" "-0.91778958 -0.39706707 0 -174.59995"
+"*trigger_brush_4_plane_10" "-0.3970671 0.91778958 0 -169.24129"
+"*trigger_bounds_mins" "-2096 -1712 -80"
+"*trigger_bounds_maxs" "2096 1712 80"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-8259.93 -3898.29 768"
+"link_to_guid_0" "8d5c25db"
+"link_guid" "20bff3cf"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 1676.9395"
+"*trigger_brush_0_plane_1" "1 0 0 1676.9297"
+"*trigger_brush_0_plane_2" "0 -1 0 1431.5415"
+"*trigger_brush_0_plane_3" "0 1 0 1431.54"
+"*trigger_brush_0_plane_4" "0 0 -1 384"
+"*trigger_brush_0_plane_5" "0 0 1 384"
+"*trigger_brush_0_plane_6" "0.86856514 -0.49557504 0 1230.6445"
+"*trigger_brush_0_plane_7" "0.32101053 0.94707561 -0 969.97974"
+"*trigger_brush_0_plane_8" "-0.97844875 0.20648976 0 1471.5179"
+"*trigger_brush_0_plane_9" "-0.25945646 -0.96575481 -0 1226.8235"
+"*trigger_brush_0_plane_10" "0.8685652 -0.4955751 0 1230.6445"
+"*trigger_brush_0_plane_11" "0.32101053 0.94707572 -0 969.97986"
+"*trigger_brush_0_plane_12" "-0.97844887 0.20648979 0 1471.5182"
+"*trigger_brush_0_plane_13" "0.38473445 -0.92302728 0 1552.2231"
+"*trigger_brush_0_plane_14" "0.93492395 0.35484812 0 1729.538"
+"*trigger_brush_0_plane_15" "-0.49514958 0.86880779 0 1838.814"
+"*trigger_brush_0_plane_16" "-0.85243279 -0.5228368 0 1858.1025"
+"*trigger_bounds_mins" "-1676.9395 -1431.5415 -384"
+"*trigger_bounds_maxs" "1676.9297 1431.54 384"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-1096 -1064 836"
+"link_to_guid_0" "7a915f75"
+"link_guid" "376be52c"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 -0 792"
+"*trigger_brush_0_plane_1" "1 0 0 792"
+"*trigger_brush_0_plane_2" "-0 -1 -0 728"
+"*trigger_brush_0_plane_3" "0 1 0 728"
+"*trigger_brush_0_plane_4" "-0 0 -1 316"
+"*trigger_brush_0_plane_5" "0 0 1 316"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 1074.8022"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 1074.8022"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 1074.8022"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 1074.8022"
+"*trigger_bounds_mins" "-792 -728 -316"
+"*trigger_bounds_maxs" "792 728 316"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-3344 -32 832"
+"link_guid" "c73b1ba0"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 -528"
+"*trigger_brush_0_plane_1" "1 -0 0 1456"
+"*trigger_brush_0_plane_2" "-0 -1 -0 1120"
+"*trigger_brush_0_plane_3" "0 1 0 96"
+"*trigger_brush_0_plane_4" "-0 0 -1 320"
+"*trigger_brush_0_plane_5" "0 0 1 320"
+"*trigger_brush_0_plane_6" "0.61887223 0.7854917 0 402.17172"
+"*trigger_brush_0_plane_7" "0.61887223 0.78549176 -0 402.17175"
+"*trigger_brush_0_plane_8" "-0.43653622 0.89968669 0 -144.1212"
+"*trigger_brush_0_plane_9" "-0.70710677 -0.70710677 0 418.60721"
+"*trigger_brush_0_plane_10" "0.70710677 -0.70710677 0 1821.5071"
+"*trigger_brush_0_plane_11" "0.89968669 0.43653628 0 1032.6772"
+"*trigger_brush_1_plane_0" "-1 0 -0 1456"
+"*trigger_brush_1_plane_1" "1 -0 -0 528"
+"*trigger_brush_1_plane_2" "-0 -1 -0 1120"
+"*trigger_brush_1_plane_3" "-0 1 0 1120"
+"*trigger_brush_1_plane_4" "-0 0 -1 320"
+"*trigger_brush_1_plane_5" "0 0 1 320"
+"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 0 1323.7039"
+"*trigger_brush_1_plane_7" "-0.70710683 0.70710683 0 1323.7039"
+"*trigger_brush_1_plane_8" "-0.70710677 -0.70710677 -0 1821.5071"
+"*trigger_brush_1_plane_9" "0.70710677 -0.70710677 -0 1165.312"
+"*trigger_brush_1_plane_10" "0.70710677 0.70710677 0 1165.312"
+"*trigger_bounds_mins" "-1456 -1120 -320"
+"*trigger_bounds_maxs" "1456 1120 320"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-7140.16 -1396.14 772"
+"link_guid" "e620fcf0"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 2224.2539"
+"*trigger_brush_0_plane_1" "1 0 0 2224.2637"
+"*trigger_brush_0_plane_2" "0 -1 0 2217.8926"
+"*trigger_brush_0_plane_3" "0 1 0 2217.8877"
+"*trigger_brush_0_plane_4" "0 -0 -1 380"
+"*trigger_brush_0_plane_5" "0 0 1 380"
+"*trigger_brush_0_plane_6" "0.72732341 -0.68629485 0 1703.6879"
+"*trigger_brush_0_plane_7" "0.68394107 0.72953725 -0 1429.9221"
+"*trigger_brush_0_plane_8" "-0.70123887 -0.71292639 -0 1406.1461"
+"*trigger_brush_0_plane_9" "-0.71656835 0.69751686 0 1744.0974"
+"*trigger_brush_0_plane_10" "0.72732347 -0.68629491 0 1703.688"
+"*trigger_brush_0_plane_11" "0.68394113 0.72953725 -0 1429.9222"
+"*trigger_brush_0_plane_12" "-0.71656841 0.69751692 0 1744.0975"
+"*trigger_bounds_mins" "-2224.2539 -2217.8926 -380"
+"*trigger_bounds_maxs" "2224.2637 2217.8877 380"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-1312 -3120 836"
+"link_to_guid_0" "e620fcf0"
+"link_guid" "8d5c25db"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 1712"
+"*trigger_brush_0_plane_1" "1 0 -0 1712"
+"*trigger_brush_0_plane_2" "-0 -1 -0 1328"
+"*trigger_brush_0_plane_3" "0 1 0 1328"
+"*trigger_brush_0_plane_4" "-0 0 -1 316"
+"*trigger_brush_0_plane_5" "0 0 1 316"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 2149.6045"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 2149.6045"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 2149.6045"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 2149.6045"
+"*trigger_bounds_mins" "-1712 -1328 -316"
+"*trigger_bounds_maxs" "1712 1328 316"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-5934.88 798.942 772"
+"link_guid" "7a915f75"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 1485.8599"
+"*trigger_brush_0_plane_1" "1 0 0 1485.8623"
+"*trigger_brush_0_plane_2" "0 -1 0 1490.5747"
+"*trigger_brush_0_plane_3" "0 1 0 1490.5756"
+"*trigger_brush_0_plane_4" "0 -0 -1 380"
+"*trigger_brush_0_plane_5" "0 0 1 380"
+"*trigger_brush_0_plane_6" "-0.68394113 -0.72953719 -0 989.97607"
+"*trigger_brush_0_plane_7" "0.70748007 0.70673329 0 1003.9444"
+"*trigger_brush_0_plane_8" "0.72732341 -0.68629485 0 1126.6088"
+"*trigger_brush_0_plane_9" "-0.71656853 0.69751674 0 1089.8322"
+"*trigger_brush_0_plane_10" "-0.68394113 -0.72953725 -0 989.97614"
+"*trigger_brush_0_plane_11" "0.72732347 -0.68629491 0 1126.6089"
+"*trigger_bounds_mins" "-1485.8599 -1490.5747 -380"
+"*trigger_bounds_maxs" "1485.8622 1490.5756 380"
+}
+{
+"editorclass" "trigger_mp_spawn_zone"
+"origin" "-4848 -4232 836"
+"link_to_guid_0" "c73b1ba0"
+"link_guid" "891ea354"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 -0 1824"
+"*trigger_brush_0_plane_1" "1 0 0 1824"
+"*trigger_brush_0_plane_2" "0 -1 0 1240"
+"*trigger_brush_0_plane_3" "0 1 0 1240"
+"*trigger_brush_0_plane_4" "-0 0 -1 316"
+"*trigger_brush_0_plane_5" "0 0 1 316"
+"*trigger_brush_0_plane_6" "0.70710677 0.70710677 -0 1861.105"
+"*trigger_brush_0_plane_7" "0.70710683 0.70710683 0 1861.1052"
+"*trigger_brush_0_plane_8" "-0.70710677 0.70710677 0 2166.5752"
+"*trigger_brush_0_plane_9" "-0.70710677 -0.70710677 0 2166.5752"
+"*trigger_brush_0_plane_10" "0.70710677 -0.70710677 0 2166.5752"
+"*trigger_bounds_mins" "-1824 -1240 -316"
+"*trigger_bounds_maxs" "1824 1240 316"
+}
+{
+"spawnflags" "0"
+"scale" "1"
+"angles" "-5 69 3.06941e-016"
+"origin" "-2120 -2960 -6692"
+"targetname" "spacenode"
+"collide_titan" "0"
+"classname" "info_target"
+}
+{
+"origin" "-1504 160 -516"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"targetname" "trigger_hurt_1"
+"damagecap" "90000"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 13184"
+"*trigger_brush_0_plane_1" "1 0 0 13184"
+"*trigger_brush_0_plane_2" "-0 -1 -0 15648"
+"*trigger_brush_0_plane_3" "0 1 0 15648"
+"*trigger_brush_0_plane_4" "0 0 -1 764"
+"*trigger_brush_0_plane_5" "0 0 1 764"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 20387.303"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 20387.303"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 20387.303"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 20387.303"
+"*trigger_bounds_mins" "-13184 -15648 -764"
+"*trigger_bounds_maxs" "13184 15648 764"
+}
+{
+"editorclass" "info_attrition_camp"
+"origin" "-716 728 560"
+"radius" "2000"
+"phase_9" "0"
+"phase_8" "0"
+"phase_7" "0"
+"phase_6" "0"
+"phase_5" "0"
+"phase_4" "0"
+"phase_3" "1"
+"phase_2" "1"
+"phase_1" "0"
+"height" "500"
+"gamemode_fw" "0"
+"classname" "info_target"
+}
+{
+"editorclass" "info_attrition_camp"
+"origin" "-8544 -3920 580.002"
+"radius" "1700"
+"phase_9" "0"
+"phase_8" "0"
+"phase_7" "0"
+"phase_6" "0"
+"phase_5" "0"
+"phase_4" "0"
+"phase_3" "1"
+"phase_2" "1"
+"phase_1" "0"
+"height" "500"
+"gamemode_fw" "0"
+"classname" "info_target"
+}
+{
+"editorclass" "info_attrition_camp"
+"origin" "-3888 -2308 725.73"
+"radius" "1800"
+"phase_9" "0"
+"phase_8" "0"
+"phase_7" "0"
+"phase_6" "0"
+"phase_5" "0"
+"phase_4" "0"
+"phase_3" "1"
+"phase_2" "0"
+"phase_1" "1"
+"height" "500"
+"gamemode_fw" "0"
+"classname" "info_target"
+}
+{
+"editorclass" "info_attrition_bank"
+"radius" "256"
+"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl"
+"height" "256"
+"scale" "1"
+"angles" "-2.44662 -0.1162 -6.31668"
+"origin" "-3728.92 -249.347 570.834"
+"classname" "info_target"
+}
+{
+"editorclass" "info_attrition_bank"
+"radius" "256"
+"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl"
+"height" "256"
+"scale" "1"
+"angles" "-0.0219147 45 -0.000732113"
+"origin" "-4634.46 -4318.01 643.997"
+"classname" "info_target"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "3.31448 90.4263 0.0792013"
+"origin" "-3792.41 -260.96 570.401"
+"powerUpType" "mp_loot_titan_build_credit"
+"classname" "script_ref"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "-5.19204e-005 90.4217 5.11617e-005"
+"origin" "-4133.64 -4605.58 644.989"
+"powerUpType" "mp_loot_titan_build_credit"
+"classname" "script_ref"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0.0002205 90.4217 -0.000274384"
+"origin" "-9398.19 -4025.82 578.673"
+"powerUpType" "mp_loot_titan_build_credit"
+"classname" "script_ref"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0.00735007 136.844 -0.00725995"
+"origin" "-1248.99 839.02 752.045"
+"powerUpType" "mp_loot_titan_build_credit"
+"classname" "script_ref"
+}
+{
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"gamemode_sur" "1"
+"gamemode_lh" "1"
+"gamemode_cp" "1"
+"gamemode_at" "0"
+"scale" "1"
+"angles" "0 167.628 0"
+"origin" "-8154.63 -3522 580.361"
+"link_guid" "dfc2c4f3"
+"triggerTarget" "trigger_hardpoint_A1"
+"targetname" "info_hardpoint_1"
+"target" "assault_hardpoint_far_A*"
+"nearTarget" "assault_hardpoint_near_A*"
+"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl"
+"hardpointName" "titangarage"
+"hardpointGroup" "A"
+"classname" "info_hardpoint"
+}
+{
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"gamemode_sur" "1"
+"gamemode_lh" "1"
+"gamemode_cp" "1"
+"gamemode_at" "0"
+"scale" "1"
+"angles" "0 -138.254 0"
+"origin" "-4333.02 -2155.06 695.002"
+"link_guid" "7749b115"
+"triggerTarget" "trigger_hardpoint_B1"
+"targetname" "info_hardpoint_3"
+"target" "assault_hardpoint_far_B*"
+"nearTarget" "assault_hardpoint_near_B*"
+"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl"
+"hardpointName" "dogwhistle"
+"hardpointGroup" "B"
+"classname" "info_hardpoint"
+}
+{
+"hardpointFrontlineYaw" "0"
+"hardpointFrontlineOverride" "0"
+"gamemode_tday" "0"
+"gamemode_sur" "1"
+"gamemode_lh" "1"
+"gamemode_cp" "1"
+"gamemode_at" "0"
+"scale" "1"
+"angles" "0 -114.836 0"
+"origin" "-1390.34 2.709 520.001"
+"link_guid" "2a84a088"
+"triggerTarget" "trigger_hardpoint_C1"
+"targetname" "info_hardpoint_2"
+"target" "assault_hardpoint_far_C*"
+"nearTarget" "assault_hardpoint_near_C*"
+"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl"
+"hardpointName" "market"
+"hardpointGroup" "C"
+"classname" "info_hardpoint"
+}
+{
+"editorclass" "info_bomb_mode_bomb"
+"spawnflags" "0"
+"origin" "-4470.68 -2688.15 724.001"
+"classname" "info_target"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 90 2.53193e-006"
+"origin" "-4612.01 -2544.57 716.025"
+"powerUpType" "mp_loot_titan_build_credit"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_lts_bomb_site"
+"teamnumber" "2"
+"spawnflags" "0"
+"model" "models/props/generator_coop/generator_coop_medium.mdl"
+"origin" "-3798.73 -258.059 587.091"
+"bombSiteLocation" "0"
+"classname" "info_target"
+}
+{
+"editorclass" "info_lts_bomb_site"
+"teamnumber" "2"
+"spawnflags" "0"
+"model" "models/props/generator_coop/generator_coop_medium.mdl"
+"origin" "-2614.51 -3454.96 644"
+"bombSiteLocation" "1"
+"classname" "info_target"
+}
+{
+"origin" "-6248 -1288 616"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"link_guid" "3148974f"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 316.78223"
+"*trigger_brush_0_plane_1" "1 0 0 316.78223"
+"*trigger_brush_0_plane_2" "0 -1 0 316.78247"
+"*trigger_brush_0_plane_3" "0 1 0 316.78241"
+"*trigger_brush_0_plane_4" "-0 0 -1 96"
+"*trigger_brush_0_plane_5" "-0 -0 1 96"
+"*trigger_brush_0_plane_6" "-0.7049914 -0.70921588 -0 224.00005"
+"*trigger_brush_0_plane_7" "-0.70921636 0.70499092 0 223.99983"
+"*trigger_brush_0_plane_8" "0.70499128 0.70921594 0 224"
+"*trigger_brush_0_plane_9" "0.70921642 -0.7049908 0 223.99986"
+"*trigger_brush_0_plane_10" "-0.70921636 0.70499086 0 223.99983"
+"*trigger_brush_0_plane_11" "0.70921648 -0.70499086 0 223.99988"
+"*trigger_bounds_mins" "-316.78223 -316.78247 -96"
+"*trigger_bounds_maxs" "316.78223 316.78241 96"
+}
+{
+"origin" "-3688 -2288 816"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"link_guid" "5bdcb1bf"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 316.78223"
+"*trigger_brush_0_plane_1" "1 0 0 316.78223"
+"*trigger_brush_0_plane_2" "0 -1 0 316.78247"
+"*trigger_brush_0_plane_3" "0 1 0 316.78241"
+"*trigger_brush_0_plane_4" "-0 0 -1 96"
+"*trigger_brush_0_plane_5" "-0 -0 1 96"
+"*trigger_brush_0_plane_6" "-0.7049908 -0.70921642 -0 224.00003"
+"*trigger_brush_0_plane_7" "-0.70921642 0.7049908 0 224.00003"
+"*trigger_brush_0_plane_8" "0.7049908 0.70921642 0 224.00003"
+"*trigger_brush_0_plane_9" "0.70921642 -0.7049908 0 223.99986"
+"*trigger_brush_0_plane_10" "-0.70499086 -0.70921648 -0 224.00005"
+"*trigger_brush_0_plane_11" "-0.70921648 0.70499086 0 224.00005"
+"*trigger_brush_0_plane_12" "0.70499086 0.70921648 -0 224.00005"
+"*trigger_brush_0_plane_13" "0.70921648 -0.70499086 0 223.99988"
+"*trigger_bounds_mins" "-316.78247 -316.78235 -96"
+"*trigger_bounds_maxs" "316.78235 316.78247 96"
+}
+{
+"origin" "-896 -2880 616"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"link_guid" "a6716741"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 225.83789"
+"*trigger_brush_0_plane_1" "1 0 0 225.83783"
+"*trigger_brush_0_plane_2" "0 -1 0 225.83789"
+"*trigger_brush_0_plane_3" "0 1 0 225.83789"
+"*trigger_brush_0_plane_4" "-0 0 -1 96"
+"*trigger_brush_0_plane_5" "-0 -0 1 96"
+"*trigger_brush_0_plane_6" "-0.99996608 -0.0082386546 -0 224.00003"
+"*trigger_brush_0_plane_7" "-0.0082386546 0.99996608 0 224.00005"
+"*trigger_brush_0_plane_8" "0.99996608 0.0082385186 0 224"
+"*trigger_brush_0_plane_9" "0.0082386564 -0.99996608 0 224.00003"
+"*trigger_brush_0_plane_10" "-0.99996614 -0.0082386555 0 224.00005"
+"*trigger_brush_0_plane_11" "-0.0082386555 0.99996614 0 224.00005"
+"*trigger_brush_0_plane_12" "0.99996614 0.0082385195 0 224.00002"
+"*trigger_brush_0_plane_13" "0.0082386564 -0.99996614 0 224.00006"
+"*trigger_brush_0_plane_14" "-0.71290839 0.70125717 0 316.78387"
+"*trigger_brush_0_plane_15" "-0.70125717 -0.71290839 0 316.78387"
+"*trigger_brush_0_plane_16" "0.70125723 0.71290833 0 316.78387"
+"*trigger_brush_0_plane_17" "0.71290827 -0.70125717 0 316.78381"
+"*trigger_bounds_mins" "-225.83789 -225.83789 -96"
+"*trigger_bounds_maxs" "225.83783 225.83789 96"
+}
+{
+"origin" "-3624 -4216 736"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"link_guid" "c9c2695"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 316.78223"
+"*trigger_brush_0_plane_1" "1 0 0 316.78223"
+"*trigger_brush_0_plane_2" "0 -1 0 316.78247"
+"*trigger_brush_0_plane_3" "0 1 0 316.78241"
+"*trigger_brush_0_plane_4" "-0 0 -1 96"
+"*trigger_brush_0_plane_5" "-0 -0 1 96"
+"*trigger_brush_0_plane_6" "-0.70880991 -0.70539957 -0 223.99986"
+"*trigger_brush_0_plane_7" "-0.70539927 0.70881015 0 224.00011"
+"*trigger_brush_0_plane_8" "0.70881015 0.70539927 0 223.99994"
+"*trigger_brush_0_plane_9" "0.70539904 -0.70881045 0 224.00003"
+"*trigger_brush_0_plane_10" "0.70881021 0.70539927 0 223.99997"
+"*trigger_bounds_mins" "-316.78296 -316.78271 -96"
+"*trigger_bounds_maxs" "316.78296 316.78296 96"
+}
+{
+"origin" "-3752 -96 656"
+"wait" "1"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "0"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "none"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4097"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"link_guid" "17679895"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 0 0 316.78223"
+"*trigger_brush_0_plane_1" "1 0 0 316.78223"
+"*trigger_brush_0_plane_2" "0 -1 0 316.78247"
+"*trigger_brush_0_plane_3" "0 1 0 316.78241"
+"*trigger_brush_0_plane_4" "-0 0 -1 96"
+"*trigger_brush_0_plane_5" "-0 -0 1 96"
+"*trigger_brush_0_plane_6" "-0.70880991 -0.70539957 -0 223.99986"
+"*trigger_brush_0_plane_7" "-0.70539945 0.70880997 0 224.00002"
+"*trigger_brush_0_plane_8" "0.70880991 0.70539957 0 224"
+"*trigger_brush_0_plane_9" "0.70539951 -0.70880997 0 224.00003"
+"*trigger_brush_0_plane_10" "-0.70539945 0.70881003 0 224.00003"
+"*trigger_brush_0_plane_11" "0.70539945 -0.70880997 0 224.00003"
+"*trigger_bounds_mins" "-316.78284 -316.78284 -96"
+"*trigger_bounds_maxs" "316.78296 316.7829 96"
+}
+{
+"spawnflags" "0"
+"origin" "-3824 -72 640"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-3824 88 624"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-3664 -72 656"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-3824 -248 624"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-4000 -72 736"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-4610.47 -4408.71 676.989"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-4522.47 -4504.71 676.989"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-4306.47 -4712.71 676.989"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-4138.47 -4712.71 676.989"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-3930.47 -4680.71 676.989"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-3754.47 -4520.71 676.989"
+"classname" "info_node"
+}
+{
+"spawnflags" "0"
+"origin" "-3418.47 -4184.71 676.989"
+"classname" "info_node"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 135 0"
+"origin" "-6522 -1025 533"
+"link_to_guid_1" "cd6e529e"
+"link_to_guid_0" "1e132096"
+"link_guid" "1e3bbebe"
+"turretId" "7"
+"teamnumber" "3"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "-0.0980319 -171.596 -0.00220506"
+"origin" "-6239.68 -4216.72 521.118"
+"link_to_guid_1" "ee670072"
+"link_to_guid_0" "4b6be066"
+"link_guid" "237cf48f"
+"turretId" "0"
+"teamnumber" "4"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"teamnumber" "4"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3818.28 -319.059 613.368"
+"link_to_guid_1" "c86bd441"
+"link_to_guid_0" "6668019f"
+"link_guid" "c9f7aad1"
+"turretId" "2"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"teamnumber" "4"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 90 -8.60438e-006"
+"origin" "-4384 -2680 756"
+"link_to_guid_1" "3b7f5395"
+"link_to_guid_0" "2365c1c9"
+"link_guid" "394a1d3c"
+"turretId" "1"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_team_tower"
+"spawnflags" "0"
+"model" "models/props/generator_coop/generator_coop_medium.mdl"
+"scale" "1"
+"angles" "-2.48038e-006 90 0"
+"origin" "-454.381 -2886.73 520.827"
+"link_to_guid_1" "63693a5c"
+"link_to_guid_0" "128fc74f"
+"link_guid" "a2589c18"
+"teamnumber" "2"
+"radius" "1"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "3.35337e-006 90 0"
+"origin" "-760 -3872 521"
+"link_to_guid_1" "feb9084e"
+"link_to_guid_0" "bcd0f203"
+"link_guid" "868d19d2"
+"turretId" "3"
+"teamnumber" "2"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_camp"
+"spawnflags" "0"
+"model" "models/vehicle/escape_pod/escape_pod.mdl"
+"height" "256"
+"origin" "-1248 448 656"
+"link_to_guid_8" "ffdb91c1"
+"link_to_guid_7" "fc571b81"
+"link_to_guid_6" "f983fcd0"
+"link_to_guid_5" "de85a29e"
+"link_to_guid_4" "ccdc3db0"
+"link_to_guid_3" "bdc38ac8"
+"link_to_guid_2" "563b6eff"
+"link_to_guid_1" "4359bf3d"
+"link_to_guid_0" "2f988812"
+"link_guid" "a9394e76"
+"radius" "900"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_camp"
+"spawnflags" "0"
+"model" "models/vehicle/escape_pod/escape_pod.mdl"
+"height" "256"
+"origin" "-4368 -2136 700"
+"link_to_guid_11" "f57064db"
+"link_to_guid_10" "df5a7c37"
+"link_to_guid_9" "a1a2ede5"
+"link_to_guid_8" "9c0be084"
+"link_to_guid_7" "7c9125e7"
+"link_to_guid_6" "436573d6"
+"link_to_guid_5" "36aeef28"
+"link_to_guid_4" "2639b847"
+"link_to_guid_3" "234799c3"
+"link_to_guid_2" "1b61f1e1"
+"link_to_guid_1" "194727c5"
+"link_to_guid_0" "5496c0f"
+"link_guid" "df7be002"
+"radius" "800"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_camp"
+"spawnflags" "0"
+"model" "models/vehicle/escape_pod/escape_pod.mdl"
+"height" "256"
+"origin" "-8064 -3544 667.01"
+"link_to_guid_8" "d982b5e0"
+"link_to_guid_7" "d57a2bb3"
+"link_to_guid_6" "d284dc2c"
+"link_to_guid_5" "a7db3193"
+"link_to_guid_4" "9503c7f8"
+"link_to_guid_3" "88df464c"
+"link_to_guid_2" "3adb10c9"
+"link_to_guid_1" "388cbaa5"
+"link_to_guid_0" "2266d6e2"
+"link_guid" "539c61dc"
+"radius" "900"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 65.8114 0"
+"origin" "-7869.5 -1013.15 681"
+"link_to_guid_1" "9b60b1b0"
+"link_to_guid_0" "7491589"
+"link_guid" "7070a0e2"
+"turretId" "6"
+"teamnumber" "3"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 135 0"
+"origin" "-6649 362 585"
+"link_to_guid_1" "9b6a7479"
+"link_to_guid_0" "6c2dd43f"
+"link_guid" "ef8ee88b"
+"turretId" "8"
+"teamnumber" "3"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0.603044 90 -1.33634"
+"origin" "-949.577 -2882.28 533.149"
+"link_to_guid_1" "ce6e0c03"
+"link_to_guid_0" "436209f5"
+"link_guid" "f4757f6f"
+"turretId" "4"
+"teamnumber" "2"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_turret_site"
+"spawnflags" "0"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "-1.1511e-005 90 -5.58721e-005"
+"origin" "-957.242 -1445.11 520.999"
+"link_to_guid_1" "3566e2c0"
+"link_to_guid_0" "263c3de7"
+"link_guid" "6c185b79"
+"turretId" "5"
+"teamnumber" "2"
+"classname" "info_target"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 90 -1.52373e-006"
+"origin" "-4384 -2534 725.88"
+"link_guid" "3b7f5395"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2642 716"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2718 716"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2642 716"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2718 716"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4384 -2534 716"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2718 726"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2642 726"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2642 726"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2718 726"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2718 736"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2642 736"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2718 736"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2642 736"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2642 746"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2718 746"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4346 -2718 746"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4422 -2642 746"
+"classname" "script_ref"
+}
+{
+"model" "*2"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-4384 -2626 886"
+"link_guid" "2365c1c9"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3726 -65 530"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -281 564"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -357 564"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -357 564"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -281 564"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 90 -1.52373e-006"
+"origin" "-3726 -65 549.88"
+"link_guid" "6668019f"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3726 -65 540"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -357 574"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -357 574"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -281 574"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -281 574"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -357 584"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -357 584"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -281 584"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -281 584"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -281 594"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -281 594"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -357 594"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -357 594"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -281 604"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -281 604"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3856 -357 604"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-3780 -357 604"
+"classname" "script_ref"
+}
+{
+"model" "*3"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-3790.5 -210 722"
+"link_guid" "c86bd441"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 97.0737 0"
+"origin" "-6197.48 -4250.06 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 97.0737 0"
+"origin" "-6282.25 -4183.92 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 45.0117 -1.52373e-006"
+"origin" "-6081.35 -4053.12 545.88"
+"link_guid" "ee670072"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 97.0737 0"
+"origin" "-6272.91 -4259.4 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45.0117 0"
+"origin" "-6081.35 -4053.12 536"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 97.0737 0"
+"origin" "-6206.85 -4174.57 512"
+"classname" "script_ref"
+}
+{
+"model" "*4"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-6177.5 -4151 678"
+"link_guid" "4b6be066"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45.0117 0"
+"origin" "-6081.35 -4053.12 526"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-722 -3834 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-798 -3834 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-722 -3910 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-608 -3870 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-798 -3910 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 90 -1.52373e-006"
+"origin" "-608 -3870 521.88"
+"link_guid" "feb9084e"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-912 -2920 522"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-912 -2844 522"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-988 -2844 522"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-988 -2920 522"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-834 -2880 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 90 -1.52373e-006"
+"origin" "-834 -2880 521.88"
+"link_guid" "ce6e0c03"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-919 -1623 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-995 -1483 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 90 -1.52373e-006"
+"origin" "-919 -1623 521.88"
+"link_guid" "263c3de7"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-995 -1407 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-919 -1407 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-919 -1483 512"
+"classname" "script_ref"
+}
+{
+"model" "*5"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-702.5 -3872 686"
+"link_guid" "bcd0f203"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"model" "*6"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-911.5 -2880 686"
+"link_guid" "436209f5"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"model" "*7"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-955.5 -1515 686"
+"link_guid" "3566e2c0"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6702.86 362.291 576"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6649.12 416.031 576"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 45 -1.52373e-006"
+"origin" "-6766.12 247.122 585.88"
+"link_guid" "6c2dd43f"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6649.11 308.55 576"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6595.37 362.29 576"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6766.12 247.122 576"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6468.37 -1024.71 524"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 45 -1.52373e-006"
+"origin" "-6799.12 -875.88 533.88"
+"link_guid" "cd6e529e"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6522.11 -1078.45 524"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6522.12 -970.969 524"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6799.12 -875.88 524"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6575.86 -1024.71 524"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6522.11 -1078.45 514"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6575.86 -1024.71 514"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7819.05 -993.456 632"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7888.55 -962.627 632"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 11.1616 0"
+"origin" "-7927.69 -782.723 576"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7919.35 -1032.1 632"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7849.92 -1062.91 632"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_battery_port"
+"spawnflags" "0"
+"model" "models/props/battery_port/battery_port_animated.mdl"
+"scale" "1"
+"angles" "3.10056e-006 11.1616 -1.52373e-006"
+"origin" "-7927.69 -782.723 585.88"
+"link_guid" "7491589"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7819.05 -993.456 642"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7849.92 -1062.91 642"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7919.35 -1032.1 642"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7888.55 -962.627 642"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7819.05 -993.456 652"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7919.35 -1032.1 652"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7849.92 -1062.91 652"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7888.55 -962.627 652"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7849.92 -1062.91 662"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7888.55 -962.627 662"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7919.35 -1032.1 662"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7819.05 -993.456 662"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7819.05 -993.456 672"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7919.35 -1032.1 672"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7888.55 -962.627 672"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 66.0615 0"
+"origin" "-7849.92 -1062.91 672"
+"classname" "script_ref"
+}
+{
+"model" "*8"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-6680.75 331.983 750"
+"link_guid" "9b6a7479"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"model" "*9"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-6633.75 -977.05 686"
+"link_guid" "1e132096"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"model" "*10"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-7869.28 -925.873 774"
+"link_guid" "9b60b1b0"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"model" "*11"
+"triangle_collision" "1"
+"editorclass" "func_brush_navmesh_separator"
+"origin" "-452 -2886 732"
+"link_guid" "63693a5c"
+"startDisconnected" "0"
+"classname" "func_brush"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-912 -2920 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-988 -2920 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-988 -2844 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-912 -2844 512"
+"classname" "script_ref"
+}
+{
+"editorclass" "info_fw_foundation_plate"
+"spawnflags" "0"
+"model" "models/industrial/grate_mod.mdl"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-6468.37 -1024.71 514"
+"classname" "script_ref"
+}
+{
+"editorclass" "trigger_fw_territory"
+"origin" "-728 -2828 885"
+"wait" "0"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "0"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "0"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "1"
+"StartDisabled" "0"
+"spawnflags" "64"
+"link_guid" "128fc74f"
+"triggerFilterUseNew" "1"
+"classname" "trigger_multiple"
+"*trigger_brush_0_plane_0" "-1 -0 -0 904"
+"*trigger_brush_0_plane_1" "1 0 0 1336"
+"*trigger_brush_0_plane_2" "-0 -1 -0 1588"
+"*trigger_brush_0_plane_3" "-0 1 0 996"
+"*trigger_brush_0_plane_4" "0 0 -1 395"
+"*trigger_brush_0_plane_5" "0 0 1 395"
+"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 1343.5029"
+"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 1762.1101"
+"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 2067.5801"
+"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 1648.9729"
+"*trigger_brush_1_plane_0" "-1 -0 -0 1336"
+"*trigger_brush_1_plane_1" "1 0 0 1336"
+"*trigger_brush_1_plane_2" "0 -1 -0 -996"
+"*trigger_brush_1_plane_3" "-0 1 -0 1588"
+"*trigger_brush_1_plane_4" "0 0 -1 395"
+"*trigger_brush_1_plane_5" "0 0 1 395"
+"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 -0 2067.5801"
+"*trigger_brush_1_plane_7" "-0.70710677 -0.70710677 -0 240.41632"
+"*trigger_brush_1_plane_8" "0.70710677 -0.70710677 0 240.41632"
+"*trigger_brush_1_plane_9" "0.70710677 0.70710677 0 2067.5801"
+"*trigger_bounds_mins" "-1336 -1588 -395"
+"*trigger_bounds_maxs" "1336 1588 395"
+}
+{
+"model" "*12"
+"triangle_collision" "1"
+"editorclass" "func_brush_fw_territory_border"
+"origin" "-1051 -2171 728"
+"VisibilityFlags" "2"
+"useNonLocalWorldLights" "0"
+"startdisabled" "0"
+"solidity" "1"
+"solidbsp" "0"
+"gamemode_tdm" "0"
+"gamemode_lh" "0"
+"gamemode_fw" "1"
+"gamemode_ffa" "0"
+"gamemode_ctf" "0"
+"gamemode_cp" "0"
+"gamemode_at" "0"
+"drawinfastreflection" "0"
+"disableshadows" "0"
+"bakedSunFraction" "-1.0"
+"teamnumber" "2"
+"classname" "func_brush"
+}
+{
+"model" "*13"
+"triangle_collision" "1"
+"editorclass" "func_brush_fw_territory_border"
+"origin" "-6613 -1533.5 674"
+"useNonLocalWorldLights" "0"
+"teamnumber" "3"
+"startdisabled" "0"
+"solidity" "1"
+"solidbsp" "0"
+"gamemode_tdm" "0"
+"gamemode_lh" "0"
+"gamemode_fw" "1"
+"gamemode_ffa" "0"
+"gamemode_ctf" "0"
+"gamemode_cp" "0"
+"gamemode_at" "0"
+"drawinfastreflection" "0"
+"disableshadows" "0"
+"bakedSunFraction" "-1.0"
+"VisibilityFlags" "4"
+"classname" "func_brush"
+}
+{
+"model" "*14"
+"triangle_collision" "1"
+"editorclass" "func_brush_fw_territory_border"
+"origin" "-1051 -2170.5 728"
+"useNonLocalWorldLights" "0"
+"startdisabled" "0"
+"solidity" "1"
+"solidbsp" "0"
+"gamemode_tdm" "0"
+"gamemode_lh" "0"
+"gamemode_fw" "1"
+"gamemode_ffa" "0"
+"gamemode_ctf" "0"
+"gamemode_cp" "0"
+"gamemode_at" "0"
+"drawinfastreflection" "0"
+"disableshadows" "0"
+"bakedSunFraction" "-1.0"
+"teamnumber" "2"
+"VisibilityFlags" "4"
+"classname" "func_brush"
+}
+{
+"model" "*15"
+"triangle_collision" "1"
+"editorclass" "func_brush_fw_territory_border"
+"origin" "-6614 -1533.5 674"
+"VisibilityFlags" "2"
+"useNonLocalWorldLights" "0"
+"teamnumber" "3"
+"startdisabled" "0"
+"solidity" "1"
+"solidbsp" "0"
+"gamemode_tdm" "0"
+"gamemode_lh" "0"
+"gamemode_fw" "1"
+"gamemode_ffa" "0"
+"gamemode_ctf" "0"
+"gamemode_cp" "0"
+"gamemode_at" "0"
+"drawinfastreflection" "0"
+"disableshadows" "0"
+"bakedSunFraction" "-1.0"
+"classname" "func_brush"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -70.647 0"
+"origin" "-1398.96 873.896 574.188"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4448 -1480 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4448 -1536 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4448 -1592 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4600 -1568 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4712 -1568 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4656 -1568 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4768 -1568 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4604 -1368 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4220 -1782 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4540 -1784 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4792 -1724 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4844 -1784 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4844 -2152 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4792 -2100 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4488 -2100 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-4436 -2152 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4648 -1924 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 174.242 0"
+"origin" "-3516.01 -2612.4 736"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -134.404 0"
+"origin" "-4005.21 -2549.17 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -134.404 0"
+"origin" "-3969.21 -2585.17 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-3363.85 -2041.39 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-3364.24 -2092.28 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-2396.24 -2092.28 656"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-2395.85 -2041.39 656"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-3612.05 -2210.29 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 45 0"
+"origin" "-3647.46 -2175.76 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4258 -2710 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4258 -2660 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-5034 -2714 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-5034 -2664 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-4758 -2662 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-4758 -2712 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 124.91 0"
+"origin" "-5305.57 -2280.73 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 124.91 0"
+"origin" "-5346.53 -2309.39 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -55.09 0"
+"origin" "-5463.47 -2054.61 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -55.09 0"
+"origin" "-5504.43 -2083.27 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4822 -2766 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-4970 -2610 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-4200 -2766 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 137.849 0"
+"origin" "-3978.23 -2674.54 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 135.697 0"
+"origin" "-3527.69 -2204.18 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -55.171 0"
+"origin" "-5292.38 -1858.66 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 49.7768 0"
+"origin" "-4953.45 -3057.54 720"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -45.163 0"
+"origin" "-6104.11 -1467.31 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -45.163 0"
+"origin" "-6068.72 -1432.03 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -45.163 0"
+"origin" "-5880.11 -1255.31 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -45.163 0"
+"origin" "-6282.72 -1650.03 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 45.2765 0"
+"origin" "-6525.59 -1797.7 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 45.2765 0"
+"origin" "-6485.59 -1837.7 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 44.837 0"
+"origin" "-6592.69 -1784.11 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 44.837 0"
+"origin" "-6656.69 -1716.11 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-6819.31 -1879.89 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-6675.31 -2023.89 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 44.837 0"
+"origin" "-6616.69 -1416.11 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-7161.31 -2245.89 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-7383.31 -2023.89 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 44.837 0"
+"origin" "-7372.69 -1516.11 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.724 0"
+"origin" "-5710.41 -974.3 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-5745.31 -889.89 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.724 0"
+"origin" "-5836.41 -898.3 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.724 0"
+"origin" "-6372.41 -690.3 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.724 0"
+"origin" "-6420.41 -650.3 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.724 0"
+"origin" "-6460.41 -610.3 592"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-6305.31 -725.89 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-6481.31 -555.89 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 44.837 0"
+"origin" "-6090.69 -350.11 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 44.837 0"
+"origin" "-5666.69 33.89 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -135.163 0"
+"origin" "-6045.31 -305.89 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -20.865 0"
+"origin" "-5194.72 232.223 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 159.135 0"
+"origin" "-5075.28 189.78 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4882 184 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-4882 -306 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -25.868 0"
+"origin" "-5272.05 6.83351 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -134.691 0"
+"origin" "-6613.74 55.0701 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -134.691 0"
+"origin" "-6895.74 339.07 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -45.061 0"
+"origin" "-5494.43 573.319 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -25.868 0"
+"origin" "-5784.05 154.834 592"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -44.691 0"
+"origin" "-7145.07 -729.74 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 75.477 0"
+"origin" "-7936.67 -3117.23 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 67.9382 0"
+"origin" "-8116.76 -3943.04 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -22.062 0"
+"origin" "-8131.04 -3881.24 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 74.9241 0"
+"origin" "-8443.99 -4197.42 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 75.0976 0"
+"origin" "-8591.52 -2940.22 596.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -14.449 0"
+"origin" "-8625.64 -2878.83 596.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -14.902 0"
+"origin" "-8646.22 -3144.48 588.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -14.902 0"
+"origin" "-8186.22 -3268.48 588.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -14.902 0"
+"origin" "-7738.22 -3388.48 588.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -14.411 0"
+"origin" "-7861.12 -3839.65 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 75.098 0"
+"origin" "-7821.52 -3916.22 588.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 44.4931 0"
+"origin" "-8843.46 -4036.85 588.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 11.4796 0"
+"origin" "-9137.74 -3522.5 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -23.152 0"
+"origin" "-6910.97 -3776.88 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 24.3059 0"
+"origin" "-7612.21 -4206.92 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -135.244 0"
+"origin" "-5389.49 -3299.08 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -135.244 0"
+"origin" "-5428.86 -3259.31 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.26 0"
+"origin" "-5311.26 -3375.59 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.26 0"
+"origin" "-5271.21 -3414.68 720"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 45.6407 0"
+"origin" "-5198.86 -3069.67 720"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -106.038 0"
+"origin" "-2273.51 -2344.4 656"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -70.647 0"
+"origin" "-2784.97 -2332.36 656"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-2606.61 -1979.85 656"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -90 0"
+"origin" "-2451.72 -1980.24 656"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -2.2529 0"
+"origin" "-8502.15 -4125.32 612.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -83.909 0"
+"origin" "-1470.54 649.606 574.188"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -70.647 0"
+"origin" "-1646.96 681.896 574.188"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -47.145 0"
+"origin" "-1909.06 268.227 574.188"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -89.666 0"
+"origin" "-1188.89 -5.46055 534.188"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -89.666 0"
+"origin" "-1128.89 -5.4606 534.188"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.361 0"
+"origin" "-1702.89 389.442 574.188"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -50.123 0"
+"origin" "-1915.84 473.333 574.185"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -89.666 0"
+"origin" "-664 608 608"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -89.666 0"
+"origin" "-432 332 616"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -89.666 0"
+"origin" "-432 1192 592"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -106.195 0"
+"origin" "-640.812 -190.785 591.967"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -73.007 0"
+"origin" "-1373.04 -230.614 536.005"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -89.666 0"
+"origin" "-1300.89 -605.461 534.188"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -106.195 0"
+"origin" "-612.868 1338.66 586.157"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -82.54 0"
+"origin" "-1021.68 1162.37 574.188"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -121.825 0"
+"origin" "-1467.78 -599.512 534.188"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -143.868 0"
+"origin" "-167.517 1018.96 595.376"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 75.8469 0"
+"origin" "-7529.91 -2887.76 592"
+"classname" "info_node_cover_stand"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-4581.92 -1857.53 755.998"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-3202.13 -2679.22 772"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-4996.1 848.459 640"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "3.20383 -2583.9 584"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-4126.89 -3645.28 708.992"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-8254.52 -4383.02 668.36"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-8468.17 -2480.01 644.36"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-7833.18 -1925.19 644.125"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-8326.67 -1573.78 644"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-5844.11 -121.301 644"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-6128.37 -720.44 644"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-6707.37 -1812.42 643.999"
+"classname" "info_node_safe_hint"
+}
+{
+"spawnflags" "0"
+"nodeFOV" "360"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "102"
+"origin" "-5257.23 -3233.01 775.998"
+"classname" "info_node_safe_hint"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-707.71 -2674.11 543.997"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-704 -3212 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -178.666 0"
+"origin" "-617.141 -2875.04 543.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-460 -3100 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -125.081 0"
+"origin" "-833.472 -2284.29 543.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 90 0"
+"origin" "-832.73 -3601.05 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -1.40334e-014 0"
+"origin" "-1399.71 -2731.27 671.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -6.4689 0"
+"origin" "-1399.62 -2638.84 671.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-1480 -3028 672"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-1720 -3100 676"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-1720 -2660 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-1992 -2828 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-1992 -2936 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-2180 -2984 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-2016 -2576 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 56.2721 0"
+"origin" "-1949.45 -3509.17 676"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-2812.8 -2664.66 740"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 25.6162 0"
+"origin" "-2812.01 -3011.4 740"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -32.531 0"
+"origin" "-2828.86 -3205.67 740"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -6.2179 0"
+"origin" "-3032 -3416.73 740"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 0.0768 0"
+"origin" "-3104.63 -3485.69 740"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-2861.49 -2863.76 740"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 180 0"
+"origin" "-2704 -2396 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.33 0"
+"origin" "-2761.52 -3471.39 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -134.33 0"
+"origin" "-2684.26 -3546.82 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -134.639 0"
+"origin" "-3202.47 -3376.52 740"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -134.859 0"
+"origin" "-3200.63 -4278.03 676.992"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -134.639 0"
+"origin" "-3550.71 -3621.72 676.992"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 155.979 0"
+"origin" "-3463.88 -4643.98 804.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 133.053 0"
+"origin" "-3741.32 -4907.18 805"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 166.354 0"
+"origin" "-3675.16 -4826.35 805"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 114.473 0"
+"origin" "-3983 -4975.73 805"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 88.2126 0"
+"origin" "-4256.72 -4967.88 805"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 46.6407 0"
+"origin" "-4512.85 -4891.3 805"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 41.8151 0"
+"origin" "-4563.67 -4841.39 805.001"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 42.579 0"
+"origin" "-4859.07 -4548.38 805"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -120.962 0"
+"origin" "-3986.54 -3549.94 676.992"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -113.45 0"
+"origin" "-4188.01 -3705.29 676.991"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 66.5706 0"
+"origin" "-4238.87 -3829.87 676.992"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 62.3857 0"
+"origin" "-4364.49 -4336.36 677.088"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 44.8382 0"
+"origin" "-4309.25 -4380.65 677.117"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 37.7505 0"
+"origin" "-4071.07 -4137.88 676.992"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 139.865 0"
+"origin" "-4222.27 -4375.36 677.088"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 167.789 0"
+"origin" "-3955.13 -4117.21 677.088"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 80.8422 0"
+"origin" "-4411.09 -4892.87 805"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 89.7471 0"
+"origin" "-4326.31 -4894.97 805"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 70.1256 0"
+"origin" "-3910.69 -4912.43 805"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 45.67 0"
+"origin" "-2818.48 -3682.61 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 45.67 0"
+"origin" "-2885.74 -3615.18 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 36.5559 0"
+"origin" "-2609.52 -3780.17 676"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 31.9057 0"
+"origin" "-3696.58 -3757.97 676.992"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -23.621 0"
+"origin" "-7441.27 -898.424 612.001"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -23.621 0"
+"origin" "-8041.74 -1434.98 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 37.0224 0"
+"origin" "-7080.78 161.468 615.988"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 53.6677 0"
+"origin" "-6786.92 -124.946 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -33.427 0"
+"origin" "-6075.92 526.058 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -35.245 0"
+"origin" "-6677.06 -1246.48 547.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 138.638 0"
+"origin" "-2417.65 -1009.07 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 141.758 0"
+"origin" "-2332.31 -564.011 544.001"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 160.837 0"
+"origin" "-2624.02 -519.857 544.001"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 169.628 0"
+"origin" "-2689.16 -113.007 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 133.483 0"
+"origin" "-2829.19 -642.056 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 149.3 0"
+"origin" "-1979.57 -1001.11 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 134.155 0"
+"origin" "-2184.13 -999.64 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 149.3 0"
+"origin" "-1686.79 -1189.54 551.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 171.47 0"
+"origin" "-1357.28 -1042.66 543.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -179.666 0"
+"origin" "-1235.46 -715.11 534.188"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -34.978 0"
+"origin" "-2730.88 -458.32 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -35.71 0"
+"origin" "-2775.54 -520.54 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -9.6773 0"
+"origin" "-2266.83 -844.802 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 3.901 0"
+"origin" "-2043.38 -1151.14 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -64.026 0"
+"origin" "-2482.02 -350.092 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -30.214 0"
+"origin" "-2714.15 -751.932 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -45.244 0"
+"origin" "-5714.85 -3386.19 631.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -45.244 0"
+"origin" "-5778.85 -3454.19 631.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -45.162 0"
+"origin" "-5143.75 -3664.94 683.684"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -28.251 0"
+"origin" "-5595.25 -3691.11 631.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 28.2911 0"
+"origin" "-6336.37 -3733.64 583.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 43.454 0"
+"origin" "-6046.74 -4089.17 567.998"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 45.5625 0"
+"origin" "-6442.85 -4307.03 596.727"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 43.454 0"
+"origin" "-6411.68 -3979.16 544.059"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -135.616 0"
+"origin" "-5636.21 -3055.44 743.998"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -134.748 0"
+"origin" "-5911.06 -3640.23 615.998"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -158.587 0"
+"origin" "-5575.21 -3991.75 616.151"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -135.047 0"
+"origin" "-5652.33 -3892.95 616.263"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -109.894 0"
+"origin" "-6004.29 -3569.17 615.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 47.6708 0"
+"origin" "-6118.64 -4004.42 567.998"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 47.6708 0"
+"origin" "-5953.49 -4363.76 551.998"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 166.432 0"
+"origin" "-5926.31 -4057.69 583.998"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -142.99 0"
+"origin" "-6006.69 -3895.67 591.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 44.8896 0"
+"origin" "-6334.8 -4509.46 596.59"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 169.812 0"
+"origin" "-4504.9 -4068.47 676.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 134.202 0"
+"origin" "-4950.18 -4283.5 691.021"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 141.776 0"
+"origin" "-4755.07 -3956.47 706.986"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 136.692 0"
+"origin" "-4788.98 -4236.91 677.36"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 142.275 0"
+"origin" "-4860.91 -4054.94 689.753"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 145.937 0"
+"origin" "-4658.05 -4180.44 677.005"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 135.456 0"
+"origin" "-4556.96 -4489.46 676.997"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 141.59 0"
+"origin" "-4368.02 -4659.16 677.095"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 50.3557 0"
+"origin" "-3067.86 -4140.96 676.992"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 31.9057 0"
+"origin" "-3220.18 -3619.63 676.991"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 128.27 0"
+"origin" "-6730.49 -4096.46 596.637"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 144.639 0"
+"origin" "-7016.04 -3992.89 615.352"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 144.639 0"
+"origin" "-6970.05 -3936.68 613.751"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 137.753 0"
+"origin" "-6828.88 -3835.72 613.356"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 127.562 0"
+"origin" "-6906.02 -4206.28 621.319"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -30.354 0"
+"origin" "-7229.86 -3833.26 628.919"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -30.354 0"
+"origin" "-7189.66 -3781.25 615.588"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 1.4328 0"
+"origin" "-7652.91 -3868.36 613.737"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 169.997 0"
+"origin" "-3390.69 -409.783 628.126"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 145.444 0"
+"origin" "-3539.24 -628.953 653.85"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 170.226 0"
+"origin" "-3422.48 163.181 678.375"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 153.366 0"
+"origin" "-3977.6 -507.186 620.654"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -87.59 0"
+"origin" "-4051.64 -1031.06 642.338"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -106.967 0"
+"origin" "-3654.05 -1080.95 691.825"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 12.1599 0"
+"origin" "-4318.36 -436.306 653.563"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 36.0196 0"
+"origin" "-4284.9 -513.31 662.829"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -11.207 0"
+"origin" "-4220.42 -156.665 650.563"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -1.414 0"
+"origin" "-4181.35 -321.315 624.302"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -1.414 0"
+"origin" "-4146.35 640.5 599.621"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -1.414 0"
+"origin" "-4251.01 554.427 604.121"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 178.584 0"
+"origin" "-3355.36 -264.48 591.022"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 178.584 0"
+"origin" "-3434.78 494.689 570.717"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 178.584 0"
+"origin" "-3370.48 572.305 569.7"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 169.186 0"
+"origin" "-3338.88 371.23 595.424"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -87.59 0"
+"origin" "-3826.48 103.86 556.936"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -94.751 0"
+"origin" "-3612.14 -8.40236 573.338"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -100.359 0"
+"origin" "-3683.58 -455.71 633.426"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -93.066 0"
+"origin" "-3761.73 -451.058 623.982"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -94.751 0"
+"origin" "-3613.3 411.581 580.228"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -119.661 0"
+"origin" "-4356.36 485.86 609.257"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -67.568 0"
+"origin" "-3133.43 306.76 585.95"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -41.623 0"
+"origin" "-3233.32 119.493 660.132"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -52.608 0"
+"origin" "-3168.23 169.574 666.278"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -3.2097 0"
+"origin" "-3645.72 -387.85 633.759"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -15.827 0"
+"origin" "-5718.78 266.283 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 149.723 0"
+"origin" "-6117.19 -1016.82 548"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 134.837 0"
+"origin" "-6511.07 -1400.55 548"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 149.723 0"
+"origin" "-6988.63 -863.72 556"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -121.753 0"
+"origin" "-7241.91 -1372.73 556"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -134.726 0"
+"origin" "-6574.62 -1243.04 547.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -59.767 0"
+"origin" "-4954.64 413.425 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -147.04 0"
+"origin" "-5435.04 961.184 608"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -152.864 0"
+"origin" "-5958.78 512.058 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -137.45 0"
+"origin" "-6242.19 758.578 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -116.477 0"
+"origin" "-7831.51 -202.67 628"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 52.7583 0"
+"origin" "-7270.91 -2360.21 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -85.297 0"
+"origin" "-4082.07 -369.953 635.191"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 36.0196 0"
+"origin" "-4220.19 -580.09 662.354"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -62.22 0"
+"origin" "-4760.92 -245.885 605.061"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -106.967 0"
+"origin" "-3491.43 -947.177 682.578"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.642 0"
+"origin" "-3806.81 -915.8 630.794"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.642 0"
+"origin" "-3941.86 -835.906 621.134"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 65.2752 0"
+"origin" "-4196.32 -1418.68 747.066"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 91.358 0"
+"origin" "-3929.93 -1441.03 756.15"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 91.358 0"
+"origin" "-3775.94 -1462.05 754.149"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 91.358 0"
+"origin" "-3842.78 -1503.14 752.756"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.827 0"
+"origin" "-6790.89 -742.16 556"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.827 0"
+"origin" "-6766.08 -864.268 556"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.827 0"
+"origin" "-6587.41 -782.693 556.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -6.8311 0"
+"origin" "-7206.05 -1215.3 556.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.827 0"
+"origin" "-6327.11 -1407.17 547.996"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.827 0"
+"origin" "-6088.45 -1240.85 547.997"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 177.117 0"
+"origin" "-6528.74 -915.604 555.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 134.344 0"
+"origin" "-6842.1 -1983.31 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -172.091 0"
+"origin" "-2720.74 -3872.36 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -104.654 0"
+"origin" "-7818.54 -2545.53 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -106.009 0"
+"origin" "-7399.23 -2652.41 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -104.654 0"
+"origin" "-7682.55 -2236.73 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -103.491 0"
+"origin" "-7539.35 -2731.02 612.361"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -106.182 0"
+"origin" "-7556.15 -2515.44 612"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -103.272 0"
+"origin" "-7677.14 -2555.86 608"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 47.2903 0"
+"origin" "-7227.17 -1653.07 620"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 68.2386 0"
+"origin" "-7138.14 -1745.69 620"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -35.745 0"
+"origin" "-7295.84 -854.727 611.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 163.129 0"
+"origin" "-1079.54 -1393.29 543.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 164.256 0"
+"origin" "-644.283 -1287.47 551.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 163.129 0"
+"origin" "-608.017 -1548.47 543.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 121.938 0"
+"origin" "-1044.76 -1919.15 551.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -96.65 0"
+"origin" "-837.209 -1825.28 543.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -96.65 0"
+"origin" "-903.926 -1817.26 544"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 88.1533 0"
+"origin" "-912.089 -1918.1 543.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 109.373 0"
+"origin" "-773.872 -1925.72 543.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -96.65 0"
+"origin" "-652.95 -1876.11 544.306"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 146.327 0"
+"origin" "-671.199 -1642.57 543.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 138.57 0"
+"origin" "-562.81 -1962.17 545.867"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 158.674 0"
+"origin" "-498.6 -2227.35 551.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 90.7323 0"
+"origin" "-620.521 -2460.53 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 90.6667 0"
+"origin" "-560.453 -2459.98 545.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 90.7323 0"
+"origin" "-894.677 -2483.51 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 90.6667 0"
+"origin" "-1112.58 -2730.83 551.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 90.6667 0"
+"origin" "-664.477 -3024.61 544"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -89.333 0"
+"origin" "-741.66 -2149.92 544.001"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -92.033 0"
+"origin" "-1111.41 -2322.08 552"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -44.455 0"
+"origin" "-1293.77 -1707.54 551.999"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -45.719 0"
+"origin" "-1251.96 -1672.37 551.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -44.385 0"
+"origin" "-1455.92 -1275.27 551.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -45.719 0"
+"origin" "-1489.37 -964.045 544"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -44.385 0"
+"origin" "-1578.43 -999.334 544"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -90.518 0"
+"origin" "-1084.1 -953.878 546.075"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -96.65 0"
+"origin" "-732.146 -1010.05 552"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -1.2453 0"
+"origin" "-1537.71 -2839.76 676"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 3.1461 0"
+"origin" "-1517.71 -2924.2 676"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 139.352 0"
+"origin" "-2670.74 -602.656 543.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 149.245 0"
+"origin" "-1335.03 -1348.38 551.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 163.141 0"
+"origin" "-1032.31 -1085.11 543.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 74.4128 0"
+"origin" "-7853.43 -3034.08 612.36"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 74.4128 0"
+"origin" "-7751.29 -3071.42 612.36"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 167.629 0"
+"origin" "-5558.09 239.798 608"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 166.842 0"
+"origin" "-5227.33 360.85 613.635"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 135.208 0"
+"origin" "-5036.83 -214.626 613.635"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -150.455 0"
+"origin" "-5086.52 870.636 608"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -72.328 0"
+"origin" "-7478.87 -1322.08 620"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -49.23 0"
+"origin" "-7623.01 -1502.26 620"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -65.552 0"
+"origin" "-7408.93 -1568.43 619.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 129.387 0"
+"origin" "-7336.82 -1684.9 620.003"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 98.3354 0"
+"origin" "-7571.35 -1622.74 620"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 42.8562 0"
+"origin" "-7656.57 -851.33 608.001"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 50.9043 0"
+"origin" "-7387.3 -708.065 610.848"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -43.957 0"
+"origin" "-7396.13 -598.89 607.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -135.93 0"
+"origin" "-7294.09 -599.115 608.001"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -91.508 0"
+"origin" "-7590.79 -518.696 608"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -44.973 0"
+"origin" "-8232.15 -1676.94 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -44.973 0"
+"origin" "-8297.91 -2135.64 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -44.973 0"
+"origin" "-7915.97 -2454.28 612"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -45.665 0"
+"origin" "-7837.14 -2371.42 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -57.871 0"
+"origin" "-7613.43 -2143.64 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -44.634 0"
+"origin" "-8221.14 -1858.24 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -44.634 0"
+"origin" "-8328.48 -1787.78 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -44.634 0"
+"origin" "-8105.31 -1568.36 612"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 135.07 0"
+"origin" "-7298.37 -1518.83 620"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 98.8941 0"
+"origin" "-7408.47 -2129.94 620"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 75.1534 0"
+"origin" "-8007.74 -1160.66 608"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 44.2621 0"
+"origin" "-7462.92 -338.168 608"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 62.0431 0"
+"origin" "-7068.96 -645.363 611.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 60.7599 0"
+"origin" "-7127.36 -397.457 608.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 60.7599 0"
+"origin" "-6927.11 -247.45 607.997"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 48.9231 0"
+"origin" "-7026.65 -5.52116 608.269"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 44.1453 0"
+"origin" "-6898.84 -14.349 608.002"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 15.7763 0"
+"origin" "-7300.53 28.8221 615.989"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 15.7763 0"
+"origin" "-7312.08 -81.1711 615.989"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -142.622 0"
+"origin" "-6235.65 488.89 608"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -142.622 0"
+"origin" "-6285.76 583.541 608"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -93.005 0"
+"origin" "-7723.87 -317.694 620"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -110.578 0"
+"origin" "-7905.4 -806.484 608"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -110.545 0"
+"origin" "-8213.91 -1169.36 615.987"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -45.24 0"
+"origin" "-7779.74 -1457.22 620.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -118.793 0"
+"origin" "-7262.46 -2112.76 620"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 134.921 0"
+"origin" "-7069.4 -2059.8 619.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 134.921 0"
+"origin" "-6965.36 -2039.65 619.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 134.921 0"
+"origin" "-7067.73 -2181.29 620"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 134.438 0"
+"origin" "-7030.15 -1103.6 548.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 136.86 0"
+"origin" "-6958.79 -1023.52 548.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -122.915 0"
+"origin" "-6945.45 -1438.47 556.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -122.915 0"
+"origin" "-7076.89 -1356.67 547.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -27.741 0"
+"origin" "-6712.3 -1092.64 548.002"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -134.322 0"
+"origin" "-5838.37 -3486.14 623.998"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -134.322 0"
+"origin" "-5496.42 -3821.66 631.422"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -140.821 0"
+"origin" "-5635.04 -3386.63 639.998"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 44.8896 0"
+"origin" "-6389.73 -4358.61 596.68"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 45.8775 0"
+"origin" "-6190.79 -4504.95 596.59"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 39.1821 0"
+"origin" "-6138.37 -4365.84 543.997"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 49.869 0"
+"origin" "-6376.99 -4116.28 544.057"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 27.2854 0"
+"origin" "-6635.28 -4149.75 596.612"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 65.6465 0"
+"origin" "-5782.65 -4230.55 583.998"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 26.5723 0"
+"origin" "-6314.25 -3798.62 575.997"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 127.22 0"
+"origin" "-3975.97 -999.631 640.261"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 92.9475 0"
+"origin" "-3872.5 -954.094 635.842"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 39.1837 0"
+"origin" "-3746.29 -970.234 648.015"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 46.5053 0"
+"origin" "-3724.16 -1060.16 683.97"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 161.034 0"
+"origin" "-4931.75 -34.5351 612"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 167.601 0"
+"origin" "-4781.9 31.9081 609.512"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.88 0"
+"origin" "-3746.59 -1326.22 758.167"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.88 0"
+"origin" "-3862.17 -1403.46 755.403"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.88 0"
+"origin" "-4003.82 -1376.79 756.963"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.88 0"
+"origin" "-3818.67 -1310.57 736.729"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -88.88 0"
+"origin" "-3934.48 -1329.37 736.936"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 37.525 0"
+"origin" "-3261.78 -3825.89 676.991"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 42.1465 0"
+"origin" "-3004.11 -3943.44 676.99"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 29.8149 0"
+"origin" "-3785.85 -3979.67 676.99"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 146.092 0"
+"origin" "-7418.79 -3618.09 613.878"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 172.826 0"
+"origin" "-7497.34 -3881.1 613.738"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 164.11 0"
+"origin" "-7547.81 -3444.96 613.877"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 157.092 0"
+"origin" "-7382.1 -3382.33 613.951"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 171.98 0"
+"origin" "-7485.88 -4015.78 613.548"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 157.092 0"
+"origin" "-7068.7 -3627.8 630.557"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 135.409 0"
+"origin" "-7242 -3626.56 613.868"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 172.826 0"
+"origin" "-8034.04 -3907.92 612.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -16.281 0"
+"origin" "-8775.36 -3606.64 612.36"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -21.388 0"
+"origin" "-8728.06 -3723.08 612.36"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -16.725 0"
+"origin" "-8815.03 -3338.83 612.36"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -16.725 0"
+"origin" "-8472.9 -3035.34 612.361"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -16.725 0"
+"origin" "-8565.71 -3076.37 612.361"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -14.902 0"
+"origin" "-8536.68 -3642.07 612.36"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 150.096 0"
+"origin" "-6212.22 -1136.77 547.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 150.096 0"
+"origin" "-6376.93 -1153.07 548.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 150.096 0"
+"origin" "-6414.51 -1276.82 548.001"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 150.096 0"
+"origin" "-6223.32 -1303.52 547.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 169.832 0"
+"origin" "-5966.13 -1125.8 547.999"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -38.38 0"
+"origin" "-5580.96 453.289 612"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -11.798 0"
+"origin" "-5505.55 126.512 608"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -23.195 0"
+"origin" "-5691.8 369.818 608"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 179.146 0"
+"origin" "-5036.52 317.736 612"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 168.352 0"
+"origin" "-5023.53 106.622 611.999"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 139.991 0"
+"origin" "-4948.58 -138.127 612"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 175.641 0"
+"origin" "-4429.96 -6.77726 602.128"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -174.096 0"
+"origin" "-4064.05 -2378.34 745.168"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 0 0"
+"origin" "-5046.06 -2380.52 745.707"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 133.798 0"
+"origin" "-2495.17 -3816.94 676"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 177.129 0"
+"origin" "-2066.1 -3675.86 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 179.93 0"
+"origin" "-2192.01 -2920.02 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 88.3595 0"
+"origin" "-2666.73 -3245.09 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -99.291 0"
+"origin" "-2636.56 -2930.83 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -99.69 0"
+"origin" "-2271.33 -2856.08 676"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -99.291 0"
+"origin" "-2536.56 -2538.83 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 93.3102 0"
+"origin" "-2538.32 -2696.92 676"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 121.451 0"
+"origin" "-2235.09 -2639.19 675.999"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "98"
+"scale" "1"
+"angles" "0 -4.3496 0"
+"origin" "-4401.73 -4281.28 677.088"
+"classname" "info_node_cover_left"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "80"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "99"
+"scale" "1"
+"angles" "0 -19.849 0"
+"origin" "-4269.17 -4009.47 676.992"
+"classname" "info_node_cover_right"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 12.1031 0"
+"origin" "-4586.41 -4582 677.095"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 12.1031 0"
+"origin" "-4728.61 -4679.2 805"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -17.189 0"
+"origin" "-4572.98 -4366.2 676.992"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 45.1009 0"
+"origin" "-3993.2 -4718.89 676.992"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 45.1009 0"
+"origin" "-3937.2 -4774.89 676.992"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -138.479 0"
+"origin" "-3158.38 -3881.2 676.992"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "100"
+"scale" "1"
+"angles" "0 -138.479 0"
+"origin" "-3102.38 -3937.2 676.992"
+"classname" "info_node_cover_stand"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 46.1752 0"
+"origin" "-3862.58 -4359.17 676.991"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 -133.625 0"
+"origin" "-3489.45 -4008.82 676.991"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 135.596 0"
+"origin" "-3206.01 -4144.01 676.991"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 135.596 0"
+"origin" "-3781.91 -4714.67 676.994"
+"classname" "info_node_cover_crouch"
+}
+{
+"TargetNode" "-1"
+"spawnflags" "0"
+"nodeFOV" "120"
+"MinimumState" "1"
+"MaximumState" "3"
+"IgnoreFacing" "2"
+"hinttype" "101"
+"scale" "1"
+"angles" "0 135.596 0"
+"origin" "-3669.82 -4608.87 676.989"
+"classname" "info_node_cover_crouch"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 90 2.53193e-006"
+"origin" "-5243 -3233 712"
+"powerUpType" "mp_loot_titan_build_credit_lts"
+"classname" "script_ref"
+}
+{
+"editorclass" "script_power_up_other"
+"model" "models/communication/flag_base_red.mdl"
+"scale" "1"
+"angles" "0 90 2.53193e-006"
+"origin" "-4492.01 -1536.57 692.025"
+"powerUpType" "mp_loot_titan_build_credit_lts"
+"classname" "script_ref"
+}
+{
+"origin" "-7697.6 -3277.22 2118"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 455.62012"
+"*trigger_brush_0_plane_1" "1 0 0 455.61328"
+"*trigger_brush_0_plane_2" "0 -1 0 513.23438"
+"*trigger_brush_0_plane_3" "0 1 0 513.2417"
+"*trigger_brush_0_plane_4" "0 -0 -1 182"
+"*trigger_brush_0_plane_5" "-0 -0 1 182"
+"*trigger_brush_0_plane_6" "-0.98972714 0.14296904 0 393.67426"
+"*trigger_brush_0_plane_7" "0.14312822 0.98970413 0 461.63812"
+"*trigger_brush_0_plane_8" "0.98972714 -0.14296904 0 393.66644"
+"*trigger_brush_0_plane_9" "-0.14312822 -0.98970413 -0 461.63187"
+"*trigger_brush_0_plane_10" "-0.98972714 0.14296903 0 393.67426"
+"*trigger_brush_0_plane_11" "0.14312823 0.98970425 -0 461.63818"
+"*trigger_brush_0_plane_12" "0.98972714 -0.14296903 0 393.66644"
+"*trigger_brush_0_plane_13" "-0.14312823 -0.98970425 -0 461.6319"
+"*trigger_brush_0_plane_14" "-0.59868395 0.80098528 0 604.84576"
+"*trigger_brush_0_plane_15" "-0.80098528 -0.59868395 0 604.74408"
+"*trigger_brush_0_plane_16" "0.80098528 0.59868395 0 604.74304"
+"*trigger_brush_0_plane_17" "0.59868395 -0.80098528 0 604.83582"
+"*trigger_bounds_mins" "-455.62012 -513.23438 -182"
+"*trigger_bounds_maxs" "455.61328 513.2417 182"
+}
+{
+"origin" "-10901 -6447.86 1272"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 3209.627"
+"*trigger_brush_0_plane_1" "1 0 0 3209.6821"
+"*trigger_brush_0_plane_2" "0 -1 0 1600.1504"
+"*trigger_brush_0_plane_3" "0 1 0 1600.1563"
+"*trigger_brush_0_plane_4" "0 0 -1 2132"
+"*trigger_brush_0_plane_5" "-0 0 1 2132"
+"*trigger_brush_0_plane_6" "-0.93357444 0.35838348 0 3260.9895"
+"*trigger_brush_0_plane_7" "0.35853338 0.93351692 0 461.64783"
+"*trigger_brush_0_plane_8" "0.93357444 -0.35838348 0 3261.0391"
+"*trigger_brush_0_plane_9" "-0.35853338 -0.93351692 -0 461.62238"
+"*trigger_brush_0_plane_10" "-0.93357456 0.35838351 0 3260.99"
+"*trigger_brush_0_plane_11" "0.93357456 -0.35838351 0 3261.0396"
+"*trigger_brush_0_plane_12" "-0.40664804 0.91358483 0 2632.5132"
+"*trigger_brush_0_plane_13" "-0.91358477 -0.40664807 0 2632.0728"
+"*trigger_brush_0_plane_14" "0.91358477 0.40664807 0 2632.1255"
+"*trigger_brush_0_plane_15" "0.40664804 -0.91358483 0 2632.5305"
+"*trigger_bounds_mins" "-3209.627 -1600.1503 -2132"
+"*trigger_bounds_maxs" "3209.6821 1600.1563 2132"
+}
+{
+"origin" "-12224.3 -2684.64 1302"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 1919.71"
+"*trigger_brush_0_plane_1" "1 0 0 1919.6924"
+"*trigger_brush_0_plane_2" "0 -1 0 2792.1941"
+"*trigger_brush_0_plane_3" "0 1 0 2792.1877"
+"*trigger_brush_0_plane_4" "0 0 -1 2162"
+"*trigger_brush_0_plane_5" "0 -0 1 2162"
+"*trigger_brush_0_plane_6" "0.35838318 0.93357456 0 2582.3491"
+"*trigger_brush_0_plane_7" "0.93351686 -0.35853344 0 1064.5466"
+"*trigger_brush_0_plane_8" "-0.3583833 -0.93357456 -0 2582.3618"
+"*trigger_brush_0_plane_9" "-0.93351692 0.35853329 0 1064.5614"
+"*trigger_brush_0_plane_10" "0.93351698 -0.35853344 0 1064.5468"
+"*trigger_brush_0_plane_11" "-0.35838333 -0.93357462 -0 2582.3618"
+"*trigger_brush_0_plane_12" "-0.93351704 0.35853329 0 1064.5614"
+"*trigger_brush_0_plane_13" "0.91358483 0.40664819 0 2578.9524"
+"*trigger_brush_0_plane_14" "-0.40664828 0.91358477 0 2578.5479"
+"*trigger_brush_0_plane_15" "0.4066481 -0.91358483 0 2578.5464"
+"*trigger_brush_0_plane_16" "-0.91358471 -0.40664825 0 2578.9709"
+"*trigger_bounds_mins" "-1919.7101 -2792.1941 -2162"
+"*trigger_bounds_maxs" "1919.6924 2792.1877 2162"
+}
+{
+"origin" "-9678.93 1486.6 1272"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 1984.2383"
+"*trigger_brush_0_plane_1" "1 0 0 1984.2451"
+"*trigger_brush_0_plane_2" "0 -1 0 2092.8115"
+"*trigger_brush_0_plane_3" "0 1 0 2092.8159"
+"*trigger_brush_0_plane_4" "0 0 -1 2132"
+"*trigger_brush_0_plane_5" "-0 0 1 2132"
+"*trigger_brush_0_plane_6" "0.66694921 0.74510318 0 2141.3713"
+"*trigger_brush_0_plane_7" "0.74499589 -0.66706908 0 745.94049"
+"*trigger_brush_0_plane_8" "-0.66694921 -0.74510318 -0 2141.3635"
+"*trigger_brush_0_plane_9" "-0.74499589 0.66706902 0 745.93823"
+"*trigger_brush_0_plane_10" "-0.66694921 -0.74510324 -0 2141.3635"
+"*trigger_brush_0_plane_11" "-0.74499595 0.66706908 0 745.93829"
+"*trigger_bounds_mins" "-1984.2383 -2092.8115 -2132"
+"*trigger_bounds_maxs" "1984.2452 2092.8157 2132"
+}
+{
+"origin" "-6096.88 -6585.13 3646"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 186.99512"
+"*trigger_brush_0_plane_1" "1 0 0 187.00488"
+"*trigger_brush_0_plane_2" "0 -1 0 195.37012"
+"*trigger_brush_0_plane_3" "0 1 0 195.37988"
+"*trigger_brush_0_plane_4" "0 0 -1 1534"
+"*trigger_brush_0_plane_5" "-0 0 1 1534"
+"*trigger_brush_0_plane_6" "-0.93360478 0.35830453 0 140.7215"
+"*trigger_brush_0_plane_7" "0.35880053 0.93341428 0 155.19298"
+"*trigger_brush_0_plane_8" "0.93355304 -0.35843927 0 140.74951"
+"*trigger_brush_0_plane_9" "-0.35841355 -0.93356293 -0 155.23872"
+"*trigger_brush_0_plane_10" "-0.93360478 0.35830456 0 140.7215"
+"*trigger_brush_0_plane_11" "0.9335531 -0.35843927 0 140.74953"
+"*trigger_brush_0_plane_12" "-0.35841355 -0.93356299 -0 155.23874"
+"*trigger_brush_0_plane_13" "-0.40655595 0.91362584 0 209.29874"
+"*trigger_brush_0_plane_14" "-0.91354162 -0.40674537 0 209.26328"
+"*trigger_brush_0_plane_15" "0.91365522 0.40649006 0 209.22247"
+"*trigger_brush_0_plane_16" "0.40667942 -0.91357088 0 209.2924"
+"*trigger_bounds_mins" "-186.99512 -195.37012 -1534"
+"*trigger_bounds_maxs" "187.00488 195.37988 1534"
+}
+{
+"origin" "-5132.81 -6293.13 3646"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 96.314941"
+"*trigger_brush_0_plane_1" "1 0 0 96.310059"
+"*trigger_brush_0_plane_2" "0 -1 0 95.370117"
+"*trigger_brush_0_plane_3" "0 1 0 95.379883"
+"*trigger_brush_0_plane_4" "0 0 -1 1534"
+"*trigger_brush_0_plane_5" "-0 0 1 1534"
+"*trigger_brush_0_plane_6" "-0.93378407 0.35783696 0 75.044144"
+"*trigger_brush_0_plane_7" "0.3588675 0.93338853 0 73.302734"
+"*trigger_brush_0_plane_8" "0.93338954 -0.35886484 0 75.00016"
+"*trigger_brush_0_plane_9" "-0.35842046 -0.93356025 -0 73.376137"
+"*trigger_brush_0_plane_10" "0.3588675 0.93338859 -0 73.302734"
+"*trigger_brush_0_plane_11" "0.9333896 -0.35886484 0 75.000168"
+"*trigger_brush_0_plane_12" "-0.35842046 -0.93356031 -0 73.376129"
+"*trigger_brush_0_plane_13" "-0.40675199 0.91353858 0 104.95502"
+"*trigger_brush_0_plane_14" "-0.91344124 -0.40697074 0 104.91621"
+"*trigger_brush_0_plane_15" "0.91376239 0.40624902 0 104.86583"
+"*trigger_brush_0_plane_16" "0.40646777 -0.91366512 0 104.89292"
+"*trigger_bounds_mins" "-96.314941 -95.370117 -1534"
+"*trigger_bounds_maxs" "96.310059 95.379883 1534"
+}
+{
+"origin" "-5816.81 -7577.13 3646"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 96.314941"
+"*trigger_brush_0_plane_1" "1 0 0 96.310059"
+"*trigger_brush_0_plane_2" "0 -1 0 95.370117"
+"*trigger_brush_0_plane_3" "0 1 0 95.379883"
+"*trigger_brush_0_plane_4" "0 0 -1 1534"
+"*trigger_brush_0_plane_5" "-0 0 1 1534"
+"*trigger_brush_0_plane_6" "-0.93378407 0.35783696 0 75.044144"
+"*trigger_brush_0_plane_7" "0.3588675 0.93338853 0 73.302734"
+"*trigger_brush_0_plane_8" "0.93338954 -0.35886484 0 75.00016"
+"*trigger_brush_0_plane_9" "-0.35842046 -0.93356025 -0 73.376137"
+"*trigger_brush_0_plane_10" "0.3588675 0.93338859 -0 73.302734"
+"*trigger_brush_0_plane_11" "0.9333896 -0.35886484 0 75.000168"
+"*trigger_brush_0_plane_12" "-0.35842046 -0.93356031 -0 73.376129"
+"*trigger_brush_0_plane_13" "-0.40675199 0.91353858 0 104.95502"
+"*trigger_brush_0_plane_14" "-0.91344124 -0.40697074 0 104.91621"
+"*trigger_brush_0_plane_15" "0.91376239 0.40624902 0 104.86583"
+"*trigger_brush_0_plane_16" "0.40646777 -0.91366512 0 104.89292"
+"*trigger_bounds_mins" "-96.314941 -95.370117 -1534"
+"*trigger_bounds_maxs" "96.310059 95.379883 1534"
+}
+{
+"origin" "-7132.81 -7741.13 3646"
+"triggerNearbyRadius" "0"
+"triggerFilterTeamOther" "1"
+"triggerFilterTeamNeutral" "1"
+"triggerFilterTeamMilitia" "1"
+"triggerFilterTeamIMC" "1"
+"triggerFilterTeamBeast" "1"
+"triggerFilterPlayer" "all"
+"triggerFilterPhaseShift" "any"
+"triggerFilterNpcOwnedByPlayer" "any"
+"triggerFilterNpcFlip" "0"
+"triggerFilterNpc" "all"
+"triggerFilterNonCharacter" "0"
+"StartDisabled" "0"
+"spawnflags" "4099"
+"nodmgforce" "1"
+"mobility_3_hard" "1"
+"mobility_2_normal" "1"
+"mobility_1_easy" "1"
+"damageSourceName" "fall"
+"damagemodel" "0"
+"damagecap" "20"
+"damage" "10000"
+"triggerFilterUseNew" "1"
+"classname" "trigger_hurt"
+"*trigger_brush_0_plane_0" "-1 0 0 96.314941"
+"*trigger_brush_0_plane_1" "1 0 0 96.310059"
+"*trigger_brush_0_plane_2" "0 -1 0 95.370117"
+"*trigger_brush_0_plane_3" "0 1 0 95.379883"
+"*trigger_brush_0_plane_4" "0 0 -1 1534"
+"*trigger_brush_0_plane_5" "-0 0 1 1534"
+"*trigger_brush_0_plane_6" "-0.93378407 0.35783696 0 75.044144"
+"*trigger_brush_0_plane_7" "0.3588675 0.93338853 0 73.302734"
+"*trigger_brush_0_plane_8" "0.93338954 -0.35886484 0 75.00016"
+"*trigger_brush_0_plane_9" "-0.35842046 -0.93356025 -0 73.376137"
+"*trigger_brush_0_plane_10" "0.3588675 0.93338859 -0 73.302734"
+"*trigger_brush_0_plane_11" "0.9333896 -0.35886484 0 75.000168"
+"*trigger_brush_0_plane_12" "-0.35842046 -0.93356031 -0 73.376129"
+"*trigger_brush_0_plane_13" "-0.40675199 0.91353858 0 104.95502"
+"*trigger_brush_0_plane_14" "-0.91344124 -0.40697074 0 104.91621"
+"*trigger_brush_0_plane_15" "0.91376239 0.40624902 0 104.86583"
+"*trigger_brush_0_plane_16" "0.40646777 -0.91366512 0 104.89292"
+"*trigger_bounds_mins" "-96.314941 -95.370117 -1534"
+"*trigger_bounds_maxs" "96.310059 95.379883 1534"
+}
+
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut
index da4e50f5c..191c3b248 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut
@@ -27,7 +27,9 @@ HarvesterStruct function SpawnHarvester( vector origin, vector angles, int healt
harvester.SetShieldHealthMax( shieldHealth )
harvester.SetShieldHealth( shieldHealth )
harvester.EnableAttackableByAI( 30, 0, AI_AP_FLAG_NONE )
- SetObjectCanBeMeleed( harvester, false )
+ SetCustomSmartAmmoTarget( harvester, true )
+ SetObjectCanBeMeleed( harvester, true )
+ SetVisibleEntitiesInConeQueriableEnabled( harvester, true )
SetTeam(harvester,team)
// create dangerous area to all AI because we dont want any AI clipping into the harvester ever
// radius of 90 cos thats like 7.5 metres? AI shouldnt rally need to get closer than that (except nuke titans and stalkers)
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut
index 539b72bc2..a5c3e2709 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut
@@ -5698,7 +5698,13 @@ bool function IsUnlockValid( string ref, string parentRef = "" )
bool function IsSubItemLocked( entity player, string ref, string parentRef )
{
- if ( DevEverythingUnlocked() )
+ if ( DevEverythingUnlocked( player ) )
+ return false
+
+ if ( IsItemPurchasableEntitlement( ref, parentRef ) )
+ return false
+
+ if ( GetItemType( ref ) == eItemTypes.PRIME_TITAN || GetSubitemType( parentRef, ref ) == eItemTypes.PRIME_TITAN )
return false
if ( IsItemInEntitlementUnlock( ref, parentRef ) )
@@ -5817,7 +5823,13 @@ bool function IsSubItemLocked( entity player, string ref, string parentRef )
bool function IsItemLocked( entity player, string ref )
{
- if ( DevEverythingUnlocked() )
+ if ( DevEverythingUnlocked( player ) )
+ return false
+
+ if ( IsItemPurchasableEntitlement( ref ) )
+ return false
+
+ if ( GetItemType( ref ) == eItemTypes.PRIME_TITAN )
return false
if ( IsItemInEntitlementUnlock( ref ) )
@@ -5906,7 +5918,7 @@ bool function IsItemLockedForEntitlement( entity player, string ref, string pare
bool function IsSubItemOwned( entity player, string ref, string parentRef )
{
- if ( DevEverythingUnlocked() )
+ if ( DevEverythingUnlocked( player ) )
return false
Assert( IsValid( player ) )
@@ -5990,7 +6002,7 @@ bool function IsSubItemOwned( entity player, string ref, string parentRef )
bool function IsItemOwned( entity player, string ref )
{
- if ( DevEverythingUnlocked() )
+ if ( DevEverythingUnlocked( player ) )
return false
Assert( IsValid( player ) )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut
index 1092bf2d8..6499faa2e 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut
@@ -65,6 +65,8 @@ bool function ClientCommandCallback_GenUp( entity player, array<string> args )
player.GenChanged()
player.XPChanged()
}
+
+ RegenPersistentLoadouts(player)
return true
} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut b/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut
index c5887f2b3..47dd9294f 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut
@@ -1601,6 +1601,9 @@ float function GetPulseFrac( rate = 1, startTime = 0 )
bool function IsPetTitan( titan )
{
Assert( titan.IsTitan() )
+
+ if ( !titan.GetTitanSoul() )
+ return false
return titan.GetTitanSoul().GetBossPlayer() != null
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut
index 6f044b7ac..2b95d1a8c 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut
@@ -1,6 +1,7 @@
global function SvXP_Init
global function PlayerProgressionAllowed
global function HandleXPGainForScoreEvent
+global function AddXP
void function SvXP_Init()
{
@@ -29,46 +30,38 @@ bool function PlayerProgressionAllowed( entity player )
void function HandleXPGainForScoreEvent( entity player, ScoreEvent event )
{
// note: obviously all xp stuff can be cheated in if people want to on customs, this is mainly just here for fun for those who want it and feature completeness
- // most score events don't have this, so we'll set this to the xp value of other categories later if needed
+
int xpValue = ScoreEvent_GetXPValue( event )
int weaponXp = ScoreEvent_GetXPValueWeapon( event )
int titanXp = ScoreEvent_GetXPValueTitan( event )
-
- if ( xpValue < weaponXp )
- xpValue = weaponXp
- else if ( xpValue < titanXp )
- xpValue = titanXp
+ int factionXp = ScoreEvent_GetXPValueFaction( event )
entity weapon = player.GetActiveWeapon()
- if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) )
- AddWeaponXP( player, xpValue )
+ if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) && weaponXp != 0 )
+ AddWeaponXP( player, weaponXp )
// if we specifically gain titan xp, then give titan xp no matter what, otherwise only give it when we're in a titan
- if ( titanXp != 0 || player.IsTitan() )
- AddTitanXP( player, xpValue )
-
- // most events don't have faction xp but almost everything should give it
- int factionXp = ScoreEvent_GetXPValueFaction( event )
- if ( xpValue > factionXp )
- factionXp = xpValue
- else if ( xpValue < factionXp )
- xpValue = factionXp
+ if ( titanXp != 0 )
+ AddTitanXP( player, titanXp )
if ( factionXp != 0 )
AddFactionXP( player, factionXp )
- if ( xpValue == 0 )
- return
-
// global xp
+ if ( xpValue != 0 )
+ AddXP( player, xpValue )
+}
+
+void function AddXP( entity player, int amount )
+{
int oldXp = player.GetPersistentVarAsInt( "xp" )
- if(oldXp<0) oldXp = 0
+ if( oldXp < 0 ) oldXp = 0
int oldLevel = GetLevelForXP( oldXp )
- player.SetPersistentVar( "xp", min( oldXp + xpValue, PlayerGetMaxXPPerGen() ) )
+ player.SetPersistentVar( "xp", min( oldXp + amount, PlayerGetMaxXPPerGen() ) )
player.XPChanged() // network xp change to client, gen can't change here
int newXp = player.GetPersistentVarAsInt( "xp" )
int newLevel = GetLevelForXP( newXp )
if ( newLevel != oldLevel )
Remote_CallFunction_NonReplay( player, "ServerCallback_PlayerLeveledUp", player.GetPersistentVarAsInt( "gen" ), newLevel )
-} \ No newline at end of file
+}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut
index 9717c76d9..89fb7a826 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut
@@ -60,6 +60,19 @@ function AiSoldiers_Init()
level.COOP_AT_WEAPON_RATES[ "mp_weapon_smr" ] <- 0.4
level.COOP_AT_WEAPON_RATES[ "mp_weapon_mgl" ] <- 0.1
+ // add stub death callback, because in _codecallbacks_common.gnut there is
+ // CodeCallback_OnEntityKilled which is only called when an entity is being tracked. An
+ // entity is set to be tracked if it has a death callback for it's class, unfortunately this
+ // is then relayed to clients and used for client side death callbacks. The end result of
+ // not having this function called is that clients become completely unaware of any grunt
+ // deaths. A noticeable difference here is that grunts do not play the kill confirmed audio
+ // except on War Games, which does register a callback for grunt deaths to make them dissolve.
+ //
+ // Whilst this may seem like a bit of a hacky solution, it is generally better than simply
+ // tracking all entities. If a different callback is created in the future for grunt deaths
+ // that is not specific to a gamemode, map, etc. then this could be removed
+ AddDeathCallback( "npc_soldier", void function( entity guy, var damageInfo ){} )
+
PrecacheSprite( $"sprites/glow_05.vmt" )
FlagInit( "disable_npcs" )
FlagInit( "Disable_IMC" )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut
index f193643c0..eb4e111c8 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut
@@ -266,6 +266,8 @@ void function UseBurnCardWeapon( entity weapon, entity player )
PlayerEarnMeter_SetRewardUsed( player )
thread PlayerInventory_PopInventoryItem( player )
+
+ UpdatePlayerStat( player, "misc_stats", "boostsActivated" )
}
void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer )
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 1a70c2896..4eb423fdb 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut
@@ -1,11 +1,33 @@
global function GruntChatter_MP_Init
global function PlayGruntChatterMPLine
+const float CHATTER_FRIENDLY_GRUNT_DOWN_DIST_MAX = 1100.0
+const float CHATTER_SQUAD_DEPLETED_FRIENDLY_NEARBY_DIST = 650.0 // if any other friendly grunt is within this dist, squad deplete chatter won't play
+const float CHATTER_ENEMY_TITAN_DOWN_DIST_MAX = 1500.0
+const float CHATTER_NEARBY_GRUNT_TRACEFRAC_MIN = 0.95 // for when we need "LOS" trace
+
void function GruntChatter_MP_Init()
{
- //ShGruntChatter_MP_Init()
+ Assert( IsMultiplayer(), "MP Grunt chatter is restricted to Multiplayer only." )
+
+ AddCallback_OnPlayerKilled( GruntChatter_OnPlayerOrNPCKilled )
+ AddCallback_OnNPCKilled( GruntChatter_OnPlayerOrNPCKilled )
}
+
+
+
+/*=====================================================================================================================================================
+ _____ _ _____ _ _ _ __ __ _ _ _ _
+ / ____| | | / ____|| | | | | | | \/ | | || | (_) | |
+ | | __ _ __ _ _ _ __ | |_ | | | |__ __ _ | |_ | |_ ___ _ __ | \ / | _ _ | || |_ _ _ __ | | __ _ _ _ ___ _ __
+ | | |_ || '__|| | | || '_ \ | __| | | | '_ \ / _` || __|| __|/ _ \| '__| | |\/| || | | || || __|| || '_ \ | | / _` || | | | / _ \| '__|
+ | |__| || | | |_| || | | || |_ | |____ | | | || (_| || |_ | |_| __/| | | | | || |_| || || |_ | || |_) || || (_| || |_| || __/| |
+ \_____||_| \__,_||_| |_| \__| \_____||_| |_| \__,_| \__| \__|\___||_| |_| |_| \__,_||_| \__||_|| .__/ |_| \__,_| \__, | \___||_|
+ | | __/ |
+ |_| |___/
+/*===================================================================================================================================================*/
+
void function PlayGruntChatterMPLine( entity grunt, string conversationType )
{
#if !GRUNT_CHATTER_MP_ENABLED
@@ -15,4 +37,175 @@ void function PlayGruntChatterMPLine( entity grunt, string conversationType )
foreach ( entity player in GetPlayerArray() )
if ( ShouldPlayGruntChatterMPLine( conversationType, player, grunt ) )
Remote_CallFunction_Replay( player, "ServerCallback_PlayGruntChatterMP", GetConversationIndex( conversationType ), grunt.GetEncodedEHandle() )
+}
+
+void function GruntChatter_OnPlayerOrNPCKilled( entity deadGuy, entity attacker, var damageInfo )
+{
+ if ( !IsValid( deadGuy ) || !IsValid( attacker ) )
+ return
+
+ if( IsGrunt( attacker ) && IsPilot( deadGuy ) )
+ PlayGruntChatterMPLine( attacker, "bc_killenemypilot" )
+ else
+ GruntChatter_TryEnemyTitanDown( deadGuy )
+
+ if ( IsGrunt( deadGuy ) )
+ {
+ GruntChatter_TryFriendlyDown( deadGuy )
+ GruntChatter_TrySquadDepleted( deadGuy )
+ }
+}
+
+void function GruntChatter_TryFriendlyDown( entity deadGuy )
+{
+ entity closestGrunt = GruntChatter_FindClosestFriendlyHumanGrunt_LOS( deadGuy.GetOrigin(), deadGuy.GetTeam(), CHATTER_FRIENDLY_GRUNT_DOWN_DIST_MAX )
+ if ( !closestGrunt )
+ return
+
+ if ( !GruntChatter_CanGruntChatterNow( closestGrunt ) )
+ return
+
+ PlayGruntChatterMPLine( closestGrunt, "bc_allygruntdown" )
+}
+
+void function GruntChatter_TrySquadDepleted( entity deadGuy )
+{
+ string deadGuySquadName = expect string( deadGuy.kv.squadname )
+ if ( deadGuySquadName == "" )
+ return
+
+ array<entity> squad = GetNPCArrayBySquad( deadGuySquadName )
+ entity lastSquadMember
+ if ( squad.len() == 1 )
+ lastSquadMember = squad[0]
+
+ if ( !GruntChatter_CanGruntChatterNow( lastSquadMember ) )
+ return
+
+ if ( lastSquadMember.GetNPCState() == "idle" )
+ return
+
+ // if another grunt from another squad is nearby, don't chatter about being alone
+ array<entity> nearbyGrunts = GetNearbyFriendlyGrunts( lastSquadMember.GetOrigin(), lastSquadMember.GetTeam(), CHATTER_SQUAD_DEPLETED_FRIENDLY_NEARBY_DIST )
+ nearbyGrunts.fastremovebyvalue( lastSquadMember )
+ if ( nearbyGrunts.len() )
+ return
+
+ PlayGruntChatterMPLine( lastSquadMember, "bc_squaddeplete" )
+}
+
+void function GruntChatter_TryEnemyTitanDown( entity deadGuy )
+{
+ if ( deadGuy.IsTitan() )
+ {
+ entity closestGrunt = GruntChatter_FindClosestEnemyHumanGrunt_LOS( deadGuy.GetOrigin(), deadGuy.GetTeam(), CHATTER_ENEMY_TITAN_DOWN_DIST_MAX )
+ if ( !closestGrunt )
+ return
+
+ PlayGruntChatterMPLine( closestGrunt, "bc_enemytitandown" )
+ }
+}
+
+entity function GruntChatter_FindClosestEnemyHumanGrunt_LOS( vector searchOrigin, int enemyTeam, float searchDist )
+{
+ array<entity> humanGrunts = GetNearbyEnemyHumanGrunts( searchOrigin, enemyTeam, searchDist )
+ return GruntChatter_GetClosestGrunt_LOS( humanGrunts, searchOrigin )
+}
+
+entity function GruntChatter_FindClosestFriendlyHumanGrunt_LOS( vector searchOrigin, int friendlyTeam, float searchDist )
+{
+ array<entity> humanGrunts = GetNearbyFriendlyHumanGrunts( searchOrigin, friendlyTeam, searchDist )
+ return GruntChatter_GetClosestGrunt_LOS( humanGrunts, searchOrigin )
+}
+
+entity function GruntChatter_GetClosestGrunt_LOS( array<entity> nearbyGrunts, vector searchOrigin )
+{
+ entity closestGrunt = null
+ float closestDist = 10000
+
+ foreach ( grunt in nearbyGrunts )
+ {
+ vector gruntOrigin = grunt.GetOrigin()
+
+ // CanSee doesn't return true if the target is dead
+ if ( !GruntChatter_CanGruntTraceToLocation( grunt, searchOrigin ) )
+ continue
+
+ if ( !closestGrunt )
+ {
+ closestGrunt = grunt
+ continue
+ }
+
+ float distFromSearchOrigin = Distance( grunt.GetOrigin(), searchOrigin )
+
+ if ( closestDist > distFromSearchOrigin )
+ continue
+
+ closestGrunt = grunt
+ closestDist = distFromSearchOrigin
+ }
+
+ return closestGrunt
+}
+
+bool function GruntChatter_CanGruntTraceToLocation( entity grunt, vector traceEnd )
+{
+ float traceFrac = TraceLineSimple( grunt.GetOrigin(), traceEnd, grunt )
+ return traceFrac > CHATTER_NEARBY_GRUNT_TRACEFRAC_MIN
+}
+
+array<entity> function GetNearbyFriendlyHumanGrunts( vector searchOrigin, int friendlyTeam, float ornull searchRange = null )
+{
+ array<entity> nearbyGrunts = GetNearbyFriendlyGrunts( searchOrigin, friendlyTeam, searchRange )
+ array<entity> humanGrunts = []
+ foreach ( grunt in nearbyGrunts )
+ {
+ if ( grunt.IsMechanical() )
+ continue
+
+ humanGrunts.append( grunt )
+ }
+
+ return humanGrunts
+}
+
+array<entity> function GetNearbyEnemyHumanGrunts( vector searchOrigin, int enemyTeam, float ornull searchRange = null )
+{
+ array<entity> nearbyGrunts = GetNearbyEnemyGrunts( searchOrigin, enemyTeam, searchRange )
+ array<entity> humanGrunts = []
+ foreach ( grunt in nearbyGrunts )
+ {
+ if ( grunt.IsMechanical() )
+ continue
+
+ humanGrunts.append( grunt )
+ }
+
+ return humanGrunts
+}
+
+bool function GruntChatter_CanGruntChatterNow( entity grunt )
+{
+ if ( !IsAlive( grunt ) )
+ return false
+
+ if ( !GruntChatter_IsGruntTypeEligibleForChatter( grunt ) )
+ return false
+
+ if ( grunt.ContextAction_IsMeleeExecution() )
+ return false
+
+ string squadname = expect string( grunt.kv.squadname )
+ // we only care about this because the grunt conversation system wants it
+ return squadname != ""
+}
+
+bool function GruntChatter_IsGruntTypeEligibleForChatter( entity grunt )
+{
+ if ( !IsGrunt( grunt ) )
+ return false
+
+ // mechanical grunts don't chatter
+ return !grunt.IsMechanical()
} \ 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 f23c841db..af074689c 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
@@ -422,6 +422,40 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
foreach ( entity otherPlayer in GetPlayerArray() )
Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_EvacObit", player.GetEncodedEHandle() )
}
+
+ // award player score to evacing team
+ int evacCount = 0
+ array<entity> evacingPlayers = GetPlayerArrayOfTeam( dropship.GetTeam() ) // all players that are supposed to evac in the dropship
+
+ // count how many players are in the dropship
+ foreach ( entity player in evacingPlayers )
+ {
+ if ( !PlayerInDropship( player, dropship ) )
+ continue
+
+ evacCount++
+ }
+
+ bool allEvac = evacCount == evacingPlayers.len()
+
+ foreach(entity player in evacingPlayers)
+ {
+ if ( !PlayerInDropship( player, dropship ) )
+ continue
+
+ AddPlayerScore( player, "HotZoneExtract" )
+ UpdatePlayerStat( player, "misc_stats", "evacsSurvived" )
+
+ if ( allEvac )
+ AddPlayerScore( player, "TeamBonusFullEvac" )
+ }
+
+ // sole survivor (but not the only one on the team)
+ if ( evacCount == 1 && !allEvac )
+ {
+ // we can assume there is one player in the array because otherwise evacCount wouldn't be 1
+ AddPlayerScore( evacingPlayers[0], "SoleSurvivor" )
+ }
}
void function AddPlayerToEvacDropship( entity dropship, entity player )
@@ -442,6 +476,8 @@ void function AddPlayerToEvacDropship( entity dropship, entity player )
if ( !PlayerInDropship( player, dropship ) )
return
+ UpdatePlayerStat( player, "misc_stats", "evacsAttempted" )
+
// need to cancel if the dropship dies
dropship.EndSignal( "OnDeath", "OnDestroy" )
@@ -507,6 +543,15 @@ void function CheckIfAnyPlayerLeft( int evacTeam )
SetTeamActiveObjective( evacTeam, "EG_DropshipExtractEvacPlayersKilled" )
SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractEvacPlayersKilled" )
thread EvacEpilogueCompleted( null )
+
+ // score for killing the entire evacing team
+ foreach ( entity player in GetPlayerArray() )
+ {
+ if ( player.GetTeam() == evacTeam )
+ continue
+
+ AddPlayerScore( player, "TeamBonusKilledAll")
+ }
}
)
while( true )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut
index 5fd7d1014..6555c875b 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut
@@ -3,8 +3,11 @@ global function AddFactionXP
void function AddFactionXP( entity player, int amount )
{
string faction = GetFactionChoice( player )
+ int oldLevel = FactionGetLevel( player, faction )
// increment xp
player.SetPersistentVar( "factionXP[" + faction + "]", min( FactionGetXP( player, faction ) + amount, FactionGetMaxXP( faction ) ) )
// note: no notif for faction level up
+ if ( FactionGetLevel( player, faction ) != oldLevel )
+ AddPlayerScore( player, "FactionLevelUp" )
} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut
index c61cb585a..93a3aa168 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut
@@ -107,7 +107,6 @@ void function GamemodeAt_Init()
// Set-up score callbacks
ScoreEvent_SetupEarnMeterValuesForMixedModes()
- AddDamageFinalCallback( "npc_titan", OnNPCTitanFinalDamaged )
AddCallback_OnPlayerKilled( AT_PlayerOrNPCKilledScoreEvent )
AddCallback_OnNPCKilled( AT_PlayerOrNPCKilledScoreEvent )
@@ -1658,9 +1657,10 @@ void function AT_HandleBossTitanSpawn( entity titan, AT_WaveOrigin campData, int
titan.Minimap_AlwaysShow( TEAM_MILITIA, null )
thread BountyBossHighlightThink( titan )
- // set up titan-specific death callbacks, mark it as bounty boss for finalDamageCallbacks to work
+ // set up titan-specific death callbacks, mark it as bounty boss
file.titanIsBountyBoss[ titan ] <- true
file.bountyTitanRewards[ titan ] <- ATTRITION_SCORE_BOSS_DAMAGE
+ AddEntityCallback_OnPostDamaged( titan, OnBountyTitanPostDamage )
AddEntityCallback_OnKilled( titan, OnBountyTitanKilled )
titan.GetTitanSoul().soul.skipDoomState = true
@@ -1684,13 +1684,7 @@ void function BountyBossHighlightThink( entity titan )
}
}
-void function OnNPCTitanFinalDamaged( entity titan, var damageInfo )
-{
- if ( titan in file.titanIsBountyBoss )
- OnBountyTitanDamaged( titan, damageInfo )
-}
-
-void function OnBountyTitanDamaged( entity titan, var damageInfo )
+void function OnBountyTitanPostDamage( entity titan, var damageInfo )
{
entity attacker = DamageInfo_GetAttacker( damageInfo )
if ( !IsValid( attacker ) ) // delayed by projectile shots
@@ -1703,14 +1697,6 @@ void function OnBountyTitanDamaged( entity titan, var damageInfo )
return
}
- // respawn FUCKED UP pilot weapon against titan's damage calculation, have to copy-paste this check from Titan_NPCTookDamage()
- if ( HeavyArmorCriticalHitRequired( damageInfo ) &&
- CritWeaponInDamageInfo( damageInfo ) &&
- !IsCriticalHit( attacker, titan, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageType( damageInfo ) ) &&
- IsValid( attacker ) &&
- !attacker.IsTitan() )
- return
-
int rewardSegment = ATTRITION_SCORE_BOSS_DAMAGE
int healthSegment = titan.GetMaxHealth() / rewardSegment
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 6f228f7cb..60bad8d1f 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
@@ -20,6 +20,7 @@ void function Sv_ItemInventory_Init()
{
AddCallback_OnClientConnected( Sv_ItemInventory_OnClientConnected )
AddCallback_OnPlayerGetsNewPilotLoadout( Sv_ItemInventory_OnPlayerGetsNewPilotLoadout )
+ AddCallback_GameStateEnter( eGameState.Prematch, PrematchClearInventory )
}
void function Sv_ItemInventory_OnClientConnected( entity player )
@@ -27,6 +28,14 @@ void function Sv_ItemInventory_OnClientConnected( entity player )
file.playerInventoryStacks[ player ] <- []
}
+void function PrematchClearInventory() // vanilla behavior
+{
+ foreach( entity player in GetPlayerArray() )
+ {
+ PlayerInventory_TakeAllInventoryItems( player )
+ }
+}
+
void function Sv_ItemInventory_OnPlayerGetsNewPilotLoadout( entity player, PilotLoadoutDef newPilotLoadout )
{
array<InventoryItem> playerInventoryStack = file.playerInventoryStacks[ player ]
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut
index ae933b713..8b65ec935 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut
@@ -14,6 +14,7 @@ void function Lobby_Init()
{
// non-private lobby clientcommands
AddClientCommandCallback( "StartPrivateMatchSearch", ClientCommandCallback_StartPrivateMatchSearch )
+ AddClientCommandCallback( "SetAnnouncementVersionSeen", ClientCommandCallback_SetAnnouncementVersionSeen )
}
}
@@ -37,3 +38,14 @@ bool function ClientCommandCallback_StartPrivateMatchSearch( entity player, arra
return true
}
+
+bool function ClientCommandCallback_SetAnnouncementVersionSeen( entity player, array<string> args )
+{
+ if ( args.len() < 1 )
+ return false
+
+ int version = int( args[0] )
+
+ player.SetPersistentVar( "announcementVersionSeen", version )
+ return true
+}
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 ccccefaff..d2be2ab41 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
@@ -17,6 +17,7 @@ void function PrivateMatchModesInit()
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" )
AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_multiplier", "1.0" )
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "player_force_respawn", "5" )
AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_TITAN", "earn_meter_titan_multiplier", "1.0" )
AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_TITAN", "aegis_upgrades", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" )
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 ec4267545..bab7eaede 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
@@ -134,6 +134,15 @@ void function CodeCallback_OnClientConnectionCompleted( entity player )
Lobby_OnClientConnectionCompleted( player )
return
}
+ else if ( !IsFDMode( GAMETYPE ) )
+ {
+ // reset this for non-fd modes
+ // for some reason the postgame scoreboard uses this to
+ // determine if it should show the FD aegis rank one
+ // FD should either set this in their own mode, or add an else
+ // to this if statement when it releases
+ player.SetPersistentVar( "lastFDTitanRef", "" )
+ }
player.hasConnected = true
@@ -274,6 +283,9 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga
ClearRespawnAvailable( player )
+ // reset this so that we default to pilot spawn
+ player.SetPersistentVar( "spawnAsTitan", false )
+
OnThreadEnd( function() : ( player )
{
if ( !IsValid( player ) )
@@ -379,6 +391,13 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga
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 )
+ thread ForceRespawnMeSignalAfterDelay( player, forceRespawn )
player.WaitSignal( "RespawnMe" ) // set in base_gametype: ClientCommand_RespawnPlayer
@@ -398,6 +417,21 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga
}
}
+// idk if this is a good delay or if it matches vanilla
+void function ForceRespawnMeSignalAfterDelay( entity player, int delay = 5 )
+{
+ player.EndSignal( "RespawnMe" )
+ player.EndSignal( "OnDestroy" )
+
+ 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" )
+}
+
void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker )
{
player.EndSignal( "RespawnMe" )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut
index 16a3ce922..0ababfc71 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut
@@ -58,7 +58,9 @@ void function CodeCallback_MatchIsOver()
#if MP
void function PopulatePostgameData()
{
- // something's busted here because this isn't showing automatically on match end, ag
+ // show the postgame scoreboard summary
+ SetUIVar( level, "showGameSummary", true )
+
foreach ( entity player in GetPlayerArray() )
{
int teams = GetCurrentPlaylistVarInt( "max_teams", 2 )
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 0555df9b8..23ae37a17 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
@@ -188,7 +188,8 @@ void function SpawnPlayerIntoDropship( entity player )
}
// respawn player and holster their weapons so they aren't out
- player.RespawnPlayer( null )
+ if ( !IsAlive( player ) )
+ player.RespawnPlayer( null )
HolsterAndDisableWeapons(player)
player.DisableWeaponViewModel()
@@ -255,4 +256,4 @@ void function PlayerJumpsFromDropship( entity player )
WaitFrame()
TryGameModeAnnouncement( player )
-} \ No newline at end of file
+}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
index 46b39ebc1..3426cec52 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
@@ -800,6 +800,8 @@ void function SetWinner( int team, string winningReason = "", string losingReaso
}
else
SetGameState( eGameState.WinnerDetermined )
+
+ ScoreEvent_MatchComplete( team )
}
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
index dacd43b0f..0b55e9ffd 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
@@ -7,6 +7,7 @@ global function ScoreEvent_PlayerKilled
global function ScoreEvent_TitanDoomed
global function ScoreEvent_TitanKilled
global function ScoreEvent_NPCKilled
+global function ScoreEvent_MatchComplete
global function ScoreEvent_SetEarnMeterValues
global function ScoreEvent_SetupEarnMeterValuesForMixedModes
@@ -230,7 +231,15 @@ void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageIn
catch ( ex ) {}
}
-
+void function ScoreEvent_MatchComplete( int winningTeam )
+{
+ foreach( entity player in GetPlayerArray() )
+ {
+ AddPlayerScore( player, "MatchComplete" )
+ if ( player.GetTeam() == winningTeam )
+ AddPlayerScore( player, "MatchVictory" )
+ }
+}
void function ScoreEvent_SetEarnMeterValues( string eventName, float earned, float owned, float coreScale = 1.0 )
{
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
index 0e8b58f45..208e6da12 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
@@ -1,3 +1,5 @@
+untyped // because entity.s
+
global function Stats_Init
global function AddStatCallback
global function Stats_SaveStatDelayed
@@ -12,67 +14,1084 @@ global function PreScoreEventUpdateStats
global function PostScoreEventUpdateStats
global function Stats_OnPlayerDidDamage
+struct {
+ table< string, array<string> > refs
+ table< string, array< void functionref( entity, float, string ) > > callbacks
+
+ table< entity, table< string, int > > cachedIntStatChanges
+ table< table< string, float > > cachedFloatStatChanges
+
+ table< entity, float > playerKills
+ table< entity, float > playerKillsPvp
+ table< entity, float > playerDeaths
+ table< entity, float > playerDeathsPvp
+
+ bool isFirstStrike = true
+} file
+
void function Stats_Init()
{
+ AddCallback_OnPlayerKilled( OnPlayerOrNPCKilled )
+ AddCallback_OnNPCKilled( OnPlayerOrNPCKilled )
+ AddCallback_OnPlayerRespawned( OnPlayerRespawned )
+ AddCallback_OnClientConnected( OnClientConnected )
+ AddCallback_OnClientDisconnected( OnClientDisconnected )
+ AddCallback_GameStateEnter( eGameState.WinnerDetermined, OnWinnerDetermined )
+ thread HandleDistanceAndTimeStats_Threaded()
+ thread SaveStatsPeriodically_Threaded()
}
-void function AddStatCallback(string statCategory, string statAlias, string statSubAlias, void functionref(entity, float, string) callback, string subRef)
+void function AddStatCallback( string statCategory, string statAlias, string statSubAlias, void functionref( entity, float, string ) callback, string subRef )
{
+ if ( !IsValidStat( statCategory, statAlias, statSubAlias ) )
+ throw format( "INVALID STAT: %s : %s : %s", statCategory, statAlias, statSubAlias )
+
+
+ string statVar = GetStatVar( statCategory, statAlias, statSubAlias )
+ if ( statVar in file.refs )
+ {
+ file.refs[ statVar ].append( subRef )
+ file.callbacks[ statVar ].append( callback )
+ }
+ else
+ {
+ file.refs[ statVar ] <- [ subRef ]
+ file.callbacks[ statVar ] <- [ callback ]
+ }
}
-void function Stats_SaveStatDelayed(entity player, string statCategory, string statAlias, string statSubAlias)
+// a lot of this file seems to be doing caching of stats in some way
+void function Stats_SaveStatDelayed( entity player, string statCategory, string statAlias, string statSubAlias, float delay = 0.1 )
{
+ // idk how long the delay is meant to be but whatever
+ wait delay
+
+ if ( !IsValid( player ) )
+ return
+
+ Stats_SaveStat( player, statCategory, statAlias, statSubAlias )
+}
+
+void function Stats_SaveAllStats( entity player )
+{
+ if ( player in file.cachedIntStatChanges )
+ {
+ foreach( string key, int val in file.cachedIntStatChanges[ player ] )
+ {
+ player.SetPersistentVar( key, player.GetPersistentVarAsInt( key ) + val )
+ }
+
+ delete file.cachedIntStatChanges[ player ]
+ }
+ // save cached float stat change
+ if ( player in file.cachedFloatStatChanges )
+ {
+ foreach( string key, float val in file.cachedFloatStatChanges[ player ] )
+ {
+ player.SetPersistentVar( key, expect float( player.GetPersistentVar( key ) ) + val )
+ }
+ delete file.cachedFloatStatChanges[ player ]
+ }
}
-int function PlayerStat_GetCurrentInt(entity player, string statCategory, string statAlias, string statSubAlias)
+void function Stats_SaveStat( entity player, string statCategory, string statAlias, string statSubAlias )
{
+ string stat = GetStatVar( statCategory, statAlias, statSubAlias )
+ // save cached int stat change
+ if ( player in file.cachedIntStatChanges && stat in file.cachedIntStatChanges[ player ] )
+ {
+ player.SetPersistentVar( stat, player.GetPersistentVarAsInt( stat ) + file.cachedIntStatChanges[ player ][ stat ] )
+ delete file.cachedIntStatChanges[ player ][ stat ]
+ return
+ }
+ // save cached float stat change
+ if ( player in file.cachedFloatStatChanges && stat in file.cachedFloatStatChanges[ player ] )
+ {
+ player.SetPersistentVar( stat, expect float( player.GetPersistentVar( stat ) ) + file.cachedFloatStatChanges[ player ][ stat ] )
+ delete file.cachedFloatStatChanges[ player ][ stat ]
+ return
+ }
+}
+
+// this gets the cached change, not the actual value
+int function PlayerStat_GetCurrentInt( entity player, string statCategory, string statAlias, string statSubAlias )
+{
+ string str = GetStatVar( statCategory, statAlias, statSubAlias )
+
+ if ( player in file.cachedIntStatChanges && str in file.cachedIntStatChanges[ player ] )
+ return file.cachedIntStatChanges[ player ][ str ]
return 0
}
-float function PlayerStat_GetCurrentFloat(entity player, string statCategory, string statAlias, string statSubAlias)
+// this gets the cached change, not the actual value
+float function PlayerStat_GetCurrentFloat( entity player, string statCategory, string statAlias, string statSubAlias )
{
+ string str = GetStatVar( statCategory, statAlias, statSubAlias )
+
+ if ( player in file.cachedFloatStatChanges && str in file.cachedFloatStatChanges[ player ] )
+ return file.cachedFloatStatChanges[ player ][ str ]
return 0
}
-void function UpdatePlayerStat(entity player, string statCategory, string subStat, int count = 0)
+void function UpdatePlayerStat( entity player, string statCategory, string subStat, int count = 1, string statAlias = "" )
{
+ if ( !IsValid( player ) )
+ return
+
+ Stats_IncrementStat( player, statCategory, subStat, statAlias, count.tofloat() )
+}
+
+void function IncrementPlayerDidPilotExecutionWhileCloaked( entity player )
+{
+ UpdatePlayerStat( player, "kills_stats", "pilotExecutePilotWhileCloaked" )
+}
+
+void function UpdateTitanDamageStat( entity attacker, float savedDamage, var damageInfo )
+{
+ if ( !IsValid( attacker ) )
+ return
+
+ Stats_IncrementStat( attacker, "titan_stats", "titanDamage", GetTitanCharacterName( attacker ), savedDamage )
+}
+
+void function UpdateTitanWeaponDamageStat( entity attacker, float savedDamage, var damageInfo )
+{
+ if ( !IsValid( attacker ) )
+ return
+
+ string weaponName = GetPersistenceRefFromDamageInfo( damageInfo )
+ if ( weaponName == "" )
+ return
+
+ Stats_IncrementStat( attacker, "weapon_stats", "titanDamage", weaponName, savedDamage )
+}
+
+void function UpdateTitanCoreEarnedStat( entity player, entity titan, int count = 1 )
+{
+ if ( !IsValid( player ) )
+ return
+
+ if ( !IsValid( titan ) )
+ return
+
+ Stats_IncrementStat( player, "titan_stats", "coresEarned", GetTitanCharacterName( titan ), count.tofloat() )
+}
+
+void function PreScoreEventUpdateStats( entity attacker, entity ent )
+{
+ // used to track kill streaks ending i think ( that stuff gets reset during score event update )
+}
+
+void function PostScoreEventUpdateStats( entity attacker, entity ent )
+{
+ if ( !attacker.IsPlayer() )
+ return
+ // used to track kill streaks starting maybe
+ if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT )
+ {
+ // killingSpressAs_<chassis>
+ if ( attacker.IsTitan() )
+ Stats_IncrementStat( attacker, "kills_stats", "killingSpressAs_" + GetTitanCharacterName( attacker ), "", 1.0 )
+
+ entity weapon = attacker.GetActiveWeapon()
+ // I guess if you dont have a valid active weapon when you get awarded a killing spree
+ // you dont get the stat. Too bad!
+ if ( !IsValid( weapon ) )
+ return
+ Stats_IncrementStat( attacker, "weapon_kill_stats", "killingSprees", weapon.GetWeaponClassName(), 1.0 )
+ }
+}
+
+void function Stats_OnPlayerDidDamage( entity victim, var damageInfo )
+{
+ // try and get the player
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
+ // get the player from their titan
+ if ( attacker.IsTitan() && IsPetTitan( attacker ) )
+ attacker = attacker.GetTitanSoul().GetBossPlayer()
+
+ if ( !attacker.IsPlayer() )
+ return
+
+ string weaponName = GetPersistenceRefFromDamageInfo( damageInfo )
+ if ( weaponName == "" )
+ return
+
+ Stats_IncrementStat( attacker, "weapon_stats", "shotsHit", weaponName, 1.0 )
+
+ if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_CRITICAL )
+ Stats_IncrementStat( attacker, "weapon_stats", "critHits", weaponName, 1.0 )
+ if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT )
+ Stats_IncrementStat( attacker, "weapon_stats", "headshots", weaponName, 1.0 )
+}
+
+void function Stats_IncrementStat( entity player, string statCategory, string statAlias, string statSubAlias, float amount )
+{
+ if ( !IsValidStat( statCategory, statAlias, statSubAlias ) )
+ {
+ printt( "invalid stat: " + statCategory + " : " + statAlias + " : " + statSubAlias )
+ return
+ }
+
+ string str = GetStatVar( statCategory, statAlias, statSubAlias )
+ int type = GetStatVarType( statCategory, statAlias, statSubAlias )
+
+ // stupid exception because respawn set this up as an int in script
+ // but it is actually a float, so the game will crash if we don't fix it somewhere
+ // i dont feel like committing all of sh_stats.gnut so im doing this instead
+ if ( str == "mapStats[%mapname%].hoursPlayed[%gamemode%]" )
+ type = ePlayerStatType.FLOAT
+
+ // this is rather hacky
+ string mode = GAMETYPE
+ int difficulty = GetDifficultyLevel()
+ if ( difficulty >= 5 )
+ return
+
+ string saveVar = Stats_GetFixedSaveVar( str, GetMapName(), mode, difficulty.tostring() )
+ // check if the map and mode exist in persistence
+ try
+ {
+ PersistenceGetEnumIndexForItemName( "gamemodes", mode )
+ PersistenceGetEnumIndexForItemName( "maps", GetMapName() )
+ }
+ catch( ex )
+ {
+ // if we have an invalid mode or map for persistence, and it is used in the
+ // persistence string, we can't save the persistence so we have to just return
+ if ( str != saveVar )
+ {
+ printt( ex )
+ return
+ }
+ }
+ str = saveVar
+
+ switch ( type )
+ {
+ case ePlayerStatType.INT:
+ // populate table if needed
+ if ( !( player in file.cachedIntStatChanges ) )
+ file.cachedIntStatChanges[ player ] <- {}
+ if ( !( str in file.cachedIntStatChanges[ player ] ) )
+ file.cachedIntStatChanges[ player ][ str ] <- 0
+
+ file.cachedIntStatChanges[ player ][ str ] += amount.tointeger()
+ break
+ case ePlayerStatType.FLOAT:
+ // populate table if needed
+ if ( !( player in file.cachedFloatStatChanges ) )
+ file.cachedFloatStatChanges[ player ] <- {}
+ if ( !( str in file.cachedFloatStatChanges[ player ] ) )
+ file.cachedFloatStatChanges[ player ][ str ] <- 0.0
+
+ file.cachedFloatStatChanges[ player ][ str ] += amount
+ break
+ default:
+ throw "UNIMPLEMENTED STAT TYPE: " + type
+ }
+
+ // amount here is never used
+ Stats_RunCallbacks( str, player, amount )
+}
+
+void function Stats_RunCallbacks( string statVar, entity player, float change )
+{
+ if ( !( statVar in file.refs ) )
+ return
+
+ for( int i = 0; i < file.refs[ statVar ].len(); i++ )
+ {
+ string ref = file.refs[ statVar ][ i ]
+ void functionref( entity, float, string ) callback = file.callbacks[ statVar ][ i ]
+
+ callback( player, change, ref )
+ }
+}
+
+void function OnClientConnected( entity player )
+{
+ Stats_IncrementStat( player, "game_stats", "game_joined", "", 1.0 )
+}
+
+void function OnClientDisconnected( entity player )
+{
+ Stats_SaveAllStats( player )
+ // maybe we can save this stuff, but idk if we can access persistence in this callback
+ if ( player in file.cachedIntStatChanges )
+ delete file.cachedIntStatChanges[ player ]
+
+ if ( player in file.cachedFloatStatChanges )
+ delete file.cachedFloatStatChanges[ player ]
+}
+
+void function OnPlayerOrNPCKilled( entity victim, entity attacker, var damageInfo )
+{
+ if ( victim.IsPlayer() )
+ thread SetLastPosForDistanceStatValid_Threaded( victim, false )
+
+ HandleDeathStats( victim, attacker, damageInfo )
+ HandleKillStats( victim, attacker, damageInfo )
+ HandleWeaponKillStats( victim, attacker, damageInfo )
+ HandleTitanStats( victim, attacker, damageInfo )
+}
+
+void function HandleDeathStats( entity player, entity attacker, var damageInfo )
+{
+ if ( !IsValid( player ) || !player.IsPlayer() )
+ return
+
+ if ( player in file.playerDeaths )
+ file.playerDeaths[ player ]++
+ else
+ file.playerDeaths[ player ] <- 1.0
+ // total
+ Stats_IncrementStat( player, "deaths_stats", "total", "", 1.0 )
+
+ // these all rely on the attacker being valid
+ if ( IsValid( attacker ) )
+ {
+ // totalPVP
+ // note: I'm not sure if owned entities count towards totalPVP
+ // such as auto-titans, turrets, etc.
+ if ( attacker.IsPlayer() || attacker.GetBossPlayer() )
+ {
+ if ( player in file.playerDeathsPvp )
+ file.playerDeathsPvp[ player ]++
+ else
+ file.playerDeathsPvp[ player ] <- 1.0
+ Stats_IncrementStat( player, "deaths_stats", "totalPVP", "", 1.0 )
+ }
+
+ // byPilots
+ if ( IsPilot( attacker ) )
+ Stats_IncrementStat( player, "deaths_stats", "byPilots", "", 1.0 )
+
+ // byTitan_<chassis>
+ if ( attacker.IsTitan() && attacker.IsPlayer() )
+ Stats_IncrementStat( player, "deaths_stats", "byTitan_" + GetTitanCharacterName( attacker ), "", 1.0 )
+
+ // bySpectres
+ if ( IsSpectre( attacker ) )
+ Stats_IncrementStat( player, "deaths_stats", "bySpectres", "", 1.0 )
+
+ // byGrunts
+ if ( IsGrunt( attacker ) )
+ Stats_IncrementStat( player, "deaths_stats", "byGrunts", "", 1.0 )
+
+ // byNPCTitans_<chassis>
+ if ( attacker.IsTitan() && attacker.IsNPC() )
+ Stats_IncrementStat( player, "deaths_stats", "byNPCTitans_" + GetTitanCharacterName( attacker ), "", 1.0 )
+ }
+
+ // asPilot
+ if ( IsPilot( player ) )
+ Stats_IncrementStat( player, "deaths_stats", "asPilot", "", 1.0 )
+
+ // asTitan_<chassis>
+ if ( player.IsTitan() )
+ Stats_IncrementStat( player, "deaths_stats", "asTitan_" + GetTitanCharacterName( player ), "", 1.0 )
+
+ // suicides
+ if ( IsSuicide( attacker, player, DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) )
+ Stats_IncrementStat( player, "deaths_stats", "suicides", "", 1.0 )
+
+ // whileEjecting
+ if ( player.p.pilotEjecting )
+ Stats_IncrementStat( player, "deaths_stats", "whileEjecting", "", 1.0 )
+}
+
+void function HandleWeaponKillStats( entity victim, entity attacker, var damageInfo )
+{
+ if ( !IsValid( attacker ) )
+ return
+
+ // get the player and it's pet titan
+ entity player
+ entity playerPetTitan
+ if ( attacker.IsPlayer() )
+ {
+ // the player is just the attacker
+ player = attacker
+ playerPetTitan = player.GetPetTitan()
+ }
+ else if ( attacker.IsTitan() && IsPetTitan( attacker ) )
+ {
+ // the attacker is the player's auto titan
+ player = attacker.GetTitanSoul().GetBossPlayer()
+ playerPetTitan = attacker
+ }
+ else
+ {
+ // attacker could be something like an NPC, or worldspawn
+ return
+ }
+
+ string damageSourceStr = GetPersistenceRefFromDamageInfo( damageInfo )
+ // cant do weapon stats for no weapon
+ if ( damageSourceStr == "" )
+ return
+
+ // check things once, for performance
+ int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo )
+ bool victimIsPlayer = victim.IsPlayer()
+ bool victimIsNPC = victim.IsNPC()
+ bool victimIsPilot = IsPilot( victim )
+ bool victimIsTitan = victim.IsTitan()
+
+ // total
+ Stats_IncrementStat( player, "weapon_kill_stats", "total", damageSourceStr, 1.0 )
+
+ // pilots
+ if ( victimIsPilot )
+ Stats_IncrementStat( player, "weapon_kill_stats", "pilots", damageSourceStr, 1.0 )
+
+ // ejecting_pilots
+ if ( victimIsPilot && victim.p.pilotEjecting )
+ Stats_IncrementStat( player, "weapon_kill_stats", "ejecting_pilots", damageSourceStr, 1.0 )
+
+ // titansTotal
+ if ( victimIsTitan )
+ Stats_IncrementStat( player, "weapon_kill_stats", "titansTotal", damageSourceStr, 1.0 )
+ // spectres
+ if ( IsSpectre( victim ) )
+ Stats_IncrementStat( player, "weapon_kill_stats", "spectres", damageSourceStr, 1.0 )
+
+ // marvins
+ if ( IsMarvin( victim ) )
+ Stats_IncrementStat( player, "weapon_kill_stats", "marvins", damageSourceStr, 1.0 )
+
+ // grunts
+ if ( IsGrunt( victim ) )
+ Stats_IncrementStat( player, "weapon_kill_stats", "grunts", damageSourceStr, 1.0 )
+
+ // ai
+ if ( victimIsNPC )
+ Stats_IncrementStat( player, "weapon_kill_stats", "ai", damageSourceStr, 1.0 )
+
+ // titans_<chassis>
+ if ( victimIsPlayer && victimIsTitan )
+ Stats_IncrementStat( player, "weapon_kill_stats", "titans_" + GetTitanCharacterName( victim ), damageSourceStr, 1.0 )
+
+ // npcTitans_<chassis>
+ if ( victimIsNPC && victimIsTitan )
+ Stats_IncrementStat( player, "weapon_kill_stats", "npcTitans_" + GetTitanCharacterName( victim ), damageSourceStr, 1.0 )
}
-void function IncrementPlayerDidPilotExecutionWhileCloaked(entity player)
+void function HandleKillStats( entity victim, entity attacker, var damageInfo )
{
+ if ( !IsValid( attacker ) )
+ return
+ // get the player and it's pet titan
+ entity player
+ entity playerPetTitan
+ if ( attacker.IsPlayer() )
+ {
+ // the player is just the attacker
+ player = attacker
+ playerPetTitan = player.GetPetTitan()
+ }
+ else if ( attacker.IsTitan() && IsPetTitan( attacker ) )
+ {
+ // the attacker is the player's auto titan
+ player = attacker.GetTitanSoul().GetBossPlayer()
+ playerPetTitan = attacker
+ }
+ else
+ {
+ // attacker could be something like an NPC, or worldspawn
+ return
+ }
+
+ // check things once, for performance
+ int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo )
+ bool victimIsPlayer = victim.IsPlayer()
+ bool victimIsNPC = victim.IsNPC()
+ bool victimIsPilot = IsPilot( victim )
+ bool victimIsTitan = victim.IsTitan()
+
+ if ( player in file.playerKills )
+ file.playerKills[ player ]++
+ else
+ file.playerKills[ player ] <- 1.0
+ // total
+ Stats_IncrementStat( player, "kills_stats", "total", "", 1.0 )
+
+ // totalPVP
+ if ( victimIsPlayer )
+ {
+ if ( player in file.playerKillsPvp )
+ file.playerKillsPvp[ player ]++
+ else
+ file.playerKillsPvp[ player ] <- 1.0
+ Stats_IncrementStat( player, "kills_stats", "totalPVP", "", 1.0 )
+ }
+
+ // pilots
+ if ( victimIsPilot )
+ Stats_IncrementStat( player, "kills_stats", "pilots", "", 1.0 )
+
+ // spectres
+ if ( IsSpectre( victim ) )
+ Stats_IncrementStat( player, "kills_stats", "spectres", "", 1.0 )
+
+ // marvins
+ if ( IsMarvin( victim ) )
+ Stats_IncrementStat( player, "kills_stats", "marvins", "", 1.0 )
+
+ // grunts
+ if ( IsGrunt( victim ) )
+ Stats_IncrementStat( player, "kills_stats", "grunts", "", 1.0 )
+
+ // totalTitans
+ if ( victimIsTitan )
+ Stats_IncrementStat( player, "kills_stats", "totalTitans", "", 1.0 )
+
+ // totalPilots
+ if ( victimIsPilot )
+ Stats_IncrementStat( player, "kills_stats", "totalPilots", "", 1.0 )
+
+ // totalNPC
+ if ( victimIsNPC )
+ Stats_IncrementStat( player, "kills_stats", "totalNPC", "", 1.0 )
+
+ // totalTitansWhileDoomed
+ if ( victimIsTitan && attacker.IsTitan() && GetDoomedState( attacker ) )
+ Stats_IncrementStat( player, "kills_stats", "totalTitansWhileDoomed", "", 1.0 )
+
+ // asPilot
+ if ( IsPilot( attacker ) )
+ Stats_IncrementStat( player, "kills_stats", "asPilot", "", 1.0 )
+
+ // totalAssists
+ // assistsTotal ( weapon_kill_stats )
+ // note: eww
+ table<int, bool> alreadyAssisted
+ foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory )
+ {
+ if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim )
+ continue
+
+ bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false
+ if( attackerInfo.attacker != attacker && !exists )
+ {
+ alreadyAssisted[ attackerInfo.attacker.GetEncodedEHandle() ] <- true
+ Stats_IncrementStat( attackerInfo.attacker, "kills_stats", "totalAssists", "", 1.0 )
+
+ string source = DamageSourceIDToString( attackerInfo.damageSourceId )
+
+ if ( IsValidStatItemString( source ) )
+ Stats_IncrementStat( attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 )
+ }
+ }
+
+ // asTitan_<chassis>
+ if ( player.IsTitan() )
+ Stats_IncrementStat( player, "kills_stats", "asTitan_" + GetTitanCharacterName( player ), "", 1.0 )
+
+ // firstStrikes
+ if ( file.isFirstStrike && attacker.IsPlayer() && victimIsPlayer )
+ {
+ Stats_IncrementStat( player, "kills_stats", "firstStrikes", "", 1.0 )
+ file.isFirstStrike = false
+ }
+
+ // ejectingPilots
+ if ( victimIsPilot && victim.p.pilotEjecting )
+ Stats_IncrementStat( player, "kills_stats", "ejectingPilots", "", 1.0 )
+
+ // whileEjecting
+ if ( attacker.IsPlayer() && attacker.p.pilotEjecting )
+ Stats_IncrementStat( player, "kills_stats", "whileEjecting", "", 1.0 )
+
+ // cloakedPilots
+ if ( victimIsPilot && IsCloaked( victim ) )
+ Stats_IncrementStat( player, "kills_stats", "cloakedPilots", "", 1.0 )
+
+ // whileCloaked
+ if ( attacker == player && IsCloaked( attacker ) )
+ Stats_IncrementStat( player, "kills_stats", "whileCloaked", "", 1.0 )
+
+ // wallrunningPilots
+ if ( victimIsPilot && victim.IsWallRunning() )
+ Stats_IncrementStat( player, "kills_stats", "wallrunningPilots", "", 1.0 )
+
+ // whileWallrunning
+ if ( attacker == player && attacker.IsWallRunning() )
+ Stats_IncrementStat( player, "kills_stats", "whileWallrunning", "", 1.0 )
+
+ // wallhangingPilots
+ if ( victimIsPilot && victim.IsWallHanging() )
+ Stats_IncrementStat( player, "kills_stats", "wallhangingPilots", "", 1.0 )
+
+ // whileWallhanging
+ if ( attacker == player && attacker.IsWallHanging() )
+ Stats_IncrementStat( player, "kills_stats", "whileWallhanging", "", 1.0 )
+
+ // pilotExecution
+ if ( damageSource == eDamageSourceId.human_execution )
+ Stats_IncrementStat( player, "kills_stats", "pilotExecution", "", 1.0 )
+
+ // pilotExecutePilot
+ if ( victimIsPilot && damageSource == eDamageSourceId.human_execution )
+ Stats_IncrementStat( player, "kills_stats", "pilotExecutePilot", "", 1.0 )
+
+ // pilotKillsWithHoloPilotActive
+ if ( victimIsPilot && GetDecoyActiveCountForPlayer( player ) > 0 )
+ Stats_IncrementStat( player, "kills_stats", "pilotKillsWithHoloPilotActive", "", 1.0 )
+
+ // pilotKillsWithAmpedWallActive
+ if ( victimIsPilot && GetAmpedWallsActiveCountForPlayer( player ) > 0 )
+ Stats_IncrementStat( player, "kills_stats", "pilotKillsWithAmpedWallActive", "", 1.0 )
+
+ // pilotExecutePilotUsing_<execution>
+ if ( victimIsPilot && damageSource == eDamageSourceId.human_execution )
+ Stats_IncrementStat( player, "kills_stats", "pilotExecutePilotUsing_" + player.p.lastExecutionUsed, "", 1.0 )
+
+ // pilotKickMelee
+ if ( damageSource == eDamageSourceId.human_melee )
+ Stats_IncrementStat( player, "kills_stats", "pilotKickMelee", "", 1.0 )
+
+ // pilotKickMeleePilot
+ if ( victimIsPilot && damageSource == eDamageSourceId.human_melee )
+ Stats_IncrementStat( player, "kills_stats", "pilotKickMeleePilot", "", 1.0 )
+
+ // titanMelee
+ if ( DamageIsTitanMelee( damageSource ) )
+ Stats_IncrementStat( player, "kills_stats", "titanMelee", "", 1.0 )
+
+ // titanMeleePilot
+ if ( victimIsPilot && DamageIsTitanMelee( damageSource ) )
+ Stats_IncrementStat( player, "kills_stats", "titanMeleePilot", "", 1.0 )
+
+ // titanStepCrush
+ if ( IsTitanCrushDamage( damageInfo ) )
+ Stats_IncrementStat( player, "kills_stats", "titanStepCrush", "", 1.0 )
+
+ // titanStepCrushPilot
+ if ( victimIsPilot && IsTitanCrushDamage( damageInfo ) )
+ Stats_IncrementStat( player, "kills_stats", "titanStepCrushPilot", "", 1.0 )
+
+ // titanExocution<capitalisedChassis>
+ // note: RESPAWN WHY? EXPLAIN
+ if ( damageSource == eDamageSourceId.titan_execution )
+ {
+ string titanName = GetTitanCharacterName( player )
+ titanName = titanName.slice( 0, 1 ).toupper() + titanName.slice( 1, titanName.len() )
+ Stats_IncrementStat( player, "kills_stats", "titanExocution" + titanName, "", 1.0 )
+ }
+
+ // titanFallKill
+ if ( damageSource == eDamageSourceId.damagedef_titan_fall )
+ Stats_IncrementStat( player, "kills_stats", "titanFallKill", "", 1.0 )
+
+ // petTitanKillsFollowMode
+ if ( attacker == playerPetTitan && player.GetPetTitanMode() == eNPCTitanMode.FOLLOW )
+ Stats_IncrementStat( player, "kills_stats", "petTitanKillsFollowMode", "", 1.0 )
+
+ // petTitanKillsGuardMode
+ if ( attacker == playerPetTitan && player.GetPetTitanMode() == eNPCTitanMode.STAY )
+ Stats_IncrementStat( player, "kills_stats", "petTitanKillsGuardMode", "", 1.0 )
+
+ // rodeo_total
+ if ( damageSource == eDamageSourceId.rodeo_battery_removal )
+ Stats_IncrementStat( player, "kills_stats", "rodeo_total", "", 1.0 )
+
+ // pilot_headshots_total
+ if ( victimIsPilot && DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT )
+ Stats_IncrementStat( player, "kills_stats", "pilot_headshots_total", "", 1.0 )
+
+ // evacShips
+ if ( IsEvacDropship( victim ) )
+ Stats_IncrementStat( player, "kills_stats", "evacShips", "", 1.0 )
+
+ // nuclearCore
+ if ( damageSource == eDamageSourceId.damagedef_nuclear_core )
+ Stats_IncrementStat( player, "kills_stats", "nuclearCore", "", 1.0 )
+
+ // meleeWhileCloaked
+ if ( IsCloaked( attacker ) && damageSource == eDamageSourceId.human_melee )
+ Stats_IncrementStat( player, "kills_stats", "meleeWhileCloaked", "", 1.0 )
+
+ // titanKillsAsPilot
+ if ( victimIsTitan && IsPilot( attacker ) )
+ Stats_IncrementStat( player, "kills_stats", "titanKillsAsPilot", "", 1.0 )
+
+ // pilotKillsWhileStimActive
+ if ( victimIsPilot && StatusEffect_Get( attacker, eStatusEffect.stim_visual_effect ) <= 0 )
+ Stats_IncrementStat( player, "kills_stats", "pilotKillsWhileStimActive", "", 1.0 )
+
+ // pilotKillsAsTitan
+ if ( victimIsPilot && attacker.IsTitan() )
+ Stats_IncrementStat( player, "kills_stats", "pilotKillsAsTitan", "", 1.0 )
+
+ // pilotKillsAsPilot
+ if ( victimIsPilot && IsPilot( attacker ) )
+ Stats_IncrementStat( player, "kills_stats", "pilotKillsAsPilot", "", 1.0 )
+
+ // titanKillsAsTitan
+ if ( victimIsTitan && attacker.IsTitan() )
+ Stats_IncrementStat( player, "kills_stats", "titanKillsAsTitan", "", 1.0 )
}
-void function UpdateTitanDamageStat(entity attacker, float savedDamage, var damageInfo)
+void function HandleTitanStats( entity victim, entity attacker, var damageInfo )
{
+ if ( !IsValid( attacker ) )
+ return
+
+ // get the player and it's pet titan
+ entity player
+ entity playerPetTitan
+ if ( attacker.IsPlayer() )
+ {
+ // the player is just the attacker
+ player = attacker
+ playerPetTitan = player.GetPetTitan()
+ }
+ else if ( attacker.IsTitan() && IsPetTitan( attacker ) )
+ {
+ // the attacker is the player's auto titan
+ player = attacker.GetTitanSoul().GetBossPlayer()
+ playerPetTitan = attacker
+ }
+ else
+ {
+ // attacker could be something like an NPC, or worldspawn
+ return
+ }
+
+ int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo )
+ bool victimIsPlayer = victim.IsPlayer()
+ bool victimIsNPC = victim.IsNPC()
+ bool victimIsPilot = IsPilot( victim )
+ bool victimIsTitan = victim.IsTitan()
+ bool titanIsPrime = IsTitanPrimeTitan( player )
+ // pilots
+ if ( victimIsPilot && attacker.IsTitan() )
+ Stats_IncrementStat( player, "titan_stats", "pilots", GetTitanCharacterName( attacker ), 1.0 )
+
+ // titansTotal
+ if ( victimIsTitan && attacker.IsTitan() )
+ Stats_IncrementStat( player, "titan_stats", "titansTotal", GetTitanCharacterName( attacker ), 1.0 )
+
+ // pilotsAsPrime
+ if ( victimIsPilot && attacker.IsTitan() && titanIsPrime )
+ Stats_IncrementStat( player, "titan_stats", "pilotsAsPrime", GetTitanCharacterName( attacker ), 1.0 )
+
+ // titansAsPrime
+ if ( victimIsTitan && attacker.IsTitan() && titanIsPrime )
+ Stats_IncrementStat( player, "titan_stats", "titansAsPrime", GetTitanCharacterName( attacker ), 1.0 )
+
+ // executionsAsPrime
+ if ( damageSource == eDamageSourceId.titan_execution && attacker.IsTitan() && titanIsPrime )
+ Stats_IncrementStat( player, "titan_stats", "executionsAsPrime", GetTitanCharacterName( attacker ), 1.0 )
}
-void function UpdateTitanWeaponDamageStat(entity attacker, float savedDamage, var damageInfo)
+void function OnPlayerRespawned( entity player )
{
+ thread SetLastPosForDistanceStatValid_Threaded( player, true )
+}
+
+void function OnWinnerDetermined()
+{
+ // award players for match completed, wins, and losses
+ foreach ( entity player in GetPlayerArray() )
+ {
+ Stats_IncrementStat( player, "game_stats", "game_completed", "", 1.0 )
+
+ if ( player.GetTeam() == GetWinningTeam() )
+ Stats_IncrementStat( player, "game_stats", "game_won", "", 1.0 )
+ else
+ Stats_IncrementStat( player, "game_stats", "game_lost", "", 1.0 )
+ }
+
+ if ( IsValidGamemodeString( GAMETYPE ) )
+ {
+ // award players with matches played on the mode
+ foreach ( entity player in GetPlayerArray() )
+ {
+ Stats_IncrementStat( player, "game_stats", "mode_played", GAMETYPE, 1.0 )
+
+ if ( player.GetTeam() == GetWinningTeam() )
+ Stats_IncrementStat( player, "game_stats", "mode_won", GAMETYPE, 1.0 )
+ }
+ }
+
+ // update player's KD
+ foreach ( entity player in GetPlayerArray() )
+ {
+ // kd stats
+ // index 0 is most recent game
+ // index 9 is least recent game
+ float playerKills = ( player in file.playerKills ) ? file.playerKills[ player ] : 0.0
+ float playerDeaths = ( player in file.playerDeaths ) ? file.playerDeaths[ player ] : 0.0
+ float kdratio_match
+ if ( playerDeaths == 0.0 )
+ kdratio_match = playerKills
+ else
+ kdratio_match = playerKills / playerDeaths
+
+ float playerKillsPvp = ( player in file.playerKillsPvp ) ? file.playerKillsPvp[ player ] : 0.0
+ float playerDeathsPvp = ( player in file.playerDeathsPvp ) ? file.playerDeathsPvp[ player ] : 0.0
+ float kdratiopvp_match
+ if ( playerDeathsPvp == 0.0 )
+ kdratiopvp_match = playerKillsPvp
+ else
+ kdratiopvp_match = playerKillsPvp / playerDeathsPvp
+
+ float totalDeaths = player.GetPersistentVarAsInt( "deathStats.total" ).tofloat()
+ float totalKills = player.GetPersistentVarAsInt( "killStats.total" ).tofloat()
+ float totalDeathsPvp = player.GetPersistentVarAsInt( "deathStats.totalPVP" ).tofloat()
+ float totalKillsPvp = player.GetPersistentVarAsInt( "killStats.totalPVP" ).tofloat()
+ float kdratio_lifetime
+ if ( totalDeaths == 0.0 )
+ kdratio_lifetime = totalKills
+ else
+ kdratio_lifetime = totalKills / totalDeaths
+ float kdratio_lifetimepvp
+ if ( totalDeathsPvp == 0.0 )
+ kdratio_lifetimepvp = totalKillsPvp
+ else
+ kdratio_lifetimepvp = totalKillsPvp / totalDeathsPvp
+
+ // shift stats by 1 to make room for new game data
+ for ( int i = NUM_GAMES_TRACK_KDRATIO - 2; i >= 0; --i )
+ {
+ player.SetPersistentVar( format( "kdratio_match[%i]", ( i + 1 ) ), player.GetPersistentVar( format("kdratio_match[%i]", i ) ) )
+ player.SetPersistentVar( format( "kdratiopvp_match[%i]", ( i + 1 ) ), player.GetPersistentVar( format( "kdratiopvp_match[%i]", i ) ) )
+ }
+ // add new game data
+ player.SetPersistentVar( "kdratio_match[0]", kdratio_match )
+ player.SetPersistentVar( "kdratiopvp_match[0]", kdratiopvp_match )
+ player.SetPersistentVar( "kdratio_lifetime", kdratio_lifetime )
+ player.SetPersistentVar( "kdratio_lifetime_pvp", kdratio_lifetimepvp )
+ }
+
+ // award mvp and top 3 in each team
+ if ( !IsFFAGame() )
+ {
+ string gamemode = GameRules_GetGameMode()
+ int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( gamemode )
+
+ for( int team = 0; team < MAX_TEAMS; team++ )
+ {
+ array<entity> players = GetPlayerArrayOfTeam( team )
+ if ( compareFunc == null )
+ {
+ printt( "gamemode doesn't have a compare func to get the top 3" )
+ return
+ }
+ players.sort( compareFunc )
+ int maxAwards = int( min( players.len(), 3 ) )
+ for ( int i = 0; i < maxAwards; i++ )
+ {
+ if ( i == 0 )
+ Stats_IncrementStat( players[ i ], "game_stats", "mvp", "", 1.0 )
+ Stats_IncrementStat( players[ i ], "game_stats", "top3OnTeam", "", 1.0 )
+ }
+ }
+
+ }
+}
+void function SetLastPosForDistanceStatValid_Threaded( entity player, bool val )
+{
+ WaitFrame()
+ if ( !IsValid( player ) )
+ return
+ player.p.lastPosForDistanceStatValid = val
}
-void function UpdateTitanCoreEarnedStat( entity player, entity titan )
+// Respawn did this through stuff found in _entitystructs.gnut (stuff like stats_wallrunTime)
+// but their implementation seems kinda bad. The advantage it has over this method is not polling
+// every 0.25 seconds, and using movement callbacks and stuff instead. However, since i can't find
+// callbacks for things like changing weapon, i would have to poll for that *anyway* and thus,
+// there is no point in doing things Respawn's way here
+void function HandleDistanceAndTimeStats_Threaded()
{
+ // just to be safe
+ if ( IsLobby() )
+ return
+
+ while ( GetGameState() < eGameState.Playing )
+ WaitFrame()
+
+ float lastTickTime = Time()
+
+ while( true )
+ {
+ // track distance stats
+ foreach ( entity player in GetPlayerArray() )
+ {
+ if ( player.p.lastPosForDistanceStatValid )
+ {
+ // not 100% sure on using Distance2D over Distance tbh
+ float distInches = Distance2D( player.p.lastPosForDistanceStat, player.GetOrigin() )
+ float distMiles = distInches / 63360.0
+
+ // more generic distance stats
+ Stats_IncrementStat( player, "distance_stats", "total", "", distMiles )
+ if ( player.IsTitan() )
+ {
+ Stats_IncrementStat( player, "distance_stats", "asTitan_" + GetTitanCharacterName( player ), "", distMiles )
+ Stats_IncrementStat( player, "distance_stats", "asTitan", "", distMiles )
+ }
+ else
+ Stats_IncrementStat( player, "distance_stats", "asPilot", "", distMiles )
+
+
+ string state = ""
+ // specific distance stats
+ if ( player.IsWallRunning() )
+ state = "wallrunning"
+ else if ( PlayerIsRodeoingTitan( player ) )
+ {
+ if ( player.GetTitanSoulBeingRodeoed().GetTeam() == player.GetTeam() )
+ state = "onFriendlyTitan"
+ else
+ state = "onEnemyTitan"
+ }
+ else if ( player.IsZiplining() )
+ state = "ziplining"
+ else if ( !player.IsOnGround() )
+ state = "inAir"
+
+ if ( state != "" )
+ Stats_IncrementStat( player, "distance_stats", state, "", distMiles )
+ }
+
+ player.p.lastPosForDistanceStat = player.GetOrigin()
+ }
+
+ float timeSeconds = Time() - lastTickTime
+ float timeHours = timeSeconds / 3600.0
+
+ // track time stats
+ foreach ( entity player in GetPlayerArray() )
+ {
+ // first tick i dont count
+ if ( timeSeconds == 0 )
+ break
+
+ // more generic time stats
+ Stats_IncrementStat( player, "time_stats", "hours_total", "", timeHours )
+ if ( player.IsTitan() )
+ {
+ Stats_IncrementStat( player, "time_stats", "hours_as_titan_" + GetTitanCharacterName( player ), "", timeHours )
+ Stats_IncrementStat( player, "time_stats", "hours_as_titan", "", timeHours )
+ }
+ else
+ Stats_IncrementStat( player, "time_stats", "hours_as_pilot", "", timeHours )
+
+ string state = ""
+ // specific time stats
+ if ( !IsAlive( player ) )
+ state = "hours_dead"
+ else if ( player.IsWallHanging() )
+ state = "hours_wallhanging"
+ else if ( player.IsWallRunning() )
+ state = "hours_wallrunning"
+ else if ( !player.IsOnGround() )
+ state = "hours_inAir"
+ if ( state != "" )
+ Stats_IncrementStat( player, "time_stats", state, "", timeHours )
+
+ // weapon time stats
+ entity activeWeapon = player.GetActiveWeapon()
+ if ( IsValid( activeWeapon ) )
+ {
+ if ( IsValidStatItemString( activeWeapon.GetWeaponClassName() ) )
+ Stats_IncrementStat( player, "weapon_stats", "hoursUsed", activeWeapon.GetWeaponClassName(), timeHours )
+
+ foreach( entity weapon in player.GetMainWeapons() )
+ {
+ if ( IsValidStatItemString( weapon.GetWeaponClassName() ) )
+ Stats_IncrementStat( player, "weapon_stats", "hoursEquipped", weapon.GetWeaponClassName(), timeHours )
+ }
+ }
+
+ // map time stats
+ Stats_IncrementStat( player, "game_stats", "hoursPlayed", "", timeHours )
+ }
+
+ lastTickTime = Time()
+ // not rly worth doing this every frame, just a couple of times per second should be fine
+ wait 0.25
+ }
+}
+
+// this is kinda shit
+void function SaveStatsPeriodically_Threaded()
+{
+ while( true )
+ {
+ foreach( entity player in GetPlayerArray() )
+ Stats_SaveAllStats( player )
+ wait 5
+ }
}
-void function PreScoreEventUpdateStats(entity attacker, entity ent)
+bool function IsValidGamemodeString( string mode )
{
+ int gameModeCount = PersistenceGetEnumCount( "gameModes" )
+ for ( int modeIndex = 0; modeIndex < gameModeCount; modeIndex++ )
+ {
+ string gameModeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeIndex )
+
+ if ( gameModeName == mode )
+ return true
+ }
+ return false
}
-void function PostScoreEventUpdateStats(entity attacker, entity ent)
+bool function IsValidStatItemString( string item )
{
+ foreach( str in shGlobalMP.statsItemsList )
+ {
+ if ( str == item )
+ return true
+ }
+ return false
}
-void function Stats_OnPlayerDidDamage(entity player, var damageInfo)
+string function GetPersistenceRefFromDamageInfo( var damageInfo )
{
+ string damageSourceString = DamageSourceIDToString( DamageInfo_GetDamageSourceIdentifier( damageInfo ) )
+
+ foreach( str in shGlobalMP.statsItemsList )
+ {
+ if ( str == damageSourceString )
+ return damageSourceString
+ }
+ return ""
+}
+
+bool function DamageIsTitanMelee( int damageSourceId )
+{
+ switch( damageSourceId )
+ {
+ case eDamageSourceId.melee_titan_punch:
+ case eDamageSourceId.melee_titan_punch_ion:
+ case eDamageSourceId.melee_titan_punch_legion:
+ case eDamageSourceId.melee_titan_punch_tone:
+ case eDamageSourceId.melee_titan_punch_scorch:
+ case eDamageSourceId.melee_titan_punch_northstar:
+ case eDamageSourceId.melee_titan_punch_fighter:
+ case eDamageSourceId.melee_titan_sword:
+ case eDamageSourceId.melee_titan_sword_aoe:
+ return true
+ default:
+ return false
+ }
+ unreachable
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut
index 5bf150c06..4956375bd 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut
@@ -261,9 +261,12 @@ bool function IsSpawnpointValid( entity spawnpoint, int team )
return false
}
- array<entity> projectiles = GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), 600 )
- foreach ( entity projectile in projectiles )
- if ( projectile.GetTeam() != team )
+ const minEnemyDist = 1000.0 // about 20 meters?
+ // in rsquirrel extend returns null unlike in vanilla squirrel
+ array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist )
+ spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) )
+ foreach ( entity blocker in spawnBlockers )
+ if ( blocker.GetTeam() != team )
return false
// los check
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut
index 85f5aa05e..7a7498b8c 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut
@@ -785,7 +785,7 @@ bool function IsSettingPrimeTitanWithoutSetFile( entity player, string loadoutTy
bool function SkipItemLockedCheck( entity player, string ref, string parentRef, string loadoutProperty ) //Hack: Skip entitlement related unlock checks for now. Can fail.
{
- if ( DevEverythingUnlocked() )
+ if ( DevEverythingUnlocked( player ) )
return true
//if ( IsItemInEntitlementUnlock( ref ) && IsLobby() ) //TODO: Look into restricting this to lobby only? But entitlement checks can fail randomly...
@@ -3993,7 +3993,7 @@ bool function IsValidTitanLoadoutIndex( int loadoutIndex )
bool function HasPrimeToMatchExecutionType( entity player, int itemType )
{
- if ( DevEverythingUnlocked() )
+ if ( DevEverythingUnlocked( player ) )
return true
switch( itemType )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut
index b26e48ca0..f8597744f 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut
@@ -1,11 +1,5 @@
globalize_all_functions
-// whether the server is a modded, northstar server
-bool function IsNorthstarServer()
-{
- return GetConVarBool( "ns_is_modded_server" )
-}
-
// whether the game should return to the lobby on GameRules_EndMatch()
bool function ShouldReturnToLobby()
{
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut
new file mode 100644
index 000000000..ceb5e837c
--- /dev/null
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut
@@ -0,0 +1,1117 @@
+global function Progression_Init
+global function ProgressionEnabledForPlayer
+#if CLIENT || UI
+global function Progression_SetPreference
+global function Progression_GetPreference
+global function UpdateCachedLoadouts_Delayed
+#endif
+
+#if SP // literally just stub the global functions and call it a day
+
+void function Progression_Init() {}
+bool function ProgressionEnabledForPlayer( entity player ) { return false }
+#if CLIENT || UI
+void function Progression_SetPreference( bool enabled ) {}
+bool function Progression_GetPreference() { return false }
+void function UpdateCachedLoadouts_Delayed() {}
+#endif // CLIENT || UI
+
+#else // MP || UI basically
+
+// SO FOR SOME GOD DAMN REASON, PUTTING THESE INTO ONE STRUCT
+// AND PUTTING THE #if STUFF AROUND THE VARS CAUSES A COMPILE
+// ERROR, SO I HAVE TO DO THIS AWFULNESS
+
+#if SERVER
+struct {
+ table<entity, bool> progressionEnabled
+} file
+#else // UI || CLIENT
+struct {
+ bool isUpdatingCachedLoadouts = false
+} file
+#endif
+
+
+void function Progression_Init()
+{
+ #if SERVER
+ AddCallback_OnClientDisconnected( OnClientDisconnected )
+ AddClientCommandCallback( "ns_progression", ClientCommand_SetProgression )
+ AddCallback_GameStateEnter( eGameState.Playing, OnPlaying )
+ #elseif CLIENT
+ AddCallback_OnClientScriptInit( OnClientScriptInit )
+ #endif
+}
+
+bool function ProgressionEnabledForPlayer( entity player )
+{
+ #if SERVER
+ if ( player in file.progressionEnabled )
+ return file.progressionEnabled[player]
+
+ return false
+ #else // CLIENT || UI
+ return GetConVarBool( "ns_progression_enabled" )
+ #endif
+}
+
+#if SERVER
+void function OnPlaying()
+{
+ SetUIVar( level, "penalizeDisconnect", false ) // dont show the "you will lose merits thing"
+}
+
+void function OnClientDisconnected( entity player )
+{
+ // cleanup table when player leaves
+ if ( player in file.progressionEnabled )
+ delete file.progressionEnabled[player]
+}
+
+bool function ClientCommand_SetProgression( entity player, array<string> args )
+{
+ if ( args.len() != 1 )
+ return false
+ if ( args[0] != "0" && args[0] != "1" )
+ return false
+
+ file.progressionEnabled[player] <- args[0] == "1"
+
+ // loadout validation when progression is turned on
+ if ( file.progressionEnabled[player] )
+ ValidateEquippedItems( player )
+
+ return true
+}
+#endif
+
+#if CLIENT
+void function OnClientScriptInit( entity player )
+{
+ // unsure if this is needed, just being safe
+ if ( player != GetLocalClientPlayer() )
+ return
+
+ Progression_SetPreference( GetConVarBool( "ns_progression_enabled" ) )
+ UpdateCachedLoadouts_Delayed()
+}
+#endif
+
+#if CLIENT || UI
+void function Progression_SetPreference( bool enabled )
+{
+ SetConVarBool( "ns_progression_enabled", enabled )
+
+ #if CLIENT
+ GetLocalClientPlayer().ClientCommand( "ns_progression " + enabled.tointeger() )
+ #else // UI
+ ClientCommand( "ns_progression " + enabled.tointeger() )
+ #endif
+}
+
+bool function Progression_GetPreference()
+{
+ return GetConVarBool( "ns_progression_enabled" )
+}
+
+void function UpdateCachedLoadouts_Delayed()
+{
+ if ( file.isUpdatingCachedLoadouts )
+ return
+
+ file.isUpdatingCachedLoadouts = true
+
+ #if UI
+ RunClientScript( "UpdateCachedLoadouts_Delayed" ) // keep client and UI synced
+ #else // CLIENT
+ RunUIScript( "UpdateCachedLoadouts_Delayed" ) // keep client and UI synced
+ #endif
+
+ thread UpdateCachedLoadouts_Threaded()
+}
+
+void function UpdateCachedLoadouts_Threaded()
+{
+ wait 1.0 // give the server time to network our new persistence
+
+ UpdateCachedLoadouts()
+
+ // below here is just making all the menu models update properly and such
+
+ #if UI
+ uiGlobal.pilotSpawnLoadoutIndex = GetPersistentSpawnLoadoutIndex( GetUIPlayer(), "pilot" )
+ uiGlobal.titanSpawnLoadoutIndex = GetPersistentSpawnLoadoutIndex( GetUIPlayer(), "titan" )
+ #endif
+
+ #if CLIENT
+ entity player = GetLocalClientPlayer()
+ ClearAllTitanPreview( player )
+ ClearAllPilotPreview( player )
+ UpdateTitanModel( player, GetPersistentSpawnLoadoutIndex( player, "titan" ) )
+ UpdatePilotModel( player, GetPersistentSpawnLoadoutIndex( player, "pilot" ) )
+ #endif
+
+ file.isUpdatingCachedLoadouts = false
+}
+#endif
+
+#if SERVER
+void function ValidateEquippedItems( entity player )
+{
+ printt( "VALIDATING EQUIPPED ITEMS FOR PLAYER: " + player.GetPlayerName() )
+
+ // banner
+ CallingCard card = PlayerCallingCard_GetActive( player )
+ if ( IsItemLocked( player, card.ref ) )
+ {
+ printt( "- BANNER CARD IS LOCKED, RESETTING" )
+ PlayerCallingCard_SetActiveByRef( player, "callsign_16_col" ) // copied from _persistentdata.gnut
+ }
+
+ // patch
+ CallsignIcon icon = PlayerCallsignIcon_GetActive( player )
+ if ( IsItemLocked( player, icon.ref ) )
+ {
+ printt( "- BANNER PATCH IS LOCKED, RESETTING" )
+ PlayerCallsignIcon_SetActiveByRef( player, "gc_icon_titanfall" ) // copied from _persistentdata.gnut
+ }
+
+ // faction
+ int factionIndex = player.GetPersistentVarAsInt( "factionChoice" )
+ string factionRef = PersistenceGetEnumItemNameForIndex( "faction", factionIndex )
+ if ( IsItemLocked( player, factionRef ) )
+ {
+ printt( "- FACTION IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "factionChoice", "faction_marauder" ) // im so sorry that i am setting you to use sarah, you don't deserve this
+ }
+
+ // boost
+ BurnReward reward = BurnReward_GetById( player.GetPersistentVarAsInt( "burnmeterSlot" ) )
+ if ( IsItemLocked( player, reward.ref ) )
+ {
+ printt( "- BOOST IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "burnmeterSlot", BurnReward_GetByRef( "burnmeter_amped_weapons" ).id )
+ }
+
+ // titan loadouts
+ for ( int titanLoadoutIndex = 0; titanLoadoutIndex < NUM_PERSISTENT_TITAN_LOADOUTS; titanLoadoutIndex++ )
+ {
+ printt( "- VALIDATING TITAN LOADOUT: " + titanLoadoutIndex )
+
+ bool isSelected = titanLoadoutIndex == player.GetPersistentVarAsInt( "titanSpawnLoadout.index" )
+ TitanLoadoutDef loadout = GetTitanLoadout( player, titanLoadoutIndex )
+ TitanLoadoutDef defaultLoadout = shGlobal.defaultTitanLoadouts[titanLoadoutIndex]
+
+ printt( " - CHASSIS: " + loadout.titanClass )
+
+ // passive1 - "Titan Kit" (things like overcore)
+ if ( loadout.passive1 != defaultLoadout.passive1 && IsSubItemLocked( player, loadout.passive1, loadout.titanClass ) )
+ {
+ printt( " - TITAN KIT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive1", defaultLoadout.passive1 )
+ }
+
+ // passive2 - "<chassis> Kit" (things like zero point tripwire)
+ if ( loadout.passive2 != defaultLoadout.passive2 && IsSubItemLocked( player, loadout.passive2, loadout.titanClass ) )
+ {
+ printt( " - CHASSIS KIT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive2", defaultLoadout.passive2 )
+ }
+
+ // passive3 - "Titanfall Kit" (warpfall/dome shield)
+ if ( loadout.passive3 != defaultLoadout.passive3 && IsSubItemLocked( player, loadout.passive3, loadout.titanClass ) )
+ {
+ printt( " - TITANFALL KIT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive3", defaultLoadout.passive3 )
+ }
+
+ // passive4 - monarch core 1
+ if ( loadout.passive4 != defaultLoadout.passive4 && IsSubItemLocked( player, loadout.passive4, loadout.titanClass ) )
+ {
+ printt( " - MONARCH CORE 1 KIT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive4", defaultLoadout.passive4 )
+ }
+
+ // passive5 - monarch core 2
+ if ( loadout.passive5 != defaultLoadout.passive5 && IsSubItemLocked( player, loadout.passive5, loadout.titanClass ) )
+ {
+ printt( " - MONARCH CORE 2 KIT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive5", defaultLoadout.passive5 )
+ }
+
+ // passive6 - monarch core 3
+ if ( loadout.passive6 != defaultLoadout.passive6 && IsSubItemLocked( player, loadout.passive6, loadout.titanClass ) )
+ {
+ printt( " - MONARCH CORE 3 KIT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive6", defaultLoadout.passive6 )
+ }
+
+ // titanExecution
+ if ( !IsRefValid( loadout.titanExecution ) || !IsValidTitanExecution( titanLoadoutIndex, "titanExecution", "", loadout.titanExecution ) )
+ {
+ printt( " - TITAN EXECUTION IS INVALID FOR CHASSIS, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution )
+ }
+ else if ( IsItemLocked( player, loadout.titanExecution ) )
+ {
+ printt( " - TITAN EXECUTION EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution )
+ }
+ else if ( GetItemData( loadout.titanExecution ).reqPrime && IsItemLocked( player, loadout.primeTitanRef ) )
+ {
+ printt( " - PRIME TITAN EXECUTION EQUIPPED WHEN PRIME TITAN IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution )
+ }
+
+ // skinIndex
+ // camoIndex
+ if ( loadout.skinIndex == TITAN_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 )
+ {
+ printt( " - INVALID TITAN CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.camoIndex]
+ if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) )
+ {
+ printt( " - TITAN CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ }
+ }
+ else if ( loadout.skinIndex == 0 )
+ {
+ if ( loadout.camoIndex != 0 )
+ {
+ printt( " - INVALID TITAN CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ }
+ else
+ {
+ string ref = GetSkinRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.skinIndex )
+ if ( ref == INVALID_REF )
+ {
+ printt( " - INVALID TITAN WARPAINT, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ else if ( IsSubItemLocked( player, ref, loadout.titanClass ) )
+ {
+ printt( " - TITAN WARPAINT EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ }
+
+ // decalIndex
+ string noseArtRef = GetNoseArtRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.decalIndex )
+ if ( loadout.decalIndex != defaultLoadout.decalIndex && IsSubItemLocked( player, noseArtRef, loadout.titanClass ) )
+ {
+ printt( " - NOSE ART EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].decalIndex", defaultLoadout.decalIndex )
+ }
+
+ // primarySkinIndex
+ // primaryCamoIndex
+ if ( loadout.primarySkinIndex == WEAPON_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ if ( loadout.primaryCamoIndex >= camoSkins.len() || loadout.primaryCamoIndex < 0 )
+ {
+ printt( " - INVALID WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.primaryCamoIndex]
+ if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) )
+ {
+ printt( " - WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+ }
+ }
+ else if ( loadout.primarySkinIndex == 0 && loadout.primaryCamoIndex != 0 )
+ {
+ // titan weapons do not have skins, if we ever do add them lots of stuff will
+ //need a refactor outside of here so with that being said, i cannot be bothered
+ printt( " - INVALID WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+
+
+ // isPrime
+ if ( loadout.isPrime == "titan_is_prime" && IsItemLocked( player, loadout.primeTitanRef ) )
+ {
+ printt( " - PRIME TITAN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].isPrime", defaultLoadout.isPrime )
+ }
+
+ // primeSkinIndex
+ // primeCamoIndex
+ if ( loadout.primeSkinIndex == TITAN_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ if ( loadout.primeCamoIndex >= camoSkins.len() || loadout.primeCamoIndex < 0 )
+ {
+ printt( " - INVALID TITAN CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.primeCamoIndex]
+ if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) )
+ {
+ printt( " - TITAN CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex )
+ }
+ }
+ }
+ else if ( loadout.primeSkinIndex == 0 )
+ {
+ if ( loadout.primeCamoIndex != 0 )
+ {
+ printt( " - INVALID TITAN CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex )
+ }
+ }
+ else
+ {
+ printt( " - INVALID PRIME TITAN SKIN, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex )
+ }
+
+ // primeDecalIndex
+ string primeNoseArtRef = GetNoseArtRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.primeDecalIndex )
+ if ( loadout.primeDecalIndex != defaultLoadout.primeDecalIndex && IsSubItemLocked( player, primeNoseArtRef, loadout.titanClass ) )
+ {
+ printt( " - PRIME NOSE ART EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeDecalIndex", defaultLoadout.primeDecalIndex )
+ }
+
+ // showArmBadge - equipped and shouldnt be able to
+ if ( loadout.showArmBadge && !CanEquipArmBadge( player, loadout.titanClass ) )
+ {
+ printt( " - ARM BADGE EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].showArmBadge", defaultLoadout.showArmBadge )
+ }
+
+ // equipped titan loadout - equipped titan class is locked
+ if ( isSelected && IsItemLocked( player, loadout.titanClass ) )
+ {
+ printt( " - SELECTED TITAN CLASS IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "titanSpawnLoadout.index", 0 )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", 0 )
+ }
+ }
+
+ Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) )
+
+ // pilot loadouts
+ for ( int pilotLoadoutIndex = 0; pilotLoadoutIndex < NUM_PERSISTENT_PILOT_LOADOUTS; pilotLoadoutIndex++ )
+ {
+ printt( "- VALIDATING PILOT LOADOUT: " + pilotLoadoutIndex )
+
+ bool isSelected = pilotLoadoutIndex == player.GetPersistentVarAsInt( "pilotSpawnLoadout.index" )
+ PilotLoadoutDef loadout = GetPilotLoadout( player, pilotLoadoutIndex )
+ PilotLoadoutDef defaultLoadout = shGlobal.defaultPilotLoadouts[pilotLoadoutIndex]
+
+ // note: for readability, I have added {} around the different items,
+ // so that you can collapse them in visual studio code (and other good IDEs)
+
+ // tactical
+ {
+ if ( !IsRefValid( loadout.suit ) )
+ {
+ printt( " - TACTICAL IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].suit", defaultLoadout.suit )
+ }
+ else if ( IsItemLocked( player, loadout.suit ) )
+ {
+ printt( " - TACTICAL IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].suit", defaultLoadout.suit )
+ }
+ }
+
+ // ordnance
+ {
+ if ( !IsRefValid( loadout.ordnance ) )
+ {
+ printt( " - ORDNANCE IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].ordnance", defaultLoadout.ordnance )
+ }
+ else if ( IsItemLocked( player, loadout.ordnance ) )
+ {
+ printt( " - ORDNANCE IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].ordnance", defaultLoadout.ordnance )
+ }
+ }
+
+ // race ( gender )
+ {
+ if ( !IsRefValid( loadout.race ) )
+ {
+ printt( " - GENDER IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].race", defaultLoadout.race )
+ }
+ else if ( IsItemLocked( player, loadout.race ) )
+ {
+ printt( " - GENDER IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].race", defaultLoadout.race )
+ }
+ }
+
+ // camoIndex
+ // skinIndex
+ {
+ if ( loadout.skinIndex == PILOT_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_PILOT )
+ if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 )
+ {
+ printt( " - INVALID PILOT CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.camoIndex]
+ if ( IsItemLocked( player, camoSkin.ref ) )
+ {
+ printt( " - PILOT CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ }
+ }
+ else if ( loadout.skinIndex == 0 )
+ {
+ if ( loadout.camoIndex != 0 )
+ {
+ printt( " - INVALID PILOT CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ }
+ else
+ {
+ // pilots can't have skins other than 0 and 1 right?
+ printt( " - INVALID PILOT SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex )
+ }
+ }
+
+ // primary weapon
+ {
+ if ( !IsRefValid( loadout.primary ) || GetItemType( loadout.primary ) != eItemTypes.PILOT_PRIMARY )
+ {
+ printt( " - PRIMARY WEAPON IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primary", defaultLoadout.primary )
+ }
+ else if ( IsItemLocked( player, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primary", defaultLoadout.primary )
+ }
+ }
+
+ // primary weapon mods
+ {
+ // mod1
+ if ( loadout.primaryMod1 == "" )
+ {
+ // do nothing
+ }
+ else if ( !HasSubitem( loadout.primary, loadout.primaryMod1 ) )
+ {
+ printt( " - PRIMARY WEAPON MOD 1 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod1", defaultLoadout.primaryMod1 )
+ }
+ else if ( IsSubItemLocked( player, loadout.primaryMod1, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON MOD 1 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod1", defaultLoadout.primaryMod1 )
+ }
+ // mod2
+ if ( loadout.primaryMod2 == "" )
+ {
+ // do nothing
+ }
+ else if ( IsSubItemLocked( player, "primarymod2", loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON MOD 2 SLOT IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 )
+ }
+ else if ( !HasSubitem( loadout.primary, loadout.primaryMod2 ) )
+ {
+ printt( " - PRIMARY WEAPON MOD 2 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 )
+ }
+ else if ( IsSubItemLocked( player, loadout.primaryMod2, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON MOD 2 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 )
+ }
+ else if ( loadout.primaryMod2 == loadout.primaryMod1 && loadout.primaryMod2 != "" )
+ {
+ printt( " - PRIMARY WEAPON MOD 2 IS DUPLICATE, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 )
+ }
+ else if ( loadout.primaryAttachment == "threat_scope" )
+ {
+ printt( " - PRIMARY WEAPON MOD 2 IS SET WITH THREAT SCOPE, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 )
+ }
+ // attachment
+ if ( loadout.primaryAttachment == "" )
+ {
+ // do nothing
+ }
+ else if ( !HasSubitem( loadout.primary, loadout.primaryAttachment ) )
+ {
+ printt( " - PRIMARY WEAPON ATTACHMENT IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryAttachment", defaultLoadout.primaryAttachment )
+ }
+ else if ( IsSubItemLocked( player, loadout.primaryAttachment, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON ATTACHMENT IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryAttachment", defaultLoadout.primaryAttachment )
+ }
+ // mod3 (pro screen)
+ if ( loadout.primaryMod3 == "" )
+ {
+ // do nothing
+ }
+ else if ( loadout.primaryMod3 == "pro_screen" )
+ {
+ // fuck you and your three mod slot stuff
+ printt( " - PRIMARY WEAPON PRO SCREEN IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod3", defaultLoadout.primaryMod3 )
+ }
+ else if ( IsSubItemLocked( player, loadout.primaryMod3, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON PRO SCREEN IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod3", defaultLoadout.primaryMod3 )
+ }
+ }
+
+ // primary weapon camoIndex
+ // primary weapon skinIndex
+ {
+ if ( loadout.primarySkinIndex == WEAPON_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ if ( loadout.primaryCamoIndex >= camoSkins.len() || loadout.primaryCamoIndex < 0 )
+ {
+ printt( " - INVALID PRIMARY WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.primaryCamoIndex]
+ if ( IsSubItemLocked( player, camoSkin.ref, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+ }
+ }
+ else if ( loadout.primarySkinIndex == 0 )
+ {
+ if ( loadout.primaryCamoIndex != 0 )
+ {
+ printt( " - INVALID PRIMARY WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+ }
+ else
+ {
+ string warpaintRef = GetWeaponWarpaintRefByIndex( loadout.primarySkinIndex, loadout.primary )
+ if ( warpaintRef == INVALID_REF || IsSubItemLocked( player, warpaintRef, loadout.primary ) )
+ {
+ printt( " - PRIMARY WEAPON SKIN LOCKED/INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex )
+ }
+ }
+ }
+
+ // secondary weapon
+ {
+ if ( !IsRefValid( loadout.secondary ) || GetItemType( loadout.secondary ) != eItemTypes.PILOT_SECONDARY )
+ {
+ printt( " - SECONDARY WEAPON IS LOCKED, RESETTING" )
+ string ref = defaultLoadout.secondary
+ if ( loadout.secondary == ref ) // item dupes swap
+ {
+ ref = defaultLoadout.weapon3
+ }
+ else if ( ItemsInSameMenuCategory( loadout.secondary, ref ) ) // category dupes assign value to other slot and swap
+ {
+ ref = defaultLoadout.weapon3
+ }
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondary", ref )
+ }
+ else if ( IsItemLocked( player, loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON IS LOCKED, RESETTING" )
+ string ref = defaultLoadout.secondary
+ if ( loadout.weapon3 == ref ) // item dupes swap
+ {
+ ref = defaultLoadout.weapon3
+ }
+ else if ( ItemsInSameMenuCategory( loadout.weapon3, ref ) ) // category dupes assign value to other slot and swap
+ {
+ ref = defaultLoadout.weapon3
+ }
+
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondary", ref )
+ }
+ }
+
+ // secondary weapon mods
+ {
+ // mod1
+ if ( loadout.secondaryMod1 == "" )
+ {
+ // do nothing
+ }
+ else if ( !HasSubitem( loadout.secondary, loadout.secondaryMod1 ) )
+ {
+ printt( " - SECONDARY WEAPON MOD 1 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod1", defaultLoadout.secondaryMod1 )
+ }
+ else if ( IsSubItemLocked( player, loadout.secondaryMod1, loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON MOD 1 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod1", defaultLoadout.secondaryMod1 )
+ }
+ // mod2
+ if ( loadout.secondaryMod2 == "" )
+ {
+ // do nothing
+ }
+ else if ( IsSubItemLocked( player, "secondarymod2", loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON MOD 2 SLOT IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 )
+ }
+ else if ( !HasSubitem( loadout.secondary, loadout.secondaryMod2 ) )
+ {
+ printt( " - SECONDARY WEAPON MOD 2 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 )
+ }
+ else if ( IsSubItemLocked( player, loadout.secondaryMod2, loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON MOD 2 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 )
+ }
+ else if ( loadout.secondaryMod2 == loadout.secondaryMod1 && loadout.secondaryMod2 != "" )
+ {
+ printt( " - SECONDARY WEAPON MOD 2 IS DUPLICATE, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 )
+ }
+ // mod3 (pro screen)
+ if ( loadout.secondaryMod3 == "" )
+ {
+ // do nothing
+ }
+ else if ( loadout.secondaryMod3 == "pro_screen" )
+ {
+ // fuck you and your three mod slot stuff
+ printt( " - SECONDARY WEAPON PRO SCREEN IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod3", defaultLoadout.secondaryMod3 )
+ }
+ else if ( IsSubItemLocked( player, "secondarymod3", loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON PRO SCREEN IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod3", defaultLoadout.secondaryMod3 )
+ }
+ }
+
+ // secondary weapon camoIndex
+ // secondary weapon skinIndex
+ {
+ if ( loadout.secondarySkinIndex == WEAPON_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ if ( loadout.secondaryCamoIndex >= camoSkins.len() || loadout.secondaryCamoIndex < 0 )
+ {
+ printt( " - INVALID SECONDARY WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.secondaryCamoIndex]
+ if ( IsSubItemLocked( player, camoSkin.ref, loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex )
+ }
+ }
+ }
+ else if ( loadout.secondarySkinIndex == 0 )
+ {
+ if ( loadout.secondaryCamoIndex != 0 )
+ {
+ printt( " - INVALID SECONDARY WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex )
+ }
+ }
+ else
+ {
+ string warpaintRef = GetWeaponWarpaintRefByIndex( loadout.secondarySkinIndex, loadout.secondary )
+ if ( warpaintRef == INVALID_REF || IsSubItemLocked( player, warpaintRef, loadout.secondary ) )
+ {
+ printt( " - SECONDARY WEAPON SKIN LOCKED/INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex )
+ }
+ }
+ }
+
+ // weapon3
+ // note: these are always eItemTypes.PILOT_SECONDARY
+ {
+ if ( !IsRefValid( loadout.weapon3 ) || GetItemType( loadout.weapon3 ) != eItemTypes.PILOT_SECONDARY )
+ {
+ printt( " - WEAPON3 WEAPON IS LOCKED, RESETTING" )
+ string ref = defaultLoadout.weapon3
+ if ( loadout.weapon3 == ref ) // item dupes swap
+ {
+ ref = defaultLoadout.secondary
+ }
+ else if ( ItemsInSameMenuCategory( loadout.weapon3, ref ) ) // category dupes assign value to other slot and swap
+ {
+ ref = defaultLoadout.secondary
+ }
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3", ref )
+ }
+ else if ( IsItemLocked( player, loadout.weapon3 ) )
+ {
+ printt( " - TERTIARY WEAPON IS LOCKED, RESETTING" )
+ string ref = defaultLoadout.weapon3
+ if ( loadout.secondary == ref ) // item dupes swap
+ {
+ ref = defaultLoadout.secondary
+ }
+ else if ( ItemsInSameMenuCategory( loadout.secondary, ref ) ) // category dupes assign value to other slot and swap
+ {
+ ref = defaultLoadout.secondary
+ }
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3", ref )
+ }
+ }
+
+ // weapon3 mods
+ {
+ // mod1
+ if ( loadout.weapon3Mod1 == "" )
+ {
+ // do nothing
+ }
+ else if ( !HasSubitem( loadout.weapon3, loadout.weapon3Mod1 ) )
+ {
+ printt( " - WEAPON3 MOD 1 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod1", defaultLoadout.weapon3Mod1 )
+ }
+ else if ( IsSubItemLocked( player, loadout.weapon3Mod1, loadout.weapon3 ) )
+ {
+ printt( " - WEAPON3 MOD 1 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod1", defaultLoadout.weapon3Mod1 )
+ }
+ // mod2
+ if ( loadout.weapon3Mod2 == "" )
+ {
+ // do nothing
+ }
+ else if ( IsSubItemLocked( player, "secondarymod2", loadout.weapon3 ) )
+ {
+ printt( " - WEAPON3 MOD 2 SLOT IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 )
+ }
+ else if ( !HasSubitem( loadout.weapon3, loadout.weapon3Mod2 ) )
+ {
+ printt( " - WEAPON3 MOD 2 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 )
+ }
+ else if ( IsSubItemLocked( player, loadout.weapon3Mod2, loadout.weapon3 ) )
+ {
+ printt( " - WEAPON3 MOD 2 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 )
+ }
+ else if ( loadout.weapon3Mod2 == loadout.weapon3Mod1 && loadout.weapon3Mod2 != "" )
+ {
+ printt( " - WEAPON3 MOD 2 IS DUPLICATE, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 )
+ }
+ // mod3 (pro screen)
+ if ( loadout.weapon3Mod3 == "" )
+ {
+ // do nothing
+ }
+ else if ( loadout.weapon3Mod3 != "pro_screen" )
+ {
+ // fuck you and your three mod slot stuff
+ printt( " - WEAPON3 PRO SCREEN IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod3", defaultLoadout.weapon3Mod3 )
+ }
+ else if ( IsSubItemLocked( player, "secondarymod3", loadout.weapon3 ) )
+ {
+ printt( " - WEAPON3 PRO SCREEN IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod3", defaultLoadout.weapon3Mod3 )
+ }
+ }
+
+ // weapon3 camoIndex
+ // weapon3 skinIndex
+ {
+ if ( loadout.weapon3SkinIndex == WEAPON_SKIN_INDEX_CAMO )
+ {
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ if ( loadout.weapon3CamoIndex >= camoSkins.len() || loadout.weapon3CamoIndex < 0 )
+ {
+ printt( " - INVALID TERTIARY WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex )
+ }
+ else
+ {
+ ItemData camoSkin = camoSkins[loadout.weapon3CamoIndex]
+ if ( IsSubItemLocked( player, camoSkin.ref, loadout.weapon3 ) )
+ {
+ printt( " - TERTIARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex )
+ }
+ }
+ }
+ else if ( loadout.weapon3SkinIndex == 0 )
+ {
+ if ( loadout.weapon3CamoIndex != 0 )
+ {
+ printt( " - INVALID TERTIARY WEAPON CAMO/SKIN, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex )
+ }
+ }
+ else
+ {
+ string warpaintRef = GetWeaponWarpaintRefByIndex( loadout.weapon3SkinIndex, loadout.weapon3 )
+ if ( warpaintRef == INVALID_REF || IsSubItemLocked( player, warpaintRef, loadout.weapon3 ) )
+ {
+ printt( " - TERTIARY WEAPON SKIN LOCKED/INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex )
+ }
+ }
+ }
+
+ // kit 1
+ {
+ if ( !IsRefValid( loadout.passive1 ) || GetItemType( loadout.passive1 ) != eItemTypes.PILOT_PASSIVE1 )
+ {
+ printt( " - KIT 1 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive1", defaultLoadout.passive1 )
+ }
+ else if ( IsItemLocked( player, loadout.passive1 ) )
+ {
+ printt( " - KIT 1 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive1", defaultLoadout.passive1 )
+ }
+ }
+
+ // kit 2
+ {
+ if ( !IsRefValid( loadout.passive2 ) || GetItemType( loadout.passive2 ) != eItemTypes.PILOT_PASSIVE2 )
+ {
+ printt( " - KIT 2 IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive2", defaultLoadout.passive2 )
+ }
+ else if ( IsItemLocked( player, loadout.passive2 ) )
+ {
+ printt( " - KIT 2 IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive2", defaultLoadout.passive2 )
+ }
+ }
+
+ // execution
+ // note: not sure why defaultLoadout has this set to "", but neck snap should be default
+ {
+ if ( !IsRefValid( loadout.execution ) || GetItemType( loadout.execution ) != eItemTypes.PILOT_EXECUTION )
+ {
+ printt( " - EXECUTION IS INVALID, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].execution", "execution_neck_snap" )
+ }
+ else if ( IsItemLocked( player, loadout.execution ) )
+ {
+ printt( " - EXECUTION IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].execution", "execution_neck_snap" )
+ }
+ }
+
+ // equipped pilot loadout
+ {
+ if ( isSelected && IsItemLocked( player, "pilot_loadout_" + ( pilotLoadoutIndex + 1 ) ) )
+ {
+ printt( " - SELECTED PILOT LOADOUT IS LOCKED, RESETTING" )
+ player.SetPersistentVar( "pilotSpawnLoadout.index", 0 )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_UpdatePilotModel", 0 )
+ }
+ }
+ }
+
+ Remote_CallFunction_NonReplay( player, "ServerCallback_UpdatePilotModel", player.GetPersistentVarAsInt( "pilotSpawnLoadout.index" ) )
+
+ printt( "ITEM VALIDATION COMPLETE FOR PLAYER: " + player.GetPlayerName() )
+}
+
+// basically just PopulateTitanLoadoutFromPersistentData but without validation, we are doing the validation in a better way
+// that doesnt just kick the player and reset the entire loadout, since we want to only reset parts of the loadout that we need
+TitanLoadoutDef function GetTitanLoadout( entity player, int loadoutIndex )
+{
+ TitanLoadoutDef loadout
+
+ loadout.name = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "name" )
+ loadout.titanClass = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "titanClass" )
+ loadout.primaryMod = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "primaryMod" )
+ loadout.special = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "special" )
+ loadout.antirodeo = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "antirodeo" )
+ loadout.passive1 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive1" )
+ loadout.passive2 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive2" )
+ loadout.passive3 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive3" )
+ loadout.passive4 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive4" )
+ loadout.passive5 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive5" )
+ loadout.passive6 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive6" )
+ loadout.camoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "camoIndex" )
+ loadout.skinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "skinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+ loadout.decalIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "decalIndex" )
+ loadout.primaryCamoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primaryCamoIndex" )
+ loadout.primarySkinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+ loadout.titanExecution = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "titanExecution" )
+ loadout.showArmBadge = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "showArmBadge" )
+
+ //Prime Titan related vars
+ loadout.isPrime = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "isPrime" )
+ loadout.primeCamoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeCamoIndex" )
+ loadout.primeSkinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeSkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+ loadout.primeDecalIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeDecalIndex" )
+
+ UpdateDerivedTitanLoadoutData( loadout )
+ OverwriteLoadoutWithDefaultsForSetFile( loadout )
+
+ return loadout
+}
+
+// basically just PopulatePilotLoadoutFromPersistentData but without validation, we are doing the validation in a better way
+// that doesnt just kick the player and reset the entire loadout, since we want to only reset parts of the loadout that we need
+PilotLoadoutDef function GetPilotLoadout( entity player, int loadoutIndex )
+{
+ PilotLoadoutDef loadout
+
+ loadout.name = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "name" )
+ loadout.suit = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "suit" )
+ loadout.race = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "race" )
+ loadout.execution = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "execution" )
+ loadout.primary = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primary" )
+ loadout.primaryAttachment = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryAttachment" )
+ loadout.primaryMod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod1" )
+ loadout.primaryMod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod2" )
+ loadout.primaryMod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod3" )
+ loadout.secondary = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondary" )
+ loadout.secondaryMod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod1" )
+ loadout.secondaryMod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod2" )
+ loadout.secondaryMod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod3" )
+ loadout.weapon3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3" )
+ loadout.weapon3Mod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod1" )
+ loadout.weapon3Mod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod2" )
+ loadout.weapon3Mod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod3" )
+ loadout.ordnance = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "ordnance" )
+ loadout.passive1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "passive1" )
+ loadout.passive2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "passive2" )
+ loadout.camoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "camoIndex" )
+ loadout.skinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "skinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+ loadout.primaryCamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "primaryCamoIndex" )
+ loadout.primarySkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "primarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+ loadout.secondaryCamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "secondaryCamoIndex" )
+ loadout.secondarySkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "secondarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+ loadout.weapon3CamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "weapon3CamoIndex" )
+ loadout.weapon3SkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "weapon3SkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes
+
+ UpdateDerivedPilotLoadoutData( loadout )
+
+ return loadout
+}
+
+bool function CanEquipArmBadge( entity player, string titanClass )
+{
+ string skinRef
+ switch ( titanClass )
+ {
+ case "ion":
+ skinRef = "ion_skin_fd"
+ break
+ case "scorch":
+ skinRef = "scorch_skin_fd"
+ break
+ case "northstar":
+ skinRef = "northstar_skin_fd"
+ break
+ case "ronin":
+ skinRef = "ronin_skin_fd"
+ break
+ case "tone":
+ skinRef = "tone_skin_fd"
+ break
+ case "legion":
+ skinRef = "legion_skin_fd"
+ break
+ case "vanguard":
+ skinRef = "monarch_skin_fd"
+ break
+ }
+
+ return !IsSubItemLocked( player, skinRef, titanClass )
+}
+
+string function GetWeaponWarpaintRefByIndex( int skinIndex, string parentRef )
+{
+ ItemData parentItem = GetItemData( parentRef )
+ foreach ( subItem in parentItem.subitems )
+ {
+ if ( GetSubitemType( parentRef, subItem.ref ) != eItemTypes.WEAPON_SKIN )
+ continue
+ if ( subItem.i.skinIndex != skinIndex )
+ continue
+
+ return subItem.ref
+ }
+
+ return INVALID_REF
+}
+#endif // SERVER
+
+#endif // MP
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut
index 7f356a181..9e7629858 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut
@@ -362,7 +362,7 @@ string function StringReplace( string baseString, string searchString, string re
source = part1 + replaceString + part2
loopedOnce = true
- findResult = source.find( searchString )
+ findResult = source.find( searchString, findResult + replaceString.len() )
}
return baseString
@@ -386,8 +386,12 @@ float function RoundToNearestMultiplier( float value, float multiplier )
return value
}
-function DevEverythingUnlocked()
+function DevEverythingUnlocked( entity player = null )
{
+ // check if player has opted into progression or not
+ if ( player != null && ProgressionEnabledForPlayer( player ) )
+ return false
+
return EverythingUnlockedConVarEnabled()
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut
index 4bfeb4f8f..0436a393c 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut
@@ -10,5 +10,8 @@ void function AddTitanXP( entity player, int amount )
// level up notif
if ( TitanGetLevel( player, titan ) != oldLevel )
+ {
Remote_CallFunction_NonReplay( player, "ServerCallback_TitanLeveledUp", shTitanXP.titanClasses.find( titan ), TitanGetGen( player, titan ), TitanGetLevel( player, titan ) )
+ AddPlayerScore( player, "TitanLevelUp" )
+ }
} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut
index 8e1002576..4e25e3019 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut
@@ -12,8 +12,11 @@ void function AddWeaponXP( entity player, int amount )
// level up notif
if ( WeaponGetLevel( player, weaponClassname ) != oldLevel )
+ {
Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponLeveledUp", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetGen( player, weaponClassname ), WeaponGetLevel( player, weaponClassname ) )
-
+ AddPlayerScore( player, "WeaponLevelUp" )
+ }
+
// proscreen
if ( player == activeWeapon.GetProScreenOwner() )
{