From e8e3442ed03bfcb70953ceeecf476d7dfbf50b3d Mon Sep 17 00:00:00 2001 From: Ahrimdon Date: Tue, 27 Feb 2024 03:20:09 -0500 Subject: [PATCH] Add game files and server configs --- cfg/!start_client.bat | 14 + cfg/!start_horde_server.bat | 23 + cfg/!start_mp_server.bat | 22 + cfg/!start_zm_server.bat | 23 + cfg/s1/server.cfg | 255 ++ cfg/s1/server_horde.cfg | 107 + cfg/s1/server_zm.cfg | 80 + data/dw/entitlement_config.info | 228 ++ data/dw/ffotd-1.22.1.ff | Bin 0 -> 21272 bytes data/dw/lootConfig_tu22.csv | 1050 +++++ data/dw/mm.cfg | 1 + data/dw/playlists_tu22.aggr | Bin 0 -> 32928 bytes data/dw/social_tu22.cfg | 171 + data/dw/winStoreConfig_tu22.csv | 206 + data/maps/mp/gametypes/_damage.gsc | 3637 +++++++++++++++++ data/maps/mp/gametypes/_gamelogic.gsc | 3548 ++++++++++++++++ data/maps/mp/gametypes/_playerlogic.gsc | 2226 ++++++++++ data/maps/mp/gametypes/gun.gsc | 507 +++ data/scripts/_team_balance.gsc | 23 + data/ui_scripts/endgame/__init__.lua | 238 ++ data/ui_scripts/hud_info/__init__.lua | 6 + data/ui_scripts/hud_info/hud.lua | 163 + data/ui_scripts/hud_info/settings.lua | 156 + data/ui_scripts/lobby/__init__.lua | 6 + data/ui_scripts/lobby/menu_xboxlive.lua | 112 + data/ui_scripts/lobby/menu_xboxlive_lobby.lua | 95 + data/ui_scripts/patches/__init__.lua | 19 + data/ui_scripts/scoreboard/__init__.lua | 30 + data/ui_scripts/server_list/__init__.lua | 5 + data/ui_scripts/server_list/serverlist.lua | 76 + data/ui_scripts/stats/__init__.lua | 204 + 31 files changed, 13231 insertions(+) create mode 100644 cfg/!start_client.bat create mode 100644 cfg/!start_horde_server.bat create mode 100644 cfg/!start_mp_server.bat create mode 100644 cfg/!start_zm_server.bat create mode 100644 cfg/s1/server.cfg create mode 100644 cfg/s1/server_horde.cfg create mode 100644 cfg/s1/server_zm.cfg create mode 100644 data/dw/entitlement_config.info create mode 100644 data/dw/ffotd-1.22.1.ff create mode 100644 data/dw/lootConfig_tu22.csv create mode 100644 data/dw/mm.cfg create mode 100644 data/dw/playlists_tu22.aggr create mode 100644 data/dw/social_tu22.cfg create mode 100644 data/dw/winStoreConfig_tu22.csv create mode 100644 data/maps/mp/gametypes/_damage.gsc create mode 100644 data/maps/mp/gametypes/_gamelogic.gsc create mode 100644 data/maps/mp/gametypes/_playerlogic.gsc create mode 100644 data/maps/mp/gametypes/gun.gsc create mode 100644 data/scripts/_team_balance.gsc create mode 100644 data/ui_scripts/endgame/__init__.lua create mode 100644 data/ui_scripts/hud_info/__init__.lua create mode 100644 data/ui_scripts/hud_info/hud.lua create mode 100644 data/ui_scripts/hud_info/settings.lua create mode 100644 data/ui_scripts/lobby/__init__.lua create mode 100644 data/ui_scripts/lobby/menu_xboxlive.lua create mode 100644 data/ui_scripts/lobby/menu_xboxlive_lobby.lua create mode 100644 data/ui_scripts/patches/__init__.lua create mode 100644 data/ui_scripts/scoreboard/__init__.lua create mode 100644 data/ui_scripts/server_list/__init__.lua create mode 100644 data/ui_scripts/server_list/serverlist.lua create mode 100644 data/ui_scripts/stats/__init__.lua diff --git a/cfg/!start_client.bat b/cfg/!start_client.bat new file mode 100644 index 0000000..c5dfe61 --- /dev/null +++ b/cfg/!start_client.bat @@ -0,0 +1,14 @@ +@echo off + +:: Either put the batch in the Advanced Warfare install dir, or change the value below to the Advanced Warfare install dir +set AW_INSTALL=%~dp0 + +:: Remove this line if automatic updates on start should be disabled +start /W alterware-launcher.exe --update + +:://///////////////////////////////////////////////////////////////////// +:://You're done!! WARNING!!! Don't mess with anything below this line // +:://///////////////////////////////////////////////////////////////////// + +set GAME_EXE=s1-mod.exe +start %GAME_EXE% diff --git a/cfg/!start_horde_server.bat b/cfg/!start_horde_server.bat new file mode 100644 index 0000000..6a6305c --- /dev/null +++ b/cfg/!start_horde_server.bat @@ -0,0 +1,23 @@ +@echo off + +set ServerFilename=server_horde.cfg + +::///////////////////////////////////////////////////////////////////////////// +::// What port do you want the server to run on? // +::// You must port forward this port & allow it through your firewall // +::///////////////////////////////////////////////////////////////////////////// +set port=27016 + + +:: Either put the batch in the Advanced Warfare install dir, or change the value below to the Advanced Warfare install dir +set AW_INSTALL=%~dp0 + +:: Remove this line if automatic updates on start should be disabled +start /W alterware-launcher.exe --update + +:://///////////////////////////////////////////////////////////////////// +:://You're done!! WARNING!!! Don't mess with anything below this line // +:://///////////////////////////////////////////////////////////////////// + +set GAME_EXE=s1-mod.exe +start %GAME_EXE% -dedicated +survival 1 +set net_port "%port%" +exec %ServerFilename% +map_rotate diff --git a/cfg/!start_mp_server.bat b/cfg/!start_mp_server.bat new file mode 100644 index 0000000..c88975e --- /dev/null +++ b/cfg/!start_mp_server.bat @@ -0,0 +1,22 @@ +@echo off + +set ServerFilename=server.cfg + +::///////////////////////////////////////////////////////////////////////////// +::// What port do you want the server to run on? // +::// You must port forward this port & allow it through your firewall // +::///////////////////////////////////////////////////////////////////////////// +set port=27016 + +:: Either put the batch in the Advanced Warfare install dir, or change the value below to the Advanced Warfare install dir +set AW_INSTALL=%~dp0 + +:: Remove this line if automatic updates on start should be disabled +start /W alterware-launcher.exe --update + +:://///////////////////////////////////////////////////////////////////// +:://You're done!! WARNING!!! Don't mess with anything below this line // +:://///////////////////////////////////////////////////////////////////// + +set GAME_EXE=s1-mod.exe +start %GAME_EXE% -dedicated +set net_port "%port%" +exec %ServerFilename% +map_rotate diff --git a/cfg/!start_zm_server.bat b/cfg/!start_zm_server.bat new file mode 100644 index 0000000..929e4bb --- /dev/null +++ b/cfg/!start_zm_server.bat @@ -0,0 +1,23 @@ +@echo off + +set ServerFilename=server_zm.cfg + +::///////////////////////////////////////////////////////////////////////////// +::// What port do you want the server to run on? // +::// You must port forward this port & allow it through your firewall // +::///////////////////////////////////////////////////////////////////////////// +set port=27016 + + +:: Either put the batch in the Advanced Warfare install dir, or change the value below to the Advanced Warfare install dir +set AW_INSTALL=%~dp0 + +:: Remove this line if automatic updates on start should be disabled +start /W alterware-launcher.exe --update + +:://///////////////////////////////////////////////////////////////////// +:://You're done!! WARNING!!! Don't mess with anything below this line // +:://///////////////////////////////////////////////////////////////////// + +set GAME_EXE=s1-mod.exe +start %GAME_EXE% -dedicated +zombiesMode 1 +set net_port "%port%" +exec %ServerFilename% +map_rotate diff --git a/cfg/s1/server.cfg b/cfg/s1/server.cfg new file mode 100644 index 0000000..82f16b3 --- /dev/null +++ b/cfg/s1/server.cfg @@ -0,0 +1,255 @@ +////////////////////////////////////////////////// +/// S1 Server Configuration // +////////////////////////////////////////////////// + +////////////////////////////////////////////////// +// SERVER NAME & COLORS TIPS // +////////////////////////////////////////////////// +// // +// ^1 Red // +// ^2 Green // +// ^3 Yellow // +// ^4 Blue // +// ^5 Cyan // +// ^6 Pink // +// ^7 White // +// ^8 Depends on the team colors playing. // +// ^9 Grey // +// ^0 Black // +// ^: Rainbow colors // +// // +////////////////////////////////////////////////// + +set sv_hostname "S1 Default Server" // Sets the server hostname. +set sv_motd "" // Sets a custom motd which is shown on the intel message loadscreen when a player joins. Leave blank for default intel messages. + +////////////////////////////////////////////////// +// ADMIN INFO (Optional) // +////////////////////////////////////////////////// + +set _Admin "" // Your username. +set _Email "" // E-mail address. you can leave blank +set _Website "" // Website. (IW4MAdmin uses this.) +set _Location "Earth" // Location + +////////////////////////////////////////////////// +// NON-GAMEPLAY CONFIGURATION // +////////////////////////////////////////////////// + +set scr_game_high_jump 1 // Disable Exos? +set party_maxplayers "18" // Max players in your server. +set rcon_password "" // Access to your server to change stuff remotely or ingame. (Empty = disabled) +set g_password "" // Password Protected Server. Leave blank if you want players to join or set password if you want to keep public out. +set sv_privateClients "0" // Maximum number of private clients allowed on the server (range 0-18 (clamped to sv_maxclients) ) +set sv_privatePassword "" // Password for reserved slots. +set sv_voice "2" // Server voice chat configuration ( 0 = "No Chat", 1 = "Free Chat", 2 = "Team Chat" (default) ) +set g_allowVote "1" // Toggle voting for [player kick/map restart/next map] (0 or 1 (default) ) +set g_deadChat "0" // Toggle allowing dead players to chat with living players (0 (default) or 1) +set g_inactivity "420" // Time in seconds before the server will kick a user for inactivity (range 0 - 10000) +set sv_kickBanTime "3600" // Time in seconds for a player temporary ban (on kick/tempban) (range 0 - 3600) +set sv_allowClientConsole "1" // Enable or Disable players ability to access server commands +set sv_timeout "60" // Timeout time period. You will timeout after (60) seconds when attempting to connect or if you are getting connection interruptions +set sv_reconnectlimit "3" // How many times you can try to reconnect +set sv_pure "1" // verifying cilent files +set sv_floodProtect "1" // Chat Spam Protection +set sv_sayName "console" // name server-side 'say' commands show up as +set logfile "2" // Enable loging 1-2? enable. 0 disable. Leave it on if you plan on using B3 or IW4MAdmin. +set g_logSync "1" // 1 always flush games_mp.log, 0 only flush on game end. Recommended to stay on for b3 and IW4MAdmin +set g_log "s1/logs/games_mp.log" // Gamelog filename. If you edit this, Make sure you change B3.xml if you have bigbrotherbot. IW4MAdmin auto-detects however. + +////////////////////////////////////////////////// +// BASE GAME CONFIGURATION // +////////////////////////////////////////////////// +// // +// dm - Free-for-all // +// war - Team Deathmatch // +// twar - Momentum // +// ball - Uplink // +// sd - Search and Destroy // +// sr - Search and Rescue // +// dom - Domination // +// conf - Kill Confirmed // +// ctf - Capture the Flag // +// hp - Hardpoint // +// infect - Infected // +// // +////////////////////////////////////////////////// + +set g_gametype "war" // Default gametype in case map rotation doesn't have any gametypes. Choose a gametype from the list above. +set scr_game_allowkillcam "1" // Allow Killcam +set team_rebalance "1" // Auto Balance teams? +set scr_teambalance "1" // Enable or Disable auto balance. +set scr_game_spectatetype "2" // Allow Spectators. 0 Disabled, 1 Team/Player only, 2 Free +set scr_thirdPerson "0" // third-person mode +set scr_game_hardpoints "1" // Enable/Disable Killstreak rewards +set scr_game_perks "1" // Allow players to have perks +set scr_nukeTimer "10" // Timer when nuke goes off +set scr_game_killstreakdelay "12" // Delay killstreak from the start of the round. + +////////////////////////////////////////////////// +// HARDCORE CONFIGURATION // +////////////////////////////////////////////////// +// uncomment below commands for some hardcore // +// by removing the // before each set dvar. // +////////////////////////////////////////////////// + +// set g_hardcore "1" // Enable hardcore mode +// set scr_hardcore "1" // Enable hardcore mode again... +// set ui_hud_hardcore "1" // Removes Heads up display which can be used both regular and HC +// set scr_player_maxhealth "30" // Percent of Health players will have on Respawn. (100 is normal. 30 is hardcore) +// set scr_team_fftype "1" // Enable or Disable Friendly Fire. (1 on, 2 reflect, 3 shared) +// set scr_player_healthregentime "0" // Time it takes you to recover damage. (5 is normal, 0 is hardcore) +// set scr_game_onlyheadshots "0" // Enable/Disable Only Headshots mode. You can only kill players by taking headshots. + +////////////////////////////////////////////////// +// FREE FOR ALL GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_dm_scorelimit "30" // Score limit to win the game. +set scr_dm_timelimit "10" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_dm_playerrespawndelay "-1" // How long player will wait until respawn. +set scr_dm_numlives "0" // Number of lives per player. 0 for unlimited. +set scr_dm_roundlimit "1" // Rounds per game. +set scr_dm_winlimit "1" // amount of wins needed to win a round-based game +set scr_dm_promode "0" + +////////////////////////////////////////////////// +// TEAM DEATHMATCH GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_war_scorelimit "75" // Score limit to win the game. +set scr_war_timelimit "10" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_war_playerrespawndelay "0" // How long player will wait until respawn. +set scr_war_waverespawndelay "0" // Duration is seconds before the first respawn in each round. +set scr_war_numlives "0" // Number of lives per player 0 for unlimited. +set scr_war_roundlimit "1" // Rounds per game. +set scr_war_winlimit "1" // amount of wins needed to win a round-based game +set scr_war_promode "0" + +////////////////////////////////////////////////// +// SEARCH AND DESTROY GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_sd_scorelimit "1" // Score limit required to win the game. +set scr_sd_timelimit "2.5" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_sd_playerrespawndelay "0" // How long player will wait until respawn. +set scr_sd_waverespawndelay "0" // Duration is seconds before the first respawn in each round. +set scr_sd_numlives "1" // Number of lives per player per game. +set scr_sd_roundlimit "0" // Rounds the game is limited to 0 for unlimited. +set scr_sd_winlimit "4" // amount of wins needed to win a round-based game. +set scr_sd_roundswitch "3" // after X rounds, switch sides. +set scr_sd_bombtimer "45" // Time taken for the bomb to detonate. +set scr_sd_defusetime "5" // Time taken to defuse the bomb. +set scr_sd_multibomb "0" // allow multiple people to 'have the bomb'. +set scr_sd_planttime "5" // How long will it take player to 'plant the bomb'. +set scr_sd_promode "0" + +////////////////////////////////////////////////// +// SEARCH AND RESCUE GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_sr_scorelimit "1" // Score limit required to win the game. +set scr_sr_timelimit "2.5" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_sr_playerrespawndelay "0" // How long player will wait until respawn. +set scr_sr_waverespawndelay "0" // Duration is seconds before the first respawn in each round. +set scr_sr_numlives "1" // Number of lives per player per game. +set scr_sr_roundlimit "0" // Rounds the game is limited to 0 for unlimited. +set scr_sr_winlimit "4" // amount of wins needed to win a round-based game. +set scr_sr_roundswitch "3" // after X rounds, switch sides. +set scr_sr_bombtimer "45" // Time taken for the bomb to detonate. +set scr_sr_defusetime "5" // Time taken to defuse the bomb. +set scr_sr_multibomb "0" // allow multiple people to 'have the bomb'. +set scr_sr_planttime "5" // How long will it take player to 'plant the bomb'. +set scr_sr_promode "0" + +////////////////////////////////////////////////// +// DOMINATION GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_dom_scorelimit "200" // Score limit to win the game. +set scr_dom_timelimit "0" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_dom_playerrespawndelay "0" // How long player will wait until respawn. +set scr_dom_waverespawndelay "0" // Duration is seconds before the first respawn in each round. +set scr_dom_numlives "0" // Number of lives per player per game. 0 is unlimited. +set scr_dom_roundlimit "1" // Rounds per game +set scr_dom_winlimit "1" // amount of wins needed to win a round-based game +set scr_dom_promode "0" + +////////////////////////////////////////////////// +// KILL CONFIRMED GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_conf_scorelimit "65" // Score limit to win the game. +set scr_conf_timelimit "10" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_conf_playerrespawndelay "0" // How long player will wait until respawn. +set scr_conf_waverespawndelay "0" // Duration is seconds before the first respawn in each round. +set scr_conf_numlives "0" // Number of lives per player 0 for unlimited. +set scr_conf_roundlimit "1" // Rounds per game. +set scr_conf_winlimit "1" // amount of wins needed to win a round-based game +set scr_conf_promode "0" + +////////////////////////////////////////////////// +// CAPTURE THE FLAG GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_ctf_scorelimit "0" // Target score before the round ends. +set scr_ctf_timelimit "10" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_ctf_numlives "0" // Number of lives per player 0 for unlimited. +set scr_ctf_halftime "1" // Half-Time +set scr_ctf_roundlimit "1" // How many rounds match would last. +set scr_ctf_returntime "30" // How many seconds before flag returns to base without nobody touching it. +set scr_ctf_playerrespawndelay "0" // Respawn wait in seconds. +set scr_ctf_waverespawndelay "10" // Time delay for first respawn before the game. +set scr_ctf_promode "0" + +////////////////////////////////////////////////// +// INFECTED GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_infect_timelimit "10" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_infect_playerrespawndelay "0" // How long player will wait until respawn. +set scr_infect_waverespawndelay "0" // Duration is seconds before the first respawn in each round. +set scr_infect_numlives "0" // Number of lives per player 0 for unlimited. +set scr_infect_roundlimit "1" // Rounds per game. +set scr_infect_winlimit "1" // amount of wins needed to win a round-based game +set scr_infect_promode "0" + +////////////////////////////////////////////////////////// +// MAP SHORT NAMES ROTATION LIST // +////////////////////////////////////////////////////////// +// // +// Ascend - mp_refraction // +// Bio Lab - mp_lab2 // +// Comeback - mp_comeback // +// Defender - mp_laser2 // +// Detroit - mp_detroit // +// Greenband - mp_greenband // +// Horizon - mp_levity // +// Instinct - mp_instinct // +// Recovery - mp_recovery // +// Retreat - mp_venus // +// Riot - mp_prison // +// Solar - mp_solar // +// Terrace - mp_terrace // +// // +// Atlas Gorge - mp_dam // +// Chop Shop - mp_spark // +// Climate - mp_climate_3 // +// Compound - mp_sector17 // +// Core - mp_lost // +// Drift - mp_torqued // +// Fracture - mp_fracture // +// Kremlin - mp_kremlin // +// Overload - mp_lair // +// Parliament - mp_bigben2 // +// Perplex - mp_perplex_1 // +// Quarantine - mp_liberty // +// Sideshow - mp_clowntown3 // +// Site 244 - mp_blackbox // +// Skyrise - mp_highrise2 // +// Swarm - mp_seoul2 // +// Urban - mp_urban // +// // +////////////////////////////////////////////////////////// + +set sv_maprotation "gametype war map mp_refraction map mp_lab2 map mp_comeback map mp_laser2 map mp_detroit map mp_greenband map mp_levity map mp_instinct map mp_recovery map mp_venus map mp_prison map mp_solar map mp_terrace map mp_dam map mp_torqued map mp_clowntown3 map mp_lost map mp_urban map mp_blackbox map mp_climate_3 map mp_perplex_1 map mp_kremlin map mp_bigbend map mp_sector17 map mp_fracture map mp_lair map mp_liberty map mp_seoul2" diff --git a/cfg/s1/server_horde.cfg b/cfg/s1/server_horde.cfg new file mode 100644 index 0000000..4628773 --- /dev/null +++ b/cfg/s1/server_horde.cfg @@ -0,0 +1,107 @@ +////////////////////////////////////////////////// +/// S1 Server Configuration // +////////////////////////////////////////////////// + +////////////////////////////////////////////////// +// SERVER NAME & COLORS TIPS // +////////////////////////////////////////////////// +// // +// ^1 Red // +// ^2 Green // +// ^3 Yellow // +// ^4 Blue // +// ^5 Cyan // +// ^6 Pink // +// ^7 White // +// ^8 Depends on the team colors playing. // +// ^9 Grey // +// ^0 Black // +// ^: Rainbow colors // +// // +////////////////////////////////////////////////// + +set sv_hostname "S1 Default Server" // Sets the server hostname. +set sv_motd "" // Sets a custom motd which is shown on the intel message loadscreen when a player joins. Leave blank for default intel messages. + +////////////////////////////////////////////////// +// ADMIN INFO (Optional) // +////////////////////////////////////////////////// + +set _Admin "" // Your username. +set _Email "" // E-mail address. you can leave blank +set _Website "" // Website. (IW4MAdmin uses this.) +set _Location "Earth" // Location + +////////////////////////////////////////////////// +// NON-GAMEPLAY CONFIGURATION // +////////////////////////////////////////////////// + +set party_maxplayers "4" // Max players in your server. +set rcon_password "" // Access to your server to change stuff remotely or ingame. (Empty = disabled) +set g_password "" // Password Protected Server. Leave blank if you want players to join or set password if you want to keep public out. +set sv_privateClients "0" // Maximum number of private clients allowed on the server (range 0-18 (clamped to sv_maxclients) ) +set sv_privatePassword "" // Password for reserved slots. +set sv_voice "2" // Server voice chat configuration ( 0 = "No Chat", 1 = "Free Chat", 2 = "Team Chat" (default) ) +set g_allowVote "1" // Toggle voting for [player kick/map restart/next map] (0 or 1 (default) ) +set g_deadChat "0" // Toggle allowing dead players to chat with living players (0 (default) or 1) +set g_inactivity "420" // Time in seconds before the server will kick a user for inactivity (range 0 - 10000) +set sv_kickBanTime "3600" // Time in seconds for a player temporary ban (on kick/tempban) (range 0 - 3600) +set sv_allowClientConsole "1" // Enable or Disable players ability to access server commands +set sv_timeout "60" // Timeout time period. You will timeout after (60) seconds when attempting to connect or if you are getting connection interruptions +set sv_reconnectlimit "3" // How many times you can try to reconnect +set sv_pure "1" // verifying cilent files +set sv_floodProtect "1" // Chat Spam Protection +set sv_sayName "console" // name server-side 'say' commands show up as +set logfile "2" // Enable loging 1-2? enable. 0 disable. Leave it on if you plan on using B3 or IW4MAdmin. +set g_logSync "1" // 1 always flush games_mp.log, 0 only flush on game end. Recommended to stay on for b3 and IW4MAdmin +set g_log "s1/logs/games_h.log" // Gamelog filename. If you edit this, Make sure you change B3.xml if you have bigbrotherbot. IW4MAdmin auto-detects however. + + +////////////////////////////////////////////////// +// EXO SURVIVAL GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_horde_scorelimit "0" // Target score before the round ends. +set scr_horde_timelimit "0" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_horde_numlives "1" // Number of lives per player 0 for unlimited. +set scr_horde_promode "0" + +////////////////////////////////////////////////////////// +// EXO SURVIVAL ROTATION LIST // +////////////////////////////////////////////////////////// +// // +// TIER 1 // +// // +// Bio Lab - mp_lab2 // +// Retreat - mp_venus // +// Detroit - mp_detroit // +// Ascend - mp_refraction // +// // +// TIER 2 // +// // +// Horizon - mp_levity // +// Comeback - mp_comeback // +// Terrace - mp_terrace // +// Instinct - mp_instinct // +// // +// TIER 3 // +// // +// Greenband - mp_greenband // +// Solar - mp_solar // +// Recovery - mp_recovery // +// Defender - mp_laser2 // +// // +// TIER 4 // +// // +// Riot - mp_prison // +// // +// BONUS // +// // +// Sideshow - mp_clowntown3 // +// Core - mp_lost // +// Drift - mp_torqued // +// Urban - mp_urban // +// // +////////////////////////////////////////////////////////// + +set sv_maprotation "gametype horde map mp_lab2 mp_venus mp_detroit mp_refraction mp_levity mp_comeback mp_terrace mp_instinct mp_greenband mp_solar mp_recovery mp_laser2 mp_prison mp_clowntown3 mp_lost mp_torqued mp_urban" diff --git a/cfg/s1/server_zm.cfg b/cfg/s1/server_zm.cfg new file mode 100644 index 0000000..72cd61e --- /dev/null +++ b/cfg/s1/server_zm.cfg @@ -0,0 +1,80 @@ +////////////////////////////////////////////////// +/// S1 Server Configuration // +////////////////////////////////////////////////// + +////////////////////////////////////////////////// +// SERVER NAME & COLORS TIPS // +////////////////////////////////////////////////// +// // +// ^1 Red // +// ^2 Green // +// ^3 Yellow // +// ^4 Blue // +// ^5 Cyan // +// ^6 Pink // +// ^7 White // +// ^8 Depends on the team colors playing. // +// ^9 Grey // +// ^0 Black // +// ^: Rainbow colors // +// // +////////////////////////////////////////////////// + +set sv_hostname "S1 Default Server" // Sets the server hostname. +set sv_motd "" // Sets a custom motd which is shown on the intel message loadscreen when a player joins. Leave blank for default intel messages. + +////////////////////////////////////////////////// +// ADMIN INFO (Optional) // +////////////////////////////////////////////////// + +set _Admin "" // Your username. +set _Email "" // E-mail address. you can leave blank +set _Website "" // Website. (IW4MAdmin uses this.) +set _Location "Earth" // Location + +////////////////////////////////////////////////// +// NON-GAMEPLAY CONFIGURATION // +////////////////////////////////////////////////// + +set party_maxplayers "4" // Max players in your server. +set rcon_password "" // Access to your server to change stuff remotely or ingame. (Empty = disabled) +set g_password "" // Password Protected Server. Leave blank if you want players to join or set password if you want to keep public out. +set sv_privateClients "0" // Maximum number of private clients allowed on the server (range 0-18 (clamped to sv_maxclients) ) +set sv_privatePassword "" // Password for reserved slots. +set sv_voice "2" // Server voice chat configuration ( 0 = "No Chat", 1 = "Free Chat", 2 = "Team Chat" (default) ) +set g_allowVote "1" // Toggle voting for [player kick/map restart/next map] (0 or 1 (default) ) +set g_deadChat "0" // Toggle allowing dead players to chat with living players (0 (default) or 1) +set g_inactivity "420" // Time in seconds before the server will kick a user for inactivity (range 0 - 10000) +set sv_kickBanTime "3600" // Time in seconds for a player temporary ban (on kick/tempban) (range 0 - 3600) +set sv_allowClientConsole "1" // Enable or Disable players ability to access server commands +set sv_timeout "60" // Timeout time period. You will timeout after (60) seconds when attempting to connect or if you are getting connection interruptions +set sv_reconnectlimit "3" // How many times you can try to reconnect +set sv_pure "1" // verifying cilent files +set sv_floodProtect "1" // Chat Spam Protection +set sv_sayName "console" // name server-side 'say' commands show up as +set logfile "2" // Enable loging 1-2? enable. 0 disable. Leave it on if you plan on using B3 or IW4MAdmin. +set g_logSync "1" // 1 always flush games_mp.log, 0 only flush on game end. Recommended to stay on for b3 and IW4MAdmin +set g_log "s1/logs/games_zm.log" // Gamelog filename. If you edit this, Make sure you change B3.xml if you have bigbrotherbot. IW4MAdmin auto-detects however. + + +////////////////////////////////////////////////// +// EXO ZOMBIES GAMETYPE SETTINGS // +////////////////////////////////////////////////// + +set scr_zombies_scorelimit "0" // Target score before the round ends. +set scr_zombies_timelimit "0" // Duration in minutes for the game to end if the score limit isn't reached. +set scr_zombies_numlives "1" // Number of lives per player 0 for unlimited. +set scr_zombies_promode "0" + +////////////////////////////////////////////////////////// +// EXO ZOMBIE ROTATION LIST // +////////////////////////////////////////////////////////// +// // +// Outbreak - mp_zombie_lab // +// Infection - mp_zombie_brg // +// Carrier - mp_zombie_ark // +// Descent - mp_zombie_h2o // +// // +////////////////////////////////////////////////////////// + +set sv_maprotation "gametype zombies map mp_zombie_ark map mp_zombie_brg map mp_zombie_h2o map mp_zombie_lab" diff --git a/data/dw/entitlement_config.info b/data/dw/entitlement_config.info new file mode 100644 index 0000000..1bae79a --- /dev/null +++ b/data/dw/entitlement_config.info @@ -0,0 +1,228 @@ +version 7 + +// Entitlement ID Ranges +// 0 - 299 ??? +// 300 - 399 Clan Entitlements +// 400 - 599 ??? +// 600 - 699 Clan War Entitlements +// 700 - 799 Generic Elite Entitlements + +// Number of keys to read from the key archive +keys_to_read 16 + +// unlocks in game - type, key index, bit, name, payload... +unlock 0 0 600 //clan wars demon_skull_p +unlock 0 1 601 //clan wars dead_ninja_p +unlock 0 2 602 //clan wars mummy_p +unlock 0 3 603 //clan wars skull_bow_p +unlock 0 4 604 //clan wars cyclops_skull_p +unlock 0 5 605 //clan wars dead_gnome_p +unlock 0 6 606 //clan wars gold_grill_p +unlock 0 7 607 //clan wars pirate_skull_p +unlock 0 8 608 //clan wars gargoyle_p +unlock 0 9 609 //clan wars vulture_p +unlock 0 10 610 //clan wars warrior_mask_p +unlock 0 11 611 //clan wars yeti_p +unlock 0 12 612 //clan wars dead_owl_p +unlock 0 13 613 //clan wars money_bags_p +unlock 0 14 614 //clan wars injured_octopus_p +unlock 0 15 615 //clan wars hotdog_p +unlock 0 16 616 //clan wars crab_p +unlock 0 17 617 //clan wars angry_robot_p +unlock 0 18 618 //clan wars triangle_dot_ret +unlock 0 19 619 //clan wars gold_chain_emb +unlock 0 20 620 //clan wars wing_emb +unlock 0 21 621 //clan wars brass_knuck_emb +unlock 0 22 622 //clan wars ninja_emb +unlock 0 25 623 //clan wars reaper head +unlock 0 26 624 //clan wars merc head +unlock 0 27 625 //clan wars body +unlock 0 28 460 //clan wars diamond division reticle +unlock 0 29 401 //clan wars diamond division camo +unlock 0 30 627 //clan wars diamond division assassin head +unlock 0 31 626 //clan wars diamond division savage head +unlock 0 32 628 //clan wars diamond division body + +unlock 3 0 700 //Download the mobile app +unlock 3 1 701 //Founder Skull + +unlock 3 4 500 //NEVERSOFT +unlock 3 3 501 //IW +unlock 3 5 502 //RAVEN +unlock 3 7 503 //HIGH_MOON +unlock 3 6 504 //BEACHHEAD + +unlock 13 0 209 //monster beast patch +unlock 13 2 210 //monster beast playercard +unlock 13 1 211 //monster viper patch +unlock 13 3 212 //monster viper playercard + +unlock 13 4 216 //riley / classic ghost head + +unlock 13 30 217 //watcher patch +unlock 13 31 213 //federation patch +unlock 13 32 215 //into the deep patch +unlock 13 33 214 //no man's land patch + +//Platform Unlocks +platform 200 255161 //team leader head +platform 201 255161 //team leader playercard +platform 202 255161 //team leader patch +platform 403 255161 //team leader camo +platform 451 255161 //team leader reticle + +platform 200 255160 //team leader head +platform 201 255160 //team leader playercard +platform 202 255160 //team leader patch +platform 403 255160 //team leader camo +platform 451 255160 //team leader reticle + +platform 206 255162 //insignia playercard +platform 205 255162 //insignia patch + +platform 216 255165 //classic ghost character + +platform 213 255167 //federation patch +platform 214 255168 //no mans land patch +platform 215 255169 //into the deep patch + +platform 207 255163 //digital hardened patch +platform 208 255163 //digital hardened playercard + +platform 217 255166 //Steam Patch - The Watcher + +platform 222 268100 //festive playercard +platform 221 268100 //festive patch +platform 410 268100 //festive camo +platform 453 268100 //festive reticle + +platform 550 268101 //wolf + +platform 551 277670 //extra slots + +platform 552 277671 // hero character - elias +platform 553 277672 // hero character - hesh +platform 554 277673 // hero character - merrick +platform 555 277674 // hero character - keegan +platform 556 277675 // hero character - price + +platform 557 281343 // Hazmat character +platform 558 281340 // Makarov Legend Pack +platform 559 281342 // Rorke Character +platform 560 281341 // Zakhaev Character + +platform 561 286632 // Soap Legend Pack +platform 562 286633 // Extinction Squad +platform 563 286634 // TF141 + +platform 490 277676 // Personalization pack 1 - Ducky +platform 491 277677 // Personalization pack 2 - Blood +platform 492 277678 // Personalization pack 3 - Inferno +platform 493 277679 // Personalization pack 4 - Kittens + +platform 494 281344 // Personalization pack 5 +platform 495 281345 // Personalization pack 6 +platform 496 281346 // Personalization pack 7 +platform 497 281347 // Personalization pack 8 +platform 498 286630 // Personalization pack 9 +platform 499 286631 // Personalization pack 10 + +platform 510 295430 // Personalization pack 11 +platform 511 295431 // Personalization pack 12 +platform 512 295432 // Personalization pack 13 +platform 513 295433 // Personalization pack 14 +platform 515 295434 // Personalization pack 15 +platform 516 295435 // Personalization pack 16 + +platform 517 295439 // Personalization pack 17 +platform 518 295440 // Personalization pack 18 +platform 519 301111 // Personalization pack 19 +platform 520 301112 // Personalization pack 20 +platform 521 301113 // Personalization pack 21 +platform 522 301114 // Personalization pack 22 +platform 523 301110 // Personalization pack Flags + +platform 564 295436 // Spectrum Character +platform 565 295437 // Astronaut Character +platform 566 295438 // Resistance Squad + +platform 567 309870 // Bluntforce Character +platform 568 309871 // Inferno Character +platform 569 309872 // Bling Character + +platform 480 259250 //dlc gun 1 +platform 480 301116 //dlc gun 1 +platform 481 259250 //dlc gun 1 +platform 481 301116 //dlc gun 1 + +platform 482 259251 //Ripper from Devastation +platform 482 255161 //Ripper from Season Pass +platform 482 301115 //Ripper from mDLC + +//Clan Entitlements - ID 300 - 399 - type, bit, entitlement id +clan 0 300 +clan 0 301 +clan 1 302 +clan 2 303 +clan 3 304 +clan 3 305 +clan 3 306 +clan 4 307 +clan 4 308 +clan 4 309 +clan 5 310 +clan 5 311 +clan 6 312 +clan 7 313 +clan 8 314 +clan 8 315 +clan 8 316 +clan 9 317 +clan 10 318 +clan 10 319 +clan 10 320 +clan 10 321 +clan 10 322 +clan 11 323 +clan 12 324 +clan 13 325 +clan 13 326 +clan 13 327 +clan 13 328 +clan 13 329 +clan 14 330 +clan 15 331 +clan 15 332 +clan 15 333 +clan 16 334 +clan 16 335 +clan 16 336 +clan 16 337 +clan 16 338 +clan 17 339 +clan 18 340 +clan 19 341 +clan 19 342 +clan 19 343 +clan 19 344 +clan 20 345 +clan 20 346 +clan 21 347 +clan 21 348 +clan 21 349 +clan 22 350 +clan 23 351 +clan 24 352 +clan 25 353 +clan 26 354 +clan 26 355 +clan 26 356 +clan 26 357 +clan 27 358 + +//Clan Level Challenges - type, required level, challenge id +clanlevelchallenge 23 ch_cam_clan_02 // Kiss of Death Camo + +//Clan War Challenges - type, key index, bit offset, challenge id +entitlementchallenge 0 18 ch_ret_clan // clan wars reticle - Triad +entitlementchallenge 0 24 ch_cam_clan_01 // clan wars camo - Body Count diff --git a/data/dw/ffotd-1.22.1.ff b/data/dw/ffotd-1.22.1.ff new file mode 100644 index 0000000000000000000000000000000000000000..74735854ddacdf593cbf31083f07a88b3ddf65fb GIT binary patch literal 21272 zcmd6Pdwdi{y7pV$J(nbtshLbd?&-+{FocjvLb#J;fPewH1n>fiP9~X2GBU{wGYJ=0 zKZ1&is}kK^T@*E5@PO+DTy=3p4Y+C$ltjgVqN2weiYqAS>ZXU=~?M z)sLW%(ZuZ*q)D=Y=3O_QAsc6#Ya~mQ(OKVr|NWB|QjC;CX~c~bjn4i$dAZ-WqB-dG z1>DU(ufMICR)kvIZLN`#3GT3`eyQ8n;eXFT2(p=(32kwSoz_%)m>C)-8P}t{g_B00D(#V`lxzgV_PNvzdEBujUIx7&YU+SaEU|Z{D zB;g07_(?xY;@2^mGDs<8`g*CcKHv`p+tPLVRPmUHkbJGAH|cmbkuH_w^}0Vapn^M6 zj~97`&TJ=VuqB7$a~m2|QXbd4o%kUq43D$WjyT#Dr&`aA8+wcxX5R6BTpZDvQqf_H zg~&nXo`_2pU6m6XC|2s8$~rEu^P&?Riu#(XY24~QCu7f z^T{ULX$Uq{x9M>>qXYY5O4i#+-iqvIY}cSTw$;thn<$Rq$`Ix1O^Yb+Ov6f&(V?Am zi)aBOGEo=VX19~WL^WiaV`18sh^FU=t(&NrFk-2jY^E+sO~jqpX?T)-Zo-*Kb|#xB z&0r!Wi>h$M(`dLO*F;Tw^rgNXH`0O4g{=l#7q+cvF^w$8 zhS9M^j3(QP$2wxG&{y^_i;6rH0M)Y1~QqL{MG7UC{4@fwAowlIEJKFj1H z)zCp%IabtZ*JbifWr?^hz&rHiJVc4c-!u9;A#;eGN?Ph8&nB;LXb84?-OZuDr`{3r z`oq5Z)~4d5<2G-bCxD578c-DWwECza81^-W{UK@$PypXz`0kXy87L5J!3WpU=%Zk$ z)n6a+)CU_&O_b*eo2lLxZ1vSQB~pFZ=k*3#6UowQOS-bv*V5!^srNbQlGY|)81tc- zjt%jIDdfSY8w~jCoBj3SV5lkB;-h74{`#ffuxABD`~lx|8dhAAKpi1JrpW+BT5qyi zTHhM-C53}+E#3$%_k{hPx`6LGvaBq$Wzo~=oMGO^-%Z7Z&FY8U+%9#2ESxANIog@@Go;i=k*=V`x=y`o!$i`{jv>)g%$$a2qKhjwlg z?~PU8rEjxFnYX^g+fw3zyX4PjM8e~;Y0X4_AXaCG-jruPsN(~d^Y`<$io5wku?DxOk%wcszeJ_5$Lse5 z>H=+HSf;SQ)%UEf=nJWEdBaL)bK51C1n{stktXNjTbPL~?yWb6-1SZVfY;qhyjZWb zd+&|Dh6el`-Ip|cRCZBIup!vka|z!a8_ezOc^&VHeo8D>iczy2rh`Y^$VXf2G%#VbEt$}%)_(}cQyou&< zok6R<*?cI6Uy(R_UR}_;s*%oeu2^16(W2zEHqZ?{hbL3iYF@?%Ajz*y3*vdFor8zLh~(rk469cay*M!IfH14=CSE8{;hw zot(yB*6EK?VYsasH|UHs1zQ{2S}xwJ`bJSk(A`uNZmt_mnQCA(C564d22Wd{^&Y*| zJ+6nBQLfY7)I!7fW=b}_+ru$Cp`d|s`9{i-dwY2aWuu^p9Q;nok*4;Zu92{j_~NH@ znLnIM=doO(FJV0v12+{@<|@oVGoKped~5>dc*k=S^GWF>#~ibfY|Yp%Gg9X5fK~_M zQZk<^CiA_o<7>_2)uhM%UUMhof9cD_%xHREGNanZ6meL~(Bv zmP{kM`B~T#*Eky5?MI6n^~GK6x3#eK{&*J1I3(_btwzU}(=sUrK+4 zVR;A!=4KRDA-@TA6vER>FZfti$X1BE#I=j01Hv}J=-N&slaW!;35>wzeUy};lD^fO- zubjH~I#O^GF!rG`w?a8cB~zLoZ@Ri6&EC=ag2mJfl!MTB|@mxT3t zWSL?iF@V_>n@O2Xc!o+BS-T1a+K?@jiGGz<8cwcDmHfjl(kEV{!-FZ9!z^TDX-a0! zb}2r@OaKud>&6v7dvddh*(x_m$(6PGoX@(&qs(xjzo!Yj?Hh^-7;_fBkk znf>xql>Oiwg5lP&S{63t^IwLaEKBtlw%x1c?@qgpI8dTapL2d z%)v@*rt9!Ak$jB#SB!Cc1NE3SCV(`wmYlQa2YF7_>}jLjNX|TG?u6O%=AB*Alwe+& z!2f28Mz6|S-aN60-jObHhl8s;S0?eNq-b=VZli5V9S}lqUL_3uR!6kgRyg8gdKjXmeN8#vea0hF_M^oL>0s0e%$)5+)zyH&BC4eS=?44Tj&n!GFsd%(uV6 zubNsKBd>@MgpGZ?K0}T zXvXds?XC2*c#qL*4|{{&Mjz;B{nF#~#yr4~Ro4yTTLp;x_rq z^4q!-WbT#uJJN3cn*5IWHwIoa{Mjfqhd`8DS_3}!*fOy3FX>I^n6Y2d+s?A_U(!2j zvB-`tMXHuQqr9V*AX$x?!R5a2f9c=Gy}W~(C+S_a_#_=hO{8k+ZspyalHCfwFzYV@ zD{M6IBlKJ)NdBE^dw5I6%k(Zu-&pvYMKAKEbaCW%H~Bov*OczLs2(6Wketmwpq)Hz z#GYdm0z&nE?I#MKOh@?;?Ablovsz@?Lk|vT2k(7v}OeAAO`;69ze0wdKEW-@s95#j| zy+w!IbEu@ZNCr}ME;6X2L=6Zzs?Sbj-VV$azw?HEmJlwB=O<_%x0?E<2>NluaC}$$ zEAhP@rPs~f<@m+z=KnqUEg5fVX9bR4;CIYDCB|oS6gCCC6%M{E5Wu9=}D5UQl*|?ttIg2GUz>f z$Kj07SU}`&Yzfs9=r+Y)WnBho136_uGB>eC+G{&b2{<-k6B7W0r}iZJf>iDzOO8$< zvrE{QZsRBHVTeiY5SUI|D3v6hCFvrz|%>u|B7Y`jjAwSnaZG6`Gp)L zCw>aFL&2tCAkr$BGq50}0tJ`qDMc5Ttxa0d=Q<0+J`JY2Bd<=JD@3ewr}pux8yuRq8~+D8yXrafe-)|X8$0&1ZF59-4vP|-*?aCimXc^=m7)#>g@c%~tEihFI2oq0g%)2X35 zV+a3rT>3G$1h4GT$-hfb$&#(v#6NOle@5y|;2UF?JsB65%^u9>-LWxjQtR7_wAwFj z>L*Eo`sSqUVldUM3A`o78~^N#gqOv#kHqcMQP^s>Wb^763%Xw_PX(DOI&S+JCu{Vz z_`?2r2#w%L_4s9`Ql)#v^4DWcJ;e{ly53p>+7-^8BiPg@MQ)8-9*))7B+t#e>yieT z64;l9hWUBsIeC0fZ0vWMpVjeAspWaijh(5~yB@4*KG;zMjebN^O??-Gh&i`-Zv+vF zwBmQ{zNLfvXg2>oNxS1ss;_UT!JM|3Pt?1}V|dstNG879;*thhpq7ecbOX)gOQ?#c zaP68uC_6HAMdRlQ4*5}X^i@w`M2Kp2op%I0tK7{cW$u(8wwNA`IZDtK-pbU_WV7JP5nPDP1U-R=A}mR|If*~s{I zV*HStZ3cn)>e_p_g{3%_O|E9P8`0Rd$%|NKFF?)j?no@kU3`GS#4WZ>X$SQ(3ci!* zSW}))&b!LDQ-bZXt&;6}Bc@m~bxXFLHN>l>lo)F|xVWD+Sp;k1wTce+QSf*LhT1`i zPL_L&oyD&qR%I)cr5o%ikt^vwqp@**nF0FnR5Y<&il;@%YWCMK19I0M+5ivQ7Qu2&ULc4j2Mw=E21O?t? zTMW6+0Y6v5cM(AMiR;Po?dN(SIbJD) zaAnbl9mo$5rfz6}pgMLbQzJ|?TaYE#OR!V#P%$ixFui)?DZ-RWSxoRF+m0G4=rQ1_ zZYHPL%YzwHx~V3#{u;oYDan8_+1kQcUti(F@+Izcl+Q}T(LWSeUv<#)NRlWpCP zN-5ndNhu?HJE+oBL6z2BY43EI$c2Xpq69Vp`8##?F&gfwtX7ys5jrnu694)drc|+f zs%%x%gS7@lDOA+^@VG9p<4SO(gq;?Zh2_i_J9kJ66|;6HQa0Lz{NxQ_;;;OUTwelzt=FipHaA$Z<(k zF`*TOI_&tx+>A3Ii}E2|es|TqWPR93Ucr&>pSIHAeB}HNgKT>W!2Tq7l3_4Ux)ORm zLFUFQggyRt8re7WP->1s>#3hBJ<4)9m=gV-S-M(J5hW{#(s?irvDI|ZtE!sP_xiz4dbhcYF@47Te-Edu!V%w5NncE-(Kd~dp zWZP{g+q?J?_CnD(IG!?h;vK2%qJ4uzR$5De)%^nM)zmysh^_a3)^t1FCO)yfb&k^NQ>& znXw=-!LcnL<9PyO!8l@LvXFYjNQHbs>L}a617h~$js%@^!kI~FGM_jkMKG%Qm_;(u z5>0qb>6P1Um;`f1%-hc28{#NPudXKBnnh$=hnvKN=G;*5NxIFpGoNg`(M|7W+&;QO z7q;WrzQHHWMj{i3&5A7@8`=|6kh5fD7n5x>(aU_4VE(gtu=%kq!?p_B8f@#Z-H2@i zw!5%x!L|*fekJ`eh+dcFSx1qSF{+8#MnE+v0fF33qcYdjkb0v~-gkD;P=3o32P^Tu zpMHEFeL&{*+X1z^q=c;?e6P`4xoYdC$Db6l74#he`S1xOVLN6hT;42xCNO6j7t<8& z!8A|#j0T9<$J7%eVm)j>e_DE-z0N>kUOUahKB2y6G#)0{qStql_RkaC4v3gvqVHWV zNEj6B$ZKpL-6xyxPy~H2Z@?laj$C*@|HmO5J@)M?^QHv6BVt`ecV$Gs4lX|{L97rr# zU@z%-_FuvsJuo;CFwBSDT1nWqCG)X4%&g}(->c9=&FFvqtXak@&d0i zzIF#*bc4CrhE8%tZ(jeKp0dIt-QhB-sknV z`j-RAx5D>wf?nk>O8fcq(kuU`|BL^Vta0q$>h^1_XnQ8!X`lJ-EcE!CAV&w-Yvx14 zK%QUV-wZt@gYvvK97oUbPlp|1Uy`)006o2GJ~Uk8Pe+HnVLVQJz5aFc$wcjSTXL6)SwEGiK9A0H+?jy`jgu{8`BvRI z!@)E-e#iG1H?W5z&4E))OEK?Z70u1T(G-UdKFVbJJ4;L2^5f zW7KOl8MDZ=P@`UNCDBkajn_)XlRQf11X8u7S(Y9a3WNmjaa;M`)z?&X z9lc}n+E1<5$@<^QTLm-$aViJw*eJgu$Wui_!-s-PRghA&x7;y^K-mhLBR^qKKlQ7f zH1bzt;Qu#3&vP8Af}!}qPL6jkK#_pjj`TB(lovPMLK!m_3Cx{nyME750c^9+L-O22 zuuTnhXMMkOXpVK-bUurv7d!(1{WTMVMB8?FHY78rf+ zEGv6umgLE&HCY2NJ?$UD^fTu`u-AMWGW%D6I`xh)eoX%!PVW*YWlSv0UPv-FkLt76iny&dffm@x7j}%rFwTVL&9al1V%3bM$dNq z7@`kvuWVxf9HhV6v2*X<8sP5lFz)aAVR~No)H1pPg+GVsmR&?wHE@hQ2g}<6&;QaEcX3H@ zNzvjtM-9f{k{o<~aoBB$?VgD34#sxhXuG2Hxpop&C&Wq@$9Ah?yA9ed^9jHbR5=(c z{H9hks-}Ow$e_yW7bi$KSZoK{V8O)zMo1V+aE(DdWBuYd1qa`VgS6lU;>?eG5;KG$ z=jwgun}bVC`_3QS4H$lKNk-0ueHVy(Ko8iN=Pf~DW^DJR@~6qBt0yDPo&t;br^ymu zJ2{mNRyybJvjPo9>~g8yjj?3@`_$1@Y=b zd1P{>bIZju?6HD$b#Z@oU7mkghf!TN!`_%>nPGRPZN-VR)Y2Kiok-BAc)5>Ej`pdg zQ(~bPqKPriQhH?aTHFa*#o2+s$#svy*qRyWff&&Rd0SR)jZ;_VEN&8QT&Ru~gGGXN z)zO1SJH|PhmSwC}-WuziziOa7U7aVg_n(9-+2m?$_^PsO^sAN7DO_@KW5XSbGx%F$ zqtOQ(*7h`V&TL2B18Ui_3=&EIz)|6)O33*)LOs`;Jvowsh7fUoH=KJUZdt}k}bE<7$5UdvLvmibq=8`P^& z^ME>LDee!6xW6&|_who_m%=SYR|s?lq$9XZ2>_ds?tBnM+DS&OB68BuA+#n9>0JFK z38)jJ$wD3;GlXi}D`P<9MB+aIB9(>0pL;BE5EQ{fYyS}z$)~wO`vv3d_a}DzkX3kE z%oX7@S}e^kg!`N@@ zEmRxR29rq|qz%>`!Z$k$^OwgVC{v!(EPoYQNl=YnkOi}+tBJAQ-l(zL3;m5xv5eoEiOr_7&sDA7}Kp$iGz!Ys6 zzP$NGhcHiv2e8LhH|F{n^e8pxEbR_*E}rwLK`Dkq70LtbyDkYLjJg4ao(U;K6hMX% znuJ#HjVO>@7p8FU4r5d-^Uyar9!wc0=o)}gW1tRwsPXY}t2`}ZIpYK_oUO8N`RVtaPv3=OGB z@OO%K4{J(`!FqmwHAif(W)U-4)6vL$m!!9@)k<~Nq+3l+T7~P>T-#j7BU;QRx_kATYK;%ff844*s!~D@7@PsnmSza>J1y#xZrqPnpG;) zcxN|EboA+ttvky`uZG>t&@63nNAWI1YT@|GnB{e>xfz!KiJO;ZHKrvm%?b+9I{$K9 zd6qg(7-A&C5RdCO#G?B#&T$&hI5gHd;+E6peG+8#!w;rwt^>L(LltNuYIgMi*Izf* zG8X+U%P8)sLI2O9|Bc#lQQnc;HyhMDmSr^YLt}w%#tZO)q#t~s?4_x}P;tpyV`Bg< zcK;Z|c%Z)Poj2YQ$VxPy0)uy}X#hsW>U05*qR~%y^}=5}j&H^tj@Sasr&<7JE>tH7 z1cju(4`g~$N&{J7qRQ-4m{8M>RK7P=kK?>;`Nzxg3I9xbHX%6TSt(n&H{F?DW3tFf zRhnsbntIT}Ov;kX%x_!>aDw7Dp&cP{N~Ur&BQL#Rs0A%KM-C%7QKX&QMqZbEPhR@08m0|& zRySSIuS|EMZ3{GsQQK+Kk928h@bNFnmm8y!Tf|2U$jn}Zfg-Xcw(j9;ddIEl&R^4k zsP0r$&mblFgJIG0oEvIB7?$9C0%;Y0E-zVq;<-GN^NIPsJn<&iIw#PKYpy?@@{9iB z#;~s?;L*ZUvBJYGqMQz1E-sC3)g8N(-+xUkA5DsRz+>`GEW)}!x_Uqjx-aJS{sY~W zkmS85!4}$-!2h29;?_aoQlF=@ppU--T2PraV}&OY5izop5en;R zq4U)`k<_=)Tz*x|L;rABzw=$Vz`ggU@*;hubl70HNq;ATs9N13_V-r(IrCO5$3SV3 zS|^hF0G-DlH=ciI1fFIDB1L@5=_0<2&SCEnKbMV(@EgXf{DnG zQ&G;|Hg7!fC5g7n3$@i%b?)}cpic`L8v`Ntk;*6&QP_2GWZ@@(2NY@gC`D`XArFGy z{egy8bjp#Gcidio1mSB~wEzvhAL(y*dc4nOj%VkQ#~Eo3F7+kQog#J)pMs~cJ=Lrm z?x=(l1-EBDoXT-q@z^yzn^M4X?IGu?t@e=4oECznnCl$XT@78?98? z^_rlVJ%ms=6O)vu9F=Vsc1j{tTF@zbC{g{PMlzYf;(yhksC(?81O*;8l$&bdy$|L5 zuw5M0slC+~lPh_eLGdn1VMU9ql(#^Y?4dMOv4<88>9U6$_Gi)fv0Zth{t#z7*+Yg* z`xi|%hb3Ud4PE|c*ho^(v4^tYNr#m<(GsWRha4wZ72*8w9q=MA{HsK?>(XXitA1+_ zyHD9I*r~lJl?& zw~^oDLevu8i|S1y#9rG&d!-A=@#xeZMu(WAv#Yp;kzTfkY;-gT+ETX!rmt+*Uz!1E zcSxpMqS>M0ol}ftgb%uXN-{aSch*qCwD!tEW)GFM+p6GjZrxLzAlueK$9e*2QV%Hu zPsJWOhsIx&mSzkwmqESR9=i3+qw}|yuNI@RsknHW`55W#A*rT7|IK~#rcRk%dh)(# z^g-zriOR=GMJ4-0xXBo5e);w~lj9)c=d!}lJD4j&uWj-rht}Mc@ z^N+K_nf$}#L=@MgoQg>s|J1Id0Xoo)) z$@qA3*lFaEKQ|GwF06)&d(uw1AIo-1!!~NflP*ddW~ZE)C}7z8u^)>4I_%HDehc<+ zsOIdpQ#t@O=8<$@^6VYh1CxuxG1|_OZ6IYOtOe?5pg)m zK4PbQ%72&{yBUId(9Z}vt~eiK7Y^R6b=w)7zN({3F}1Tf-@dzJf9iYJ6EiO8=9aweMcr7oGX^gDT)1V;)5+Qzwu!a z%_W?|2M4^p|IIXS@AL8-1CHZvSqo?VkR6OlgJGYB@=hQefM*_H#|Tc|LofG#PZ|oE zoX)?c=iMS)J@Of<9b$(Ne4wGB-|64vR~Qbh*H+4cu6|AX<;(N%?H#8>=54wBefB(W z81|;-s4k6-`M=dSb@!*3Cz~+X7x-SO&)h8`plSE#2tpX-z*fz#sDW?z8*mc>uzf*? z(CwT20DGP9x4v%;ylUk=QXd{dAAe4IgWeQ3`-b^J8-Us#WZ&c)ll!E%#6vk~yfy{* z{VHFZ@`lta0jnJ{FCT)D?Gy3TW`8RGfW3@x;kS85N}sba@SBu3Fi-Qfh6DUD`E}km z`E?Y|&VP>|W_|QmGGCzw0Nlsc>apC1T|P#_P7*Hb5#uJ(vKQjV%6E-Td~X~ASdwoX z4<{VM5|s%&PO25Fo0Lb!i(ueIQ&z*54UH2~wDJTkDEOJSI(G~Q`@&fiPYXy%X7F&o zPiS9wxC`QFFV;cX;M4ov#Kbf@ZkdEn1soDfU5LuDRbZQjtqR*jqE9EzpMu=fB}A8v z!vs=5^xxx-({z;0z&0A&c%rW-(3=ysjm5z@Y!it7Fs`H&(J15SmT~l}aa1{xo}EZn zPoRWJCBupSIFbG|q2^3ftGJDL0Cc zVr7XWH4xNg0QHf1ZMMQ22%-E9fg9-3a}XgDTv5cBjTUMS@WMgDv+k{-SCv1t;PHy^ zwdRVq9#hKWGAk;Fl5##>AtLRtK&j%Hgc{)judv57=6l4NG!0{R{4n$<8uQ>Kn*&nw zPhH?woA~>uwdN0X`9ddVxtFKGiTy(==Dy?~EQV3=|A@Z{Mh)R=BsZATOkm-qW!4_i$9N0o{+q zo}LDaD1a z;o6i7QrPMXtW;oCrBjipR^?CU;~hzZB2g`i2Bc^FjHh)W>U1dm!Tu~<Nq%O}%f_#RH4=1a=mS^&Exl zyG1td`{%(ItVNy2AOswYr)32fQ6l1ME1R`t{QXcw^h9khka@?-4r7MAOaTBX)K^Y_$+@;14=*x z?joTpg9x;CF)#tRwDX>N-7Y?o0Vcp`j?QirQ)yb61Tv7@{=kpd=RL||F{gXkAb<8T zWyVGak8Npjk!93x#R^yE32Qw?AZ`%w&*?|!QO)3)*kH{hbYtI>_@Kb9sZ&t+m9KHJN#?$;b}GE02nEIwi}e?X)At zH#WtiCFN4DR@lGmuldWn=~-JA(diyCj{vpp@Mp#)H(-}DLhCm1>;}}Z`9X!2ft8?> zLyf67!qtvkf9F|^@RnyaGMqFWYD8)qkw&Q{-!-19qqF$|)0W{w#>sWaq5+ZJl1ACv z>?94erHeJ0IMVtI@EgWZqSZ^C2|B;SpPRD|hH!`f)}onR`2KeIHx$L~JS>Zcim@t6 z(df+iNoC5^GE+erpIVlpd^=j~Y};`4)G{4^ee@jud})CHtt1-#qx7IzrQ1eU@m@7s z*{x!ynHeMpC5E zT=b~uWPkPcH}J3xXC)X@W@!-e?U z0)P8`<(E}1{u;Yjk(NGIdOc&c2~H;N<_rY>W9YZ4Wn!dAPLK3u;Z#5CSA(vMZiQdH z2V?D4d5@}{U^N(D^|V{#F@4-k+Hxogg0K+mz#wb$BTwf)H#ZAm1H__bO!7amIJY=( z#*6L8R>$W32P+?bW_9k4Ssko-U{$0HvODi-QVlxoM$1*OJj2D}ZrI9nO|%)jO5E`= zgdffFxK1w;ABd#-7cI|Nge@ZWvwEuQ^b+www&$b{24{A~f6DmewPU${zwH^kT70na zaS7wInGF9g&fMOuu;FnN9JD6j3 z#c54yz$DdZCTXLzU@9z>FiNMs>t8lX;%iU%sZl~lTHJ+^N=BI&fXjtHGEK^1c3v)C zJ#5o5qK0YouUIGi*8s7C{HNBbe@O(mneIf2SP-EJFj}O?AdlxM6E%jCC1t2A^h^P# zuP#M!{2|HeeoF#Tk)Mor9@&0ErxZg?L11>=6PQesm`jsKG{@#lA(KcbfECaR)`0fL>G}gf-Hm=+m4v{Vuko3ibtRr0*uJcw3C|MjzLRy7H@;{qV71%6p_JLg{w3Z zZ73b4DR}x$Vi`|q?pxP@`_{ldGCOBJ)sBZ3*A6#U%wpyQ5t0gix|)0g4Fv^9a1ytsNjRG69j_@k!ukrwu=)&1 z`ZOK%5j&jNor-haGhK>4ZKPdM(iBa}sRrHFbt>>(lUj6`X%f>YyQJ-t(hek+LY_9A{^Sb zGcjqxs$5tpEgV`SlSQ6w=On>*5%-@XlX>ZjSe&}(xRQCAN#3aZB9mOD|0O1wXDvTs z!pZ+Ik+ePDoca?UsrG)4e||Cy0NawSVJP!IhDIlcbR{^4r2Ba{Ki=p^BU=!7@M9o?D9cUdht=F3)uc|2RsL(gGov*dXk}E9a9kjBhU0g+7|L^~ zSx*(oSxG%A-&DS_606&K)Z5f?Jpfcl1fUux#&r5`3*rj)XHOSaODo*)!|?xs*5NJw z>1yfEjlBO~Qi;gAk9BoX^=DpVtcvP)D8jAjt_ypXVzrC-=ZNm&QcsX7kF$Yw$o+m; z_Ym5rIh9d)DXOj{cLg+_%ZT^Q8sVIhXBc^f^Y&E3NV!0y&Id(SOSN0E^9P!cDLxH1 z#qkA>wo!Ogn?@N%*3)>sn%+0-0f83{BX3p58%8pb^uM&eS<#oZIEVwY)Dk)7!t8%? zTM!Dd`Qpo*aYYAaX+?hnbWKzN&+!|=I?QyJiO$&zIq3nHTrzs}Z(b5WzNBtCAldT* x_=>A8aFmb7NSeoQzW5S;*)@Rf69n)@(%(Nay+1|PTj7)MRmTgZYAQ$VWf^kX93BJZYyoG zwuY?wdi{UU9>k0ub`*wXe4TgXobKANn@0nCm;z$ouXX3dkH~xE511m$6t(6KnnF7X zlGBR0LOL<+=VRA`;A^dwIsnxQedHJ%1+*a0?(5MZ-h7cf&XNVoG)Bxef88;CkH2-xE~hIFQQ|A_D7$4}%j7E#}CHk)%yo#LYaOJ(^LhCxR4^O;@@ z@*DP%@mIS?7RqOTEH-$XFuVa-(X2fjbw*$_w&ls{c4bON4a2}VRNK`-}na%excZofCp)*^dtMl`!CX)a90U|Y{N!%7sYn#IGq zGuey~hDqytbX~p&)O@OoB=)N0-)$9=rdqQ(UCmU+Ij8wftr>f8WScr1(^OUWKyK}G z>>TY;o9Gh?)xB&>bE&#Uj4@X~RL6i|Tau|pMo~UbZX|TJ3M;Txn+9jYZ5isp{+8{jzi&m|ZOLHvH}ggS=zR7|eCVawGdy1bvcx zb$!{)UUQU1%PB4Q&f1~<6YF1u+781o#f(bbd_wT*4+I&TST{4@GlogIo7YXiyML6A zEY(ix?%(MQ6E1Ni;0S`cxl~Y~@|OaZ*O&p>Lzp{#{h(7$5T;3{3I$zMDYC-aA?E)F z1b8}RLZl1@Gq#E0>-wSaKlaXJzi}i<@#e|`A(18fqp9&GMW!fJkpLG2 zr7m5@&#d>}``z*Fy=V6we4~vNl^v`w1f*WS8b6T%!@&1Pewj!>6BDnW>q85By2|Or zjRVt+8@<*+qZhTV+ih-7l7Uu{X*OP+=7AaJ^Y>qWoMsn~uiNtZY<5+J@-NCa%h$`N z%QwpB%Qu$4S-xV*XCU;-b>c~$6n-!K4D88Ce!hNLng`cGycP#>2w~X|y4Nu*Gj55s zJ&rMk<-{mf@QLGK$#Ab&Ck$b6njy4aliv?P{QZ7gP-`+R%!SQ=#osipdPuy-LHHZ9 zL6*C5GD(1{kAEC>Jotv7vy2g2KmDpG5KA*`x+BX}Oj}@#>fO!PlJRV%8^;y_9(DYjQ^zu8)@02f>ua-{} zI@pOaKp@4)gqTQT}9B2Eg%IV;$(UTMR5!5|^V?1{`kl^8aW*$fVLRA>Cf~ld1W5J*3V=rdl>1`VDG86;c^f2Wu=naD~flN?8iqZrvCp_f(O)3Fk;pt%*?_ zvI#`3r~)EhvKkbfVex81^v{6Mw;}v$`R4N56romBiBL;rs3k-6Ans9&TG5uqQT#;? z5;jOAVGF4@XQ?H_1VwE{3Qhkk@YLD_RJbO{k8k_N>FE_OpTO|SL4V`S*>Q0O?%kzD zf|d?5y!BrtnNJZaFDzI`2Zg#wuO0oz3D8&O+7FrrpsKaTaF%Ok`)odB;Sq~e_OV%d zD%}$H;2cZ@jY&RnLvkZn{JP&$dNn9CgH_Vv$LyZa9}JQiq^yqOwNzMgOK6-x*9uqA zoVZ!B_@^Qn74&X!&px!_Aa-ckJ%A-J@*yL6%9;pMDDHdh{e2T19qzO{2XT|2E|dZR z-%lQ0BttuRXdzTwY%{d~5lDWyd@28T+>0p2F-N%1 zI>E+0M(#bS`-31S7NhIsiU_F~!NMFPp;(K*WpKil0Ze}lk<4`;h$@xM;6}B^k!A&D ziPo`#H`lFh2KCHpC4b-pt>gnY%9_`%hP)*sh!@wJ8E*2bWE~kv*hZ4Jz4Eo?Z!N#GZ3tm_2nLpq zQ?42h8ix!kOhl;GV_2WVw$MFc7>UAP&xpcZBT(xxEXM(NVo;60D*twyv2?Y4K&en> z9(>$CZAr3p1~jbqL&JC8j-->kQ%buKz|9^-l|IB}$Cr5Z^LkjL{ zb%wF&&@|nw$g{_U+m3^N22x-nD40)~4?yp+E>3`^zKKJgxQD9;RLHL6snX8f1}4qn>8Z6* z(jUE7fy4_~pQKh)7a?i{x49Fn!A(mArzMjk`#}vJ!4G1CjF0FCMSxl=L9IwdNVbEV zqWW%7_j>iM;(w~y%Qu+4j++hUZj;xW+4;GXW?j2>d~Ts(lw_L6>$sxWKyeNShdpqA z$5S}9A;XV>8fb{T)& z#y)p;9Ra+KNL@#K9^!Yvon41JyACII$MqXeWFPAgHepQf{V%U@BJe?zaGmk&H@SkF37QbZuxEI zq{yME2zPcGY#G)r(_k-R_kY}Qt$sZ&K_BD_#3&XCcZmYT5Eg~c<3ct5jHwSc#j*Zm zeKf&Thcca;)twNrgM+~Y~#WLxda8_0*evPDh@v); zBx`9$L^}90N456&!@LN(`#~e|-jY*RN;k z1n5Rz*S}sL1%Os`1LarG@mA=*r3t?!D_=JCviN0Bk8v)4+0jb?v@`-*k&J+B=NSde z#NTr6w%Vm97m?ygfeC{9_=W2eO&6jhvos>XIiXba85xf$km>g=42xorU% z){Lz=0b82@ZUi=V2trveo7g;T51TW>SO%jD4`R(dpOfUm;=jgmuiuGHuN9k}{l+eV zOFm6Bp2O_qy&rgQehQ86{W(MHPl28v0A5coziXD?_nk=j9Pd8ZN$~!ow?iR{n!=3h z{yl=v`j%K+Ov8d=lyK9y$Ed-*A~G1l@`T6}75OK|32ch%k_v5UD>Nt$sYo=Ar5q*OfWm@5DJ?>GK;-s8g_?r!t{H*fQ~8zlanY!oz+?f>|v!*@@I@170^ z8Gk~R@!3=w(@wJ_Er@!LeayfGw8i4bBW_oG#;mZHAZSMgTe$Ifp0bSsC0jl4g8we$7VWD9~DfAe^b8Y z$C}~&&bO|_`0DbzREc<8KI}ZE3OweM*vCg*Ccs|I1b8fY0}MV7gl)r@D`Dg3m!u%kw z6FVLUfqhC6*l3H~H^dV8AlDp5*Q>Eh^o9|v!DXQ2THvj(Y5MIs6$!K)HSY^-LK~!#ph1P<|-_55)8XEkr;VLIq(A6@($I5Rau6 zqeMg)ezGJ~Mi|0UG&&(fs=!}~@S6t>tz?5T%HW`98Pm~G>P#2n=9b@if?b)pf0che zt@W{-zRw*`sSx8NHQm*FpIbNoS`O^ANOG=KJ+kJqwQIC5POXYX0K)x9AN&a2|EC#L_`U@PtIqot93u9{ zMICOc-@4F2;R*U%7d5cZ-@cIRqQh{bH{?_X^cOGuHP>Fe;Oh5bRsHJwMzZ>`fxmm9 ztDnDpfnlzG{e3zW0QUX`1K=|p0RJknO2BQt2qPn*e^#IlA2ztuC*{*LDogD9 z0*s~43Z04Gm)vOGosN*S2BZ!^_1A&u;OJTUI*@8&^z|Tm^>kWpwWLqxgq<3vL|zag zQPPWgIwta(5SbH<^EDwVCu~&+hB+z90zj1%vMwax@i~si*;K`&{wy+QLzqym#YDYn zW}OEmuX@_K4i(x=v|KTjhucn2t4QE^NjylC)e;UcU#;UH&s>W*V4Tli3pn6Oau^`W zSx{!PbrznO*5-Z2=MjqkgeNI?Pg3rlqzLodch64lo}GM%XD5=R&a!;ysG{PhGSi*s z=gGOH78jbfX1<9Ds+&!7dk)*U^wJv0Biiy?F8=Do~x;U+rR$ z_)ouNfXi%@pemyEP9$jW;nqRsizkoAx zOrt+9Uj<3Nxdqz%P5+F+FTWAz$jJ$yR{0eOt^5*%7J3b~4djGIx&EP*lz!Vd+>%v& zy;Ugq`eBt)6P-)HQ!4g$XscIg1c8@20I?E&^{Tb?KVTC6MoN@r(0~wKW|Nb|%_NMz zylNs8VRRj#RhVFdsR%;Y1AE4Zao*3*eFNoypCodCQA8j_g=a#3M*JCmH~#X`!M%1I zx?-(5T;ZXKN*vl&_2&A2b%U&4wCdJbg` zat;!_g^a@=BQc*a@Ha||;lu=C|Bw7TBzJ#@Waw5G9ZdE*PuFv}s|BMjb(6=Y@TXT~ z=IR5J+s5o9`KU?Bvh}E1dVBE%)aynrWy9d*qFr_W>Ncn`zwrEGJK1B{t;2fsZ$v)%cyKT z*RvSqiO5(oqcVPR;>0=Xew(&k6?3`mUAX}km^qGQSBQLMyDqz->r53Ty-=)wME$&U zpgo;#X-Mf{sl~dW1Zr&V{mZ#gpsQj+RXx?O{KChiyVM?CxWozELMbrYbblUkIs601 zDHz+HE+?o=diZH6n!uxe@CbA_jA{3lZ70KzO}oxiI;UB<>-uf-E7|Ctwod!rXxV3M z+tsrvJ@ZsI*O%%WRpaLGtsi1a`=VfbL4uABHD;m4NnfGOIiL15uD(T8X0@?}Te3m{ z7{%bK{mM69IJdU4w6=0#ZRNGKr4QFuURqmue{K1VwUsv@Tz+1hF32%ZSLWB<;CKVzbBd-# z{#;&KQG|UDdxQ1~74m+3=?TAO^5vzKOOL_q{nC?)R1J^Ot)G(`>{X{UK1XF@$MW2z zjc!yB!cA-C44<-(3fZ_-Naiqs16BdMECe>{(T;4 zm5a*w5RPil!9E{z?PoHKVkBzcopm|x_HqitwuK0RyQg)z#}@ABpbJ4~d%8nEPutE? zqLv3~`QaUmB(*7*j7oDem1}2GKSBI5@ngt3xiKluXIv2#Sy$&*F1rTt8TlH~8H;)e zU0s;`j{0@0c4bopsB4!jp+=Q?W^01d8b>V42&()Sky|ZhBo?ugZ2>CavWtOq&|})tBM>$DRaE77SpNjhg)XF+gmjdy5y7&xm3+)1lz{c1w z!3N4-Kfl$mc}xTOHcuza6B4BJ=~E&%NL>O1Xfj%*=aQk55q1{(dwiW{acwq8wa6)?Nq&N^KO z?cFTT=&|Uc%&FZsL5IB0>5ri`c66RzVR<`EjX0?DS@35yb)%HZ1J!Op;7pInsDheC zEuPcBRb>-6fts>yPrzeB_egtk!!4rm(;jP!;wovITHhe!8q}TE)FM3?(xooOuA?U4 z*?8*NZ(n%>z_YgU_}a?K+VbhO<$rSjKD++=Kdqm9>U+cNH}+d3_13JXwzFVt|NB`~ znS=Oh#uR-;klt^>M+}(UQZ=b1uJ4hgG+lq+4ODTnP8%EywD*$%W(dd``7b@HaP$&4 zgY0i9kiSu*c>KU#0Llre;N!%l6o?pj16lrRF$9}9AFlY2)q{#;{Xl#Y_=Vh2zmR$K z7edefUMThHQrKdVSPlrWUlXuYEDXF_`XAX)B}@8#Tr9)ndiC(vY8aRr@l44R5!X$`i#E#7s4?a|7FL8 zSX|Vqjx8+ivK>DsV@X)3Y)T%do~WHBoxn^l&c=xeVWibiy*w->Vuuv?P<*VlZ2DdJ9BL+WY~53a5B>`SEglwp z3fd^SdXM7s`WtV3^XAEow@=k3{`a6ITz*0hW%Z-_*!z(f$jz|3UB3^Bv-|Qzm2@=` z?_XY-E&7Ypx&WeTVY8P4s(@qWS$W#jnmp-eX&gzPap3qQk>2OR+QO@k!x_6vPyD@# zTCPnf)wI_*p+<(##x0kgiZJ8$y}D+?`{fu3?-$!bcndnO0Uk9YPJaZIjcVSGn?q32 zZHtNje=R0%L;r2){~kgA?G2~f8%{sPa?hV^6x&TBjyT>v;uu+~9iPs#1(oHht@C`* z=}wOgo)PgPmM~@J#J(BoSm|(yb+D18+7ar%>8q?#U7fb+FF=zkuHfQz1yc;K)$WED zRNv}}t;de%y1?_*Ds!bBxPU$kOZpb{NnJ`a)@Cd>>SS6W^{2)4C`jr*cf;JqQ>#$Tsg^ zL>FaaDZf6lC-dC&OhJEUl^a2Z5~#xaCl4L3)q_8U$uu#n{?1Swa7L zZRH)Om_6alo?nL^80OILLRGu`(c04IYU9bJwWU9kI(Kd9Yx=+SNB@zSe{Jarweg!5 z)|Q^dH4Hx9tgCo0|MtxK*Dp1#(zgGn!HSr?U;X7V)va18$=oi2doS9LU0dorb-q8{ zCSiNVs*B5id9>Y6vx~oP+X>ZLRQ)7t(Ut)f;x{Uy3$^E+s{diqv@g+e&2I@n53gtq zMH>Q8#?#jWas=I@t$<~$!n{)6uhl-GyD6u;fihkB=1?L0&50TaeZF~LA+lr}{|mmQ zwDpZkGXMFK%P}vN9K=#aA(k)=v8V<_EMg`SqSinl$cTjuM=Y!JQIH8l@M-SHf~UMtAQcO1 zRK+p|t01bg6=!0+`Wf)5M=vHVtGIpq!H_{9*5tfShl87n?4GTJSa`CvZL3Q=uO(rL zG)Y;$Kw%sY`Qd|m4;{bnpg^rb{Q|c3_vXy7ACi|zg+-r7r}SEqfW;MzGKTMV-E1+{ z^?TUZnBL`-PQ2$$LYua8qYK0D!Kwe+zKn41lqPD*N7=xaSyeb2n-KrxArDuugrS?& z@k*HBxK!Q4oSo$+SMynkR)^QBOgU&pE=q+8oxUj}E#cv~%+S3d+zJQ`)xdU!CQGL@ zPb?eZxI|syA?Vy$&+rp5s_l!+MR9iZ3uRM0in7!rE#dJ-e7F?gow1B<-VDa1^pI9R zEkowJVO(Tfmi^PY^5e(nFG^#ncyBvTig}=?$?GNeD{r)ORU7y+g95#)ix4U%7>PKO zlYAEx+%;1dpT-Y}Zc~c*&Fr16Sv@a(dcwOXB+gkG{RO@&d>tm>m#goLE2k;@Z+H4n3Y*TY8(U z2I{~;c|3C{STDp*?EOfIa=mS`8Wj9CrN8df*QXr+{1fT1*I$2W{Wq_vAJ*^mw|Ucs z%ddWL`STC|t{G;>{1J+q!Y|N1L{ZLKf1BNTXl5a>Lfn+Nk|qS$OVlH zx#Mvm^F%I$p2>wUP`MPggow#ph&`JNDbx8TDf77yGoiD%#^@|#N@t1SbdeB9T}Z*| zLgZ*&$e7nzEQp=ug4tPKqjr`FZfAL&+=bM$yU5G*F2v05EUpv0ka~t^VU6NhR_FMi zgX5>?nBZ^w92}?5!7UwvogTERknR`8aO@S;)L-XKJoV~FjlC&{T?b?H`*Oe)sET1< z@VFoU>DGANH~eU8KTExxP&@pj$7>3|wsO*;%Hx8A=nNoO2?oG#-U0_$V_%Lj99gY4 ze<8mw$5aWi`O8d~B=dUZTkCl0_kKX$>U_?>6A9?ka}v!VVJP=kjN|^2LEK+5g4Zrv ze8Jf51q|GL&8Qu&8M0ZxcW7@AqYxD1H^Wk?v2 zaV6l`OBjp&H3KoHGYYeSA=nETfBiLsFD`4y>k=7ue*xGn5{BK|5qH1$5qBfN>};S_ zsb`I%L6L$H973iY*UZE>(_gBrHDl;C&BqK7_NEGqm!~j4m>`lLsCAFUZ z;_-wmRBN}JDLp@L@=aP^eIlG+ft^aOmFM$3e3&C>FZu743Axz zL2KmUfNUO!7WG2Au{W_H&! z@TZq*)$duIl2$at>U4Gl{s&4IeVu5^);3*HQll$Tk4u4Bz&+=n81)Lt$LYuXI1H^p zN&NHXV~9>pb^zy~){K$P)*t09PamN=pauVJC4#9;XWCFc=##Aprgul zSYd(0pq9whwyDr-OqI6RC_i0 zR`Z#MAO}ag)LkYIcAVa2hTrdZThk;)0Hp`4!G-&PnhrRL>RTIj?SU!p@iV2ZY;pX4e@R?w%ibDDvE|&52$fNjBuV&YfBYI z5;w=Y&f7l5Q|r&1-FWc}(wxM65O}=}>=l>4fU*T;pWS%=qm7fFC{(w_JHLJT%Z(3S zkE7*yzggReq3VD7E&CbiFvI#S|EiZ=ywJ4^Hkicrb*r1rW^Ru^OLCp`HQjhaX;%I9 z6p4i^jhGh=m*+Fo=2V1X$N$SvF>N0q=cFPx>yyPwh!~c{kUC{dn8BWR-9IM1rxX-a^F39 zBu#Z;wdIqWH+@odo6?`|GXY*N`A zd?QX^m~86CVqynOUF$KOEsX>ou1E5|nd#Y?Fj_YoBk~!W(I;$Ps@o6NZ391bhilHm zlK~I+?{ZA$dLP-XJ~aoU(+BDGK8SZEXJ-0%%c+?~es1Q=Fgf#en4S6BPtW!1mb(%Y zG)w#p%>tgHS-^8NOL&rIiJzrwh3XzIS3@EvYZmcr%_2Wt z<5JAmEaC~91!2Z!0Z-X1;W?WnJZZDQ&)T@IPusYx&)Y8im`$gshUnD2-z7_zvq4OO z0OU-Kgt8QRHArnAixxR8`*L)W$@y3$iHVrg>{7}%Oc{*lEHx8YMiwr=36|w?-B-w{(-LYh zS0B9+D8eizx0Xh698ENN!Q_caF}d@&q6wZa zYUfhCvT5~#zu70q^C?$VKlu(OncK=tG#zzF!!sozKUA$kY=76Y5H6L^d&B`^Y?TPk zI9%`@-dL?xCEU688mcqCG8&H+->mBgN1{|Rm_5mJ{98D5ic_g8SP?IMM8@{(&z-`e zd+p&THy(L)~{ zEfIJ<$~qX1`06u6*y^Ue_*vzE<0RfLm6duQw;bs_=@5TT=4Yio%KmojI8=v1Ib#`V4v(i zFxwa|psuY^2_JT#6Ai|nXdv-SR+%c_=Ewli^9$CS&1b4(v$ig&p&?;Ho$< z0M*|%92odM4xk9P{`fn_tNQK^P6~8&@8WHGszzlrux9&`+CohEVkAz=_>TB3VrovhHrNqewV&4G|`e0{9c9p|1AT?I(9oBgmDW1O~1(~GKr z&ZZ~;Ve{^&1UjYX9SM4$kA}Nul~EatVGSjPPL(7q{42D+>@>-csB+WE=w^c+QtL|e zYS5`eR3&WViaE4Q_j+_4MR#on<8Ys2?LhGexSI}O9l^TbM#%KM#J{r%?@1`!V7*P^ zp3oZ~;R_~?us=+!2?cvYNb}Ha7?=A~w{%b~V?*Hz?Bx5h^Qh@iZLXA^2eZUd=k7J& z;eD%bQ02H(q~HzLc*4aYA2o_0%~L??l_{Vz`E z?xWMySB9kVVa3wIcB;XPvq{Fky$p5md&8ad?(m;Qyt@n)*Ir$w3KL8PO{y%0C$%qb zGx_hck8&AA`V{Ub{qhXfHpAV_xSN@xG2hEny840aYS85C`LIBmGu%-ZzZgqw8k4#2 z4%>D&xOS{Z8==Lpl8&A>X~*QYsx-VhTR9hAk_3nM)xLJD_x}23Xzom@=EDlqEde6 z6;&_jwD5+b3yMZ&-zdvw97&ewlFUkBoJtwR`N87nhZ# zBFcQRg|_(qR@A$@OkZ_eozaEoDOxFh1~XCDxxb!ri$Pw2!VRl}6R3Z}`jI5qnD8D~ zPh-1dLixpG*#5x&1roen>!lUk^ZU6g}+xkS0PrQkxEj|kmwO2o+&mNZ<=P7&Nn zu5xAgD9}Plq&#G3GdgRXcpBnEsl6gMo`>s9!jY2HGodH5@l z3+WNho2UDDHsOeBw>rLe@*thApFDog!O7#h?};suML}x8meWC-ov3^6+cV)FpH_*+ zFU$v?n!>@Xq)S$nmYU*!!ds5d=2atAs;Gsi5GzFNR}@%zc2-|6Lm)Qm*1FCp$T&lv z(z*>d3;*#r#j^TNY$e$glFhNRC5XwVbellISFKA;b?Y>>p}RE1tE`s4o6)30%M*7DOLx^G^~iKwkMJ*^oR0f_9bX+Ie}L_*H&jiUU3o7VSKyZ$$P;CJ zIlO;}lD*oSwBXi>~lv1?6r(0woB&UT?w)0Tq$=DM2o{?mC?Xt(f+JRJ zkvO6Qjy~n;rF%RZQbUjth!;b+?RoQCFvb~!#SKUYe!Sd2KqNA?nsp;=P;_caXbehs znzmCQK3j@EhBr8-^Td~x@G}|mhSY9~=EYKm3zqO^M@__t!y?}D5TX_fgr_7HGWD>m zzWw240^__;5Eu&?nONetLik#GQDQM~h_HePM!ZmLj<8gCS89tWT`Un^ zmRQOgB`mA&m3W!hF7ZOKW8#Iv^HN*J<$_2=tYoFbH>+)0UK6TImxKXy4U zfxDvM*%WDYB!D(VPn8fV!<0r5G@elcsEj@u=u=BR1kl~P|G)vY`|zQ=_a8mDcTWTi z#p4qcD}s9Nih}IOfSbcWD*;rtH^QHr+q>=f8ISrqM)-`6!g0W7!^j;wfQk`52K*dP z4Oji~Z7X?-fxV63DU05A?u>-~y^#cZZSj6@B_16f54UmDDgD|!R}Ir>EWoTxVlHK| zgww`Ivr=BeR4H#ssQ}idsIwwLplfsNS&?EC|XXCblVV+R)_`X zM#9pHBuTst!D)q9vM(n|0B(#@D-r|>M`G31QzR5OMXY7Hz+)B*M*eA?k!!KXB_B6r z5o~-VAxg#} zj(wDGo5IYGKw8nJ2+m$<)3&2*t?04SE5F8Z04tBKadRqnV+?${%_T>EAlr$g^%1nK zI68(gFMr853_c^@hFb?T#aq4&nF&9R2EZJS81JPLD`nhxFOo1RqQ?tSt0oZiD8k6I zOfut8FnJbAQWPQOS;BnC*8&Y?YL~ZKO(-|)Og)NpqutT}*F9YDNEh@Y>F#=*(#L>rRMyc> z>gyZsk^!Zc_!tRp-EqAn!_gk>N7Lc8`m`Tz?Y6UGEPlZl$uT}2$H9;dV|eT^IW*G8 zfR$sbW7N-ZJ4us=_GV|FDzQ1JYPiaBk$qNd!eX*KhO*H)`e~L`a`E zJtMtAY-M<;LZ=0#SH2)(%O6m|TQbrtOxo9IibV;Q)(F>XdYMh92HAH`&Z5&My>=VQ z!lu4TOLd0hR1d{Zg@jVtX z0_mQ%&dd5C{)GBrs)iYSZ)^tV!qA+#&4=X^f1WgutUvnkOc6j4f z?%OtP+cxalHf-89?b$YM*$(a4iVfT5{o01@TDe<0v{~D%XwAp?%Zax~b9*r4~Mr}u-(TL$_ zqupp-D#vou7J=L$7}_8h+8-F&9uT_&4VweQdjrE;0}VR^4I2Y;UtsgLK;y2!@TP#+ z6Oda14Lbr&8v;%H0dhN_X*XbaGhlcxpkXVZVJBdCBVcGBKyCxbU4T1W5R^GLLfS^< zgn7wO__D0m(xp0TbYfFD|2dLlYqKXE7*ae~>U1zTtyJ6HCKveO-k!!m@W2H<9D}z}vBL`GH@AZ$X=sGywsfYt${5f6q z^kBV8OJ3bw(2Ip%-PXJm@rTQOx3G&jSZlVj@MX_twa(p9&trzUo4%C85hEOH9vJge^_lW&WdGxz@Y!|K?5NAKT%|D*^^(bRi(08iRK z4jq)*VT;TUf+nvPxaV|J5Hrz$$Yggnkz1+SS%x^~C7g5y^Ra3UE)jp?%p6U^t`i5Y z6c_ZoagG#&6Z~B&bjT=OsBV^a@ZZI(Qf-~?Xr4OnLez==PUnKxq^=R(B6Fsqo$nuz z#{4JjyVqM=ZgT58uRE33(f4VlKpR36eDqRhxrv69rZ)#4zw`iGB;OI4o6#EG={mQv zwFlw@msW5lNd@#W%-la=pSv6pB})@s8YKEK7`qe?R;%Xh>K887#axxy9g(Si^$i-W z!C@`FCM{dINct9`)=b`7y^toRyy74?rCWOl#IJk7bM6DC+YK@O@1}%c*eN2UsX?^< zqEua-cFc|lO6>NJ03B4*x+pc?277hILrX$nhyV=;Gv77Zd(`GY6}!~Gp5h;ri}0el znRC57R~gE?Bf=&(rvbt;v?{5bUKkCvGe|vc3pY4rYl2(YEDepYsSS-7G=UQ76`Xp= z_6CheOui!qO$d+m##>a?-_DETUjrFyO?TV<;8fHaHS62Zp0TR0Qk}FB=)!p- zg?;Ii?rQqa0uiAPk1>d~M$c|mIdj!zvc)hnJ0b+w%x zZrk&$^Q8HCEye|v0l^PpQmTGZO8`gy-6mJ2&XN=+r<)>e&?f4${4oy=QYaT~V53uo z@?oS(fiuqShym%?228}QW(3ZD9D%c+j9{~o?k!lfZ;0$>iG3biC^j- zJ)gCuS4+s$2oiHi#@|1Z$9y(HWxkr7>bmGmC0zFiOcQxW@)~Cq=WHhLKfGJT*-bvR z(FEr!+5*S<8zjw%hDoN2u(khECyFxoh9A^(>IjWpw{tDIZ0NNYRj#^h7=h3SbGX+P zB{(WRD2gf=LnNk)``goqBHUES)j;0)_6O5=GYBA{FJh+`%;{NEO4EY)zyfi0vm)3S z_?FRpT!z;bvwYZ6No>NskDd2#PW);8vg7T5`plCRJdN>&01L!v139PM>6Y~W)33DTYW{Fl(g4=8V*X&U zm^Xwx{OVaOCWVN_ePfVrF}LR1wr$(CZQHhO+qP}ncAs|lY4>TLHclJU-@Q{cbF1e6 z>|ocyw0 zm0YUxaa;7DZkYv^UN#rAq@rr6xw<9>k#UE5nCh3HqGYPcxz_v=O^#H>qART0 zQ`QOc)4-z@cUzJyz3TSM1o~&Bq>1NX>(bOs?*i%es-4zbgdM74oA*z>H1*%U<(q0f zb}jWfWAFC0{dLjo{{%BgSM=7yw&|`|!VvKf_z1h8AvjtVutYndv~QNEDh|;pB<$~0dge3wAs_Jhwz5fEZgKFZ7?pE{RvjeTJ z;zPR~N&HI4m+P-F8we)Zg!QX4(f?4?x;X-|m%$TJ5;D#<4}*$sa3Jj_okIZFU7-+xnVamkB3BvjV?6_cPgK*BEdq!E zLx^;A;f&a+Sax?|o}qcp!iDEXT`>Ilyv@_(<5__~;TDwQDEnk??v=jFxtrslUi^1r zfi^kXk&mtGz)z;uH-y0NGJqBHgs?(|y$80IKUtpR+ky_(amt!gpP$XK_FRa}*J*zo zb@OZUex1Jh&?QysZusTi2Q~C#+9V#VdZI{&Zorz8IRcM zJhlnTKY_ArG@Wl2TgVA*<&mw8%!JP*>NdMMA~H{)#u*YFqbisP zN^hf~v+mZHJ6;5L@sa?IB zOHue?e8}TM!TxLH$y1{*E!O5s%MsdY!s%ECk}0~Dq5CpPr0Ka|K8`o#X`d}$Nbu$0 z^gCLO)3EaYvb2jjIgzmRR?iUl4|KL+JM}YS8Hd6DKvmJ8hcAahevvjl(9%X`CN-$p zF4zC${^qRRL(0o-N$yF3CxPf@dEnwy%IROJ_V?8U&P}g$*`;F1(7_wg3wjRJUzR_# zzEtLq(#>JkO%WtyKN70}rwDJse~-3J8_S}X7^j#%;Kxbj)E%A5JRthYTtPmNcGEN!lWI5NwzzGr- z?D&@QPI)Vc0Yvx4E{hIq!+i7btDSVwKEJq^J}E|v)%^=xgqx_>P`p7tkRSc!)4V5= zfC3IzaCVk^SN*9=&fnrG_4Z!*iY_2@yeh;uI&FzB3qCr)hx=V7C$Te)orl(isL!*< zX4jOb0eDCi-RXpt*(#(eF2RJ>T8bJgIwe-{$b^1+fP!8hAh?=TNnd};#OfIIw&CK`{iqG{qyq3KnrsJ5`A9GEAlIN!DYhg)#Fofonv-CipNd5oIc_u7F(un_=(?TxIUf ze_qIw9t2eR19{NAX9q6|NX`n8+;vjOxZX>6bkF?&*KL+=YO6FWX?Pk{zxwbE^Q&bq zfjVR)a`n8U^m5R$0{St@H{+1M=|@aha^iOQ_)|T`^#|b958=bOzf#ojWqWm zhm4%f>FQ`GIGGgr&Y{X0dvim@$t^0X@5L9mk>Tw^8*s!wC8x1cPsS9nT?Hk#W|A3% zYjywZtoBR5S#7}@wGD->F_9kZ2vT(~%!YklDEsBBk2+A`efpitE&0BjE)RhnGz=Ll zpzv^g{8*}SOHiKP8Ks-?vmb1JDgX6c_b$K4zqE6$UsDq}jZ0!Es zsuCHcR^vW1aq5>>)B8Zy9N}^3(c_>&uj~n~xt_tw<>T<5kK1MjgF6lh2+lRFSAf*tzOjjY-?L_N-0W=a)bmpGb`gYx<_O zuE{yRA0J~k922$3i{}uKnuPILoBhnU zg88zhEaqUI0LeSWU@3`oH~0b{dgCqC@H$zri2K|p6qzrafXe(3nI|%PzJ9_v;d8G7 zCktns&-f?KwqwDVd_PKV3HeIrv%vKxbPu(40mNUHjlTqK7B@Pf*#cdUqyG?TTMov% zey#l)xV@UzxF}%Y5%yJK5~`;g=xO)G2fVJ$To8O>Q%}WZ6lm-CZwKx99ENY+wK>D) zzNZ9CFw;lFOK2^5F+UIX!}IBiff&ne8fE{+B0iD@*B>@psV3%3hF1%3hchp zTy`DT!VEp(3L1?v!et!pJnFDm+xb~b6(nz9n?)cdhJm1MUgpnU2%fl-n@NcDIG zn`BlI)F+ciL)-8Y#%M_G%~PW%C3voD?kd)g`i9a{Rb9$AE}tuh%G769)k7jWt?O-; zwWzMlG`rPBx^B3drOpq?L;TdLpU!s|L>Uufxb`*5i_se9eaaJ22Kk@Cq_){X%o>g1 zJpBhd z?!Y)&oS=nve_ImC+KH0RwF-u0g@6ne#lViIc=UR>TB&!S!D49iYT~a;H4+{QG|f1C zBnyL?HhLMrpjEkwO*;~oo^>37)MM8wtwA0ec*s6y3HW1IuD8rmLfw$=E zH)>O~IkJtNnkvtCm@5f_$A_wjo)k_WGjL`YIb0&Jk!#!3_XexLr*+j+R~k~MTuhvT zgV)r_DWF_&C_%ujbjM9&%okT-#Eeisg^Hbnv4t9#=t>?aYM)%~^y1;u(k|i+KEff6 zPsu^JT*f=z04ejxO8CG}O{9V~5#_%^T})dw!#$%MtW;eNAuK$P^g(U(7hj^PR5= zQG7|BUnKPNN&3i46@UDk{YVB+O``sx#2Yv=Nhwl8OzQE=|9-uL|9SBPLi|XV8WIUHZ zr~`lrVf^Sh;t|aGyyQy4xFlW@0Pn677ubjkG6G-}A4Sxdc1%*@4jFoKx-i=#(W1;F z#SZo@zzLpC&aLp5Mz^szdk+`G2)M^+hq}q?^k&sh0{&9K^(J)lzafdw)rZfQY90ic z+Z;@gs61Yl3Ea|q6Yo#*iYp2K+bN+q`s~ly?neJ_p;HZG`Vxt95NmS&FYyp2!76eJbhe%T{A=pz@$RHdbqEd&OX)BtOW@2Am@Kzk{q?KSEJt~SX-vlr zUzP26%o#lgq~sw}EIzgYZ)w!zqS(pZu$~8L#~9teY~m4@l{Dy*IlWGAW!)*@`Ae#% z%AfSdlXdXM@o2=+DWlNz`{3`{gqxkMqeCo|B#@yZR)b63*Q0-2=j>L>DBRiZ@C3Md zI|n_!6FPZXodMCpgqw?N;@{R+7U2}m#LA%HOwW0%Eu8~<*o6c%SOx+NwEE16UJ!Iy zqo&=-Z8O&W4I4ewH+dcs>pMcvO3nmO9<5swDW%#y%vaYfJhS!0JSvx#jVyxDCc^Nc zsF7==gnXEhl&?lz2+9PTzJV`>H%68SBi@0JjQYG(2+a7jyc-^g*MeI>%_FXO@T*2y z@G7pE`6Da1>Bo&^5m%hHV+YK*?fZ^8|EWq?7I3ROW5)?Mlx_) zRvXeIMy$3)MsKh(7MynAGq6|8f@XnJfTSW`a4XnWOiHFnqr~9_@DWA~O8V3vh|ll^ z$E03kx1meX7?=;t3c4koq;_J9pc&A(FbvE}tBTQZVJ2oO>;v;wRj84s`s|_6gjcoT z@O)0E^uIb`0MAkb$s6~vzQmaup+3a6o26dFf?J_(Mbt&ALta4h-%LmVCS-7;#RrC! z%R4b9Jyk?1k(rd1a(Ze(YBI92u(T8vmB=(1S?Nb9EENG2*>R$?B$hHf6%ko!>VE{% zQ;CkBK0BLXN+1D*kikvGNQnZwZ2}tpaV#-k6Yo(mD{j*lYwL8kH+8r4QBmWDNkh~r zX5`#F1R^YD--6Z|YXTJ;JS+LM9NG?~oi1Y%$sltO#R{qglRqf=E{res2f|zGl+dg? zI26oUFe{-mmP>n0KfIty@LJZ=x9w%Sa9k$b~JOc{&fehHyUdl#Ed+t^U@oEt;W>Qs~O!ZV6LVtc7ur= zFL~;T&8an<$=Ln&{s-)y-7c>_=L)R{|1kzfF9C?D5%Kh+bipPLm$f@JIGS^o>tVR& zmST_H+Ur@g@49fIpdu>zWzljX95t9|GAtlTQZ}!q2kH3B`k*ka^L)Q?9HY+TUCALP@TM8c)J$zO?$9y4$0u>hg*&+9>hbCAK^Y$G(=-H=@+T)D=fj%ScCOHv~ z%G+}edz^xzjc`>C9Yo*4q*$|mxRS)$jml}%n+U6}yTfgzFKX4iM0}E#oipPrVoGf*5wJ{{7V@B@Bi~xs>p-!5koU|sm&{z`1u_NZ=Mx2L|MNX7f zxae%~%h(Z7aUxcSj9pHcyPU9&xapkmF}M*%@ggOMihnt6-EqByu-S>?Vu|8liQ{64 z;Zl;s*OJ8Hlf~te#nY3;*OJ5Iq(+uXn-Ju&xfHO;DdBWd#nV&8cT>gj)57bdNq$L_ zoJx~G$dJ&;kjTi8Sjdos$c(I&H6iF@mp3AaU5enmFHG{cHYcS1jyS#?34Ah=d~dAu z(_G_6ZBG#0ikQ0^xqV6sepmd%PwPxj-i3g&6QTTU)cnr4?T2~GPwPd1-iI)<8!`S| z^ys(o!B5+QOQj88mM+qCtZ2`L+=&~m3on-;vUSXO>x}8mrQDBO7XKf|<$HY7Re^Me=X9NbmtBYtEBI=AUAPP!1|y0B^=X^-4uhZLBCX3;|&^du=uvV+L{BKzMsXT=VE zHxq33sEWi<+j=M0g3bCY860oD$q{5H|IN^HQ4=;Unzpog<0<)i1Yl~6kei-=8>#leW-j1WyezNF^jYoc_ub+Jz4yp?w@u_1$GKHJ3plU17L zd_Y9t$VGUR@#gaAMo6JEtVb<_XGc2Dl5+L>B>RgPT0b|4xc?h z(b91CIlV-i*m>0(`RZ)>^DK5;@sD4a%%O#Mzi0yH6&1l?OW^A>G1bnWCgA(^CL$k} z447e3ql+-{+yBnoNnL2c_eJs)y1-fOM3w(GdzPo-0$Q?4P@^XJ_8bt(cf5Z(%4dtC%~f1`9gUriNA?xvj`eEaTI7z+SVK(R^c;Iz zP2I|l`mJ*ge}~SUOP|__KaJCnTGzq!4@jZwP+HgdxbHaHXYOw1x{De^&&{FxkG@-5 z*Tn||>a#i>PsinNkh8*Ja7yl6tW^0a*CY!V@x0)_sp>wab=`KL4Kl%VOzk#ZQVX`# z_9^aqd-g;gO5QQsS*&}cAL#!$UO@i_>MwhzEM0Ijl=oIUfroXR^@#1L*>zC%)L(R0FF1pw*J!m{bxF8?BL&A|Of z2ye!WR-^61_=Xn)bs~xLi@KW=>B;$x)$3$9bcUs0XO z**|!fuTe_wdy?eRaA{l??S?Do)BK5=|TmT?Sr_9g7KFQqrO@MNMHn+bgwuhy*qGkuaCt= zgF(3Fm$6hpA?2bYqFXBk7;{XLwR`R6sOF?--o+@Ro${NA*EYKzW!`AV@$jJfm)naW zh6`!V&&hUcYJ|@eCI`RFe6eqZ4D;XS0=$oO6%TK~Moxj_{d^Ao zQil<<$=EH~i%*&l%axh^G-XIKO;Z@#=@Sm05yo+~Tz8>9ad#%_8VnT;{Hz$a5nrfs z^Q>SNz_yRf)a8o_pJsS}id9kRaGBq?>#J;&|GL$ez*_Tlst%-)5b(I=}hF$u|m~Gy|@3LOl=u~0R17xz?w_^9z+m+RGdm*EG;MO|S z0{6E6d~p^N(2|Q~xx#$DPgSM#b&N=;WmJ^?AG6}fg4jLbTZg;~k-k7$LSTeuDlvpuaG^GH8HRNC<#l0rq4`Iu z3Y}IO3f)%PV08}k7MTAUE4VuhQj4MZLWeqzkK`x%roiWf zlh{h1Gpylls+QEH< z&qFWvIO~V@hWIB_=%Luo*cTFww!lMaK-?FybiB+X^sjYnK-C+fZl=gXk@GMHiCeY8 zqXlP5&01TIz8&8(CuGj!<)Q1(w!Oyk$V>$vEOlzNtnYpMM&Z`W>iIz#GpD zTOUdNhcN*Wy~ku01q-iW;hreLfzWXDSe3BCT@la8bajCvY zlGqV}fZJ_Hw(23!u6%yDCN#d@bO%U9^T~9+c*)j?&(d@04Xf7#`iX$dVmOoAIk{{E zTM!dkfa2J1ruvPIa-Seqim1(^i`7@ zay){{nieJ02Q#p#jThDI?y}usSZ33bem?o)MDFgz*N6hnyw4#RcV{tz;wey_dQ@>i z7TH!7^<3?l-UCcM4`q!-rfmJVHT|CYNF8uqDE7hq3Uofwr;CyJzuD@v*-hU!@HLw* zpjL@V^+upo@>7t}>CPVq-Ni+WqPykaWiXvq+1(?2&?brqJ7zZJtT8&MN!-5lwJ=ytE>s?xnJr|OjRO)n1ojvSROotln!dsFmb3HPU%5r6n z^ShkUCM0(yyEwqJ)mbgg(ENcL+Tf(#ICg%2>_@v@O~iVR9up*=nj{T}um_{Z&{F&= zg&|4h|EtfYWIKTE7T`(;=hL#XJInq%hG)^LS-5$*41rrtt=R3fHQE_^poM$6={lNV zvBh7!LrUTwgn%V!mh@p`QWas*JF!AemW;FerS`UUl34sI8pi9*>CO;Bv%hkOh(U4u z-47kCa>V7rtg$wE+ku_%vu7_!db>}^IeNlL?^lxltO0>nw8Y+&cH`})eNr!(Ms_%1 z!6Y#dR}F0fDxFoo0r;L;c!u~FhI18`&d1Ox*{42t%;WWmsS4kAHtv z(*X52GpilYX?Jfin-2Kn=F-b9%z1S49t<&*1X}F3{~I>aC3r1e8hVyHU{D5;aTQ5n z1-6N~1M0ibICYV~{OMVpgvEAyp$J~MJ2d$9zI_--oZt%KgFaoQPatadhg+2A00SqZ zCky}S#Xg1Y00F;uoa)_+6%_!}daBRgA_9J=Z;Je{w}FDr?`2h6dAxu>K@6Rsw!M11 z|1JXf-nVY}|AjE*750CZi&w0T;{+7^i7W6#Fqw-gj% zmvP*Gi?n-+MwaSpG&0BxX%u=gB)UIuvQGlrZRU9Sl&^4{jq5jp*0V7Nv19vP#I7f;pjRsYH(G`NqfpbDA!>wQ<8}L+ zdO4=!+1+^OoJWSWWmkV1p;rF%OXN$pw!A<3%_(J5Ev0=-Oa68cl~PSE>1pIt=VZkl z4c9jV#m7-=TtWGw0O3omq+&Nf1twziyS={hoMX0~t2v)FAQbqCOE;i0lGK074Zms? zZ1+1}C2VE2DdgAUjr>3x(Pw~D&YvL+PQ`(Gc!tt3y1@H@s-zx{r7tY@gzWC1$ zHL7p-T1CHsI-*yrH-qeO*p>A;C{5D)WHwof!Rxcnd5NT&fPfLqd-$4gDw$f9)(_N6 zMX%%VhInmWwQXRwk1B7u+O+kZA%h1sf7J!tM6jI`6I#p$*rwF*AMajGLOv9OpvPiQ zvv9^@}o;q_2QwBTL&atgYq7RfYaxk&&+b(&9VWQc=-=#DJcW0XmeOn)y_za#?_P%}H=K z>}B3m!Zv1txe9!gZ3S71S&GLRrkA#q$Rf0a05#hLD(bR~;Ej;3(C=skG2gV^1mdx! zyh>D%aj=4*Z7IX+XJb!uAB47%<8e&0k>P1qfF`~Qv{D!0X>SD~*XO&^Z0UL3jSodS zo5%*6wgoZMmsK?3Ph}z)q#Q!Wuf-HWRVI3zAyfTx|AA{9%&+Ue{2Pa3*HMYu?0QSE zx&oioub&Y@_4bsoD0F7Gec%|9b@$aNe!p(|)iT)ly;3CK@nH7|O1ZXK5dN%9V8)^t zqO@5gTM)5Ree=o$(*6ZGe%~vdNcF68Oc7Y;Ourl|5)(m5zQGfZ#BA(+|70Pwj;(zB zoCEkGCSei ztu&3QV5>GsJeKI7{f3-sHj?{yoAcK~yPCLU`c6QGPg4cYkWK*6Dy+g^J!1t(G@7|Sj{Y8qQxPdZpH3REb*?F^j{J*jm%wzY z_9neni;go~I|uu$4@HgDg=y7wuC48%DUsDGvlhjouKc^d_`_70zeLy>NBtOD25{bU9 z!Q!e;vB0s6o7iO!$L^?~{{!FlK_k}~!;(X|2^Y>5k$>BF^M(^X^s3eFD3(oYx=a58 z^%C_$^?wCx*_!k==~ij28u6c?*oJLhM_q?pH{J@}YOPh1*%sXjtyLpgllmj`^DSN@ zYD1@G6I!;0pmtGZF!pxkd-ZoZqq>Iy;ppM2h zh1f;N#cie~Na>OSYNZScg&L*7Z)|JR1F{pve;FTZIy&s_LatP5e|`Hy`@MHvROoeO zUpKEubg1-o`8m@=3hc2u61F*kj>v`*;jp1Ct`f03NvMI*if?6^8XKc+%Tu9e&^w>IbhcBP2{O;` z>TFzfWr@$Nz-yc5+j7QtU;g;$=&aFpz||UlKBamCYDL8CRiPzYi#>0_<*gje=7ZmO zg$3!?GXKw`U(n~FZ{%4&Pjk6v*R@PlW$bk~Tv}gm@22*trmUe=tW5hUcf6!3Vx&WC z0yTlmlAhTnx`sSK%VYud3z;4G7YXpgP@im!UU6pIZgUYQzhO0g zKX(F3M!{v_WY0gx8IyurVr2n~G{t99dA3K%1LIC~$Zfnx|7+7sqXEEqXCsO{XH2>= z;1gV)NfuvfW{EQOVn>*?tx6|`UoHlE_`JIvx?3e#hlZpQ1pBTWEQ#x#SmR6xeW8ka zUrGI-=%`!sr>B}Z(XUcgTv_G7(m8E*L72i+%@@1f82O&YeW+;$UJ3?xK2Ord6BA!# zQe}dkh27O8D~REG89g5Qt2@$i-HNn${ir<7w_PMcVi59?2(S5*|s28K!% zqA-`i*Hl-p=A0;3vT#I#nrC`nujeZap`^0-raOwrO1qOM0)@PiYO*?7!Q0Di7FKBh zwOVpY@f2T8ABK+OF&%%@na7_@ak8Y-Wl$hxqjpK?dB+`VI`*>T4-5l?k4JHqh_B(# zXT7e|5*H5Qy)Q4PyEqC4|9=~074}0<_x8?x+eiK9GcFu^LKHm($uahh&;&zo-}ZVi zLO%%M++l4F!QDSExoW2_0v*m zfos%(2ckW^FULF_tMV%Ah-T`Zo$`boyX9e#Wrj_pFD$$Z&Z@Gjv^WGxL|rh{a|M~S zNP;KHL{->K(W&I%k`G>l&ZawfI7H%>fbV3R7;kRAKkh+c$Bn}#wKiE*YC(aF-#u{+Fi0OIZD8Bp(Rpk7O9l{77=6N_4cpLCk0w9al@p8=NPk9Cq?cYEcn35 z8>Fv}5Vcr#5E2=7UXRC~uZ@$&S00iAW$6rY!%7OT1&KCseBi`fMaGQyHfjrgSHn$T z-9ph)oN~m|DWMKXRZg=Z`gOW|6W(1c=WPY969k^+8zh{YG_Z!88(U8!r$F3wqc>D7 zQsx&?=7+VU9%xV#5+Ju|_9M0*m|F?O;hV- zp&xRvcWbpiX%)s-qo(|-$%q8JJ~-+5sDYzF(k1RhDrkF^oQ@iDW#Kl_?^Mpo9IpbG zmhf)nW;|2ZlQciXlWmtt|3;6`>p0bQBe840>;j|cpf&GnrYU~hTD%rau=Wl;7zAlB z?1qpNs0nR`$!=&2#C?q3)+VKJhy^mKkHFXT9Z79b-akpuNHQ$u6ojG!KDPCs&m9qzt`M#I3U$cnW3WdyL|4@ zQm2cx)onc}n(C`e=71sf`DZQu>}{*)h+K!wyd4dDhp>}|SG2df_z;Kzg5$%d$le{( zQowUMF^Yxo=Y$el0*r^R`|%XSDBGX==RN(-i?AQtalAgkAWO*U9~^=~*mgNM?qC>j z+UvqG=zW>Z!?=E9o*MW*CPbYuiW@Ap0S7xd7&mW`vD6#kgy<2cO0J&sATiSg1;8of>5SxA~7*c`> ziZX;*Fca<9xK8$u=eY_=@Tq_Bm5*ZZgb3HG_!|~u{{!uB6@zO9?NQ#L8-M`|2TwXW zCj8A1R06)kqZZm$sk2MLl9h05&hJZ@;}3cRdwPUUb1svcXKQ=a^>4>JB#}H~!D&h5 z1@chItlX=2{cusqMX54`MD~S)S?vyga=Fk)RDa(<0*-0n=r0Ub;U$$~=aLj-VM<|1 zdueey>>lvU)w9+hRk0)n`cAJ7#owzvRA<|dp!zAEatCAqGI+8p1Cf12{`4A$^%l<) ztNJ(=PITtJ8^|gUx7nC}VoWsy)hxqt0%~8VzeX%=>%i}kmVl76g%Q)Uks~@De>aVT zP4DJ3-zt1UavRGv8DG&F_o7WI(pOf;5-YB4G0lju-A1Lvk-O&#tA4FE*w{(vK^SQj z6J@7|6$$$${G8q}W@<^+F;~^-NazBZvvV=eXErQR1NUWIqlF&(;M4mu&@yC4!?bV4 zc=UVjUr;jkJYSYh3n(Z3JT%cCf!oepga6R=uI^awkHcKsmNnm)$L9V1;s*wPFTiTcNbQ!~*7nY0?TIVPHXUuHmhO&gsP=`-PX@^w zc2LosrYi%UAX&Z(%M~w}hEIJFWVHeA;(Je&4s`O_h^?qefJ`HJMaX2EHo ze~W&ZJ0!(0xGjwYy)BkKLnTYBN=n`uEdD)`)-9cw0rB?TCMd6%5j+t@y=o`biwaU~KED4aKC7*Bt?7=q9BlY1kH9jQE~-%HvBj zp{g8kofQo3<=Ydmd^GB5R@o!F$!spuMzv+MbwFkrTDkK z;Lw_$Z`~ce7ih5SWXYU)SLqfm@!9g2mlE`GJ*-9}F}5~VYKh{~x=~F_7ADM1X*?Xe za&cj($|6QoZGPQ=uhF(X$GK6RI@AZ2{0o;am5zsbS%jhY=E%S;aln*dv+Uq}%R=%3 z?F-I6EF2S+8$X_Osa!aZ(VuYQ=o*P`LMwqiLiNw!7}c(W)Y+25&ZKzjS`=gfg2AHNwI~ zi)C#C7hcVHkZv}1@&XOcA$1Uydv+Nh#VL9D)+HV7cSx*n-O_y%!?n#tl5ewtyKden zN1TazR#%3Thx7CM*L%#a@siuDzOpT4%G?F;VkCxFG}M^DjRTlAk60_vHHwF z0)qlfVa3W}?|YVz{G(^$Z51!LB}YemyG7o3HL%I>{6(Tcxxc@B<707Ef`c%O=NXNJ z8+UmwuHweS+lWO6^5zePi%!t;`RRoR&wcB_!oR^$RWJaGEW`%7R(KL`I)>A=8xQU+ zEwSxzBqqR+Zgma6?X*{gM}|ujiIJvJ*tz!Fv9R_?8SsJhzHKrRYZ&%jZs07cTgGeE z|5zJ?Ffv&LLoK%ST(xA%2PZMYbLSyAlkHO@{0=d*HaxPOFQJnb*|^OO7PxihlS^PC z4x_%5&CJn2dl%D8;N*iQ!^$s`jPsTLTp;~TOeUbR=%q|W=D&XgEzW2C6}xoEVKd}g zy%Ov#jn<5Njmxqi?o9G)X0&<4dn(kKxv$_Qt9n(pedk4d$UR4Vd2;KYYXa4wut=(I zWAgeXy{n&yE}qET2DqRt1QW}>-=)?3nSw4lzW5;}<0b8*;*>vmC<&2&5Zz*NGjeaWYG~vMsETt#>29c0-92WR+1OhFg~EU4@F_*ic@57AUtgb)+rR z7-P{C)QC1k>E)rsoBw)@>oyq;#*ob-T>;Zu4yr)63wfrOd`0mDsS+Jo6C&?-i8X49 z#*lfi8WIX#Vd=qXNdK?y(8vg)bC?Ll$uiFDNI^;gfgq)>3TBeDIj4oGlow)lZea1l zJr~nU&G=YprRr0G;nJ(0TOhJn`$5ILu}-8UlMKkm(-56uLzPEI-#Ua-n{pVVvMf-c zEL6XMd4+IMa%i0Bqole}e_J3Y&+{S?2q`D0%SNg6^^%0VLV(L+CohR5X4)AOLJSqH zP&*-P?7l3Tpq^3eH`|lru~TP7c#FTPB}QV7w_&-Bj=y`f1{ zr+8h{mr(w$V#=fb9=nE$RNthjh?5r4itH5=rEeUoITbz-a>{BDLZO^5cAe8t`ma&% z_~OxC#39?fz5{iG6X(Nip#GteN)UXW3`fa2CllJ$@+~&Rlum)-uo^r=K1eMm{tX-c z`@?rBmp{JeX6cehFrE-5V821%R>v<8^F3e7tN>=T{R)?`y$;6|XRF;U-0*8G^TsAs z&!_3=PZ^dqv+o(?YAdoSnPd1X8SYdOFDwg5Rpm* z>Cv2HT`Gy!W^vh5cQDAbU55Ke;Sy8}#cUp{*}dTL?miIypAbgz<=z!N9ns!xho{Op zwDldQEtB4V@<>bUcCIM!mQjt-B8-;X+gJ}3w78YU@0}OvHl7rZ>!jzA^xZH6%0h;H zuDs-pre7akFc=7`^Ca8ja=yso)(ucgEPZY$@YST(gBw&R>GhbA*w=$MA|@ZE*dK(SeiU8xmJ;*M?6z<|Ym%RY?Q7hOQD zJgzHI8y+Hyi6fP~No=Au8W!Nc{(5d+ErXop3*iFxPj`Q}@77{DeLK=DBM zK=w_va{)zkFf*l}4EJm^ye(;+2?}~xM{-x+)|cMUkkhaMrWzF!lb@53X=zLx@SpPk z>ZDmUB>-UmW;?^~aDF<|X*VZ(an^RrUcJ5Ux6N*|U5`13>GRebeL^2ti$X3g1HDOnsT3L!z!bv5AVbP@dQ3A7ag{*YXk9xgbFkp?!Upyj-1Zk1o1u%TJ=6XG6Fy>ti(1MRtf z2}+Dbxd9`mNsvmRlHj9&Ad41jQUN0-qt=^oW{1{kpBLhAQvQNBLV%r@&1G@gJ*rXx zpLzgCxJ4uYn5fOq1i!b@+pep73<}i&YEKwp@dX@Cf~#V{r$+p?-DcQ&L0}cB4l3)t z0sdi-gWw0EYY4P@jfP*vWFbd)kR47a1%MJ)MW}-;{%#O>Dnc5N!*Y4uc4x%ssUI_> z%LM8JA^{SCYgos!tPeh+{>lELmx~60S(Uwj{HE7qaT$vI1*WQ?LM0oU7>&vS0Q{%W zb2DdZa8R+^U4a~AF%W57(eV*H85?8|H8|w~MmdQzfoa>MbJQ{YfO$kM{2dkn6F)d4j27S;NJ$Sd z3$m#6`r1`RMTnjaG7oGO34&idT0}SnZ#aPiOpZpFTn>*ojsqM&Rn_VqNE*V358;V^ ze2Rv03b-G%LuLOQvZTkH1N)g&2myfc1K%Fsp8r{Mw4a*u0+F&|VnX9$VWM*uR%`D= z5@Q|sk|%mIf&=S^7lH8y@=bC=Nu9AHzte$?;38fnX{Ht<=H?nCMw5EQ9^j9Vg}1h%Om|2WZDX00<@H4aReT%2ErG z+Cu>91{8`wLhr%@O_(V!t+0WUVTV0&_q9?BG-Pu@CP6xsHXb4VYf6kg0XCF7Df}_# z!Az_;8M7SRtU*?Q_76AZPyC;4g8OL`EZ~1?12ietksn2p4-*84VPpZAU=ZIlHzakv&=V3Ky&13oRNRTnh#)F) ze0o}59;j&v&k0jH1P{zs8=JK!Gy36CI5nRNeujj=|M!8H9{kMvo zsq63vrwC&wfbzv&y~akl1MhVinE`+^cG;Jo_)Y3II4T2u2D<`d^ZQ B4 0 ) + { + var_0.pers["teamKillPunish"] = 1; + var_0 maps\mp\_utility::_suicide(); + } + + var_3 = maps\mp\gametypes\_tweakables::gettweakablevalue( "team", "teamkillkicklimit" ); + + if ( var_3 > 0 ) + { + var_4 = var_0.pers["totalTeamKills"]; + + if ( var_4 >= var_3 ) + thread friendlyfirekick( var_0 ); + } +} + +friendlyfirekick( var_0 ) +{ + waittillframeend; + kick( var_0 getentitynumber(), "EXE_PLAYERKICKED_TEAMKILL" ); + level thread maps\mp\gametypes\_gamelogic::updategameevents(); +} + +handlenormaldeath( var_0, var_1, var_2, var_3, var_4 ) +{ + var_1 thread maps\mp\_events::killedplayer( var_0, self, var_3, var_4, var_2 ); + var_1 killnotification(); + + if ( var_4 == "MOD_HEAD_SHOT" ) + { + var_1 playlocalsound( "mp_headshot_killer" ); + self playsound( "mp_headshot_killed" ); + } + + var_1 thread maps\mp\_events::killedplayerevent( self, var_3, var_4 ); + var_5 = var_1.pers["cur_kill_streak"]; + + if ( isalive( var_1 ) ) + { + if ( maps\mp\_utility::ismeleemod( var_4 ) && !var_1 maps\mp\_utility::isjuggernaut() || var_1 maps\mp\_utility::killshouldaddtokillstreak( var_3 ) ) + { + var_1.pers["cur_kill_streak"]++; + var_1.killstreakcount = var_1.pers["cur_kill_streak"]; + var_1 notify( "kill_streak_increased" ); + + if ( !maps\mp\_utility::iskillstreakweapon( var_3 ) ) + var_1.pers["cur_kill_streak_for_nuke"]++; + + var_6 = 30; + + if ( var_1 maps\mp\_utility::_hasperk( "specialty_hardline" ) ) + var_6--; + + if ( !maps\mp\_utility::iskillstreakweapon( var_3 ) && var_1.pers["cur_kill_streak_for_nuke"] == var_6 ) + { + var_7 = var_1 maps\mp\killstreaks\_killstreaks::getnextkillstreakslotindex( "nuke", 0 ); + var_1 thread maps\mp\killstreaks\_killstreaks::givekillstreak( "nuke", 0, 1, var_1 ); + var_1 thread maps\mp\gametypes\_hud_message::killstreaksplashnotify( "nuke", var_6, undefined, undefined, var_7 ); + } + } + + var_1 maps\mp\_utility::setplayerstatifgreater( "longestkillstreak", var_1.pers["cur_kill_streak"] ); + + if ( var_1.pers["cur_kill_streak"] > var_1 maps\mp\_utility::getpersstat( "longestStreak" ) ) + var_1 maps\mp\_utility::setpersstat( "longestStreak", var_1.pers["cur_kill_streak"] ); + } + + var_1.pers["cur_death_streak"] = 0; + + if ( var_1.pers["cur_kill_streak"] > var_1 maps\mp\gametypes\_persistence::statgetchild( "round", "killStreak" ) ) + var_1 maps\mp\gametypes\_persistence::statsetchild( "round", "killStreak", var_1.pers["cur_kill_streak"] ); + + if ( var_1 maps\mp\_utility::rankingenabled() ) + { + if ( var_1.pers["cur_kill_streak"] > var_1.kill_streak ) + { + var_1 maps\mp\gametypes\_persistence::statset( "killStreak", var_1.pers["cur_kill_streak"] ); + var_1.kill_streak = var_1.pers["cur_kill_streak"]; + } + } + + var_8 = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "deathpointloss" ); + givescoreloss( var_8 ); + level notify( "player_got_killstreak_" + var_1.pers["cur_kill_streak"], var_1 ); + var_1 notify( "got_killstreak", var_1.pers["cur_kill_streak"] ); + var_1 notify( "killed_enemy" ); + + if ( isdefined( level.onnormaldeath ) && var_1.pers["team"] != "spectator" ) + [[ level.onnormaldeath ]]( self, var_1, var_0 ); + + if ( !level.teambased ) + { + self.attackers = []; + return; + } + + level thread maps\mp\gametypes\_battlechatter_mp::saylocalsounddelayed( var_1, "kill", 0.75 ); + + if ( isdefined( self.lastattackedshieldplayer ) && isdefined( self.lastattackedshieldtime ) && self.lastattackedshieldplayer != var_1 ) + { + if ( gettime() - self.lastattackedshieldtime < 5000 ) + self.lastattackedshieldplayer thread maps\mp\_events::processassistevent( self, "assist_riot_shield" ); + } + + if ( !maps\mp\_utility::iskillstreakweapon( var_3 ) ) + { + if ( isdefined( self.is_being_tracked ) && self.is_being_tracked && isdefined( self.trackedbyplayer ) ) + { + if ( self.trackedbyplayer != var_1 ) + self.trackedbyplayer thread maps\mp\killstreaks\_marking_util::playerprocesstaggedassist( self ); + } + + var_9 = []; + + foreach ( var_11 in level.uavmodels[var_1.team] ) + { + if ( !isdefined( var_11.owner ) || var_11.owner == var_1 ) + continue; + + if ( common_scripts\utility::array_contains( var_9, var_11.owner ) ) + continue; + + var_9[var_9.size] = var_11.owner; + + if ( var_11.assistpoints ) + var_11.owner thread maps\mp\_events::processassistevent( self, "assist_uav_plus" ); + else + var_11.owner thread maps\mp\_events::processassistevent( self, "assist_uav" ); + + var_11.owner thread maps\mp\gametypes\_missions::processchallenge( "ch_streak_uav" ); + } + } + + if ( isdefined( self.tagmarkedby ) ) + self.tagmarkedby = undefined; + + if ( level.teambased && level.teamemped[self.team] || !level.teambased && isdefined( level.empplayer ) && level.empplayer != self ) + { + if ( isdefined( level.empowner ) && level.empassistpoints && level.empowner != var_1 ) + level.empowner thread maps\mp\_events::processassistevent( self, "assist_emp" ); + } + + if ( isdefined( self.attackers ) ) + { + foreach ( var_14 in self.attackers ) + { + if ( !isdefined( maps\mp\_utility::_validateattacker( var_14 ) ) ) + continue; + + if ( var_14 == var_1 ) + continue; + + if ( self == var_14 ) + continue; + + var_14 thread maps\mp\_events::processassistevent( self ); + } + + self.attackers = []; + } +} + +isplayerweapon( var_0 ) +{ + if ( weaponclass( var_0 ) == "non-player" ) + return 0; + + if ( weaponclass( var_0 ) == "turret" ) + return 0; + + if ( weaponinventorytype( var_0 ) == "primary" || weaponinventorytype( var_0 ) == "altmode" ) + return 1; + + return 0; +} + +callback_playerkilled( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8 ) +{ + playerkilled_internal( var_0, var_1, self, var_2, var_3, var_4, var_5, var_6, var_7, var_8, 0 ); +} + +callback_playergrenadesuicide( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7 ) +{ + if ( isdefined( level.ishorde ) && level.ishorde ) + { + var_8 = 0; + + if ( level.players.size > 1 ) + var_8 = 1; + else if ( self.hasselfrevive ) + var_8 = 1; + + if ( var_8 ) + var_0 laststanddie(); + + [[ level.callbackplayerlaststand ]]( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, 0 ); + } +} + +callback_entityoutofworld() +{ + self delete(); +} + +launchshield( var_0, var_1 ) +{ + self refreshshieldmodels(); + maps\mp\_riotshield::riotshield_clear(); +} + +playerkilled_internal( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10 ) +{ + var_2 endon( "spawned" ); + var_2 notify( "killed_player" ); + + if ( isdefined( var_1 ) && isplayer( var_1 ) && isdefined( var_1.exo_ping_on ) && var_1.exo_ping_on == 1 ) + var_1 maps\mp\gametypes\_missions::processchallenge( "ch_exoability_ping" ); + + if ( isdefined( var_2.prekilledfunc ) ) + var_2 [[ var_2.prekilledfunc ]]( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10 ); + + var_2 maps\mp\gametypes\_playerlogic::resetuidvarsondeath(); + var_2.abilitychosen = 0; + var_2.perkoutlined = 0; + var_2.sensoroutlined = 0; + var_1 = maps\mp\_utility::_validateattacker( var_1 ); + + if ( isdefined( var_1 ) ) + var_1.assistedsuicide = undefined; + + if ( !isdefined( var_2.idflags ) ) + { + if ( var_4 == "MOD_SUICIDE" ) + var_2.idflags = 0; + else if ( var_4 == "MOD_GRENADE" ) + { + if ( ( issubstr( var_5, "frag_grenade" ) || issubstr( var_5, "thermobaric_grenade" ) ) && var_3 == 100000 ) + var_2.idflags = 0; + else if ( var_5 == "nuke_mp" ) + var_2.idflags = 0; + else if ( level.friendlyfire >= 2 ) + var_2.idflags = 0; + else + { + + } + } + } + + if ( var_2 maps\mp\_riotshield::hasriotshieldequipped() ) + var_2 launchshield( var_3, var_4 ); + + var_11 = maps\mp\_utility::ismeleemod( var_4 ) && ( issubstr( var_5, "knife" ) || issubstr( var_5, "tactical" ) ); + var_11 = var_11 || var_5 == maps\mp\_grappling_hook::get_grappling_hook_weapon(); + + if ( var_11 ) + { + if ( isdefined( common_scripts\utility::getfx( "exo_knife_blood" ) ) ) + { + if ( isdefined( var_7 ) && isdefined( var_6 ) && isdefined( gethitloctag( var_7 ) ) ) + playimpactheadfatalfx( var_2 gettagorigin( gethitloctag( var_7 ) ), var_6 ); + else + playimpactheadfatalfx( var_2 gettagorigin( "j_neck" ), anglestoforward( var_2 gettagangles( "j_neck" ) ) ); + } + } + + maps\mp\gametypes\_weapons::recordtogglescopestates(); + + if ( !var_10 ) + { + if ( isdefined( var_2.endgame ) ) + maps\mp\_utility::revertvisionsetforplayer( 2 ); + else + { + maps\mp\_utility::revertvisionsetforplayer( 0 ); + var_2 thermalvisionoff(); + } + } + else + { + var_2.fauxdead = 1; + self notify( "death", var_1, var_4, var_5 ); + } + + if ( game["state"] == "postgame" ) + return; + + var_12 = 0; + + if ( !isplayer( var_0 ) && isdefined( var_0.primaryweapon ) ) + var_13 = var_0.primaryweapon; + else if ( isdefined( var_1 ) && isplayer( var_1 ) && var_1 getcurrentprimaryweapon() != "none" ) + var_13 = var_1 getcurrentprimaryweapon(); + else if ( issubstr( var_5, "alt_" ) ) + var_13 = getsubstr( var_5, 4, var_5.size ); + else + var_13 = undefined; + + if ( isdefined( var_2.uselaststandparams ) || isdefined( var_2.laststandparams ) && var_4 == "MOD_SUICIDE" ) + { + var_2 ensurelaststandparamsvalidity(); + var_2.uselaststandparams = undefined; + var_0 = var_2.laststandparams.einflictor; + var_1 = maps\mp\_utility::_validateattacker( var_2.laststandparams.attacker ); + var_3 = var_2.laststandparams.idamage; + var_4 = var_2.laststandparams.smeansofdeath; + var_5 = var_2.laststandparams.sweapon; + var_13 = var_2.laststandparams.sprimaryweapon; + var_6 = var_2.laststandparams.vdir; + var_7 = var_2.laststandparams.shitloc; + var_12 = ( gettime() - var_2.laststandparams.laststandstarttime ) / 1000; + var_2.laststandparams = undefined; + } + + if ( ( !isdefined( var_1 ) || var_1.classname == "trigger_hurt" || var_1.classname == "worldspawn" || var_1.classname == "script_model" && ( isdefined( var_1.isenvironmentweapon ) && var_1.isenvironmentweapon == 1 ) || var_1 == var_2 ) && isdefined( self.attackers ) ) + { + var_14 = undefined; + + foreach ( var_16 in self.attackers ) + { + if ( !isdefined( maps\mp\_utility::_validateattacker( var_16 ) ) ) + continue; + + if ( !isdefined( var_2.attackerdata[var_16.guid].damage ) ) + continue; + + if ( var_16 == var_2 || level.teambased && var_16.team == var_2.team ) + continue; + + if ( var_2.attackerdata[var_16.guid].lasttimedamaged + 2500 < gettime() && ( var_1 != var_2 && ( isdefined( var_2.laststand ) && var_2.laststand ) ) ) + continue; + + if ( var_2.attackerdata[var_16.guid].damage > 1 && !isdefined( var_14 ) ) + { + var_14 = var_16; + continue; + } + + if ( isdefined( var_14 ) && var_2.attackerdata[var_16.guid].damage > var_2.attackerdata[var_14.guid].damage ) + var_14 = var_16; + } + + if ( isdefined( var_14 ) ) + { + var_1 = var_14; + var_1.assistedsuicide = 1; + var_5 = var_2.attackerdata[var_14.guid].weapon; + var_6 = var_2.attackerdata[var_14.guid].vdir; + var_7 = var_2.attackerdata[var_14.guid].shitloc; + var_8 = var_2.attackerdata[var_14.guid].psoffsettime; + var_4 = var_2.attackerdata[var_14.guid].smeansofdeath; + var_3 = var_2.attackerdata[var_14.guid].damage; + var_13 = var_2.attackerdata[var_14.guid].sprimaryweapon; + var_0 = var_1; + } + } + else if ( isdefined( var_1 ) ) + var_1.assistedsuicide = undefined; + + if ( maps\mp\_utility::isheadshot( var_5, var_7, var_4, var_1 ) ) + var_4 = "MOD_HEAD_SHOT"; + else if ( !maps\mp\_utility::ismeleemod( var_4 ) && !isdefined( var_2.nuked ) ) + var_2 maps\mp\_utility::playdeathsound(); + + var_18 = isfriendlyfire( var_2, var_1 ); + + if ( isdefined( var_1 ) ) + { + if ( var_1.code_classname == "script_vehicle" && isdefined( var_1.owner ) ) + var_1 = var_1.owner; + + if ( var_1.code_classname == "misc_turret" && isdefined( var_1.owner ) ) + { + if ( isdefined( var_1.vehicle ) ) + var_1.vehicle notify( "killedPlayer", var_2 ); + + var_1 = var_1.owner; + } + + if ( isagent( var_1 ) && isdefined( var_1.owner ) ) + { + var_1 = var_1.owner; + var_5 = "agent_mp"; + var_4 = "MOD_RIFLE_BULLET"; + } + + if ( var_1.code_classname == "script_model" && isdefined( var_1.owner ) ) + { + var_1 = var_1.owner; + + if ( !isfriendlyfire( var_2, var_1 ) && var_1 != var_2 ) + var_1 notify( "crushed_enemy" ); + } + } + + if ( var_4 != "MOD_SUICIDE" && ( maps\mp\_utility::isaigameparticipant( var_2 ) || maps\mp\_utility::isaigameparticipant( var_1 ) ) && isdefined( level.bot_funcs ) && isdefined( level.bot_funcs["get_attacker_ent"] ) ) + { + var_19 = [[ level.bot_funcs["get_attacker_ent"] ]]( var_1, var_0 ); + + if ( isdefined( var_19 ) ) + { + if ( maps\mp\_utility::isaigameparticipant( var_2 ) ) + var_2 botmemoryevent( "death", var_5, var_19.origin, var_2.origin, var_19 ); + + if ( maps\mp\_utility::isaigameparticipant( var_1 ) ) + { + var_20 = 1; + + if ( var_19.classname == "script_vehicle" && isdefined( var_19.helitype ) || var_19.classname == "rocket" || var_19.classname == "misc_turret" ) + var_20 = 0; + + if ( var_20 ) + var_1 botmemoryevent( "kill", var_5, var_19.origin, var_2.origin, var_2 ); + } + } + } + + var_21 = var_2 getcurrentweapon(); + var_2 thread maps\mp\gametypes\_weapons::dropscavengerfordeath( var_1 ); + + if ( !isdefined( var_2.agentbody ) ) + var_2 thread [[ level.weapondropfunction ]]( var_1, var_4 ); + else + var_2.agentbody thread [[ level.weapondropfunction ]]( var_1, var_4 ); + + if ( !var_10 ) + var_2 maps\mp\_utility::updatesessionstate( "dead" ); + + var_22 = isdefined( var_2.fauxdead ) && var_2.fauxdead && isdefined( var_2.switching_teams ) && var_2.switching_teams; + + if ( !var_22 ) + var_2 maps\mp\gametypes\_playerlogic::removefromalivecount(); + + if ( !isdefined( var_2.switching_teams ) && !( isdefined( level.iszombiegame ) && level.iszombiegame ) ) + { + var_23 = var_2; + + if ( isdefined( var_2.commanding_bot ) ) + var_23 = var_2.commanding_bot; + + var_23 maps\mp\_utility::incpersstat( "deaths", 1 ); + var_23.deaths = var_23 maps\mp\_utility::getpersstat( "deaths" ); + var_23 maps\mp\_utility::updatepersratio( "kdRatio", "kills", "deaths" ); + var_23 maps\mp\gametypes\_persistence::statsetchild( "round", "deaths", var_23.deaths ); + var_23 maps\mp\_utility::incplayerstat( "deaths", 1 ); + } + + if ( !maps\mp\_utility::practiceroundgame() ) + obituary( var_2, var_1, var_5, var_4 ); + + var_24 = 0; + var_2 logprintplayerdeath( self.lifeid, var_1, var_3, var_4, var_5, var_13, var_7 ); + var_2 maps\mp\_matchdata::logplayerlife( 1 ); + var_2 maps\mp\_matchdata::logplayerdeath( self.lifeid, var_1, var_3, var_4, var_5, var_13, var_7, var_21 ); + + if ( maps\mp\_utility::ismeleemod( var_4 ) && isplayer( var_1 ) && !issubstr( var_5, "riotshield" ) ) + var_1 maps\mp\_utility::incplayerstat( "knifekills", 1 ); + + if ( var_2 isswitchingteams() ) + handleteamchangedeath(); + else if ( !isplayer( var_1 ) || isplayer( var_1 ) && var_4 == "MOD_FALLING" ) + { + handleworlddeath( var_1, self.lifeid, var_4, var_7 ); + + if ( isagent( var_1 ) ) + var_24 = 1; + + if ( maps\mp\gametypes\_killcam::isworldkillcam( var_0, var_1 ) ) + var_24 = 1; + } + else if ( var_1 == var_2 && ( isdefined( var_0 ) && ( !isdefined( var_0.isorbitalcam ) || var_0.isorbitalcam == 0 ) ) ) + handlesuicidedeath( var_4, var_7 ); + else if ( var_18 ) + { + if ( !isdefined( var_2.nuked ) && ( !isdefined( level.iszombiegame ) || !level.iszombiegame ) ) + handlefriendlyfiredeath( var_1 ); + } + else + { + if ( var_4 == "MOD_GRENADE" && var_0 == var_1 || var_4 == "MOD_IMPACT" || var_4 == "MOD_GRENADE_SPLASH" || var_4 == "MOD_EXPLOSIVE" ) + addattacker( var_2, var_1, var_0, var_5, var_3, ( 0, 0, 0 ), var_6, var_7, var_8, var_4 ); + + var_24 = 1; + + if ( isai( var_2 ) && isdefined( level.bot_funcs ) && isdefined( level.bot_funcs["should_do_killcam"] ) ) + var_24 = var_2 [[ level.bot_funcs["should_do_killcam"] ]](); + + if ( isdefined( var_0 ) && ( !isdefined( var_0.isorbitalcam ) || var_0.isorbitalcam == 0 ) ) + { + handlenormaldeath( self.lifeid, var_1, var_0, var_5, var_4 ); + var_2 thread maps\mp\gametypes\_missions::playerkilled( var_0, var_1, var_3, var_4, var_5, var_13, var_7, var_1.modifiers ); + } + + var_2.pers["cur_death_streak"]++; + + if ( isplayer( var_1 ) && var_2 maps\mp\_utility::isjuggernaut() ) + var_1 thread maps\mp\_utility::teamplayercardsplash( "callout_killed_juggernaut", var_1 ); + } + + var_25 = 0; + var_26 = undefined; + + if ( isdefined( self.previousprimary ) ) + { + var_25 = 1; + var_26 = self.previousprimary; + self.previousprimary = undefined; + } + + if ( isplayer( var_1 ) && var_1 != self && ( !level.teambased || level.teambased && self.team != var_1.team ) ) + { + if ( var_25 && isdefined( var_26 ) ) + var_27 = var_26; + else + var_27 = self.lastdroppableweapon; + + thread maps\mp\gametypes\_gamelogic::trackleaderboarddeathstats( var_27, var_4 ); + var_1 thread maps\mp\gametypes\_gamelogic::trackattackerleaderboarddeathstats( var_5, var_4, var_0 ); + } + + var_2.wasswitchingteamsforonplayerkilled = undefined; + + if ( isdefined( var_2.switching_teams ) ) + var_2.wasswitchingteamsforonplayerkilled = 1; + + var_2 resetplayervariables(); + var_2.lastattacker = var_1; + var_2.lastinflictor = var_0; + + if ( !isdefined( var_2.agentbody ) ) + var_2.lastdeathpos = var_2.origin; + else + var_2.lastdeathpos = var_2.agentbody.origin; + + var_2.deathtime = gettime(); + var_2.wantsafespawn = 0; + var_2.revived = 0; + var_2.sameshotdamage = 0; + var_2 maps\mp\killstreaks\_killstreaks::resetadrenaline( 0 ); + var_28 = maps\mp\_awards::gettotalscore( var_2 ) - var_2.scoreatlifestart; + var_2 maps\mp\_utility::setplayerstatifgreater( "mostScorePerLife", var_28 ); + var_29 = undefined; + + if ( maps\mp\_utility::isrocketcorpse() ) + { + var_24 = 1; + var_10 = 0; + var_29 = self.killcament; + self waittill( "final_rocket_corpse_death" ); + } + else + { + if ( var_10 ) + { + var_24 = 0; + + if ( !isdefined( var_2.agentbody ) ) + var_9 = var_2 playerforcedeathanim( var_0, var_4, var_5, var_7, var_6 ); + } + + if ( isdefined( var_2.hideondeath ) && var_2.hideondeath ) + { + var_2 playerhide(); + thread maps\mp\gametypes\_deathicons::adddeathicon( var_2, var_2, var_2.team, 5.0, var_1 ); + } + else if ( !isdefined( var_2.agentbody ) ) + { + var_2.body = var_2 cloneplayer( var_9 ); + + if ( var_10 ) + var_2 playerhide(); + + if ( var_2 isonladder() || var_2 ismantling() || !var_2 isonground() || isdefined( var_2.nuked ) ) + var_2.body startragdoll(); + + if ( !isdefined( var_2.switching_teams ) ) + thread maps\mp\gametypes\_deathicons::adddeathicon( var_2.body, var_2, var_2.team, 5.0, var_1 ); + + thread delaystartragdoll( var_2.body, var_7, var_6, var_5, var_0, var_4 ); + } + else if ( !isdefined( var_2.switching_teams ) ) + thread maps\mp\gametypes\_deathicons::adddeathicon( var_2.agentbody, var_2, var_2.team, 5.0, var_1 ); + } + + var_2 thread [[ level.onplayerkilled ]]( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, self.lifeid ); + + if ( isai( var_2 ) && isdefined( level.bot_funcs ) && isdefined( level.bot_funcs["on_killed"] ) ) + var_2 thread [[ level.bot_funcs["on_killed"] ]]( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, self.lifeid ); + + if ( maps\mp\_utility::isgameparticipant( var_1 ) ) + var_30 = var_1 getentitynumber(); + else + var_30 = -1; + + if ( isdefined( level.iszombiegame ) && level.iszombiegame ) + var_30 = -1; + + if ( !isdefined( var_29 ) && isdefined( var_1 ) ) + var_29 = var_2 getkillcamentity( var_1, var_0, var_5 ); + + var_31 = -1; + var_32 = 0; + var_33 = 0; + + if ( isdefined( var_29 ) ) + { + var_31 = var_29 getentitynumber(); + var_32 = var_29.birthtime; + + if ( isdefined( var_29.killcamstarttime ) ) + { + var_32 = var_29.killcamstarttime; + var_33 = 1; + } + + if ( !isdefined( var_32 ) ) + var_32 = 0; + } + else if ( var_5 == "orbital_laser_fov_mp" && isdefined( var_0 ) && isdefined( var_0.killcamstarttime ) ) + { + var_32 = var_0.killcamstarttime; + var_33 = 1; + } + + if ( isdefined( var_1 ) && isdefined( var_1.lastspawntime ) ) + var_34 = ( gettime() - var_1.lastspawntime ) / 1000.0; + else + var_34 = 0; + + if ( var_4 != "MOD_SUICIDE" && !( !isdefined( var_1 ) || var_1.classname == "trigger_hurt" || var_1.classname == "worldspawn" || var_1 == var_2 ) ) + recordfinalkillcam( 5.0, var_2, var_1, var_30, var_31, var_32, var_5, var_12, var_8, var_4, "normal", var_33 ); + + if ( maps\mp\gametypes\_killcam::killcamvalid( var_2, var_24 ) ) + { + var_35 = maps\mp\gametypes\_playerlogic::timeuntilspawn( 1 ); + var_36 = maps\mp\gametypes\_gamelogic::timeuntilroundend(); + var_37 = maps\mp\gametypes\_killcam::killcamtime( var_32, var_5, 0, var_35, var_36, var_33, 0 ); + var_38 = maps\mp\gametypes\_killcam::killcamarchivetime( var_37, var_34, var_12, var_8 / 1000 ); + var_2 maps\mp\gametypes\_killcam::prekillcamnotify( var_0, var_1, var_38, var_21 ); + } + else if ( maps\mp\_utility::isvalidclass( var_2.class ) ) + var_2 maps\mp\gametypes\_playerlogic::streamclassweapons(); + + var_39 = gettime() + 5000; + + if ( !var_10 ) + { + wait 0.25; + var_2 thread maps\mp\gametypes\_killcam::cancelkillcamonuse(); + wait 0.25; + self.respawntimerstarttime = gettime() + 1000; + var_35 = maps\mp\gametypes\_playerlogic::timeuntilspawn( 1 ); + + if ( var_35 < 1 ) + var_35 = 1; + + wait 1.0; + + if ( isdefined( self.streamweapons ) && self.streamweapons.size > 0 ) + { + while ( maps\mp\gametypes\_killcam::killcamvalid( var_2, var_24 ) && isplayer( self ) && isplayer( var_1 ) && !self hasloadedcustomizationplayerview( var_1, self.streamweapons ) && gettime() < var_39 ) + waitframe(); + } + + var_2 notify( "death_delay_finished" ); + } + + var_40 = ( gettime() - var_2.deathtime ) / 1000; + self.respawntimerstarttime = gettime(); + var_41 = gettime() >= var_39; + + if ( maps\mp\gametypes\_killcam::killcamvalid( var_2, var_24 ) && !var_41 ) + { + var_42 = !( maps\mp\_utility::getgametypenumlives() && !var_2.pers["lives"] ); + var_35 = maps\mp\gametypes\_playerlogic::timeuntilspawn( 1 ); + var_43 = var_42 && var_35 <= 0; + + if ( !var_42 ) + { + var_35 = -1; + level notify( "player_eliminated", var_2 ); + } + + var_2 maps\mp\gametypes\_killcam::killcam( var_0, var_30, var_31, var_32, var_5, var_40 + var_12, var_8, var_35, maps\mp\gametypes\_gamelogic::timeuntilroundend(), var_1, var_2, var_4, "normal", var_34, var_33 ); + } + + if ( game["state"] != "playing" ) + { + if ( !level.showingfinalkillcam ) + { + var_2 maps\mp\_utility::updatesessionstate( "dead" ); + var_2 maps\mp\_utility::clearkillcamstate(); + } + + return; + } + + var_44 = maps\mp\_utility::getgametypenumlives(); + var_45 = self.pers["lives"]; + + if ( self == var_2 && isdefined( var_2.battlebuddy ) && maps\mp\_utility::isreallyalive( var_2.battlebuddy ) && ( !maps\mp\_utility::getgametypenumlives() || self.pers["lives"] ) && !var_2 maps\mp\_utility::isusingremote() ) + maps\mp\gametypes\_battlebuddy::waitforplayerrespawnchoice(); + + if ( maps\mp\_utility::isvalidclass( var_2.class ) ) + var_2 thread maps\mp\gametypes\_playerlogic::spawnclient(); +} + +waittimerforspawn() +{ + self endon( "randomSpawnPressed" ); + self.kc_teamspawntext settext( &"PLATFORM_PRESS_TO_TEAMSPAWN" ); + self.kc_teamspawntext.alpha = 1; + self.kc_randomspawntext settext( &"PLATFORM_PRESS_TO_RESPAWN" ); + self.kc_randomspawntext.alpha = 1; + thread waitteamspawnbutton(); + thread waitspawnrandombutton(); + + if ( isdefined( self.skippedkillcam ) && self.skippedkillcam ) + var_0 = 8; + else + var_0 = 9; + + if ( isdefined( self.timestartedtowait ) ) + var_1 = int( ceil( var_0 - ( gettime() - self.timestartedtowait ) / 1000 ) ); + else + var_1 = var_0; + + self.partnerspawning = 0; + wait 0.5; + + for ( var_2 = var_1; var_2 > 0; var_2-- ) + { + maps\mp\_utility::setlowermessage( "kc_info", &"MP_TIME_TILL_SPAWN", var_1, 1, 1 ); + wait 1; + } + + self.kc_randomspawntext.alpha = 0; + self.kc_teamspawntext.alpha = 0; + maps\mp\_utility::clearlowermessage( "kc_info" ); + self notify( "abort_fireteam_spawn" ); +} + +waitspawnrandombutton() +{ + self endon( "disconnect" ); + self endon( "abort_fireteam_spawn" ); + + while ( self usebuttonpressed() ) + wait 0.05; + + while ( !self usebuttonpressed() ) + { + wait 0.05; + + if ( !maps\mp\_utility::isreallyalive( self.partner ) ) + break; + } + + self.partnerspawning = 0; + self notify( "randomSpawnPressed" ); + self.kc_randomspawntext.alpha = 0; + self.kc_teamspawntext.alpha = 0; + maps\mp\_utility::clearlowermessage( "kc_info" ); + self notify( "abort_fireteam_spawn" ); +} + +waitteamspawnbutton() +{ + self endon( "disconnect" ); + self endon( "abort_fireteam_spawn" ); + + while ( self attackbuttonpressed() ) + wait 0.05; + + while ( !self attackbuttonpressed() ) + wait 0.05; + + self.partnerspawning = 1; + self playlocalsound( "copycat_steal_class" ); + self notify( "teamSpawnPressed" ); + self.kc_randomspawntext.alpha = 0; + self.kc_teamspawntext.alpha = 0; +} + +checkforcebleedout() +{ + if ( level.diehardmode != 1 ) + return 0; + + if ( !maps\mp\_utility::getgametypenumlives() ) + return 0; + + if ( level.livescount[self.team] > 0 ) + return 0; + + foreach ( var_1 in level.players ) + { + if ( !isalive( var_1 ) ) + continue; + + if ( var_1.team != self.team ) + continue; + + if ( var_1 == self ) + continue; + + if ( !var_1.inlaststand ) + return 0; + } + + foreach ( var_1 in level.players ) + { + if ( !isalive( var_1 ) ) + continue; + + if ( var_1.team != self.team ) + continue; + + if ( var_1.inlaststand && var_1 != self ) + var_1 laststandbleedout( 0 ); + } + + return 1; +} + +initfinalkillcam() +{ + level.finalkillcam_delay = []; + level.finalkillcam_victim = []; + level.finalkillcam_attacker = []; + level.finalkillcam_attackernum = []; + level.finalkillcam_killcamentityindex = []; + level.finalkillcam_killcamentitystarttime = []; + level.finalkillcam_sweapon = []; + level.finalkillcam_deathtimeoffset = []; + level.finalkillcam_psoffsettime = []; + level.finalkillcam_timerecorded = []; + level.finalkillcam_timegameended = []; + level.finalkillcam_smeansofdeath = []; + level.finalkillcam_type = []; + level.finalkillcam_usestarttime = []; + + if ( level.multiteambased ) + { + foreach ( var_1 in level.teamnamelist ) + { + level.finalkillcam_delay[var_1] = undefined; + level.finalkillcam_victim[var_1] = undefined; + level.finalkillcam_attacker[var_1] = undefined; + level.finalkillcam_attackernum[var_1] = undefined; + level.finalkillcam_killcamentityindex[var_1] = undefined; + level.finalkillcam_killcamentitystarttime[var_1] = undefined; + level.finalkillcam_sweapon[var_1] = undefined; + level.finalkillcam_deathtimeoffset[var_1] = undefined; + level.finalkillcam_psoffsettime[var_1] = undefined; + level.finalkillcam_timerecorded[var_1] = undefined; + level.finalkillcam_timegameended[var_1] = undefined; + level.finalkillcam_smeansofdeath[var_1] = undefined; + level.finalkillcam_type[var_1] = undefined; + level.finalkillcam_usestarttime[var_1] = undefined; + } + } + else + { + level.finalkillcam_delay["axis"] = undefined; + level.finalkillcam_victim["axis"] = undefined; + level.finalkillcam_attacker["axis"] = undefined; + level.finalkillcam_attackernum["axis"] = undefined; + level.finalkillcam_killcamentityindex["axis"] = undefined; + level.finalkillcam_killcamentitystarttime["axis"] = undefined; + level.finalkillcam_sweapon["axis"] = undefined; + level.finalkillcam_deathtimeoffset["axis"] = undefined; + level.finalkillcam_psoffsettime["axis"] = undefined; + level.finalkillcam_timerecorded["axis"] = undefined; + level.finalkillcam_timegameended["axis"] = undefined; + level.finalkillcam_smeansofdeath["axis"] = undefined; + level.finalkillcam_type["axis"] = undefined; + level.finalkillcam_usestarttime["axis"] = undefined; + level.finalkillcam_delay["allies"] = undefined; + level.finalkillcam_victim["allies"] = undefined; + level.finalkillcam_attacker["allies"] = undefined; + level.finalkillcam_attackernum["allies"] = undefined; + level.finalkillcam_killcamentityindex["allies"] = undefined; + level.finalkillcam_killcamentitystarttime["allies"] = undefined; + level.finalkillcam_sweapon["allies"] = undefined; + level.finalkillcam_deathtimeoffset["allies"] = undefined; + level.finalkillcam_psoffsettime["allies"] = undefined; + level.finalkillcam_timerecorded["allies"] = undefined; + level.finalkillcam_timegameended["allies"] = undefined; + level.finalkillcam_smeansofdeath["allies"] = undefined; + level.finalkillcam_type["allies"] = undefined; + level.finalkillcam_usestarttime["allies"] = undefined; + } + + level.finalkillcam_delay["none"] = undefined; + level.finalkillcam_victim["none"] = undefined; + level.finalkillcam_attacker["none"] = undefined; + level.finalkillcam_attackernum["none"] = undefined; + level.finalkillcam_killcamentityindex["none"] = undefined; + level.finalkillcam_killcamentitystarttime["none"] = undefined; + level.finalkillcam_sweapon["none"] = undefined; + level.finalkillcam_deathtimeoffset["none"] = undefined; + level.finalkillcam_psoffsettime["none"] = undefined; + level.finalkillcam_timerecorded["none"] = undefined; + level.finalkillcam_timegameended["none"] = undefined; + level.finalkillcam_smeansofdeath["none"] = undefined; + level.finalkillcam_type["none"] = undefined; + level.finalkillcam_usestarttime["none"] = undefined; + level.finalkillcam_winner = undefined; +} + +recordfinalkillcam( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_11 ) +{ + if ( level.teambased && isdefined( var_2.team ) ) + { + level.finalkillcam_delay[var_2.team] = var_0; + level.finalkillcam_victim[var_2.team] = var_1; + level.finalkillcam_attacker[var_2.team] = var_2; + level.finalkillcam_attackernum[var_2.team] = var_3; + level.finalkillcam_killcamentityindex[var_2.team] = var_4; + level.finalkillcam_killcamentitystarttime[var_2.team] = var_5; + level.finalkillcam_sweapon[var_2.team] = var_6; + level.finalkillcam_deathtimeoffset[var_2.team] = var_7; + level.finalkillcam_psoffsettime[var_2.team] = var_8; + level.finalkillcam_timerecorded[var_2.team] = maps\mp\_utility::getsecondspassed(); + level.finalkillcam_timegameended[var_2.team] = maps\mp\_utility::getsecondspassed(); + level.finalkillcam_smeansofdeath[var_2.team] = var_9; + level.finalkillcam_type[var_2.team] = var_10; + level.finalkillcam_usestarttime[var_2.team] = isdefined( var_11 ) && var_11; + } + + level.finalkillcam_delay["none"] = var_0; + level.finalkillcam_victim["none"] = var_1; + level.finalkillcam_attacker["none"] = var_2; + level.finalkillcam_attackernum["none"] = var_3; + level.finalkillcam_killcamentityindex["none"] = var_4; + level.finalkillcam_killcamentitystarttime["none"] = var_5; + level.finalkillcam_sweapon["none"] = var_6; + level.finalkillcam_deathtimeoffset["none"] = var_7; + level.finalkillcam_psoffsettime["none"] = var_8; + level.finalkillcam_timerecorded["none"] = maps\mp\_utility::getsecondspassed(); + level.finalkillcam_timegameended["none"] = maps\mp\_utility::getsecondspassed(); + level.finalkillcam_timegameended["none"] = maps\mp\_utility::getsecondspassed(); + level.finalkillcam_smeansofdeath["none"] = var_9; + level.finalkillcam_type["none"] = var_10; + level.finalkillcam_usestarttime["none"] = isdefined( var_11 ) && var_11; +} + +erasefinalkillcam() +{ + if ( level.multiteambased ) + { + for ( var_0 = 0; var_0 < level.teamnamelist.size; var_0++ ) + { + level.finalkillcam_delay[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_victim[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_attacker[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_attackernum[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_killcamentityindex[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_killcamentitystarttime[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_sweapon[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_deathtimeoffset[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_psoffsettime[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_timerecorded[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_timegameended[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_smeansofdeath[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_type[level.teamnamelist[var_0]] = undefined; + level.finalkillcam_usestarttime[level.teamnamelist[var_0]] = undefined; + } + } + else + { + level.finalkillcam_delay["axis"] = undefined; + level.finalkillcam_victim["axis"] = undefined; + level.finalkillcam_attacker["axis"] = undefined; + level.finalkillcam_attackernum["axis"] = undefined; + level.finalkillcam_killcamentityindex["axis"] = undefined; + level.finalkillcam_killcamentitystarttime["axis"] = undefined; + level.finalkillcam_sweapon["axis"] = undefined; + level.finalkillcam_deathtimeoffset["axis"] = undefined; + level.finalkillcam_psoffsettime["axis"] = undefined; + level.finalkillcam_timerecorded["axis"] = undefined; + level.finalkillcam_timegameended["axis"] = undefined; + level.finalkillcam_smeansofdeath["axis"] = undefined; + level.finalkillcam_type["axis"] = undefined; + level.finalkillcam_usestarttime["axis"] = undefined; + level.finalkillcam_delay["allies"] = undefined; + level.finalkillcam_victim["allies"] = undefined; + level.finalkillcam_attacker["allies"] = undefined; + level.finalkillcam_attackernum["allies"] = undefined; + level.finalkillcam_killcamentityindex["allies"] = undefined; + level.finalkillcam_killcamentitystarttime["allies"] = undefined; + level.finalkillcam_sweapon["allies"] = undefined; + level.finalkillcam_deathtimeoffset["allies"] = undefined; + level.finalkillcam_psoffsettime["allies"] = undefined; + level.finalkillcam_timerecorded["allies"] = undefined; + level.finalkillcam_timegameended["allies"] = undefined; + level.finalkillcam_smeansofdeath["allies"] = undefined; + level.finalkillcam_type["allies"] = undefined; + level.finalkillcam_usestarttime["allies"] = undefined; + } + + level.finalkillcam_delay["none"] = undefined; + level.finalkillcam_victim["none"] = undefined; + level.finalkillcam_attacker["none"] = undefined; + level.finalkillcam_attackernum["none"] = undefined; + level.finalkillcam_killcamentityindex["none"] = undefined; + level.finalkillcam_killcamentitystarttime["none"] = undefined; + level.finalkillcam_sweapon["none"] = undefined; + level.finalkillcam_deathtimeoffset["none"] = undefined; + level.finalkillcam_psoffsettime["none"] = undefined; + level.finalkillcam_timerecorded["none"] = undefined; + level.finalkillcam_timegameended["none"] = undefined; + level.finalkillcam_smeansofdeath["none"] = undefined; + level.finalkillcam_type["none"] = undefined; + level.finalkillcam_usestarttime["none"] = undefined; + level.finalkillcam_winner = undefined; +} + +streamfinalkillcam() +{ + if ( isai( self ) ) + return; + + var_0 = "none"; + + if ( isdefined( level.finalkillcam_winner ) ) + var_0 = level.finalkillcam_winner; + + var_1 = level.finalkillcam_victim[var_0]; + var_2 = level.finalkillcam_attacker[var_0]; + var_3 = level.finalkillcam_timegameended[var_0]; + var_4 = level.finalkillcam_timerecorded[var_0]; + + if ( !finalkillcamvalid( var_1, var_2, var_3, var_4 ) ) + return; + + var_5 = level.finalkillcam_killcamentitystarttime[var_0]; + var_6 = level.finalkillcam_sweapon[var_0]; + var_7 = level.finalkillcam_usestarttime[var_0]; + var_8 = level.finalkillcam_psoffsettime[var_0]; + var_9 = level.finalkillcam_deathtimeoffset[var_0]; + var_10 = ( gettime() - var_1.deathtime ) / 1000; + var_11 = var_10 + var_9; + var_12 = maps\mp\gametypes\_killcam::killcamtime( var_5, var_6, var_11, 0, getkillcambuffertime(), var_7, 1 ); + var_13 = var_12 + var_11 + var_8 / 1000; + self onlystreamactiveweapon( 1 ); + thread maps\mp\gametypes\_killcam::prekillcamnotify( level.finalkillcam_attacker[var_0], level.finalkillcam_attacker[var_0], var_13, "none" ); +} + +streamcheck( var_0 ) +{ + level endon( "stream_end" ); + + foreach ( var_2 in level.players ) + { + if ( isai( var_2 ) ) + continue; + + if ( isdefined( var_2.streamweapons ) && var_2.streamweapons.size > 0 ) + { + while ( isplayer( var_2 ) && isplayer( var_0 ) && !var_2 hasloadedcustomizationplayerview( var_0, var_2.streamweapons[0] ) ) + waitframe(); + } + } + + level notify( "stream_end" ); +} + +resetonlystreamactive() +{ + foreach ( var_1 in level.players ) + { + if ( !isai( var_1 ) ) + var_1 onlystreamactiveweapon( 0 ); + } +} + +streamtimeout( var_0 ) +{ + level endon( "stream_end" ); + wait(var_0); + level notify( "stream_end" ); +} + +waitforstream( var_0 ) +{ + thread streamtimeout( 5.0 ); + streamcheck( var_0 ); +} + +getkillcambuffertime() +{ + return 15; +} + +finalkillcamvalid( var_0, var_1, var_2, var_3 ) +{ + var_4 = isdefined( var_0 ) && isdefined( var_1 ) && !maps\mp\_utility::practiceroundgame(); + + if ( var_4 ) + { + var_5 = getkillcambuffertime(); + var_6 = var_2 - var_3; + + if ( var_6 <= var_5 ) + return 1; + } + + return 0; +} + +endfinalkillcam() +{ + resetonlystreamactive(); + level.showingfinalkillcam = 0; + level notify( "final_killcam_done" ); +} + +dofinalkillcam() +{ + level waittill( "round_end_finished" ); + level.showingfinalkillcam = 1; + var_0 = "none"; + + if ( isdefined( level.finalkillcam_winner ) ) + var_0 = level.finalkillcam_winner; + + var_1 = level.finalkillcam_delay[var_0]; + var_2 = level.finalkillcam_victim[var_0]; + var_3 = level.finalkillcam_attacker[var_0]; + var_4 = level.finalkillcam_attackernum[var_0]; + var_5 = level.finalkillcam_killcamentityindex[var_0]; + var_6 = level.finalkillcam_killcamentitystarttime[var_0]; + var_7 = level.finalkillcam_usestarttime[var_0]; + var_8 = level.finalkillcam_sweapon[var_0]; + var_9 = level.finalkillcam_deathtimeoffset[var_0]; + var_10 = level.finalkillcam_psoffsettime[var_0]; + var_11 = level.finalkillcam_timerecorded[var_0]; + var_12 = level.finalkillcam_timegameended[var_0]; + var_13 = level.finalkillcam_smeansofdeath[var_0]; + var_14 = level.finalkillcam_type[var_0]; + + if ( !finalkillcamvalid( var_2, var_3, var_12, var_11 ) ) + { + endfinalkillcam(); + return; + } + + if ( isdefined( var_3 ) ) + { + var_3.finalkill = 1; + + if ( level.gametype == "conf" && isdefined( level.finalkillcam_attacker[var_3.team] ) && level.finalkillcam_attacker[var_3.team] == var_3 ) + { + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_theedge" ); + + if ( isdefined( var_3.modifiers["revenge"] ) ) + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_moneyshot" ); + + if ( isdefined( var_3.infinalstand ) && var_3.infinalstand ) + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_lastresort" ); + + if ( isdefined( var_2 ) && isdefined( var_2.explosiveinfo ) && isdefined( var_2.explosiveinfo["stickKill"] ) && var_2.explosiveinfo["stickKill"] ) + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_stickman" ); + + if ( isdefined( var_2.attackerdata[var_3.guid] ) && isdefined( var_2.attackerdata[var_3.guid].smeansofdeath ) && isdefined( var_2.attackerdata[var_3.guid].weapon ) && issubstr( var_2.attackerdata[var_3.guid].smeansofdeath, "MOD_MELEE" ) && issubstr( var_2.attackerdata[var_3.guid].weapon, "riotshield_mp" ) ) + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_owned" ); + + switch ( level.finalkillcam_sweapon[var_3.team] ) + { + case "artillery_mp": + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_finishingtouch" ); + break; + case "stealth_bomb_mp": + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_technokiller" ); + break; + case "sentry_minigun_mp": + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_absentee" ); + break; + case "ac130_40mm_mp": + case "ac130_105mm_mp": + case "ac130_25mm_mp": + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_deathfromabove" ); + break; + case "remotemissile_projectile_mp": + var_3 maps\mp\gametypes\_missions::processchallenge( "ch_dronekiller" ); + break; + default: + break; + } + } + } + + waitforstream( var_3 ); + var_15 = ( gettime() - var_2.deathtime ) / 1000; + + foreach ( var_17 in level.players ) + { + var_17 maps\mp\_utility::revertvisionsetforplayer( 0 ); + var_17 setblurforplayer( 0, 0 ); + var_17.killcamentitylookat = var_2 getentitynumber(); + + if ( isdefined( var_3 ) && isdefined( var_3.lastspawntime ) ) + var_18 = ( gettime() - var_3.lastspawntime ) / 1000.0; + else + var_18 = 0; + + var_17 thread maps\mp\gametypes\_killcam::killcam( var_3, var_4, var_5, var_6, var_8, var_15 + var_9, var_10, 0, getkillcambuffertime(), var_3, var_2, var_13, var_14, var_18, var_7 ); + } + + wait 0.1; + + while ( anyplayersinkillcam() ) + wait 0.05; + + endfinalkillcam(); +} + +anyplayersinkillcam() +{ + foreach ( var_1 in level.players ) + { + if ( isdefined( var_1.killcam ) ) + return 1; + } + + return 0; +} + +resetplayervariables() +{ + self.killedplayerscurrent = []; + self.switching_teams = undefined; + self.joining_team = undefined; + self.leaving_team = undefined; + self.pers["cur_kill_streak"] = 0; + self.pers["cur_kill_streak_for_nuke"] = 0; + self.killstreakcount = 0; + maps\mp\gametypes\_gameobjects::detachusemodels(); +} + +getkillcamentity( var_0, var_1, var_2 ) +{ + if ( isdefined( var_0.didturretexplosion ) && var_0.didturretexplosion && isdefined( var_0.turret ) ) + { + var_0.didturretexplosion = undefined; + return var_0.turret.killcament; + } + + switch ( var_2 ) + { + case "boost_slam_mp": + return var_1; + case "iw5_dlcgun12loot6_mp": + case "remotemissile_projectile_cluster_child_mp": + case "orbital_carepackage_pod_plane_mp": + case "refraction_turret_mp": + case "agent_mp": + case "stealth_bomb_mp": + case "artillery_mp": + case "orbital_carepackage_droppod_mp": + case "orbital_carepackage_pod_mp": + case "explosive_drone_mp": + case "bouncingbetty_mp": + case "bomb_site_mp": + return var_1.killcament; + case "killstreak_laser2_mp": + if ( isdefined( var_1.samturret ) && isdefined( var_1.samturret.killcament ) ) + return var_1.samturret.killcament; + + break; + case "ball_drone_projectile_mp": + case "ball_drone_gun_mp": + if ( isplayer( var_0 ) && isdefined( var_0.balldrone ) && isdefined( var_0.balldrone.turret ) && isdefined( var_0.balldrone.turret.killcament ) ) + return var_0.balldrone.turret.killcament; + + break; + case "drone_assault_remote_turret_mp": + case "ugv_missile_mp": + if ( isdefined( var_1.killcament ) ) + return var_1.killcament; + else + return undefined; + case "assaultdrone_c4_mp": + if ( isdefined( var_1.hasaioption ) && var_1.hasaioption ) + return var_1; + else + return undefined; + case "warbird_missile_mp": + case "dam_turret_mp": + case "killstreak_solar_mp": + if ( isdefined( var_1 ) && isdefined( var_1.killcament ) ) + return var_1.killcament; + + break; + case "warbird_remote_turret_mp": + if ( isdefined( var_1 ) && isdefined( var_1.killcament ) ) + return var_1.killcament; + else + return undefined; + case "orbital_laser_fov_mp": + return undefined; + case "killstreakmahem_mp": + case "remote_energy_turret_mp": + case "sentry_minigun_mp": + if ( isdefined( var_1 ) && isdefined( var_1.remotecontrolled ) ) + return undefined; + + break; + case "none": + if ( isdefined( var_1.targetname ) && var_1.targetname == "care_package" ) + return var_1.killcament; + + break; + case "killstreak_terrace_mp": + case "detroit_tram_turret_mp": + case "remote_turret_mp": + case "ugv_turret_mp": + case "ac130_40mm_mp": + case "ac130_105mm_mp": + case "ac130_25mm_mp": + return undefined; + case "iw5_dlcgun12loot8_mp": + if ( isdefined( var_1.killcament ) ) + return var_1.killcament; + else + return undefined; + } + + if ( maps\mp\_utility::isdestructibleweapon( var_2 ) || maps\mp\_utility::isbombsiteweapon( var_2 ) ) + { + if ( isdefined( var_1.killcament ) && !var_0 attackerinremotekillstreak() ) + return var_1.killcament; + else + return undefined; + } + + if ( maps\mp\gametypes\_killcam::isworldkillcam( var_1, var_0 ) ) + return var_0.killcament; + + if ( !isdefined( var_1 ) || var_0 == var_1 && !isagent( var_0 ) ) + return undefined; + + return var_1; +} + +attackerinremotekillstreak() +{ + if ( !isdefined( self ) ) + return 0; + + if ( isdefined( level.chopper ) && isdefined( level.chopper.gunner ) && self == level.chopper.gunner ) + return 1; + + if ( isdefined( self.using_remote_turret ) && self.using_remote_turret ) + return 1; + + if ( isdefined( self.using_remote_tank ) && self.using_remote_tank ) + return 1; + + return 0; +} + +hitlocdebug( var_0, var_1, var_2, var_3, var_4 ) +{ + var_5 = []; + var_5[0] = 2; + var_5[1] = 3; + var_5[2] = 5; + var_5[3] = 7; + + if ( !getdvarint( "scr_hitloc_debug" ) ) + return; + + if ( !isdefined( var_0.hitlocinited ) ) + { + for ( var_6 = 0; var_6 < 6; var_6++ ) + var_0 setclientdvar( "ui_hitloc_" + var_6, "" ); + + var_0.hitlocinited = 1; + } + + if ( level.splitscreen || !isplayer( var_0 ) ) + return; + + var_7 = 6; + + if ( !isdefined( var_0.damageinfo ) ) + { + var_0.damageinfo = []; + + for ( var_6 = 0; var_6 < var_7; var_6++ ) + { + var_0.damageinfo[var_6] = spawnstruct(); + var_0.damageinfo[var_6].damage = 0; + var_0.damageinfo[var_6].hitloc = ""; + var_0.damageinfo[var_6].bp = 0; + var_0.damageinfo[var_6].jugg = 0; + var_0.damageinfo[var_6].colorindex = 0; + } + + var_0.damageinfocolorindex = 0; + var_0.damageinfovictim = undefined; + } + + for ( var_6 = var_7 - 1; var_6 > 0; var_6-- ) + { + var_0.damageinfo[var_6].damage = var_0.damageinfo[var_6 - 1].damage; + var_0.damageinfo[var_6].hitloc = var_0.damageinfo[var_6 - 1].hitloc; + var_0.damageinfo[var_6].bp = var_0.damageinfo[var_6 - 1].bp; + var_0.damageinfo[var_6].jugg = var_0.damageinfo[var_6 - 1].jugg; + var_0.damageinfo[var_6].colorindex = var_0.damageinfo[var_6 - 1].colorindex; + } + + var_0.damageinfo[0].damage = var_2; + var_0.damageinfo[0].hitloc = var_3; + var_0.damageinfo[0].bp = var_4 & level.idflags_penetration; + var_0.damageinfo[0].jugg = var_1 maps\mp\_utility::isjuggernaut(); + + if ( isdefined( var_0.damageinfovictim ) && var_0.damageinfovictim != var_1 ) + { + var_0.damageinfocolorindex++; + + if ( var_0.damageinfocolorindex == var_5.size ) + var_0.damageinfocolorindex = 0; + } + + var_0.damageinfovictim = var_1; + var_0.damageinfo[0].colorindex = var_0.damageinfocolorindex; + + for ( var_6 = 0; var_6 < var_7; var_6++ ) + { + var_8 = "^" + var_5[var_0.damageinfo[var_6].colorindex]; + + if ( var_0.damageinfo[var_6].hitloc != "" ) + { + var_9 = var_8 + var_0.damageinfo[var_6].hitloc; + + if ( var_0.damageinfo[var_6].bp ) + var_9 += " (BP)"; + + if ( var_0.damageinfo[var_6].jugg ) + var_9 += " (Jugg)"; + + var_0 setclientdvar( "ui_hitloc_" + var_6, var_9 ); + } + + var_0 setclientdvar( "ui_hitloc_damage_" + var_6, var_8 + var_0.damageinfo[var_6].damage ); + } +} + +ishardwrireprotected( var_0 ) +{ + if ( !maps\mp\_utility::_hasperk( "specialty_stun_resistance" ) ) + return 0; + + switch ( var_0 ) + { + case "mp_lab_gas": + case "killstreak_strike_missile_gas_mp": + return 1; + } + + return 0; +} + +callback_playerdamage_internal( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10 ) +{ + if ( getdvarint( "virtuallobbyactive", 0 ) ) + return "virtuallobbyactive"; + + var_1 = maps\mp\_utility::_validateattacker( var_1 ); + var_11 = maps\mp\_utility::strip_suffix( var_6, "_lefthand" ); + + if ( isdefined( var_5 ) && var_5 == "MOD_CRUSH" && isdefined( var_0 ) && isdefined( var_0.classname ) && var_0.classname == "script_vehicle" ) + return "crushed"; + + if ( !maps\mp\_utility::isreallyalive( var_2 ) && !isdefined( var_2.inliveplayerkillstreak ) ) + return "!isReallyAlive( victim )"; + + if ( isdefined( var_1 ) && var_1.classname == "script_origin" && isdefined( var_1.type ) && var_1.type == "soft_landing" ) + return "soft_landing"; + + if ( var_6 == "killstreak_emp_mp" ) + return "sWeapon == killstreak_emp_mp"; + + if ( var_2 ishardwrireprotected( var_6 ) ) + return "specialty_stun_resistance"; + + if ( ( var_11 == "emp_grenade_mp" || var_11 == "emp_grenade_var_mp" || var_11 == "emp_grenade_killstreak_mp" ) && var_5 != "MOD_IMPACT" ) + var_2 notify( "emp_grenaded", var_1 ); + + if ( isdefined( level.hostmigrationtimer ) ) + return "level.hostMigrationTimer"; + + if ( var_5 == "MOD_FALLING" ) + var_2 thread emitfalldamage( var_3 ); + + if ( var_5 == "MOD_EXPLOSIVE_BULLET" && var_3 != 1 ) + { + var_3 *= getdvarfloat( "scr_explBulletMod" ); + var_3 = int( var_3 ); + } + + if ( isdefined( var_1 ) && var_1.classname == "worldspawn" ) + var_1 = undefined; + + if ( isdefined( var_1 ) && isdefined( var_1.gunner ) ) + var_1 = var_1.gunner; + + if ( isdefined( var_1 ) && var_1 == var_2 && var_6 == "killstreak_strike_missile_gas_mp" ) + return "gasCloudOwner"; + + if ( isdefined( var_1 ) && isplayer( var_1 ) && isexplosivedamagemod( var_5 ) && issubstr( var_6, "explosive_drone" ) && var_2 maps\mp\_utility::_hasperk( "_specialty_blastshield" ) && maps\mp\_utility::isreallyalive( var_2 ) ) + var_2.explosive_drone_owner = var_1; + + var_12 = maps\mp\_utility::attackerishittingteam( var_2, var_1 ); + var_13 = isdefined( var_1 ) && isdefined( var_0 ) && isdefined( var_2 ) && isplayer( var_1 ) && var_1 == var_0 && var_1 == var_2 && !isdefined( var_0.poison ); + + if ( var_13 ) + return "attackerIsInflictorVictim"; + + var_14 = 0.0; + + if ( var_4 & level.idflags_stun ) + { + var_14 = 0.0; + var_3 = 0.0; + } + else if ( var_9 == "shield" ) + { + if ( var_12 && level.friendlyfire == 0 ) + return "attackerIsHittingTeammate"; + + if ( var_5 == "MOD_PISTOL_BULLET" || var_5 == "MOD_RIFLE_BULLET" || var_5 == "MOD_EXPLOSIVE_BULLET" && !var_12 ) + { + if ( isplayer( var_1 ) ) + { + var_1.lastattackedshieldplayer = var_2; + var_1.lastattackedshieldtime = gettime(); + } + + if ( maps\mp\_utility::isenvironmentweapon( var_6 ) ) + var_16 = 25; + else + var_16 = maps\mp\perks\_perks::cac_modified_damage( var_2, var_1, var_3, var_5, var_6, var_7, var_8, var_9 ); + + var_2.shielddamage += var_16; + + if ( !maps\mp\_utility::isenvironmentweapon( var_6 ) || common_scripts\utility::cointoss() ) + { + var_2.shieldbullethits++; + + if ( isdefined( var_2.pers["bulletsBlockedByShield"] ) ) + var_2.pers["bulletsBlockedByShield"]++; + } + + if ( var_2.shieldbullethits >= level.riotshieldxpbullets ) + { + var_2.shielddamage = 0; + var_2.shieldbullethits = 0; + } + } + + if ( var_4 & level.idflags_shield_explosive_impact ) + { + var_9 = "none"; + + if ( !( var_4 & level.idflags_shield_explosive_impact_huge ) ) + var_3 *= 0.0; + } + else if ( var_4 & level.idflags_shield_explosive_splash ) + { + if ( isdefined( var_0 ) && isdefined( var_0.stuckenemyentity ) && var_0.stuckenemyentity == var_2 ) + var_3 = 51; + + var_9 = "none"; + } + else + return "hit shield"; + } + else if ( maps\mp\_utility::ismeleemod( var_5 ) && issubstr( var_6, "riotshield" ) ) + { + if ( !( var_12 && level.friendlyfire == 0 ) ) + { + var_14 = 0.0; + var_2 stunplayer( 0.0 ); + } + } + + if ( !var_12 ) + var_3 = maps\mp\perks\_perks::cac_modified_damage( var_2, var_1, var_3, var_5, var_6, var_7, var_8, var_9, var_0 ); + + if ( isdefined( level.modifyplayerdamage ) ) + var_3 = [[ level.modifyplayerdamage ]]( var_2, var_0, var_1, var_3, var_5, var_6, var_7, var_8, var_9 ); + + if ( var_2 maps\mp\_utility::isjuggernaut() && !isagent( var_2 ) ) + { + if ( isdefined( level.customjuggernautdamagefunc ) ) + var_3 = [[ level.customjuggernautdamagefunc ]]( var_2, var_1, var_3, var_5, var_6, var_7, var_8, var_9, var_0 ); + else + var_3 = maps\mp\killstreaks\_juggernaut::juggernautmodifydamage( var_2, var_1, var_3, var_5, var_6, var_7, var_8, var_9, var_0 ); + } + + var_17 = isdefined( var_1 ) && !isdefined( var_1.gunner ) && ( var_1.classname == "script_vehicle" || var_1.classname == "misc_turret" || var_1.classname == "script_model" ); + var_12 = maps\mp\_utility::attackerishittingteam( var_2, var_1 ); + + if ( !var_3 ) + return "!iDamage"; + + var_2.idflags = var_4; + var_2.idflagstime = gettime(); + + if ( game["state"] == "postgame" ) + return "game[ state ] == postgame"; + + if ( var_2.sessionteam == "spectator" ) + return "victim.sessionteam == spectator"; + + if ( isdefined( var_2.candocombat ) && !var_2.candocombat ) + return "!victim.canDoCombat"; + + if ( isdefined( var_1 ) && isplayer( var_1 ) && isdefined( var_1.candocombat ) && !var_1.candocombat ) + return "!eAttacker.canDoCombat"; + + if ( isdefined( var_1 ) && isalive( var_1 ) && !isdefined( var_1.perkoutlined ) ) + var_1.perkoutlined = 0; + + if ( var_17 && var_12 ) + { + if ( var_5 == "MOD_CRUSH" ) + { + var_2 maps\mp\_utility::_suicide(); + return "suicide crush"; + } + + if ( !level.friendlyfire ) + return "!level.friendlyfire"; + } + + if ( isai( self ) ) + self [[ level.bot_funcs["on_damaged"] ]]( var_1, var_3, var_5, var_6, var_0, var_9 ); + + if ( !isdefined( var_8 ) ) + var_4 |= level.idflags_no_knockback; + + var_18 = 0; + + if ( var_2.health == var_2.maxhealth && ( !isdefined( var_2.laststand ) || !var_2.laststand ) || !isdefined( var_2.attackers ) && !isdefined( var_2.laststand ) ) + { + var_2.attackers = []; + var_2.attackerdata = []; + } + + if ( maps\mp\_utility::isheadshot( var_6, var_9, var_5, var_1 ) ) + var_5 = "MOD_HEAD_SHOT"; + + if ( maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "onlyheadshots" ) ) + { + if ( var_5 == "MOD_PISTOL_BULLET" || var_5 == "MOD_RIFLE_BULLET" || var_5 == "MOD_EXPLOSIVE_BULLET" ) + return "getTweakableValue( game, onlyheadshots )"; + else if ( var_5 == "MOD_HEAD_SHOT" ) + { + if ( var_2 maps\mp\_utility::isjuggernaut() ) + var_3 = 75; + else + var_3 = 150; + } + } + + if ( var_6 == "none" && isdefined( var_0 ) ) + { + if ( isdefined( var_0.destructible_type ) && issubstr( var_0.destructible_type, "vehicle_" ) ) + var_6 = "destructible_car"; + } + + if ( gettime() < var_2.spawntime + level.killstreakspawnshield ) + { + var_19 = int( max( var_2.health / 4, 1 ) ); + + if ( var_3 >= var_19 && maps\mp\_utility::iskillstreakweapon( var_6 ) && !maps\mp\_utility::ismeleemod( var_5 ) ) + var_3 = var_19; + } + + if ( !( var_4 & level.idflags_no_protection ) ) + { + if ( !level.teambased && var_17 && isdefined( var_1.owner ) && var_1.owner == var_2 ) + { + if ( var_5 == "MOD_CRUSH" ) + var_2 maps\mp\_utility::_suicide(); + + return "ffa suicide"; + } + + if ( ( issubstr( var_5, "MOD_GRENADE" ) || issubstr( var_5, "MOD_EXPLOSIVE" ) || issubstr( var_5, "MOD_PROJECTILE" ) ) && isdefined( var_0 ) && isdefined( var_1 ) ) + { + if ( var_2 != var_1 && var_0.classname == "grenade" && var_2.lastspawntime + 3500 > gettime() && isdefined( var_2.lastspawnpoint ) && distance( var_0.origin, var_2.lastspawnpoint.origin ) < 250 ) + return "spawnkill grenade protection"; + + var_2.explosiveinfo = []; + var_2.explosiveinfo["damageTime"] = gettime(); + var_2.explosiveinfo["damageId"] = var_0 getentitynumber(); + var_2.explosiveinfo["returnToSender"] = 0; + var_2.explosiveinfo["counterKill"] = 0; + var_2.explosiveinfo["chainKill"] = 0; + var_2.explosiveinfo["cookedKill"] = 0; + var_2.explosiveinfo["throwbackKill"] = 0; + var_2.explosiveinfo["suicideGrenadeKill"] = 0; + var_2.explosiveinfo["weapon"] = var_6; + var_20 = issubstr( var_6, "frag_" ); + + if ( var_1 != var_2 ) + { + if ( ( issubstr( var_6, "c4_" ) || issubstr( var_6, "claymore_" ) ) && isdefined( var_1 ) && isdefined( var_0.owner ) ) + { + var_2.explosiveinfo["returnToSender"] = var_0.owner == var_2; + var_2.explosiveinfo["counterKill"] = isdefined( var_0.wasdamaged ); + var_2.explosiveinfo["chainKill"] = isdefined( var_0.waschained ); + var_2.explosiveinfo["bulletPenetrationKill"] = isdefined( var_0.wasdamagedfrombulletpenetration ); + var_2.explosiveinfo["cookedKill"] = 0; + } + + if ( isdefined( var_1.lastgrenadesuicidetime ) && var_1.lastgrenadesuicidetime >= gettime() - 50 && var_20 ) + var_2.explosiveinfo["suicideGrenadeKill"] = 1; + } + + if ( var_20 ) + { + var_2.explosiveinfo["cookedKill"] = isdefined( var_0.iscooked ); + var_2.explosiveinfo["throwbackKill"] = isdefined( var_0.threwback ); + } + + var_2.explosiveinfo["stickKill"] = isdefined( var_0.isstuck ) && var_0.isstuck == "enemy"; + var_2.explosiveinfo["stickFriendlyKill"] = isdefined( var_0.isstuck ) && var_0.isstuck == "friendly"; + + if ( isplayer( var_1 ) && var_1 != self ) + maps\mp\gametypes\_gamelogic::setinflictorstat( var_0, var_1, var_6 ); + } + + if ( issubstr( var_5, "MOD_IMPACT" ) && ( var_6 == "m320_mp" || issubstr( var_6, "gl" ) || issubstr( var_6, "gp25" ) ) ) + { + if ( isplayer( var_1 ) && var_1 != self ) + maps\mp\gametypes\_gamelogic::setinflictorstat( var_0, var_1, var_6 ); + } + + if ( var_12 ) + { + if ( level.friendlyfire == 0 || !isplayer( var_1 ) && level.friendlyfire != 1 ) + { + if ( var_6 == "artillery_mp" || var_6 == "stealth_bomb_mp" ) + var_2 damageshellshockandrumble( var_0, var_6, var_5, var_3, var_4, var_1 ); + + return "friendly fire"; + } + else if ( level.friendlyfire == 1 ) + { + if ( var_3 < 1 ) + var_3 = 1; + + if ( var_2 maps\mp\_utility::isjuggernaut() ) + var_3 = maps\mp\perks\_perks::cac_modified_damage( var_2, var_1, var_3, var_5, var_6, var_7, var_8, var_9 ); + + var_2.lastdamagewasfromenemy = 0; + var_2 finishplayerdamagewrapper( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_14 ); + } + else if ( level.friendlyfire == 2 && maps\mp\_utility::isreallyalive( var_1 ) ) + { + var_3 = int( var_3 * 0.5 ); + + if ( var_3 < 1 ) + var_3 = 1; + + var_1.lastdamagewasfromenemy = 0; + var_1.friendlydamage = 1; + var_1 finishplayerdamagewrapper( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_14 ); + var_1.friendlydamage = undefined; + } + else if ( level.friendlyfire == 3 && maps\mp\_utility::isreallyalive( var_1 ) ) + { + var_3 = int( var_3 * 0.5 ); + + if ( var_3 < 1 ) + var_3 = 1; + + var_2.lastdamagewasfromenemy = 0; + var_1.lastdamagewasfromenemy = 0; + var_2 finishplayerdamagewrapper( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_14 ); + + if ( maps\mp\_utility::isreallyalive( var_1 ) ) + { + var_1.friendlydamage = 1; + var_1 finishplayerdamagewrapper( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_14 ); + var_1.friendlydamage = undefined; + } + } + + var_18 = 1; + } + else + { + if ( var_3 < 1 ) + var_3 = 1; + + if ( isdefined( var_1 ) && isplayer( var_1 ) ) + addattacker( var_2, var_1, var_0, var_6, var_3, var_7, var_8, var_9, var_10, var_5 ); + + if ( isdefined( var_1 ) && !isplayer( var_1 ) && isdefined( var_1.owner ) && ( !isdefined( var_1.scrambled ) || !var_1.scrambled ) ) + addattacker( var_2, var_1.owner, var_0, var_6, var_3, var_7, var_8, var_9, var_10, var_5 ); + else if ( isdefined( var_1 ) && !isplayer( var_1 ) && isdefined( var_1.secondowner ) && isdefined( var_1.scrambled ) && var_1.scrambled ) + addattacker( var_2, var_1.secondowner, var_0, var_6, var_3, var_7, var_8, var_9, var_10, var_5 ); + + if ( var_5 == "MOD_EXPLOSIVE" || var_5 == "MOD_GRENADE_SPLASH" && var_3 < var_2.health ) + var_2 notify( "survived_explosion", var_1 ); + + if ( isdefined( var_1 ) && isplayer( var_1 ) && isdefined( var_6 ) ) + var_1 thread maps\mp\gametypes\_weapons::checkhit( var_6, var_2 ); + + var_2.attackerposition = undefined; + + if ( isdefined( var_1 ) && isplayer( var_1 ) && isdefined( var_6 ) && var_1 != var_2 ) + var_2.attackerposition = var_1.origin; + + if ( issubstr( var_5, "MOD_GRENADE" ) && isdefined( var_0 ) && isdefined( var_0.iscooked ) ) + var_2.wascooked = gettime(); + else + var_2.wascooked = undefined; + + if ( issubstr( var_5, "MOD_IMPACT" ) && isdefined( var_0 ) && isdefined( var_0.recall ) && var_0.recall ) + var_2.wasrecall = 1; + else + var_2.wasrecall = 0; + + var_2.lastdamagewasfromenemy = isdefined( var_1 ) && var_1 != var_2; + + if ( var_2.lastdamagewasfromenemy ) + { + var_21 = gettime(); + var_1.damagedplayers[var_2.guid] = var_21; + var_2.lastdamagedtime = var_21; + } + + var_2 finishplayerdamagewrapper( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_14 ); + var_2 thread maps\mp\gametypes\_missions::playerdamaged( var_0, var_1, var_3, var_5, var_6, var_9 ); + } + + if ( var_3 > 0 && var_5 != "MOD_FALLING" ) + var_2 setclientomnvar( "ui_damage_flash", 1 ); + + if ( var_17 && isdefined( var_1.gunner ) ) + var_22 = var_1.gunner; + else + var_22 = var_1; + + if ( isdefined( var_22 ) && ( var_22 != var_2 || maps\mp\_utility::iskillstreakweapon( var_6 ) ) && var_3 > 0 && ( !isdefined( var_9 ) || var_9 != "shield" ) ) + { + if ( !maps\mp\_utility::isreallyalive( var_2 ) ) + { + if ( var_9 == "head" ) + var_23 = "killshot_headshot"; + else + var_23 = "killshot"; + } + else if ( var_4 & level.idflags_stun ) + var_23 = "stun"; + else if ( var_9 == "head" ) + var_23 = "headshot"; + else if ( isdefined( var_2.exo_health_on ) && var_2.exo_health_on == 1 ) + var_23 = "hitmorehealth"; + else if ( isexplosivedamagemod( var_5 ) && var_2 maps\mp\_utility::_hasperk( "_specialty_blastshield" ) ) + var_23 = "hitblastshield"; + else if ( isdefined( var_2.lightarmorhp ) && var_5 != "MOD_HEAD_SHOT" && !maps\mp\_utility::isfmjdamage( var_6, var_5, var_1 ) ) + var_23 = "hitlightarmor"; + else if ( var_2 maps\mp\_utility::isjuggernaut() ) + var_23 = "hitjuggernaut"; + else if ( !shouldweaponfeedback( var_6 ) ) + var_23 = "none"; + else if ( var_6 == "killstreak_solar_mp" ) + var_23 = "mp_solar"; + else if ( var_6 == "killstreak_laser2_mp" ) + var_23 = "laser"; + else if ( isdefined( var_2.exo_health_on ) && var_2.exo_health_on ) + var_23 = "hitjuggernaut"; + else + var_23 = "standard"; + + var_22 thread maps\mp\gametypes\_damagefeedback::updatedamagefeedback( var_23 ); + } + + maps\mp\gametypes\_gamelogic::sethasdonecombat( var_2, 1 ); + } + + if ( isdefined( var_1 ) && var_1 != var_2 && !var_18 ) + level.usestartspawns = 0; + + if ( var_2.sessionstate != "dead" ) + { + var_24 = var_2 getentitynumber(); + var_25 = var_2.name; + var_26 = var_2.pers["team"]; + var_27 = var_2.guid; + var_28 = ""; + + if ( isplayer( var_1 ) ) + { + var_29 = var_1 getentitynumber(); + var_30 = var_1.guid; + var_31 = var_1.name; + var_28 = var_1.pers["team"]; + } + else + { + var_29 = -1; + var_30 = ""; + var_31 = ""; + var_28 = "world"; + } + + if ( isplayer( var_1 ) ) + { + var_32 = var_1.name; + var_33 = var_1.origin; + var_34 = var_1.lifeid; + } + else + { + var_32 = "world"; + var_33 = var_2.origin; + var_34 = -1; + } + + var_35 = gettime(); + + if ( !isagent( var_2 ) && isdefined( var_2.spawninfo ) && isdefined( var_2.spawninfo.spawntime ) ) + { + var_36 = ( var_35 - var_2.spawninfo.spawntime ) / 1000.0; + + if ( var_36 <= 3.0 && var_2.spawninfo.damagereceivedtoofast == 0 ) + { + if ( !isdefined( level.matchdata ) ) + level.matchdata = []; + + if ( !isdefined( level.matchdata["badSpawnDmgReceivedCount"] ) ) + level.matchdata["badSpawnDmgReceivedCount"] = 1; + else + level.matchdata["badSpawnDmgReceivedCount"]++; + + var_2.spawninfo.damagereceivedtoofast = 1; + + if ( var_2.spawninfo.badspawn == 0 ) + { + if ( !isdefined( level.matchdata["badSpawnByAnyMeansCount"] ) ) + level.matchdata["badSpawnByAnyMeansCount"] = 1; + else + level.matchdata["badSpawnByAnyMeansCount"]++; + + var_2.spawninfo.badspawn = 1; + } + } + } + else + var_36 = -1; + + if ( isdefined( var_1 ) && isdefined( var_1.spawninfo ) && isdefined( var_1.spawninfo.spawntime ) && isplayer( var_1 ) ) + { + var_37 = ( var_35 - var_1.spawninfo.spawntime ) / 1000.0; + + if ( var_37 <= 3.0 && var_1.spawninfo.damagedealttoofast == 0 ) + { + if ( !isdefined( level.matchdata ) ) + level.matchdata = []; + + if ( !isdefined( level.matchdata["badSpawnDmgDealtCount"] ) ) + level.matchdata["badSpawnDmgDealtCount"] = 1; + else + level.matchdata["badSpawnDmgDealtCount"]++; + + var_1.spawninfo.damagedealttoofast = 1; + + if ( var_1.spawninfo.badspawn == 0 ) + { + if ( !isdefined( level.matchdata["badSpawnByAnyMeansCount"] ) ) + level.matchdata["badSpawnByAnyMeansCount"] = 1; + else + level.matchdata["badSpawnByAnyMeansCount"]++; + + var_1.spawninfo.badspawn = 1; + } + } + } + else + var_37 = -1; + + if ( !isagent( var_2 ) ) + reconspatialevent( var_2.origin, "script_mp_damage: player_name %s, player_angles %v, hit_loc %s, attacker_name %s, attacker_pos %v, damage %d, weapon %s, damage_type %s, gameTime %d, life_id %d, attacker_life_id %d, spawnToDamageReceivedTime %f, spawnToDamageDealtTime %f", var_2.name, var_2.angles, var_9, var_32, var_33, var_3, var_6, var_5, var_35, var_2.lifeid, var_34, var_36, var_37 ); + + logprint( "D;" + var_27 + ";" + var_24 + ";" + var_26 + ";" + var_25 + ";" + var_30 + ";" + var_29 + ";" + var_28 + ";" + var_31 + ";" + var_6 + ";" + var_3 + ";" + var_5 + ";" + var_9 + "\n" ); + } + + hitlocdebug( var_1, var_2, var_3, var_9, var_4 ); + + if ( isagent( self ) ) + self [[ maps\mp\agents\_agent_utility::agentfunc( "on_damaged_finished" ) ]]( var_0, var_1, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10 ); + + return "finished"; +} + +shouldweaponfeedback( var_0 ) +{ + switch ( var_0 ) + { + case "stealth_bomb_mp": + case "artillery_mp": + return 0; + } + + return 1; +} + +addattacker( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 ) +{ + if ( !isdefined( var_0.attackerdata ) ) + var_0.attackerdata = []; + + if ( !isdefined( var_0.attackerdata[var_1.guid] ) ) + { + var_0.attackers[var_1.guid] = var_1; + var_0.attackerdata[var_1.guid] = spawnstruct(); + var_0.attackerdata[var_1.guid].damage = 0; + var_0.attackerdata[var_1.guid].attackerent = var_1; + var_0.attackerdata[var_1.guid].firsttimedamaged = gettime(); + } + + if ( maps\mp\gametypes\_weapons::isprimaryweapon( var_3 ) && !maps\mp\gametypes\_weapons::issidearm( var_3 ) ) + var_0.attackerdata[var_1.guid].isprimary = 1; + + var_0.attackerdata[var_1.guid].damage += var_4; + var_0.attackerdata[var_1.guid].weapon = var_3; + var_0.attackerdata[var_1.guid].vpoint = var_5; + var_0.attackerdata[var_1.guid].vdir = var_6; + var_0.attackerdata[var_1.guid].shitloc = var_7; + var_0.attackerdata[var_1.guid].psoffsettime = var_8; + var_0.attackerdata[var_1.guid].smeansofdeath = var_9; + var_0.attackerdata[var_1.guid].attackerent = var_1; + var_0.attackerdata[var_1.guid].lasttimedamaged = gettime(); + + if ( isdefined( var_2 ) && !isplayer( var_2 ) && isdefined( var_2.primaryweapon ) ) + var_0.attackerdata[var_1.guid].sprimaryweapon = var_2.primaryweapon; + else if ( isdefined( var_1 ) && isplayer( var_1 ) && var_1 getcurrentprimaryweapon() != "none" ) + var_0.attackerdata[var_1.guid].sprimaryweapon = var_1 getcurrentprimaryweapon(); + else + var_0.attackerdata[var_1.guid].sprimaryweapon = undefined; + + if ( !isdefined( var_0.enemyhitcounts ) ) + var_0.enemyhitcounts = []; + + if ( isplayer( var_1 ) ) + { + if ( !isdefined( var_0.enemyhitcounts[var_1.guid] ) ) + var_0.enemyhitcounts[var_1.guid] = 0; + + var_0.enemyhitcounts[var_1.guid]++; + var_0.lastshotby = var_1.clientid; + } +} + +resetattackerlist() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + clearfirefightdata(); + wait 1.75; + self.attackers = []; + self.attackerdata = []; +} + +clearfirefightdata() +{ + self.enemyhitcounts = []; + self.currentfirefightshots = 0; +} + +clearfirefightshotsoninterval() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + for (;;) + { + wait 3; + + if ( isdefined( self.enemyhitcounts ) && self.enemyhitcounts.size > 0 ) + continue; + else + self.currentfirefightshots = 0; + } +} + +is_countered_by_hardwired( var_0 ) +{ + switch ( var_0 ) + { + case "paint_grenade_var_mp": + case "emp_grenade_var_mp": + case "stun_grenade_var_mp": + case "emp_grenade_mp": + case "paint_grenade_mp": + case "stun_grenade_mp": + return 1; + } + + return 0; +} + +callback_playerdamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 ) +{ + var_10 = callback_playerdamage_internal( var_0, var_1, self, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 ); +} + +finishplayerdamagewrapper( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10 ) +{ + var_11 = 0; + + if ( maps\mp\_utility::isusingremote() && var_2 >= self.health && !( var_3 & level.idflags_stun ) && !isdefined( self.inliveplayerkillstreak ) && !self isgod() ) + var_11 = 1; + + if ( isdefined( level.ishorde ) && level.ishorde ) + var_11 = 0; + + if ( var_11 || maps\mp\_utility::isrocketcorpse() ) + { + if ( !isdefined( var_7 ) ) + var_7 = ( 0, 0, 0 ); + + if ( !isdefined( var_1 ) && !isdefined( var_0 ) ) + { + var_1 = self; + var_0 = var_1; + } + + playerkilled_internal( var_0, var_1, self, var_2, var_4, var_5, var_7, var_8, var_9, 0, 1 ); + } + else + { + if ( !callback_killingblow( var_0, var_1, var_2 - var_2 * var_10, var_3, var_4, var_5, var_6, var_7, var_8, var_9 ) ) + return; + + if ( !isalive( self ) ) + return; + + if ( isplayer( self ) ) + { + var_12 = shouldplayblastimpact( var_3, var_4, var_5 ); + var_13 = self finishplayerdamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_12 ); + + if ( isdefined( var_13 ) ) + thread finishplayerdamage_impactfxwrapper( var_13[0], var_13[1], var_13[2], var_13[3], var_13[4], var_13[5], var_13[6] ); + } + } + + if ( var_4 == "MOD_EXPLOSIVE_BULLET" ) + self shellshock( "damage_mp", getdvarfloat( "scr_csmode" ) ); + + damageshellshockandrumble( var_0, var_5, var_4, var_2, var_3, var_1 ); +} + +shouldplayblastimpact( var_0, var_1, var_2 ) +{ + if ( var_0 & level.idflags_radius && isexplosivedamagemod( var_1 ) ) + { + if ( is_countered_by_hardwired( var_2 ) ) + { + if ( !maps\mp\_utility::_hasperk( "specialty_class_hardwired" ) ) + return 1; + } + else if ( !maps\mp\_utility::_hasperk( "specialty_hard_shell" ) ) + return 1; + } + + return 0; +} + +finishplayerdamage_impactfxwrapper( var_0, var_1, var_2, var_3, var_4, var_5, var_6 ) +{ + waittillframeend; + + if ( !isdefined( self ) || !isdefined( var_0 ) ) + return; + + self finishplayerdamage_impactfx( var_0, var_1, var_2, var_3, var_4, var_5, var_6 ); +} + +callback_playerlaststand( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8 ) +{ + var_9 = spawnstruct(); + var_9.einflictor = var_0; + var_9.attacker = var_1; + var_9.idamage = var_2; + var_9.attackerposition = var_1.origin; + + if ( var_1 == self ) + var_9.smeansofdeath = "MOD_SUICIDE"; + else + var_9.smeansofdeath = var_3; + + var_9.sweapon = var_4; + + if ( isdefined( var_1 ) && isplayer( var_1 ) && var_1 getcurrentprimaryweapon() != "none" ) + var_9.sprimaryweapon = var_1 getcurrentprimaryweapon(); + else + var_9.sprimaryweapon = undefined; + + var_9.vdir = var_5; + var_9.shitloc = var_6; + var_9.laststandstarttime = gettime(); + var_10 = maydolaststand( var_4, var_3, var_6 ); + + if ( isdefined( self.endgame ) ) + var_10 = 0; + + if ( level.teambased && isdefined( var_1.team ) && var_1.team == self.team ) + var_10 = 0; + + if ( level.diehardmode ) + { + if ( level.teamcount[self.team] <= 1 ) + var_10 = 0; + else if ( maps\mp\_utility::isteaminlaststand() ) + { + var_10 = 0; + maps\mp\_utility::killteaminlaststand( self.team ); + } + } + + if ( !var_10 ) + { + self.laststandparams = var_9; + self.uselaststandparams = 1; + maps\mp\_utility::_suicide(); + } + else + { + self.inlaststand = 1; + var_11 = spawnstruct(); + + if ( maps\mp\_utility::_hasperk( "specialty_finalstand" ) ) + { + var_11.titletext = game["strings"]["final_stand"]; + var_11.iconname = level.specialty_finalstand_icon; + } + else + { + var_11.titletext = game["strings"]["last_stand"]; + var_11.iconname = level.specialty_finalstand_icon; + } + + var_11.glowcolor = ( 1, 0, 0 ); + var_11.sound = "mp_last_stand"; + var_11.duration = 2.0; + self.health = 1; + thread maps\mp\gametypes\_hud_message::notifymessage( var_11 ); + var_12 = "frag_grenade_mp"; + + if ( maps\mp\_utility::_hasperk( "specialty_finalstand" ) ) + { + self.laststandparams = var_9; + self.infinalstand = 1; + var_13 = self getweaponslistexclusives(); + + foreach ( var_15 in var_13 ) + self takeweapon( var_15 ); + + common_scripts\utility::_disableusability(); + thread enablelaststandweapons(); + thread laststandtimer( 20, 1 ); + } + else + { + if ( level.diehardmode ) + { + var_1 thread maps\mp\_events::killedplayerevent( self, var_4, var_3 ); + self.laststandparams = var_9; + common_scripts\utility::_disableweapon(); + thread laststandtimer( 20, 0 ); + common_scripts\utility::_disableusability(); + return; + } + + self.laststandparams = var_9; + var_17 = undefined; + var_18 = self getweaponslistprimaries(); + + foreach ( var_15 in var_18 ) + { + if ( maps\mp\gametypes\_weapons::issidearm( var_15 ) ) + var_17 = var_15; + } + + if ( !isdefined( var_17 ) ) + { + var_17 = "iw6_p226_mp"; + maps\mp\_utility::_giveweapon( var_17 ); + } + + self givemaxammo( var_17 ); + self disableweaponswitch(); + common_scripts\utility::_disableusability(); + + if ( !maps\mp\_utility::_hasperk( "specialty_laststandoffhand" ) ) + self disableoffhandweapons(); + + self switchtoweapon( var_17 ); + thread laststandtimer( 10, 0 ); + } + } +} + +dieaftertime( var_0 ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "joined_team" ); + level endon( "game_ended" ); + wait(var_0); + self.uselaststandparams = 1; + maps\mp\_utility::_suicide(); +} + +detonateonuse() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "joined_team" ); + level endon( "game_ended" ); + self waittill( "detonate" ); + self.uselaststandparams = 1; + c4deathdetonate(); +} + +detonateondeath() +{ + self endon( "detonate" ); + self endon( "disconnect" ); + self endon( "joined_team" ); + level endon( "game_ended" ); + self waittill( "death" ); + c4deathdetonate(); +} + +c4deathdetonate() +{ + self playsound( "detpack_explo_default" ); + self.c4deatheffect = playfx( level.c4death, self.origin ); + radiusdamage( self.origin, 312, 100, 100, self ); + + if ( isalive( self ) ) + maps\mp\_utility::_suicide(); +} + +enablelaststandweapons() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + maps\mp\_utility::freezecontrolswrapper( 1 ); + wait 0.3; + maps\mp\_utility::freezecontrolswrapper( 0 ); +} + +laststandtimer( var_0, var_1 ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "revive" ); + level endon( "game_ended" ); + level notify( "player_last_stand" ); + thread laststandwaittilldeath(); + self.laststand = 1; + + if ( !var_1 && ( !isdefined( self.inc4death ) || !self.inc4death ) ) + { + thread laststandallowsuicide(); + maps\mp\_utility::setlowermessage( "last_stand", &"PLATFORM_COWARDS_WAY_OUT", undefined, undefined, undefined, undefined, undefined, undefined, 1 ); + thread laststandkeepoverlay(); + } + + if ( level.diehardmode == 1 && level.diehardmode != 2 ) + { + var_2 = spawn( "script_model", self.origin ); + var_2 setmodel( "tag_origin" ); + var_2 setcursorhint( "HINT_NOICON" ); + var_2 sethintstring( &"PLATFORM_REVIVE" ); + var_2 revivesetup( self ); + var_2 endon( "death" ); + var_3 = newteamhudelem( self.team ); + var_3 setshader( "waypoint_revive", 8, 8 ); + var_3 setwaypoint( 1, 1 ); + var_3 settargetent( self ); + var_3 thread destroyonreviveentdeath( var_2 ); + var_3.color = ( 0.33, 0.75, 0.24 ); + maps\mp\_utility::playdeathsound(); + + if ( var_1 ) + { + wait(var_0); + + if ( self.infinalstand ) + thread laststandbleedout( var_1, var_2 ); + } + + return; + } + else if ( level.diehardmode == 2 ) + { + thread laststandkeepoverlay(); + var_2 = spawn( "script_model", self.origin ); + var_2 setmodel( "tag_origin" ); + var_2 setcursorhint( "HINT_NOICON" ); + var_2 sethintstring( &"PLATFORM_REVIVE" ); + var_2 revivesetup( self ); + var_2 endon( "death" ); + var_3 = newteamhudelem( self.team ); + var_3 setshader( "waypoint_revive", 8, 8 ); + var_3 setwaypoint( 1, 1 ); + var_3 settargetent( self ); + var_3 thread destroyonreviveentdeath( var_2 ); + var_3.color = ( 0.33, 0.75, 0.24 ); + maps\mp\_utility::playdeathsound(); + + if ( var_1 ) + { + wait(var_0); + + if ( self.infinalstand ) + thread laststandbleedout( var_1, var_2 ); + } + + wait(var_0 / 3); + var_3.color = ( 1, 0.64, 0 ); + + while ( var_2.inuse ) + wait 0.05; + + maps\mp\_utility::playdeathsound(); + wait(var_0 / 3); + var_3.color = ( 1, 0, 0 ); + + while ( var_2.inuse ) + wait 0.05; + + maps\mp\_utility::playdeathsound(); + wait(var_0 / 3); + + while ( var_2.inuse ) + wait 0.05; + + wait 0.05; + thread laststandbleedout( var_1 ); + return; + } + + thread laststandkeepoverlay(); + wait(var_0); + thread laststandbleedout( var_1 ); +} + +maxhealthoverlay( var_0, var_1 ) +{ + self endon( "stop_maxHealthOverlay" ); + self endon( "revive" ); + self endon( "death" ); + + for (;;) + { + self.health -= 1; + self.maxhealth = var_0; + wait 0.05; + self.maxhealth = 50; + self.health += 1; + wait 0.5; + } +} + +laststandbleedout( var_0, var_1 ) +{ + if ( var_0 ) + { + self.laststand = undefined; + self.infinalstand = 0; + self notify( "revive" ); + maps\mp\_utility::clearlowermessage( "last_stand" ); + maps\mp\gametypes\_playerlogic::laststandrespawnplayer(); + + if ( isdefined( var_1 ) ) + var_1 delete(); + } + else + { + self.uselaststandparams = 1; + self.beingrevived = 0; + maps\mp\_utility::_suicide(); + } +} + +laststandallowsuicide() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "game_ended" ); + self endon( "revive" ); + + for (;;) + { + if ( self usebuttonpressed() ) + { + var_0 = gettime(); + + while ( self usebuttonpressed() ) + { + wait 0.05; + + if ( gettime() - var_0 > 700 ) + break; + } + + if ( gettime() - var_0 > 700 ) + break; + } + + wait 0.05; + } + + thread laststandbleedout( 0 ); +} + +laststandkeepoverlay() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "revive" ); + + while ( !level.gameended ) + { + self.health = 2; + wait 0.05; + self.health = 1; + wait 0.5; + } + + self.health = self.maxhealth; +} + +laststandwaittilldeath() +{ + self endon( "disconnect" ); + self endon( "revive" ); + level endon( "game_ended" ); + self waittill( "death" ); + maps\mp\_utility::clearlowermessage( "last_stand" ); + self.laststand = undefined; +} + +maydolaststand( var_0, var_1, var_2 ) +{ + if ( var_1 == "MOD_TRIGGER_HURT" ) + return 0; + + if ( var_1 != "MOD_PISTOL_BULLET" && var_1 != "MOD_RIFLE_BULLET" && var_1 != "MOD_FALLING" && var_1 != "MOD_EXPLOSIVE_BULLET" ) + return 0; + + if ( var_1 == "MOD_IMPACT" && ( var_0 == "throwingknife_mp" || var_0 == "throwingknifejugg_mp" ) ) + return 0; + + if ( var_1 == "MOD_IMPACT" && ( var_0 == "m79_mp" || issubstr( var_0, "gl_" ) ) ) + return 0; + + if ( maps\mp\_utility::isheadshot( var_0, var_2, var_1 ) ) + return 0; + + if ( maps\mp\_utility::isusingremote() ) + return 0; + + return 1; +} + +ensurelaststandparamsvalidity() +{ + if ( !isdefined( self.laststandparams.attacker ) ) + self.laststandparams.attacker = self; +} + +gethitlocheight( var_0 ) +{ + switch ( var_0 ) + { + case "neck": + case "helmet": + case "head": + return 60; + case "left_hand": + case "right_hand": + case "left_arm_lower": + case "right_arm_lower": + case "left_arm_upper": + case "right_arm_upper": + case "torso_upper": + case "gun": + return 48; + case "torso_lower": + return 40; + case "left_leg_upper": + case "right_leg_upper": + return 32; + case "left_leg_lower": + case "right_leg_lower": + return 10; + case "left_foot": + case "right_foot": + return 5; + } + + return 48; +} + +gethitloctag( var_0 ) +{ + switch ( var_0 ) + { + case "helmet": + return "j_neck"; + case "head": + return "j_neck"; + case "neck": + return "j_neck"; + case "torso_upper": + return "j_neck"; + case "right_arm_upper": + return "J_Shoulder_RI"; + case "left_arm_upper": + return "J_Shoulder_LE"; + case "right_arm_lower": + return "J_Elbow_RI"; + case "left_arm_lower": + return "J_Elbow_LE"; + case "right_hand": + return "J_Wrist_RI"; + case "left_hand": + return "J_Wrist_LE"; + case "gun": + return "J_Wrist_RI"; + case "torso_lower": + return "J_SpineLower"; + case "right_leg_upper": + return "J_Hip_RI"; + case "left_leg_upper": + return "J_Hip_LE"; + case "right_leg_lower": + return "J_Knee_RI"; + case "left_leg_lower": + return "J_Knee_LE"; + case "right_foot": + return "J_Ankle_RI"; + case "left_foot": + return "J_Ankle_LE"; + } + + return undefined; +} + +delaystartragdoll( var_0, var_1, var_2, var_3, var_4, var_5 ) +{ + if ( isdefined( var_0 ) ) + { + var_6 = var_0 getcorpseanim(); + + if ( animhasnotetrack( var_6, "ignore_ragdoll" ) ) + return; + } + + if ( isdefined( level.noragdollents ) && level.noragdollents.size ) + { + foreach ( var_8 in level.noragdollents ) + { + if ( distancesquared( var_0.origin, var_8.origin ) < 65536 ) + return; + } + } + + wait 0.2; + + if ( !isdefined( var_0 ) ) + return; + + if ( var_0 isragdoll() ) + return; + + var_6 = var_0 getcorpseanim(); + var_10 = 0.35; + + if ( animhasnotetrack( var_6, "start_ragdoll" ) ) + { + var_11 = getnotetracktimes( var_6, "start_ragdoll" ); + + if ( isdefined( var_11 ) ) + var_10 = var_11[0]; + } + + var_12 = var_10 * getanimlength( var_6 ); + wait(var_12); + + if ( isdefined( var_0 ) ) + var_0 startragdoll(); +} + +getmostkilledby() +{ + var_0 = ""; + var_1 = 0; + var_2 = getarraykeys( self.killedby ); + + for ( var_3 = 0; var_3 < var_2.size; var_3++ ) + { + var_4 = var_2[var_3]; + + if ( self.killedby[var_4] <= var_1 ) + continue; + + var_1 = self.killedby[var_4]; + var_5 = var_4; + } + + return var_0; +} + +getmostkilled() +{ + var_0 = ""; + var_1 = 0; + var_2 = getarraykeys( self.killedplayers ); + + for ( var_3 = 0; var_3 < var_2.size; var_3++ ) + { + var_4 = var_2[var_3]; + + if ( self.killedplayers[var_4] <= var_1 ) + continue; + + var_1 = self.killedplayers[var_4]; + var_0 = var_4; + } + + return var_0; +} + +damageshellshockandrumble( var_0, var_1, var_2, var_3, var_4, var_5 ) +{ + thread maps\mp\gametypes\_weapons::onweapondamage( var_0, var_1, var_2, var_3, var_5 ); + self playrumbleonentity( "sniper_fire" ); +} + +revivesetup( var_0 ) +{ + var_1 = var_0.team; + self linkto( var_0, "tag_origin" ); + self.owner = var_0; + self.inuse = 0; + self makeusable(); + updateusablebyteam( var_1 ); + thread trackteamchanges( var_1 ); + thread revivetriggerthink( var_1 ); + thread deleteonreviveordeathordisconnect(); +} + +deleteonreviveordeathordisconnect() +{ + self endon( "death" ); + self.owner common_scripts\utility::waittill_any( "death", "disconnect" ); + self delete(); +} + +updateusablebyteam( var_0 ) +{ + foreach ( var_2 in level.players ) + { + if ( var_0 == var_2.team && var_2 != self.owner ) + { + self enableplayeruse( var_2 ); + continue; + } + + self disableplayeruse( var_2 ); + } +} + +trackteamchanges( var_0 ) +{ + self endon( "death" ); + + for (;;) + { + level waittill( "joined_team" ); + updateusablebyteam( var_0 ); + } +} + +tracklaststandchanges( var_0 ) +{ + self endon( "death" ); + + for (;;) + { + level waittill( "player_last_stand" ); + updateusablebyteam( var_0 ); + } +} + +revivetriggerthink( var_0 ) +{ + self endon( "death" ); + level endon( "game_ended" ); + + for (;;) + { + self waittill( "trigger", var_1 ); + self.owner.beingrevived = 1; + + if ( isdefined( var_1.beingrevived ) && var_1.beingrevived ) + { + self.owner.beingrevived = 0; + continue; + } + + self makeunusable(); + self.owner maps\mp\_utility::freezecontrolswrapper( 1 ); + var_2 = reviveholdthink( var_1 ); + self.owner.beingrevived = 0; + + if ( !isalive( self.owner ) ) + { + self delete(); + return; + } + + self.owner maps\mp\_utility::freezecontrolswrapper( 0 ); + + if ( var_2 ) + { + level thread maps\mp\gametypes\_rank::awardgameevent( "reviver", var_1 ); + self.owner.laststand = undefined; + self.owner maps\mp\_utility::clearlowermessage( "last_stand" ); + self.owner.movespeedscaler = level.baseplayermovescale; + + if ( self.owner maps\mp\_utility::_hasperk( "specialty_lightweight" ) ) + self.owner.movespeedscaler = maps\mp\_utility::lightweightscalar(); + + self.owner common_scripts\utility::_enableweapon(); + self.owner.maxhealth = 100; + self.owner maps\mp\gametypes\_weapons::updatemovespeedscale(); + self.owner maps\mp\gametypes\_playerlogic::laststandrespawnplayer(); + self.owner maps\mp\_utility::giveperk( "specialty_pistoldeath", 0 ); + self.owner.beingrevived = 0; + self delete(); + return; + } + + self makeusable(); + updateusablebyteam( var_0 ); + } +} + +reviveholdthink( var_0, var_1, var_2 ) +{ + var_3 = 3000; + var_4 = spawn( "script_origin", self.origin ); + var_4 hide(); + + if ( isplayer( var_0 ) ) + var_0 playerlinkto( var_4 ); + else + var_0 linkto( var_4 ); + + var_0 playerlinkedoffsetenable(); + + if ( !isdefined( var_2 ) ) + var_2 = 1; + + if ( var_2 ) + var_0 common_scripts\utility::_disableweapon(); + + self.curprogress = 0; + self.inuse = 1; + self.userate = 0; + + if ( isdefined( var_1 ) ) + self.usetime = var_1; + else + self.usetime = var_3; + + if ( isdefined( level.ishorde ) && level.ishorde ) + var_0 thread personalusebaroldstyle( self ); + else + var_0 thread personalusebar( self ); + + thread reviveholdthink_cleanup( var_0, var_2, var_4 ); + var_5 = reviveholdthinkloop( var_0 ); + self.inuse = 0; + var_4 delete(); + + if ( isdefined( var_5 ) && var_5 ) + { + self.owner thread maps\mp\gametypes\_hud_message::playercardsplashnotify( "revived", var_0 ); + self.owner.inlaststand = 0; + return 1; + } + + return 0; +} + +reviveholdthink_cleanup( var_0, var_1, var_2 ) +{ + common_scripts\utility::waittill_any_ents( self, "death", var_2, "death" ); + + if ( !isremovedentity( var_2 ) ) + var_2 delete(); + + if ( isdefined( var_0 ) && maps\mp\_utility::isreallyalive( var_0 ) ) + { + var_0 unlink(); + + if ( var_1 ) + var_0 common_scripts\utility::_enableweapon(); + } +} + +personalusebar( var_0 ) +{ + self setclientomnvar( "ui_use_bar_text", 3 ); + self setclientomnvar( "ui_use_bar_start_time", int( gettime() ) ); + var_1 = undefined; + + if ( isdefined( var_0 ) && isdefined( var_0.owner ) ) + { + var_1 = var_0.owner; + var_1 setclientomnvar( "ui_use_bar_text", 4 ); + var_1 setclientomnvar( "ui_use_bar_start_time", int( gettime() ) ); + } + + var_2 = -1; + + while ( maps\mp\_utility::isreallyalive( self ) && isdefined( var_0 ) && var_0.inuse && !level.gameended && isdefined( self ) ) + { + if ( var_2 != var_0.userate ) + { + if ( var_0.curprogress > var_0.usetime ) + var_0.curprogress = var_0.usetime; + + if ( var_0.userate > 0 ) + { + var_3 = gettime(); + var_4 = var_0.curprogress / var_0.usetime; + var_5 = var_3 + ( 1 - var_4 ) * var_0.usetime / var_0.userate; + self setclientomnvar( "ui_use_bar_end_time", int( var_5 ) ); + + if ( isdefined( var_1 ) ) + var_1 setclientomnvar( "ui_use_bar_end_time", int( var_5 ) ); + } + + var_2 = var_0.userate; + } + + wait 0.05; + } + + if ( isdefined( self ) ) + self setclientomnvar( "ui_use_bar_end_time", 0 ); + + if ( isdefined( var_1 ) ) + var_1 setclientomnvar( "ui_use_bar_end_time", 0 ); +} + +personalusebaroldstyle( var_0 ) +{ + var_1 = maps\mp\gametypes\_hud_util::createprimaryprogressbar(); + var_2 = maps\mp\gametypes\_hud_util::createprimaryprogressbartext(); + var_2 settext( &"MPUI_REVIVING" ); + var_3 = var_0.owner maps\mp\gametypes\_hud_util::createprimaryprogressbar(); + var_4 = var_0.owner maps\mp\gametypes\_hud_util::createprimaryprogressbartext(); + var_4 settext( &"MPUI_BEING_REVIVED" ); + var_5 = -1; + + while ( maps\mp\_utility::isreallyalive( self ) && isdefined( var_0 ) && var_0.inuse && !level.gameended && isdefined( self ) ) + { + if ( var_5 != var_0.userate ) + { + if ( var_0.curprogress > var_0.usetime ) + var_0.curprogress = var_0.usetime; + + var_1 maps\mp\gametypes\_hud_util::updatebar( var_0.curprogress / var_0.usetime, 1000 / var_0.usetime * var_0.userate ); + var_3 maps\mp\gametypes\_hud_util::updatebar( var_0.curprogress / var_0.usetime, 1000 / var_0.usetime * var_0.userate ); + + if ( !var_0.userate ) + { + var_1 maps\mp\gametypes\_hud_util::hideelem(); + var_2 maps\mp\gametypes\_hud_util::hideelem(); + var_3 maps\mp\gametypes\_hud_util::hideelem(); + var_4 maps\mp\gametypes\_hud_util::hideelem(); + } + else + { + var_1 maps\mp\gametypes\_hud_util::showelem(); + var_2 maps\mp\gametypes\_hud_util::showelem(); + var_3 maps\mp\gametypes\_hud_util::showelem(); + var_4 maps\mp\gametypes\_hud_util::showelem(); + } + } + + var_5 = var_0.userate; + wait 0.05; + } + + if ( isdefined( var_1 ) ) + var_1 maps\mp\gametypes\_hud_util::destroyelem(); + + if ( isdefined( var_2 ) ) + var_2 maps\mp\gametypes\_hud_util::destroyelem(); + + if ( isdefined( var_3 ) ) + var_3 maps\mp\gametypes\_hud_util::destroyelem(); + + if ( isdefined( var_4 ) ) + var_4 maps\mp\gametypes\_hud_util::destroyelem(); +} + +reviveholdthinkloop( var_0 ) +{ + level endon( "game_ended" ); + self.owner endon( "death" ); + self.owner endon( "disconnect" ); + + while ( maps\mp\_utility::isreallyalive( var_0 ) && var_0 usebuttonpressed() && self.curprogress < self.usetime && !( isdefined( var_0.inlaststand ) && var_0.inlaststand ) ) + { + self.curprogress += 50 * self.userate; + self.userate = 1; + + if ( self.curprogress >= self.usetime ) + { + self.inuse = 0; + return maps\mp\_utility::isreallyalive( var_0 ); + } + + wait 0.05; + } + + return 0; +} + +callback_killingblow( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 ) +{ + if ( isdefined( self.lastdamagewasfromenemy ) && self.lastdamagewasfromenemy && var_2 >= self.health && isdefined( self.combathigh ) && self.combathigh == "specialty_endgame" ) + { + maps\mp\_utility::giveperk( "specialty_endgame", 0 ); + return 0; + } + + return 1; +} + +emitfalldamage( var_0 ) +{ + physicsexplosionsphere( self.origin, 64, 64, 1 ); + var_1 = []; + + for ( var_2 = 0; var_2 < 360; var_2 += 30 ) + { + var_3 = cos( var_2 ) * 16; + var_4 = sin( var_2 ) * 16; + var_5 = bullettrace( self.origin + ( var_3, var_4, 4 ), self.origin + ( var_3, var_4, -6 ), 1, self ); + + if ( isdefined( var_5["entity"] ) && isdefined( var_5["entity"].targetname ) && ( var_5["entity"].targetname == "destructible_vehicle" || var_5["entity"].targetname == "destructible_toy" ) ) + var_1[var_1.size] = var_5["entity"]; + } + + if ( var_1.size ) + { + var_6 = spawn( "script_origin", self.origin ); + var_6 hide(); + var_6.type = "soft_landing"; + var_6.destructibles = var_1; + radiusdamage( self.origin, 64, 100, 100, var_6 ); + wait 0.1; + var_6 delete(); + } +} + +_obituary( var_0, var_1, var_2, var_3 ) +{ + var_4 = var_0.team; + + foreach ( var_6 in level.players ) + { + var_7 = var_6.team; + + if ( var_7 == "spectator" ) + { + var_6 iprintln( &"MP_OBITUARY_NEUTRAL", var_1.name, var_0.name ); + continue; + } + + if ( var_7 == var_4 ) + { + var_6 iprintln( &"MP_OBITUARY_ENEMY", var_1.name, var_0.name ); + continue; + } + + var_6 iprintln( &"MP_OBITUARY_FRIENDLY", var_1.name, var_0.name ); + } +} + +logprintplayerdeath( var_0, var_1, var_2, var_3, var_4, var_5, var_6 ) +{ + var_7 = self getentitynumber(); + var_8 = self.name; + var_9 = self.team; + var_10 = self.guid; + + if ( isplayer( var_1 ) ) + { + var_11 = var_1.guid; + var_12 = var_1.name; + var_13 = var_1.team; + var_14 = var_1 getentitynumber(); + var_15 = var_1.xuid + "(" + var_12 + ")"; + } + else + { + var_11 = ""; + var_12 = ""; + var_13 = "world"; + var_14 = -1; + var_15 = "none"; + } + + logprint( "K;" + var_10 + ";" + var_7 + ";" + var_9 + ";" + var_8 + ";" + var_11 + ";" + var_14 + ";" + var_13 + ";" + var_12 + ";" + var_4 + ";" + var_2 + ";" + var_3 + ";" + var_6 + "\n" ); +} + +destroyonreviveentdeath( var_0 ) +{ + var_0 waittill( "death" ); + self destroy(); +} + +gamemodemodifyplayerdamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8 ) +{ + if ( isdefined( var_2 ) && isplayer( var_2 ) && isalive( var_2 ) ) + { + if ( level.matchrules_damagemultiplier ) + var_3 *= level.matchrules_damagemultiplier; + + if ( level.matchrules_vampirism ) + var_2.health = int( min( float( var_2.maxhealth ), float( var_2.health + 20 ) ) ); + } + + return var_3; +} + +setentitydamagecallback( var_0, var_1, var_2, var_3, var_4 ) +{ + if ( !isdefined( var_4 ) ) + var_4 = 0; + + if ( !isdefined( var_1 ) ) + var_1 = "normal"; + + if ( !isdefined( var_3 ) ) + var_3 = ::modifydamage; + + self setcandamage( 1 ); + + if ( isdefined( self.classname ) && self.classname != "script_vehicle" ) + self setdamagecallbackon( 1 ); + + self.health = 999999; + self.maxhealth = var_0; + self.damagetaken = 0; + self.biskillstreak = var_4; + self.damagefeedback = var_1; + self.damagecallback = ::processdamagetaken; + self.modifydamagefunc = var_3; + self.ondeathfunc = var_2; + self.attackerlist = []; +} + +processdamagetaken( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, var_10, var_11 ) +{ + if ( !isdefined( self ) ) + return; + + if ( !( isdefined( level.ishorde ) && level.ishorde ) && !( isdefined( level.iszombiegame ) && level.iszombiegame ) && isdefined( var_1 ) && !maps\mp\_utility::isgameparticipant( var_1 ) ) + return; + + if ( isdefined( var_1 ) && !maps\mp\gametypes\_weapons::friendlyfirecheck( self.owner, var_1 ) ) + return; + + var_1 playrumbleonentity( "damage_light" ); + + if ( isdefined( self.iscrashing ) && self.iscrashing ) + return; + + if ( isdefined( self.isleaving ) && self.isleaving ) + return; + + if ( isdefined( self.stopdamagefunc ) && self.stopdamagefunc ) + return; + + var_12 = var_2; + + if ( isdefined( var_5 ) ) + { + var_13 = maps\mp\_utility::strip_suffix( var_5, "_lefthand" ); + + switch ( var_13 ) + { + case "smoke_grenade_var_mp": + case "paint_grenade_var_mp": + case "smoke_grenade_mp": + case "paint_grenade_mp": + return; + } + + if ( isdefined( level.ishorde ) && level.ishorde ) + self.damageloc = var_11; + + var_12 = [[ self.modifydamagefunc ]]( var_1, var_5, var_4, var_2 ); + + if ( isdefined( level.ishorde ) && level.ishorde ) + self.damageloc = undefined; + } + + if ( var_12 < 0 ) + return 1; + + if ( isdefined( var_3 ) && var_3 & level.idflags_penetration ) + self.wasdamagedfrombulletpenetration = 1; + + self.wasdamaged = 1; + self.damagetaken += var_12; + maps\mp\killstreaks\_killstreaks::killstreakhit( var_1, var_5, self ); + + if ( isdefined( var_1 ) && isplayer( var_1 ) ) + { + var_1 maps\mp\gametypes\_damagefeedback::updatedamagefeedback( self.damagefeedback ); + + if ( isnewattacker( var_1 ) ) + self.attackerlist[self.attackerlist.size] = var_1; + } + + if ( self.damagetaken >= self.maxhealth ) + { + if ( self.biskillstreak && isplayer( var_1 ) ) + var_1 notify( "destroyed_killstreak", var_5 ); + + if ( self.classname == "script_vehicle" || self.classname == "script_model" ) + { + var_14 = maps\mp\_utility::getbaseweaponname( var_5, 1 ); + + if ( maps\mp\_utility::islootweapon( var_14 ) ) + var_14 = maps\mp\gametypes\_class::getbasefromlootversion( var_14 ); + + var_15 = maps\mp\gametypes\_missions::get_challenge_weapon_class( var_5, var_14 ); + + if ( isdefined( self.model ) && var_15 == "weapon_launcher" ) + { + if ( issubstr( self.model, "uav" ) ) + { + if ( isdefined( level.challengeinfo["ch_uav_" + var_14] ) ) + var_1 maps\mp\gametypes\_missions::processchallenge( "ch_uav_" + var_14 ); + } + + if ( issubstr( self.model, "warbird" ) ) + { + if ( isdefined( level.challengeinfo["ch_warbird_" + var_14] ) ) + var_1 maps\mp\gametypes\_missions::processchallenge( "ch_warbird_" + var_14 ); + } + + if ( issubstr( self.model, "orbital_platform" ) ) + { + if ( isdefined( level.challengeinfo["ch_paladin_" + var_14] ) ) + var_1 maps\mp\gametypes\_missions::processchallenge( "ch_paladin_" + var_14 ); + } + + if ( issubstr( self.model, "drone" ) && !issubstr( self.model, "uav" ) ) + { + if ( isdefined( level.challengeinfo["ch_drone_" + var_14] ) ) + var_1 maps\mp\gametypes\_missions::processchallenge( "ch_drone_" + var_14 ); + } + } + } + + self.stopdamagefunc = 1; + self thread [[ self.ondeathfunc ]]( var_1, var_5, var_4, var_2 ); + } +} + +isnewattacker( var_0 ) +{ + foreach ( var_2 in self.attackerlist ) + { + if ( var_0 == var_2 ) + return 0; + } + + return 1; +} + +modifydamage( var_0, var_1, var_2, var_3 ) +{ + var_4 = var_3; + var_4 = handlemeleedamage( var_1, var_2, var_4 ); + var_4 = handleempdamage( var_1, var_2, var_4, var_0 ); + var_4 = handlemissiledamage( var_1, var_2, var_4 ); + var_4 = handlegrenadedamage( var_1, var_2, var_4 ); + var_4 = handleapdamage( var_1, var_2, var_4, var_0 ); + return var_4; +} + +handlemissiledamage( var_0, var_1, var_2 ) +{ + var_3 = var_2; + + switch ( var_0 ) + { + case "orbitalsupport_missile_mp": + case "orbitalsupport_105mm_mp": + case "airstrike_missile_mp": + case "remotemissile_projectile_secondary_mp": + case "remotemissile_projectile_cluster_child_hellfire_mp": + case "warbird_missile_mp": + case "dam_turret_mp": + case "remotemissile_projectile_cluster_child_mp": + case "orbital_carepackage_pod_plane_mp": + case "stealth_bomb_mp": + case "stinger_mp": + case "orbital_carepackage_droppod_mp": + case "orbital_carepackage_pod_mp": + case "remotemissile_projectile_gas_mp": + case "remotemissile_projectile_cluster_parent_mp": + case "remotemissile_projectile_mp": + case "bomb_site_mp": + self.largeprojectiledamage = 1; + var_3 = self.maxhealth + 1; + break; + case "killstreak_laser2_mp": + self.largeprojectiledamage = 1; + var_4 = level.sentrygun.ownerlist; + var_5 = 0.34; + + if ( isdefined( var_4 ) && var_4.size > 0 ) + { + var_6 = var_4.size; + + if ( var_4.size >= 3 ) + var_6 = 3; + + var_5 *= var_6; + } + + var_3 = self.maxhealth * var_5; + break; + case "killstreak_orbital_laser_mp": + case "killstreakmahem_mp": + case "assaultdrone_c4_mp": + case "ugv_missile_mp": + case "turretheadrocket_mp": + self.largeprojectiledamage = 0; + var_3 = self.maxhealth + 1; + break; + case "orbitalsupport_40mmbuddy_mp": + case "orbitalsupport_40mm_mp": + self.largeprojectiledamage = 0; + var_3 *= 2; + break; + } + + return var_3; +} + +handlegrenadedamage( var_0, var_1, var_2 ) +{ + var_3 = maps\mp\_utility::strip_suffix( var_0, "_lefthand" ); + + if ( var_3 == "stun_grenade_mp" || var_3 == "stun_grenade_var_mp" || var_3 == "stun_grenade_horde_mp" ) + { + self notify( "concussed" ); + return 0; + } + else if ( isexplosivedamagemod( var_1 ) ) + { + switch ( var_3 ) + { + case "explosive_drone_mp": + case "semtex_mp": + case "frag_grenade_mp": + var_2 *= 4; + break; + default: + if ( maps\mp\_utility::isstrstart( var_0, "alt_" ) ) + var_2 *= 3; + + break; + } + } + + return var_2; +} + +handlemeleedamage( var_0, var_1, var_2 ) +{ + if ( maps\mp\_utility::ismeleemod( var_1 ) ) + { + var_3 = int( self.maxhealth / 3 ) + 1; + + if ( var_3 > var_2 ) + return var_3; + } + + return var_2; +} + +handleempdamage( var_0, var_1, var_2, var_3 ) +{ + var_4 = maps\mp\_utility::strip_suffix( var_0, "_lefthand" ); + + if ( ( var_4 == "emp_grenade_mp" || var_4 == "emp_grenade_var_mp" || var_4 == "emp_grenade_killstreak_mp" ) && ( var_1 == "MOD_GRENADE_SPLASH" || var_1 == "MOD_GRENADE" ) ) + { + self notify( "emp_damage", var_3, 8.0 ); + return 0; + } + + return var_2; +} + +handleapdamage( var_0, var_1, var_2, var_3 ) +{ + if ( var_1 == "MOD_RIFLE_BULLET" || var_1 == "MOD_PISTOL_BULLET" ) + { + if ( var_3 maps\mp\_utility::_hasperk( "specialty_armorpiercing" ) || maps\mp\_utility::isfmjdamage( var_0, var_1, var_3 ) ) + return var_2 * level.armorpiercingmod; + } + + return var_2; +} + +onkillstreakkilled( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7 ) +{ + var_8 = undefined; + + if ( isdefined( var_0 ) && isdefined( self.owner ) ) + { + if ( isdefined( var_0.owner ) && isplayer( var_0.owner ) ) + var_0 = var_0.owner; + + if ( var_0 == self.owner ) + return; + + if ( !isalliedsentient( self.owner, var_0 ) ) + var_8 = var_0; + } + + if ( isdefined( var_8 ) ) + { + var_8 notify( "destroyed_killstreak", var_1 ); + var_8 maps\mp\_utility::incplayerstat( var_4, 1 ); + level thread maps\mp\gametypes\_rank::awardgameevent( var_4, var_8, var_1, undefined, var_2 ); + + if ( isdefined( var_1 ) && var_1 == "killstreak_laser2_mp" && isdefined( level.sentrygun ) && isdefined( level.sentrygun.ownerlist ) ) + { + foreach ( var_10 in level.sentrygun.ownerlist ) + { + if ( var_10 != var_8 ) + { + var_10 notify( "destroyed_killstreak", var_1 ); + var_10 maps\mp\_utility::incplayerstat( var_4, 1 ); + level thread maps\mp\gametypes\_rank::awardgameevent( var_4, var_10, var_1, undefined, var_2 ); + } + } + } + + if ( isdefined( var_6 ) ) + level thread maps\mp\_utility::teamplayercardsplash( var_6, var_8 ); + + if ( isdefined( var_7 ) && var_7 ) + level thread maps\mp\gametypes\_missions::vehiclekilled( self.owner, self, undefined, var_8, var_3, var_2, var_1 ); + } + + thread maps\mp\_events::checkvandalismmedal( var_8 ); + + if ( isdefined( self.owner ) && isdefined( var_5 ) ) + self.owner thread maps\mp\_utility::leaderdialogonplayer( var_5, undefined, undefined, self.origin ); +} diff --git a/data/maps/mp/gametypes/_gamelogic.gsc b/data/maps/mp/gametypes/_gamelogic.gsc new file mode 100644 index 0000000..05384fb --- /dev/null +++ b/data/maps/mp/gametypes/_gamelogic.gsc @@ -0,0 +1,3548 @@ +// S1 GSC SOURCE +// Dumped by https://github.com/xensik/gsc-tool + +onforfeit( var_0 ) +{ + if ( isdefined( level.forfeitinprogress ) ) + return; + + level endon( "abort_forfeit" ); + level thread forfeitwaitforabort(); + level.forfeitinprogress = 1; + + if ( !level.teambased && level.players.size > 1 ) + wait 10; + else + wait 1.05; + + level.forfeit_aborted = 0; + var_1 = 20.0; + matchforfeittimer( var_1 ); + var_2 = &""; + + if ( !isdefined( var_0 ) ) + { + level.finalkillcam_winner = "none"; + var_2 = game["end_reason"]["players_forfeited"]; + var_3 = level.players[0]; + } + else if ( var_0 == "axis" ) + { + level.finalkillcam_winner = "axis"; + var_2 = game["end_reason"]["allies_forfeited"]; + + if ( level.gametype == "infect" ) + var_2 = game["end_reason"]["survivors_forfeited"]; + + var_3 = "axis"; + } + else if ( var_0 == "allies" ) + { + level.finalkillcam_winner = "allies"; + var_2 = game["end_reason"]["axis_forfeited"]; + + if ( level.gametype == "infect" ) + var_2 = game["end_reason"]["infected_forfeited"]; + + var_3 = "allies"; + } + else if ( level.multiteambased && issubstr( var_0, "team_" ) ) + var_3 = var_0; + else + { + level.finalkillcam_winner = "none"; + var_3 = "tie"; + } + + level.forcedend = 1; + + if ( isplayer( var_3 ) ) + logstring( "forfeit, win: " + var_3 getxuid() + "(" + var_3.name + ")" ); + else + logstring( "forfeit, win: " + var_3 + ", allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + + thread endgame( var_3, var_2 ); +} + +forfeitwaitforabort() +{ + level endon( "game_ended" ); + level waittill( "abort_forfeit" ); + level.forfeit_aborted = 1; + setomnvar( "ui_match_countdown", 0 ); + setomnvar( "ui_match_countdown_title", 0 ); + setomnvar( "ui_match_countdown_toggle", 0 ); +} + +matchforfeittimer_internal( var_0 ) +{ + waittillframeend; + level endon( "match_forfeit_timer_beginning" ); + setomnvar( "ui_match_countdown_title", 3 ); + setomnvar( "ui_match_countdown_toggle", 1 ); + + while ( var_0 > 0 && !level.gameended && !level.forfeit_aborted && !level.ingraceperiod ) + { + setomnvar( "ui_match_countdown", var_0 ); + wait 1; + var_0--; + } +} + +matchforfeittimer( var_0 ) +{ + level notify( "match_forfeit_timer_beginning" ); + var_1 = int( var_0 ); + matchforfeittimer_internal( var_1 ); + setomnvar( "ui_match_countdown", 0 ); + setomnvar( "ui_match_countdown_title", 0 ); + setomnvar( "ui_match_countdown_toggle", 0 ); +} + +default_ondeadevent( var_0 ) +{ + level.finalkillcam_winner = "none"; + + if ( var_0 == "allies" ) + { + logstring( "team eliminated, win: opfor, allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + level.finalkillcam_winner = "axis"; + thread endgame( "axis", game["end_reason"]["allies_eliminated"] ); + } + else if ( var_0 == "axis" ) + { + logstring( "team eliminated, win: allies, allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + level.finalkillcam_winner = "allies"; + thread endgame( "allies", game["end_reason"]["axis_eliminated"] ); + } + else + { + logstring( "tie, allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + level.finalkillcam_winner = "none"; + + if ( level.teambased ) + thread endgame( "tie", game["end_reason"]["tie"] ); + else + thread endgame( undefined, game["end_reason"]["tie"] ); + } +} + +default_ononeleftevent( var_0 ) +{ + if ( level.teambased ) + { + var_1 = maps\mp\_utility::getlastlivingplayer( var_0 ); + var_1 thread givelastonteamwarning(); + } + else + { + var_1 = maps\mp\_utility::getlastlivingplayer(); + logstring( "last one alive, win: " + var_1.name ); + level.finalkillcam_winner = "none"; + thread endgame( var_1, game["end_reason"]["enemies_eliminated"] ); + } + + return 1; +} + +default_ontimelimit() +{ + var_0 = undefined; + level.finalkillcam_winner = "none"; + + if ( level.teambased ) + { + if ( game["teamScores"]["allies"] == game["teamScores"]["axis"] ) + var_0 = "tie"; + else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] ) + { + level.finalkillcam_winner = "axis"; + var_0 = "axis"; + } + else + { + level.finalkillcam_winner = "allies"; + var_0 = "allies"; + } + + if ( maps\mp\_utility::practiceroundgame() ) + var_0 = "none"; + + logstring( "time limit, win: " + var_0 + ", allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + } + else + { + var_0 = maps\mp\gametypes\_gamescore::gethighestscoringplayer(); + + if ( isdefined( var_0 ) ) + logstring( "time limit, win: " + var_0.name ); + else + logstring( "time limit, tie" ); + } + + thread endgame( var_0, game["end_reason"]["time_limit_reached"] ); +} + +default_onhalftime( var_0 ) +{ + var_1 = undefined; + level.finalkillcam_winner = "none"; + thread endgame( "halftime", game["end_reason"][var_0] ); +} + +forceend() +{ + if ( level.hostforcedend || level.forcedend ) + return; + + var_0 = undefined; + level.finalkillcam_winner = "none"; + + if ( level.teambased ) + { + if ( isdefined( level.ishorde ) ) + var_0 = "axis"; + else if ( game["teamScores"]["allies"] == game["teamScores"]["axis"] ) + var_0 = "tie"; + else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] ) + { + level.finalkillcam_winner = "axis"; + var_0 = "axis"; + } + else + { + level.finalkillcam_winner = "allies"; + var_0 = "allies"; + } + + logstring( "host ended game, win: " + var_0 + ", allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + } + else + { + var_0 = maps\mp\gametypes\_gamescore::gethighestscoringplayer(); + + if ( isdefined( var_0 ) ) + logstring( "host ended game, win: " + var_0.name ); + else + logstring( "host ended game, tie" ); + } + + level.forcedend = 1; + level.hostforcedend = 1; + + if ( level.splitscreen ) + var_1 = game["end_reason"]["ended_game"]; + else + var_1 = game["end_reason"]["host_ended_game"]; + + thread endgame( var_0, var_1 ); +} + +onscorelimit() +{ + var_0 = game["end_reason"]["score_limit_reached"]; + var_1 = undefined; + level.finalkillcam_winner = "none"; + + if ( level.multiteambased ) + { + var_1 = maps\mp\gametypes\_gamescore::getwinningteam(); + + if ( var_1 == "none" ) + var_1 = "tie"; + } + else if ( level.teambased ) + { + if ( game["teamScores"]["allies"] == game["teamScores"]["axis"] ) + var_1 = "tie"; + else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] ) + { + var_1 = "axis"; + level.finalkillcam_winner = "axis"; + } + else + { + var_1 = "allies"; + level.finalkillcam_winner = "allies"; + } + + logstring( "scorelimit, win: " + var_1 + ", allies: " + game["teamScores"]["allies"] + ", opfor: " + game["teamScores"]["axis"] ); + } + else + { + var_1 = maps\mp\gametypes\_gamescore::gethighestscoringplayer(); + + if ( isdefined( var_1 ) ) + logstring( "scorelimit, win: " + var_1.name ); + else + logstring( "scorelimit, tie" ); + } + + thread endgame( var_1, var_0 ); + return 1; +} + +updategameevents() +{ + if ( maps\mp\_utility::matchmakinggame() && !level.ingraceperiod && !getdvarint( "force_ranking" ) && ( !isdefined( level.disableforfeit ) || !level.disableforfeit ) ) + { + if ( level.multiteambased ) + { + var_0 = 0; + var_1 = 0; + + for ( var_2 = 0; var_2 < level.teamnamelist.size; var_2++ ) + { + var_0 += level.teamcount[level.teamnamelist[var_2]]; + + if ( level.teamcount[level.teamnamelist[var_2]] ) + var_1 += 1; + } + + for ( var_2 = 0; var_2 < level.teamnamelist.size; var_2++ ) + { + if ( var_0 == level.teamcount[level.teamnamelist[var_2]] && game["state"] == "playing" ) + { + thread onforfeit( level.teamnamelist[var_2] ); + return; + } + } + + if ( var_1 > 1 ) + { + level.forfeitinprogress = undefined; + level notify( "abort_forfeit" ); + } + } + else if ( level.teambased ) + { + if ( level.teamcount["allies"] < 1 && level.teamcount["axis"] > 0 && game["state"] == "playing" ) + { + thread onforfeit( "axis" ); + return; + } + + if ( level.teamcount["axis"] < 1 && level.teamcount["allies"] > 0 && game["state"] == "playing" ) + { + thread onforfeit( "allies" ); + return; + } + + if ( level.teamcount["axis"] > 0 && level.teamcount["allies"] > 0 ) + { + level.forfeitinprogress = undefined; + level notify( "abort_forfeit" ); + } + } + else + { + if ( level.teamcount["allies"] + level.teamcount["axis"] == 1 && level.maxplayercount >= 1 && !getdvarint( "virtualLobbyActive", 0 ) ) + { + thread onforfeit(); + return; + } + + if ( level.teamcount["axis"] + level.teamcount["allies"] > 1 ) + { + level.forfeitinprogress = undefined; + level notify( "abort_forfeit" ); + } + } + } + + if ( !maps\mp\_utility::getgametypenumlives() && ( !isdefined( level.disablespawning ) || !level.disablespawning ) ) + return; + + if ( !maps\mp\_utility::gamehasstarted() ) + return; + + if ( level.ingraceperiod ) + return; + + if ( level.multiteambased ) + return; + + if ( level.teambased ) + { + var_3["allies"] = level.livescount["allies"]; + var_3["axis"] = level.livescount["axis"]; + + if ( isdefined( level.disablespawning ) && level.disablespawning ) + { + var_3["allies"] = 0; + var_3["axis"] = 0; + } + + if ( !level.alivecount["allies"] && !level.alivecount["axis"] && !var_3["allies"] && !var_3["axis"] ) + return [[ level.ondeadevent ]]( "all" ); + + if ( !level.alivecount["allies"] && !var_3["allies"] ) + return [[ level.ondeadevent ]]( "allies" ); + + if ( !level.alivecount["axis"] && !var_3["axis"] ) + return [[ level.ondeadevent ]]( "axis" ); + + var_4 = level.alivecount["allies"] == 1 && !var_3["allies"]; + var_5 = level.alivecount["axis"] == 1 && !var_3["axis"]; + + if ( ( var_4 || var_5 ) && !isdefined( level.bot_spawn_from_devgui_in_progress ) ) + { + var_6 = undefined; + + if ( var_4 && !isdefined( level.onelefttime["allies"] ) ) + { + level.onelefttime["allies"] = gettime(); + var_7 = [[ level.ononeleftevent ]]( "allies" ); + + if ( isdefined( var_7 ) ) + { + if ( !isdefined( var_6 ) ) + var_6 = var_7; + + var_6 = var_6 || var_7; + } + } + + if ( var_5 && !isdefined( level.onelefttime["axis"] ) ) + { + level.onelefttime["axis"] = gettime(); + var_8 = [[ level.ononeleftevent ]]( "axis" ); + + if ( isdefined( var_8 ) ) + { + if ( !isdefined( var_6 ) ) + var_6 = var_8; + + var_6 = var_6 || var_8; + } + } + + return var_6; + return; + } + } + else + { + if ( !level.alivecount["allies"] && !level.alivecount["axis"] && ( !level.livescount["allies"] && !level.livescount["axis"] ) ) + return [[ level.ondeadevent ]]( "all" ); + + var_9 = maps\mp\_utility::getpotentiallivingplayers(); + + if ( var_9.size == 1 ) + return [[ level.ononeleftevent ]]( "all" ); + } +} + +waittillfinalkillcamdone() +{ + if ( !isdefined( level.finalkillcam_winner ) ) + return 0; + + level waittill( "final_killcam_done" ); + return 1; +} + +timelimitclock_intermission( var_0 ) +{ + setgameendtime( gettime() + int( var_0 * 1000 ) ); + var_1 = spawn( "script_origin", ( 0, 0, 0 ) ); + var_1 hide(); + + if ( var_0 >= 10.0 ) + wait(var_0 - 10.0); + + for (;;) + { + var_1 playsound( "ui_mp_timer_countdown" ); + wait 1.0; + } +} + +waitforplayers( var_0 ) +{ + var_1 = gettime(); + var_2 = var_1 + var_0 * 1000 - 200; + + if ( var_0 > 5 ) + var_3 = gettime() + getdvarint( "min_wait_for_players" ) * 1000; + else + var_3 = 0; + + if ( isdefined( level.iszombiegame ) && level.iszombiegame ) + var_4 = level.connectingplayers; + else + var_4 = level.connectingplayers / 3; + + var_5 = 0; + + for (;;) + { + if ( isdefined( game["roundsPlayed"] ) && game["roundsPlayed"] ) + break; + + var_6 = level.maxplayercount; + var_7 = gettime(); + + if ( var_6 >= var_4 && var_7 > var_3 || var_7 > var_2 ) + break; + + wait 0.05; + } +} + +prematchperiod() +{ + level endon( "game_ended" ); + level.connectingplayers = getdvarint( "party_partyPlayerCountNum" ); + + if ( level.prematchperiod > 0 ) + { + level.waitingforplayers = 1; + matchstarttimerwaitforplayers(); + level.waitingforplayers = 0; + } + else + matchstarttimerskip(); + + for ( var_0 = 0; var_0 < level.players.size; var_0++ ) + { + level.players[var_0] maps\mp\_utility::freezecontrolswrapper( 0 ); + level.players[var_0] enableweapons(); + level.players[var_0] enableammogeneration(); + var_1 = maps\mp\_utility::getobjectivehinttext( level.players[var_0].pers["team"] ); + + if ( !isdefined( var_1 ) || !level.players[var_0].hasspawned ) + continue; + + level.players[var_0] thread maps\mp\gametypes\_hud_message::hintmessage( var_1 ); + } + + if ( game["state"] != "playing" ) + return; +} + +graceperiod() +{ + level endon( "game_ended" ); + + if ( !isdefined( game["clientActive"] ) ) + { + while ( getactiveclientcount() == 0 ) + wait 0.05; + + game["clientActive"] = 1; + } + + while ( level.ingraceperiod > 0 ) + { + wait 1.0; + level.ingraceperiod--; + } + + level notify( "grace_period_ending" ); + wait 0.05; + maps\mp\_utility::gameflagset( "graceperiod_done" ); + level.ingraceperiod = 0; + + if ( game["state"] != "playing" ) + return; + + level thread updategameevents(); +} + +sethasdonecombat( var_0, var_1 ) +{ + var_0.hasdonecombat = var_1; + var_0 notify( "hasDoneCombat" ); + var_2 = !isdefined( var_0.hasdoneanycombat ) || !var_0.hasdoneanycombat; + + if ( var_2 && var_1 ) + { + var_0.hasdoneanycombat = 1; + var_0.pers["participation"] = 1; + + if ( isdefined( var_0.pers["hasMatchLoss"] ) && var_0.pers["hasMatchLoss"] ) + return; + + updatelossstats( var_0 ); + } +} + +updatewinstats( var_0 ) +{ + if ( !var_0 maps\mp\_utility::rankingenabled() ) + return; + + if ( ( !isdefined( var_0.hasdoneanycombat ) || !var_0.hasdoneanycombat ) && !( level.gametype == "infect" ) ) + return; + + var_0 maps\mp\gametypes\_persistence::statadd( "losses", -1 ); + var_0 maps\mp\gametypes\_persistence::statadd( "wins", 1 ); + var_0 maps\mp\_utility::updatepersratio( "winLossRatio", "wins", "losses" ); + var_0 maps\mp\gametypes\_persistence::statadd( "currentWinStreak", 1 ); + var_1 = var_0 maps\mp\gametypes\_persistence::statget( "currentWinStreak" ); + + if ( var_1 > var_0 maps\mp\gametypes\_persistence::statget( "winStreak" ) ) + var_0 maps\mp\gametypes\_persistence::statset( "winStreak", var_1 ); + + var_0 maps\mp\gametypes\_persistence::statsetchild( "round", "win", 1 ); + var_0 maps\mp\gametypes\_persistence::statsetchild( "round", "loss", 0 ); + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_" + level.gametype + "_wins" ); + var_0.combatrecordwin = 1; + var_0 maps\mp\gametypes\_missions::processchallengedaily( 25, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 26, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 27, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 28, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 29, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 30, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 36, undefined, undefined ); + var_0 maps\mp\gametypes\_missions::processchallengedaily( 37, undefined, undefined ); + + if ( maps\mp\_utility::isgrapplinghookgamemode() ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_tier2_4_iw5_dlcgun12" ); + + if ( level.players.size > 5 ) + { + superstarchallenge( var_0 ); + + switch ( level.gametype ) + { + case "war": + if ( game["teamScores"][var_0.team] >= game["teamScores"][maps\mp\_utility::getotherteam( var_0.team )] + 20 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_war_crushing" ); + + break; + case "hp": + if ( game["teamScores"][var_0.team] >= game["teamScores"][maps\mp\_utility::getotherteam( var_0.team )] + 70 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_hp_crushing" ); + + break; + case "conf": + if ( game["teamScores"][var_0.team] >= game["teamScores"][maps\mp\_utility::getotherteam( var_0.team )] + 15 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_conf_crushing" ); + + break; + case "ball": + if ( game["teamScores"][var_0.team] >= game["teamScores"][maps\mp\_utility::getotherteam( var_0.team )] + 7 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_ball_crushing" ); + + break; + case "infect": + if ( var_0.team == "allies" ) + { + if ( game["teamScores"][var_0.team] >= 4 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_infect_crushing" ); + + if ( game["teamScores"][maps\mp\_utility::getotherteam( var_0.team )] == 1 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_infect_cleanup" ); + } + + break; + case "dm": + if ( isdefined( level.placement["all"][0] ) ) + { + var_2 = level.placement["all"][0]; + var_3 = 9999; + + if ( var_0 == var_2 ) + { + foreach ( var_5 in level.players ) + { + if ( var_0 == var_5 ) + continue; + + var_6 = var_0.score - var_5.score; + + if ( var_6 < var_3 ) + var_3 = var_6; + } + + if ( var_3 >= 7 ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_dm_crushing" ); + } + } + + break; + case "gun": + foreach ( var_9 in level.players ) + { + if ( var_0 == var_9 ) + continue; + + if ( var_0.score < var_9.score + 5 ) + break; + } + + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_gun_crushing" ); + break; + case "twar": + case "ctf": + if ( game["shut_out"][var_0.team] ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_" + level.gametype + "_crushing" ); + + break; + } + } +} + +superstarchallenge( var_0 ) +{ + var_1 = 0; + var_2 = 9999; + + foreach ( var_4 in level.players ) + { + if ( var_4.kills > var_1 ) + var_1 = var_4.kills; + + if ( var_4.deaths < var_2 ) + var_2 = var_4.deaths; + } + + if ( var_0.kills >= var_1 && var_0.deaths <= var_2 && var_0.kills > 0 && !isai( var_0 ) ) + var_0 maps\mp\gametypes\_missions::processchallenge( "ch_" + level.gametype + "_star" ); +} + +checkgameendchallenges() +{ + if ( level.gametype == "dom" ) + { + foreach ( var_1 in level.domflags ) + { + if ( !isdefined( var_1.ownedtheentireround ) || !var_1.ownedtheentireround ) + continue; + + var_2 = var_1 maps\mp\gametypes\_gameobjects::getownerteam(); + + foreach ( var_4 in level.players ) + { + if ( var_4.team != var_2 ) + continue; + + switch ( var_1.label ) + { + case "_a": + var_4 maps\mp\gametypes\_missions::processchallenge( "ch_dom_alphalock" ); + break; + case "_b": + var_4 maps\mp\gametypes\_missions::processchallenge( "ch_dom_bravolock" ); + break; + case "_c": + var_4 maps\mp\gametypes\_missions::processchallenge( "ch_dom_charlielock" ); + break; + } + } + } + } +} + +updatelossstats( var_0 ) +{ + if ( !var_0 maps\mp\_utility::rankingenabled() ) + return; + + if ( !isdefined( var_0.hasdoneanycombat ) || !var_0.hasdoneanycombat ) + return; + + var_0.pers["hasMatchLoss"] = 1; + var_0 maps\mp\gametypes\_persistence::statadd( "losses", 1 ); + var_0 maps\mp\_utility::updatepersratio( "winLossRatio", "wins", "losses" ); + var_0 maps\mp\gametypes\_persistence::statsetchild( "round", "loss", 1 ); +} + +updatetiestats( var_0 ) +{ + if ( !var_0 maps\mp\_utility::rankingenabled() ) + return; + + if ( !isdefined( var_0.hasdoneanycombat ) || !var_0.hasdoneanycombat ) + return; + + var_0 maps\mp\gametypes\_persistence::statadd( "losses", -1 ); + var_0 maps\mp\gametypes\_persistence::statadd( "ties", 1 ); + var_0 maps\mp\_utility::updatepersratio( "winLossRatio", "wins", "losses" ); + var_0 maps\mp\gametypes\_persistence::statset( "currentWinStreak", 0 ); + var_0.combatrecordtie = 1; +} + +updatewinlossstats( var_0 ) +{ + if ( maps\mp\_utility::privatematch() ) + return; + + if ( maps\mp\_utility::practiceroundgame() ) + return; + + if ( !isdefined( var_0 ) || isdefined( var_0 ) && isstring( var_0 ) && var_0 == "tie" ) + { + foreach ( var_2 in level.players ) + { + if ( isdefined( var_2.connectedpostgame ) ) + continue; + + if ( level.hostforcedend && var_2 ishost() ) + { + var_2 maps\mp\gametypes\_persistence::statset( "currentWinStreak", 0 ); + continue; + } + + updatetiestats( var_2 ); + } + } + else if ( isplayer( var_0 ) ) + { + var_4[0] = var_0; + + if ( level.players.size > 5 ) + var_4 = maps\mp\gametypes\_gamescore::gethighestscoringplayersarray( 3 ); + + foreach ( var_2 in var_4 ) + { + if ( isdefined( var_2.connectedpostgame ) ) + continue; + + if ( level.hostforcedend && var_2 ishost() ) + { + var_2 maps\mp\gametypes\_persistence::statset( "currentWinStreak", 0 ); + continue; + } + + updatewinstats( var_2 ); + } + } + else if ( isstring( var_0 ) ) + { + foreach ( var_2 in level.players ) + { + if ( isdefined( var_2.connectedpostgame ) ) + continue; + + if ( level.hostforcedend && var_2 ishost() ) + { + var_2 maps\mp\gametypes\_persistence::statset( "currentWinStreak", 0 ); + continue; + } + + if ( var_0 == "tie" ) + { + updatetiestats( var_2 ); + continue; + } + + if ( var_2.pers["team"] == var_0 ) + { + updatewinstats( var_2 ); + continue; + } + + var_2 maps\mp\gametypes\_persistence::statset( "currentWinStreak", 0 ); + } + } + + if ( level.players.size > 5 ) + { + var_4 = maps\mp\gametypes\_gamescore::gethighestscoringplayersarray( 3 ); + + for ( var_9 = 0; var_9 < var_4.size; var_9++ ) + { + if ( var_9 == 0 ) + var_4[var_9] maps\mp\gametypes\_missions::processchallenge( "ch_" + level.gametype + "_mvp" ); + + var_4[var_9] maps\mp\gametypes\_missions::processchallenge( "ch_" + level.gametype + "_superior" ); + } + } +} + +freezeplayerforroundend( var_0 ) +{ + self endon( "disconnect" ); + maps\mp\_utility::clearlowermessages(); + + if ( !isdefined( var_0 ) ) + var_0 = 0.05; + + self closepopupmenu(); + self closeingamemenu(); + wait(var_0); + maps\mp\_utility::freezecontrolswrapper( 1 ); +} + +updatematchbonusscores( var_0 ) +{ + if ( !game["timePassed"] ) + return; + + if ( !maps\mp\_utility::matchmakinggame() ) + return; + + if ( maps\mp\_utility::practiceroundgame() ) + return; + + if ( level.teambased ) + { + if ( var_0 == "allies" ) + { + var_1 = "allies"; + var_2 = "axis"; + } + else if ( var_0 == "axis" ) + { + var_1 = "axis"; + var_2 = "allies"; + } + else + { + var_1 = "tie"; + var_2 = "tie"; + } + + if ( var_1 != "tie" ) + setwinningteam( var_1 ); + + foreach ( var_4 in level.players ) + { + if ( isdefined( var_4.connectedpostgame ) ) + continue; + + if ( !var_4 maps\mp\_utility::rankingenabled() ) + continue; + + if ( var_4.timeplayed["total"] < 1 || var_4.pers["participation"] < 1 ) + continue; + + if ( level.hostforcedend && var_4 ishost() ) + continue; + + var_5 = 0; + + if ( var_1 == "tie" ) + { + var_5 = maps\mp\gametypes\_rank::getscoreinfovalue( "tie" ); + var_4.didtie = 1; + var_4.iswinner = 0; + } + else if ( isdefined( var_4.pers["team"] ) && var_4.pers["team"] == var_1 ) + { + var_5 = maps\mp\gametypes\_rank::getscoreinfovalue( "win" ); + var_4.iswinner = 1; + } + else if ( isdefined( var_4.pers["team"] ) && var_4.pers["team"] == var_2 ) + { + var_5 = maps\mp\gametypes\_rank::getscoreinfovalue( "loss" ); + var_4.iswinner = 0; + } + + var_4.matchbonus = int( var_5 ); + } + } + else + { + foreach ( var_4 in level.players ) + { + if ( isdefined( var_4.connectedpostgame ) ) + continue; + + if ( !var_4 maps\mp\_utility::rankingenabled() ) + continue; + + if ( var_4.timeplayed["total"] < 1 || var_4.pers["participation"] < 1 ) + continue; + + if ( level.hostforcedend && var_4 ishost() ) + continue; + + var_4.iswinner = 0; + + for ( var_8 = 0; var_8 < min( level.placement["all"].size, 3 ); var_8++ ) + { + if ( level.placement["all"][var_8] != var_4 ) + continue; + + var_4.iswinner = 1; + } + + var_5 = 0; + + if ( var_4.iswinner ) + var_5 = maps\mp\gametypes\_rank::getscoreinfovalue( "win" ); + else + var_5 = maps\mp\gametypes\_rank::getscoreinfovalue( "loss" ); + + var_4.matchbonus = int( var_5 ); + } + } + + foreach ( var_4 in level.players ) + { + if ( !isdefined( var_4 ) ) + continue; + + if ( !isdefined( var_4.iswinner ) ) + continue; + + var_11 = "loss"; + + if ( var_4.iswinner ) + var_11 = "win"; + + if ( isdefined( var_4.didtie ) && var_4.didtie ) + var_11 = "tie"; + + var_4 thread givematchbonus( var_11, var_4.matchbonus ); + } +} + +givematchbonus( var_0, var_1 ) +{ + self endon( "disconnect" ); + level waittill( "give_match_bonus" ); + maps\mp\gametypes\_rank::giverankxp( var_0, var_1 ); + maps\mp\_utility::logxpgains(); +} + +setxenonranks( var_0 ) +{ + var_1 = level.players; + + for ( var_2 = 0; var_2 < var_1.size; var_2++ ) + { + var_3 = var_1[var_2]; + + if ( !isdefined( var_3.score ) || !isdefined( var_3.pers["team"] ) ) + continue; + } + + for ( var_2 = 0; var_2 < var_1.size; var_2++ ) + { + var_3 = var_1[var_2]; + + if ( !isdefined( var_3.score ) || !isdefined( var_3.pers["team"] ) ) + continue; + + var_4 = var_3.score; + + if ( maps\mp\_utility::getminutespassed() ) + var_4 = var_3.score / maps\mp\_utility::getminutespassed(); + + setplayerteamrank( var_3, var_3.clientid, int( var_4 ) ); + } +} + +checktimelimit( var_0 ) +{ + if ( isdefined( level.timelimitoverride ) && level.timelimitoverride ) + return; + + if ( game["state"] != "playing" ) + { + setgameendtime( 0 ); + return; + } + + if ( maps\mp\_utility::gettimelimit() <= 0 ) + { + if ( isdefined( level.starttime ) ) + setgameendtime( level.starttime ); + else + setgameendtime( 0 ); + + return; + } + + if ( !maps\mp\_utility::gameflag( "prematch_done" ) ) + { + setgameendtime( 0 ); + return; + } + + if ( !isdefined( level.starttime ) ) + return; + + if ( maps\mp\_utility::gettimepassedpercentage() > level.timepercentagecutoff ) + setnojiptime( 1 ); + + var_1 = gettimeremaining(); + + if ( maps\mp\_utility::gethalftime() && game["status"] != "halftime" ) + setgameendtime( gettime() + int( var_1 ) - int( maps\mp\_utility::gettimelimit() * 60 * 1000 * 0.5 ) ); + else + setgameendtime( gettime() + int( var_1 ) ); + + if ( var_1 > 0 ) + { + if ( maps\mp\_utility::gethalftime() && checkhalftime( var_0 ) ) + [[ level.onhalftime ]]( "time_limit_reached" ); + + return; + } + + [[ level.ontimelimit ]](); +} + +checkhalftimescore() +{ + if ( !level.halftimeonscorelimit ) + return 0; + + if ( !level.teambased ) + return 0; + + if ( game["status"] != "normal" ) + return 0; + + var_0 = maps\mp\_utility::getwatcheddvar( "scorelimit" ); + + if ( var_0 ) + { + if ( game["teamScores"]["allies"] >= var_0 || game["teamScores"]["axis"] >= var_0 ) + return 0; + + var_1 = int( var_0 / 2 + 0.5 ); + + if ( game["teamScores"]["allies"] >= var_1 || game["teamScores"]["axis"] >= var_1 ) + { + game["roundMillisecondsAlreadyPassed"] = maps\mp\_utility::gettimepassed(); + game["round_time_to_beat"] = maps\mp\_utility::getminutespassed(); + return 1; + } + } + + return 0; +} + +checkhalftime( var_0 ) +{ + if ( !level.teambased ) + return 0; + + if ( game["status"] != "normal" ) + return 0; + + if ( maps\mp\_utility::gettimelimit() ) + { + var_1 = maps\mp\_utility::gettimelimit() * 60 * 1000 * 0.5; + + if ( maps\mp\_utility::gettimepassed() >= var_1 && var_0 < var_1 && var_0 > 0 ) + { + game["roundMillisecondsAlreadyPassed"] = maps\mp\_utility::gettimepassed(); + return 1; + } + } + + return 0; +} + +gettimeremaining() +{ + var_0 = maps\mp\_utility::gettimepassed(); + var_1 = maps\mp\_utility::gettimelimit() * 60 * 1000; + + if ( maps\mp\_utility::gethalftime() && game["status"] == "halftime" && isdefined( level.firsthalftimepassed ) ) + { + var_2 = var_1 * 0.5; + + if ( level.firsthalftimepassed < var_2 ) + { + if ( level.halftimeonscorelimit ) + var_0 = var_1 - level.firsthalftimepassed + var_0 - level.firsthalftimepassed; + else + var_0 += var_2 - level.firsthalftimepassed; + } + } + + return var_1 - var_0; +} + +checkteamscorelimitsoon( var_0 ) +{ + if ( maps\mp\_utility::getwatcheddvar( "scorelimit" ) <= 0 || maps\mp\_utility::isobjectivebased() ) + return; + + if ( isdefined( level.scorelimitoverride ) && level.scorelimitoverride ) + return; + + if ( level.gametype == "conf" ) + return; + + if ( !level.teambased ) + return; + + if ( maps\mp\_utility::gettimepassed() < 60000 ) + return; + + var_1 = estimatedtimetillscorelimit( var_0 ); + + if ( var_1 < 2 ) + level notify( "match_ending_soon", "score" ); +} + +checkplayerscorelimitsoon() +{ + if ( maps\mp\_utility::getwatcheddvar( "scorelimit" ) <= 0 || maps\mp\_utility::isobjectivebased() ) + return; + + if ( level.teambased ) + return; + + if ( maps\mp\_utility::gettimepassed() < 60000 ) + return; + + var_0 = estimatedtimetillscorelimit(); + + if ( var_0 < 2 ) + level notify( "match_ending_soon", "score" ); +} + +checkscorelimit() +{ + if ( maps\mp\_utility::isobjectivebased() ) + return 0; + + if ( isdefined( level.scorelimitoverride ) && level.scorelimitoverride ) + return 0; + + if ( game["state"] != "playing" ) + return 0; + + if ( maps\mp\_utility::getwatcheddvar( "scorelimit" ) <= 0 ) + return 0; + + if ( maps\mp\_utility::gethalftime() && checkhalftimescore() ) + return [[ level.onhalftime ]]( "score_limit_reached" ); + else if ( level.multiteambased ) + { + var_0 = 0; + + for ( var_1 = 0; var_1 < level.teamnamelist.size; var_1++ ) + { + if ( game["teamScores"][level.teamnamelist[var_1]] >= maps\mp\_utility::getwatcheddvar( "scorelimit" ) ) + var_0 = 1; + } + + if ( !var_0 ) + return 0; + } + else if ( level.teambased ) + { + if ( game["teamScores"]["allies"] < maps\mp\_utility::getwatcheddvar( "scorelimit" ) && game["teamScores"]["axis"] < maps\mp\_utility::getwatcheddvar( "scorelimit" ) ) + return 0; + } + else + { + if ( !isplayer( self ) ) + return 0; + + if ( self.score < maps\mp\_utility::getwatcheddvar( "scorelimit" ) ) + return 0; + } + + return onscorelimit(); +} + +updategametypedvars() +{ + level endon( "game_ended" ); + + while ( game["state"] == "playing" ) + { + if ( isdefined( level.starttime ) ) + { + if ( gettimeremaining() < 3000 ) + { + wait 0.1; + continue; + } + } + + wait 1; + } +} + +matchstarttimerwaitforplayers() +{ + setomnvar( "ui_match_countdown_title", 6 ); + setomnvar( "ui_match_countdown_toggle", 0 ); + + if ( level.currentgen ) + setomnvar( "ui_cg_world_blur", 1 ); + + waitforplayers( level.prematchperiod ); + + if ( level.prematchperiodend > 0 && !isdefined( level.hostmigrationtimer ) ) + matchstarttimer( level.prematchperiodend ); +} + +matchstarttimer_internal( var_0 ) +{ + waittillframeend; + level endon( "match_start_timer_beginning" ); + setomnvar( "ui_match_countdown_title", 1 ); + setomnvar( "ui_match_countdown_toggle", 1 ); + + while ( var_0 > 0 && !level.gameended ) + { + setomnvar( "ui_match_countdown", var_0 ); + var_0--; + + if ( level.currentgen ) + setomnvar( "ui_cg_world_blur", 1 ); + + wait 1; + } + + if ( level.currentgen ) + setomnvar( "ui_cg_world_blur_fade_out", 1 ); + + if ( level.xpscale > 1 && !( isdefined( level.ishorde ) && level.ishorde ) && !maps\mp\_utility::privatematch() && !maps\mp\_utility::practiceroundgame() && !( isdefined( level.iszombiegame ) && level.iszombiegame ) ) + { + foreach ( var_2 in level.players ) + var_2 thread maps\mp\gametypes\_hud_message::splashnotify( "double_xp" ); + } + + setomnvar( "ui_match_countdown_toggle", 0 ); + setomnvar( "ui_match_countdown", 0 ); + setomnvar( "ui_match_countdown_title", 2 ); + level endon( "match_forfeit_timer_beginning" ); + wait 1.5; + setomnvar( "ui_match_countdown_title", 0 ); +} + +matchstarttimer( var_0 ) +{ + self notify( "matchStartTimer" ); + self endon( "matchStartTimer" ); + level notify( "match_start_timer_beginning" ); + var_1 = int( var_0 ); + + if ( var_1 >= 2 ) + { + matchstarttimer_internal( var_1 ); + visionsetnaked( "", 3.0 ); + } + else + { + if ( level.currentgen ) + setomnvar( "ui_cg_world_blur_fade_out", 1 ); + + if ( level.xpscale > 1 && !( isdefined( level.ishorde ) && level.ishorde ) && !maps\mp\_utility::privatematch() && !maps\mp\_utility::practiceroundgame() && !( isdefined( level.iszombiegame ) && level.iszombiegame ) ) + { + foreach ( var_3 in level.players ) + var_3 thread maps\mp\gametypes\_hud_message::splashnotify( "double_xp" ); + } + + visionsetnaked( "", 1.0 ); + } +} + +matchstarttimerskip() +{ + visionsetnaked( "", 0 ); +} + +onroundswitch() +{ + if ( !isdefined( game["switchedsides"] ) ) + game["switchedsides"] = 0; + + if ( game["roundsWon"]["allies"] == maps\mp\_utility::getwatcheddvar( "winlimit" ) - 1 && game["roundsWon"]["axis"] == maps\mp\_utility::getwatcheddvar( "winlimit" ) - 1 ) + { + var_0 = getbetterteam(); + + if ( var_0 != game["defenders"] ) + game["switchedsides"] = !game["switchedsides"]; + + level.halftimetype = "overtime"; + game["dynamicEvent_Overtime"] = 1; + } + else + { + level.halftimetype = "halftime"; + game["switchedsides"] = !game["switchedsides"]; + } +} + +checkroundswitch() +{ + if ( !level.teambased ) + return 0; + + if ( !isdefined( level.roundswitch ) || !level.roundswitch ) + return 0; + + if ( game["roundsPlayed"] % level.roundswitch == 0 ) + { + onroundswitch(); + return 1; + } + + return 0; +} + +timeuntilroundend() +{ + if ( level.gameended ) + { + var_0 = ( gettime() - level.gameendtime ) / 1000; + var_1 = level.postroundtime - var_0; + + if ( var_1 < 0 ) + return 0; + + return var_1; + } + + if ( maps\mp\_utility::gettimelimit() <= 0 ) + return undefined; + + if ( !isdefined( level.starttime ) ) + return undefined; + + var_2 = maps\mp\_utility::gettimelimit(); + var_0 = ( gettime() - level.starttime ) / 1000; + var_1 = maps\mp\_utility::gettimelimit() * 60 - var_0; + + if ( isdefined( level.timepaused ) ) + var_1 += level.timepaused; + + return var_1 + level.postroundtime; +} + +freegameplayhudelems() +{ + if ( isdefined( self.perkicon ) ) + { + if ( isdefined( self.perkicon[0] ) ) + { + self.perkicon[0] maps\mp\gametypes\_hud_util::destroyelem(); + self.perkname[0] maps\mp\gametypes\_hud_util::destroyelem(); + } + + if ( isdefined( self.perkicon[1] ) ) + { + self.perkicon[1] maps\mp\gametypes\_hud_util::destroyelem(); + self.perkname[1] maps\mp\gametypes\_hud_util::destroyelem(); + } + + if ( isdefined( self.perkicon[2] ) ) + { + self.perkicon[2] maps\mp\gametypes\_hud_util::destroyelem(); + self.perkname[2] maps\mp\gametypes\_hud_util::destroyelem(); + } + } + + self notify( "perks_hidden" ); + self.lowermessage maps\mp\gametypes\_hud_util::destroyelem(); + self.lowertimer maps\mp\gametypes\_hud_util::destroyelem(); + + if ( isdefined( self.proxbar ) ) + self.proxbar maps\mp\gametypes\_hud_util::destroyelem(); + + if ( isdefined( self.proxbartext ) ) + self.proxbartext maps\mp\gametypes\_hud_util::destroyelem(); +} + +gethostplayer() +{ + var_0 = getentarray( "player", "classname" ); + + for ( var_1 = 0; var_1 < var_0.size; var_1++ ) + { + if ( var_0[var_1] ishost() ) + return var_0[var_1]; + } +} + +hostidledout() +{ + var_0 = gethostplayer(); + + if ( isdefined( var_0 ) && !var_0.hasspawned && !isdefined( var_0.selectedclass ) ) + return 1; + + return 0; +} + +roundendwait( var_0, var_1 ) +{ + foreach ( var_3 in level.players ) + var_3 maps\mp\gametypes\_damage::streamfinalkillcam(); + + var_5 = 0; + + while ( !var_5 ) + { + var_6 = level.players; + var_5 = 1; + + foreach ( var_3 in var_6 ) + { + if ( !isdefined( var_3.doingsplash ) ) + continue; + + if ( !var_3 maps\mp\gametypes\_hud_message::isdoingsplash() ) + continue; + + var_5 = 0; + } + + wait 0.5; + } + + if ( !var_1 ) + { + wait(var_0); + var_6 = level.players; + + foreach ( var_3 in var_6 ) + var_3 setclientomnvar( "ui_round_end", 0 ); + + level notify( "round_end_finished" ); + return; + } + + wait(var_0 / 2); + level notify( "give_match_bonus" ); + wait(var_0 / 2); + var_5 = 0; + + while ( !var_5 ) + { + var_6 = level.players; + var_5 = 1; + + foreach ( var_3 in var_6 ) + { + if ( !isdefined( var_3.doingsplash ) ) + continue; + + if ( !var_3 maps\mp\gametypes\_hud_message::isdoingsplash() ) + continue; + + var_5 = 0; + } + + wait 0.5; + } + + var_6 = level.players; + + foreach ( var_3 in var_6 ) + var_3 setclientomnvar( "ui_round_end", 0 ); + + level notify( "round_end_finished" ); +} + +roundenddof( var_0 ) +{ + self setdepthoffield( 0, 128, 512, 4000, 6, 1.8 ); +} + +callback_startgametype() +{ + maps\mp\_load::main(); + maps\mp\_utility::levelflaginit( "round_over", 0 ); + maps\mp\_utility::levelflaginit( "game_over", 0 ); + maps\mp\_utility::levelflaginit( "block_notifies", 0 ); + level.prematchperiod = 0; + level.prematchperiodend = 0; + level.postgamenotifies = 0; + level.intermission = 0; + setdvar( "bg_compassShowEnemies", getdvar( "scr_game_forceuav" ) ); + + if ( !isdefined( game["gamestarted"] ) ) + { + game["clientid"] = 0; + var_0 = getmapcustom( "allieschar" ); + + if ( !isdefined( var_0 ) || var_0 == "" ) + { + if ( !isdefined( game["allies"] ) ) + var_0 = "sentinel"; + else + var_0 = game["allies"]; + } + + var_1 = getmapcustom( "axischar" ); + + if ( !isdefined( var_1 ) || var_1 == "" ) + { + if ( !isdefined( game["axis"] ) ) + var_1 = "atlas"; + else + var_1 = game["axis"]; + } + + if ( level.multiteambased ) + { + var_2 = getmapcustom( "allieschar" ); + + if ( !isdefined( var_2 ) || var_2 == "" ) + var_2 = "delta_multicam"; + + for ( var_3 = 0; var_3 < level.teamnamelist.size; var_3++ ) + game[level.teamnamelist[var_3]] = var_2; + } + + game["allies"] = var_0; + game["axis"] = var_1; + + if ( !isdefined( game["attackers"] ) || !isdefined( game["defenders"] ) ) + thread common_scripts\utility::error( "No attackers or defenders team defined in level .gsc." ); + + if ( !isdefined( game["attackers"] ) ) + game["attackers"] = "allies"; + + if ( !isdefined( game["defenders"] ) ) + game["defenders"] = "axis"; + + if ( !isdefined( game["state"] ) ) + game["state"] = "playing"; + + if ( level.teambased ) + { + game["strings"]["waiting_for_teams"] = &"MP_WAITING_FOR_TEAMS"; + game["strings"]["opponent_forfeiting_in"] = &"MP_OPPONENT_FORFEITING_IN"; + } + else + { + game["strings"]["waiting_for_teams"] = &"MP_WAITING_FOR_MORE_PLAYERS"; + game["strings"]["opponent_forfeiting_in"] = &"MP_OPPONENT_FORFEITING_IN"; + } + + game["strings"]["press_to_spawn"] = &"PLATFORM_PRESS_TO_SPAWN"; + game["strings"]["match_starting_in"] = &"MP_MATCH_STARTING_IN"; + game["strings"]["match_resuming_in"] = &"MP_MATCH_RESUMING_IN"; + game["strings"]["waiting_for_players"] = &"MP_WAITING_FOR_PLAYERS"; + game["strings"]["spawn_tag_wait"] = &"MP_SPAWN_TAG_WAIT"; + game["strings"]["spawn_next_round"] = &"MP_SPAWN_NEXT_ROUND"; + game["strings"]["waiting_to_spawn"] = &"MP_WAITING_TO_SPAWN"; + game["strings"]["match_starting"] = &"MP_MATCH_STARTING"; + game["strings"]["change_class"] = &"MP_CHANGE_CLASS_NEXT_SPAWN"; + game["strings"]["change_class_cancel"] = &"MP_CHANGE_CLASS_CANCEL"; + game["strings"]["change_class_wait"] = &"MP_CHANGE_CLASS_WAIT"; + game["strings"]["last_stand"] = &"MPUI_LAST_STAND"; + game["strings"]["final_stand"] = &"MPUI_FINAL_STAND"; + game["strings"]["cowards_way"] = &"PLATFORM_COWARDS_WAY_OUT"; + game["colors"]["blue"] = ( 0.25, 0.25, 0.75 ); + game["colors"]["red"] = ( 0.75, 0.25, 0.25 ); + game["colors"]["white"] = ( 1, 1, 1 ); + game["colors"]["black"] = ( 0, 0, 0 ); + game["colors"]["grey"] = ( 0.5, 0.5, 0.5 ); + game["colors"]["green"] = ( 0.25, 0.75, 0.25 ); + game["colors"]["yellow"] = ( 0.65, 0.65, 0 ); + game["colors"]["orange"] = ( 1, 0.45, 0 ); + game["colors"]["cyan"] = ( 0.35, 0.7, 0.9 ); + game["strings"]["allies_name"] = maps\mp\gametypes\_teams::getteamname( "allies" ); + game["icons"]["allies"] = maps\mp\gametypes\_teams::getteamicon( "allies" ); + game["colors"]["allies"] = maps\mp\gametypes\_teams::getteamcolor( "allies" ); + game["strings"]["axis_name"] = maps\mp\gametypes\_teams::getteamname( "axis" ); + game["icons"]["axis"] = maps\mp\gametypes\_teams::getteamicon( "axis" ); + game["colors"]["axis"] = maps\mp\gametypes\_teams::getteamcolor( "axis" ); + + if ( game["colors"]["allies"] == ( 0, 0, 0 ) ) + game["colors"]["allies"] = ( 0.5, 0.5, 0.5 ); + + if ( game["colors"]["axis"] == ( 0, 0, 0 ) ) + game["colors"]["axis"] = ( 0.5, 0.5, 0.5 ); + + [[ level.onprecachegametype ]](); + setdvarifuninitialized( "min_wait_for_players", 5 ); + + if ( level.console ) + { + if ( !level.splitscreen ) + { + if ( isdedicatedserver() ) + level.prematchperiod = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "graceperiod_ds" ); + else + level.prematchperiod = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "graceperiod" ); + + level.prematchperiodend = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "matchstarttime" ); + } + } + else + { + if ( isdedicatedserver() ) + level.prematchperiod = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "playerwaittime_ds" ); + else + level.prematchperiod = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "playerwaittime" ); + + level.prematchperiodend = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "matchstarttime" ); + } + } + else + { + setdvarifuninitialized( "min_wait_for_players", 5 ); + + if ( level.console ) + { + if ( !level.splitscreen ) + { + level.prematchperiod = 5; + level.prematchperiodend = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "roundstarttime" ); + } + } + else + { + level.prematchperiod = 5; + level.prematchperiodend = maps\mp\gametypes\_tweakables::gettweakablevalue( "game", "roundstarttime" ); + } + } + + if ( !isdefined( game["status"] ) ) + game["status"] = "normal"; + + if ( game["status"] != "overtime" && game["status"] != "halftime" && game["status"] != "overtime_halftime" ) + { + game["teamScores"]["allies"] = 0; + game["teamScores"]["axis"] = 0; + + if ( level.multiteambased ) + { + for ( var_3 = 0; var_3 < level.teamnamelist.size; var_3++ ) + game["teamScores"][level.teamnamelist[var_3]] = 0; + } + } + + if ( !isdefined( game["timePassed"] ) ) + game["timePassed"] = 0; + + if ( !isdefined( game["roundsPlayed"] ) ) + game["roundsPlayed"] = 0; + + setomnvar( "ui_current_round", game["roundsPlayed"] + 1 ); + + if ( !isdefined( game["roundsWon"] ) ) + game["roundsWon"] = []; + + if ( level.teambased ) + { + if ( !isdefined( game["roundsWon"]["axis"] ) ) + game["roundsWon"]["axis"] = 0; + + if ( !isdefined( game["roundsWon"]["allies"] ) ) + game["roundsWon"]["allies"] = 0; + + if ( level.multiteambased ) + { + for ( var_3 = 0; var_3 < level.teamnamelist.size; var_3++ ) + { + if ( !isdefined( game["roundsWon"][level.teamnamelist[var_3]] ) ) + game["roundsWon"][level.teamnamelist[var_3]] = 0; + } + } + } + + level.gameended = 0; + level.forcedend = 0; + level.hostforcedend = 0; + level.hardcoremode = getdvarint( "g_hardcore" ); + + if ( level.hardcoremode ) + logstring( "game mode: hardcore" ); + + level.diehardmode = getdvarint( "scr_diehard" ); + + if ( !level.teambased ) + level.diehardmode = 0; + + if ( level.diehardmode ) + logstring( "game mode: diehard" ); + + level.killstreakrewards = getdvarint( "scr_game_hardpoints" ); + + if ( !isdefined( level.iszombiegame ) ) + level.iszombiegame = 0; + + level.usestartspawns = 1; + level.objectivepointsmod = 1; + level.baseplayermovescale = 1; + level.maxallowedteamkills = 2; + thread maps\mp\_teleport::main(); + thread maps\mp\gametypes\_persistence::init(); + thread maps\mp\gametypes\_menus::init(); + thread maps\mp\gametypes\_hud::init(); + thread maps\mp\gametypes\_serversettings::init(); + thread maps\mp\gametypes\_teams::init(); + thread maps\mp\gametypes\_weapons::init(); + thread maps\mp\gametypes\_killcam::init(); + thread maps\mp\gametypes\_shellshock::init(); + thread maps\mp\gametypes\_deathicons::init(); + thread maps\mp\gametypes\_damagefeedback::init(); + thread maps\mp\gametypes\_healthoverlay::init(); + thread maps\mp\gametypes\_spectating::init(); + thread maps\mp\gametypes\_objpoints::init(); + thread maps\mp\gametypes\_gameobjects::init(); + thread maps\mp\gametypes\_spawnlogic::init(); + thread maps\mp\gametypes\_battlechatter_mp::init(); + thread maps\mp\gametypes\_music_and_dialog::init(); + thread maps\mp\gametypes\_high_jump_mp::init(); + thread maps\mp\_grappling_hook::init(); + thread maps\mp\_matchdata::init(); + thread maps\mp\_awards::init(); + thread maps\mp\_areas::init(); + + if ( !maps\mp\_utility::invirtuallobby() ) + thread maps\mp\killstreaks\_killstreaks_init::init(); + + thread maps\mp\perks\_perks::init(); + thread maps\mp\_events::init(); + thread maps\mp\gametypes\_damage::initfinalkillcam(); + thread maps\mp\_threatdetection::init(); + thread maps\mp\_exo_suit::init(); + thread maps\mp\_reinforcements::init(); + thread maps\mp\_snd_common_mp::init(); + thread maps\mp\_utility::buildattachmentmaps(); + + if ( level.teambased ) + thread maps\mp\gametypes\_friendicons::init(); + + thread maps\mp\gametypes\_hud_message::init(); + thread maps\mp\gametypes\_divisions::init(); + + foreach ( var_5 in game["strings"] ) + precachestring( var_5 ); + + foreach ( var_8 in game["icons"] ) + precacheshader( var_8 ); + + game["gamestarted"] = 1; + level.maxplayercount = 0; + level.wavedelay["allies"] = 0; + level.wavedelay["axis"] = 0; + level.lastwave["allies"] = 0; + level.lastwave["axis"] = 0; + level.waveplayerspawnindex["allies"] = 0; + level.waveplayerspawnindex["axis"] = 0; + level.aliveplayers["allies"] = []; + level.aliveplayers["axis"] = []; + level.activeplayers = []; + + if ( level.multiteambased ) + { + for ( var_3 = 0; var_3 < level.teamnamelist.size; var_3++ ) + { + level._wavedelay[level.teamnamelist[var_3]] = 0; + level._lastwave[level.teamnamelist[var_3]] = 0; + level._waveplayerspawnindex[level.teamnamelist[var_3]] = 0; + level._aliveplayers[level.teamnamelist[var_3]] = []; + } + } + + setdvar( "ui_scorelimit", 0 ); + setdvar( "ui_allow_teamchange", 1 ); + + if ( maps\mp\_utility::getgametypenumlives() ) + setdvar( "g_deadChat", 0 ); + else + setdvar( "g_deadChat", 1 ); + + var_10 = getdvarfloat( "scr_" + level.gametype + "_waverespawndelay" ); + + if ( var_10 > 0 ) + { + level.wavedelay["allies"] = var_10; + level.wavedelay["axis"] = var_10; + level.lastwave["allies"] = 0; + level.lastwave["axis"] = 0; + + if ( level.multiteambased ) + { + for ( var_3 = 0; var_3 < level.teamnamelist.size; var_3++ ) + { + level._wavedelay[level.teamnamelist[var_3]] = var_10; + level._lastwave[level.teamnamelist[var_3]] = 0; + } + } + + level thread wavespawntimer(); + } + + maps\mp\_utility::gameflaginit( "prematch_done", 0 ); + level.graceperiod = 15; + level.ingraceperiod = level.graceperiod; + maps\mp\_utility::gameflaginit( "graceperiod_done", 0 ); + level.roundenddelay = 4; + level.halftimeroundenddelay = 4; + level.noragdollents = getentarray( "noragdoll", "targetname" ); + + if ( level.teambased ) + { + maps\mp\gametypes\_gamescore::updateteamscore( "axis" ); + maps\mp\gametypes\_gamescore::updateteamscore( "allies" ); + + if ( level.multiteambased ) + { + for ( var_3 = 0; var_3 < level.teamnamelist.size; var_3++ ) + maps\mp\gametypes\_gamescore::updateteamscore( level.teamnamelist[var_3] ); + } + } + else + thread maps\mp\gametypes\_gamescore::initialdmscoreupdate(); + + thread updateuiscorelimit(); + level notify( "update_scorelimit" ); + [[ level.onstartgametype ]](); + level.scorepercentagecutoff = getdvarint( "scr_" + level.gametype + "_score_percentage_cut_off", 80 ); + level.timepercentagecutoff = getdvarint( "scr_" + level.gametype + "_time_percentage_cut_off", 80 ); + + if ( !level.console && ( getdvar( "dedicated" ) == "dedicated LAN server" || getdvar( "dedicated" ) == "dedicated internet server" ) ) + thread verifydedicatedconfiguration(); + + setattackingteam(); + thread startgame(); + level thread maps\mp\_utility::updatewatcheddvars(); + level thread timelimitthread(); + level thread maps\mp\gametypes\_damage::dofinalkillcam(); +} + +setattackingteam() +{ + if ( game["attackers"] == "axis" ) + var_0 = 1; + else if ( game["attackers"] == "allies" ) + var_0 = 2; + else + var_0 = 0; + + setomnvar( "ui_attacking_team", var_0 ); +} + +callback_codeendgame() +{ + endparty(); + + if ( !level.gameended ) + level thread forceend(); +} + +verifydedicatedconfiguration() +{ + for (;;) + { + if ( level.rankedmatch ) + exitlevel( 0 ); + + if ( !getdvarint( "xblive_privatematch" ) ) + exitlevel( 0 ); + + if ( getdvar( "dedicated" ) != "dedicated LAN server" && getdvar( "dedicated" ) != "dedicated internet server" ) + exitlevel( 0 ); + + wait 5; + } +} + +timelimitthread() +{ + level endon( "game_ended" ); + var_0 = maps\mp\_utility::gettimepassed(); + + while ( game["state"] == "playing" ) + { + thread checktimelimit( var_0 ); + var_0 = maps\mp\_utility::gettimepassed(); + + if ( isdefined( level.starttime ) ) + { + if ( gettimeremaining() < 3000 ) + { + wait 0.1; + continue; + } + } + + wait 1; + } +} + +updateuiscorelimit() +{ + for (;;) + { + level common_scripts\utility::waittill_either( "update_scorelimit", "update_winlimit" ); + + if ( !maps\mp\_utility::isroundbased() || !maps\mp\_utility::isobjectivebased() ) + { + setdvar( "ui_scorelimit", maps\mp\_utility::getwatcheddvar( "scorelimit" ) ); + thread checkscorelimit(); + continue; + } + + setdvar( "ui_scorelimit", maps\mp\_utility::getwatcheddvar( "winlimit" ) ); + } +} + +playtickingsound() +{ + self endon( "death" ); + self endon( "stop_ticking" ); + level endon( "game_ended" ); + var_0 = level.bombtimer; + + for (;;) + { + self playsound( "ui_mp_suitcasebomb_timer" ); + + if ( var_0 > 10 ) + { + var_0 -= 1; + wait 1; + } + else if ( var_0 > 4 ) + { + var_0 -= 0.5; + wait 0.5; + } + else if ( var_0 > 1 ) + { + var_0 -= 0.4; + wait 0.4; + } + else + { + var_0 -= 0.3; + wait 0.3; + } + + maps\mp\gametypes\_hostmigration::waittillhostmigrationdone(); + } +} + +stoptickingsound() +{ + self notify( "stop_ticking" ); +} + +timelimitclock() +{ + level endon( "game_ended" ); + wait 0.05; + var_0 = spawn( "script_origin", ( 0, 0, 0 ) ); + var_0 hide(); + + while ( game["state"] == "playing" ) + { + if ( !level.timerstopped && maps\mp\_utility::gettimelimit() ) + { + var_1 = gettimeremaining() / 1000; + var_2 = int( var_1 + 0.5 ); + var_3 = int( maps\mp\_utility::gettimelimit() * 60 * 0.5 ); + + if ( maps\mp\_utility::gethalftime() && var_2 > var_3 ) + var_2 -= var_3; + + if ( var_2 >= 30 && var_2 <= 60 ) + level notify( "match_ending_soon", "time" ); + + if ( var_2 <= 10 || var_2 <= 30 && var_2 % 2 == 0 ) + { + level notify( "match_ending_very_soon" ); + + if ( var_2 == 0 ) + break; + + var_0 playsound( "ui_mp_timer_countdown" ); + } + + if ( var_1 - floor( var_1 ) >= 0.05 ) + wait(var_1 - floor( var_1 )); + } + + wait 1.0; + } +} + +gametimer() +{ + level endon( "game_ended" ); + level waittill( "prematch_over" ); + level.starttime = gettime(); + level.discardtime = 0; + level.matchdurationstarttime = gettime(); + + if ( isdefined( game["roundMillisecondsAlreadyPassed"] ) ) + { + level.starttime -= game["roundMillisecondsAlreadyPassed"]; + level.firsthalftimepassed = game["roundMillisecondsAlreadyPassed"]; + game["roundMillisecondsAlreadyPassed"] = undefined; + } + + var_0 = gettime(); + + while ( game["state"] == "playing" ) + { + if ( !level.timerstopped ) + game["timePassed"] += gettime() - var_0; + + var_0 = gettime(); + wait 1.0; + } +} + +updatetimerpausedness() +{ + var_0 = level.timerstoppedforgamemode || isdefined( level.hostmigrationtimer ); + + if ( !maps\mp\_utility::gameflag( "prematch_done" ) ) + var_0 = 0; + + if ( !level.timerstopped && var_0 ) + { + level.timerstopped = 1; + level.timerpausetime = gettime(); + } + else if ( level.timerstopped && !var_0 ) + { + level.timerstopped = 0; + level.discardtime += gettime() - level.timerpausetime; + } +} + +pausetimer() +{ + level.timerstoppedforgamemode = 1; + updatetimerpausedness(); +} + +resumetimer() +{ + level.timerstoppedforgamemode = 0; + updatetimerpausedness(); +} + +startgame() +{ + thread gametimer(); + level.timerstopped = 0; + level.timerstoppedforgamemode = 0; + setdvar( "ui_inprematch", 1 ); + prematchperiod(); + maps\mp\_utility::gameflagset( "prematch_done" ); + level notify( "prematch_over" ); + setdvar( "ui_inprematch", 0 ); + level.prematch_done_time = gettime(); + updatetimerpausedness(); + thread timelimitclock(); + thread graceperiod(); + thread maps\mp\gametypes\_missions::roundbegin(); + thread maps\mp\_matchdata::matchstarted(); + var_0 = isdefined( level.ishorde ) && level.ishorde; + var_1 = isdefined( level.iszombiegame ) && level.iszombiegame; + + if ( var_0 || var_1 ) + thread updategameduration(); + + lootserviceonstartgame(); +} + +wavespawntimer() +{ + level endon( "game_ended" ); + + while ( game["state"] == "playing" ) + { + var_0 = gettime(); + + if ( var_0 - level.lastwave["allies"] > level.wavedelay["allies"] * 1000 ) + { + level notify( "wave_respawn_allies" ); + level.lastwave["allies"] = var_0; + level.waveplayerspawnindex["allies"] = 0; + } + + if ( var_0 - level.lastwave["axis"] > level.wavedelay["axis"] * 1000 ) + { + level notify( "wave_respawn_axis" ); + level.lastwave["axis"] = var_0; + level.waveplayerspawnindex["axis"] = 0; + } + + if ( level.multiteambased ) + { + for ( var_1 = 0; var_1 < level.teamnamelist.size; var_1++ ) + { + if ( var_0 - level.lastwave[level.teamnamelist[var_1]] > level._wavedelay[level.teamnamelist[var_1]] * 1000 ) + { + var_2 = "wave_rewpawn_" + level.teamnamelist[var_1]; + level notify( var_2 ); + level.lastwave[level.teamnamelist[var_1]] = var_0; + level.waveplayerspawnindex[level.teamnamelist[var_1]] = 0; + } + } + } + + wait 0.05; + } +} + +getbetterteam() +{ + var_0["allies"] = 0; + var_0["axis"] = 0; + var_1["allies"] = 0; + var_1["axis"] = 0; + var_2["allies"] = 0; + var_2["axis"] = 0; + + foreach ( var_4 in level.players ) + { + var_5 = var_4.pers["team"]; + + if ( isdefined( var_5 ) && ( var_5 == "allies" || var_5 == "axis" ) ) + { + var_0[var_5] += var_4.score; + var_1[var_5] += var_4.kills; + var_2[var_5] += var_4.deaths; + } + } + + if ( var_0["allies"] > var_0["axis"] ) + return "allies"; + else if ( var_0["axis"] > var_0["allies"] ) + return "axis"; + + if ( var_1["allies"] > var_1["axis"] ) + return "allies"; + else if ( var_1["axis"] > var_1["allies"] ) + return "axis"; + + if ( var_2["allies"] < var_2["axis"] ) + return "allies"; + else if ( var_2["axis"] < var_2["allies"] ) + return "axis"; + + if ( randomint( 2 ) == 0 ) + return "allies"; + + return "axis"; +} + +rankedmatchupdates( var_0 ) +{ + if ( !maps\mp\_utility::waslastround() ) + return; + + var_0 = getgamewinner( var_0, 0 ); + + if ( maps\mp\_utility::matchmakinggame() ) + { + setxenonranks(); + + if ( hostidledout() ) + { + level.hostforcedend = 1; + logstring( "host idled out" ); + endlobby(); + } + + updatematchbonusscores( var_0 ); + } + + updatewinlossstats( var_0 ); +} + +displayroundend( var_0, var_1 ) +{ + if ( !maps\mp\_utility::practiceroundgame() ) + { + foreach ( var_3 in level.players ) + { + if ( isdefined( var_3.connectedpostgame ) || var_3.pers["team"] == "spectator" && !var_3 ismlgspectator() ) + continue; + + if ( level.teambased ) + { + var_3 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( var_0, 1, var_1 ); + continue; + } + + var_3 thread maps\mp\gametypes\_hud_message::outcomenotify( var_0, var_1 ); + } + } + + if ( !maps\mp\_utility::waslastround() ) + level notify( "round_win", var_0 ); + + if ( maps\mp\_utility::waslastround() ) + roundendwait( level.roundenddelay, 0 ); + else + roundendwait( level.roundenddelay, 1 ); +} + +displaygameend( var_0, var_1 ) +{ + if ( !maps\mp\_utility::practiceroundgame() ) + { + foreach ( var_3 in level.players ) + { + if ( isdefined( var_3.connectedpostgame ) || var_3.pers["team"] == "spectator" && !var_3 ismlgspectator() ) + continue; + + if ( level.teambased ) + { + var_3 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( var_0, 0, var_1, 1 ); + continue; + } + + var_3 thread maps\mp\gametypes\_hud_message::outcomenotify( var_0, var_1 ); + } + } + + level notify( "game_win", var_0 ); + roundendwait( level.postroundtime, 1 ); +} + +displayroundswitch() +{ + var_0 = level.halftimetype; + + if ( var_0 == "halftime" ) + { + if ( maps\mp\_utility::getwatcheddvar( "roundlimit" ) ) + { + if ( game["roundsPlayed"] * 2 == maps\mp\_utility::getwatcheddvar( "roundlimit" ) ) + var_0 = "halftime"; + else + var_0 = "intermission"; + } + else if ( maps\mp\_utility::getwatcheddvar( "winlimit" ) ) + { + if ( game["roundsPlayed"] == maps\mp\_utility::getwatcheddvar( "winlimit" ) - 1 ) + var_0 = "halftime"; + else + var_0 = "intermission"; + } + else + var_0 = "intermission"; + } + + level notify( "round_switch", var_0 ); + + foreach ( var_2 in level.players ) + { + if ( isdefined( var_2.connectedpostgame ) || var_2.pers["team"] == "spectator" && !var_2 ismlgspectator() ) + continue; + + var_2 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( var_0, 1, game["end_reason"]["switching_sides"] ); + } + + roundendwait( level.halftimeroundenddelay, 0 ); +} + +freezeallplayers( var_0, var_1 ) +{ + if ( !isdefined( var_0 ) ) + var_0 = 0; + + foreach ( var_3 in level.players ) + { + var_3 disableammogeneration(); + var_3 thread freezeplayerforroundend( var_0 ); + var_3 thread roundenddof( 4.0 ); + var_3 freegameplayhudelems(); + + if ( isdefined( var_1 ) && var_1 ) + { + continue; + } + } + + if ( isdefined( level.agentarray ) ) + { + foreach ( var_6 in level.agentarray ) + var_6 maps\mp\_utility::freezecontrolswrapper( 1 ); + } +} + +endgameovertime( var_0, var_1 ) +{ + setdvar( "bg_compassShowEnemies", 0 ); + freezeallplayers( 1.0, 1 ); + + foreach ( var_3 in level.players ) + { + var_3.pers["stats"] = var_3.stats; + var_3.pers["segments"] = var_3.segments; + } + + level notify( "round_switch", "overtime" ); + var_5 = 0; + var_6 = var_0 == "overtime"; + + if ( level.gametype == "ctf" ) + { + var_0 = "tie"; + var_5 = 1; + + if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] ) + var_0 = "axis"; + + if ( game["teamScores"]["allies"] > game["teamScores"]["axis"] ) + var_0 = "allies"; + } + + foreach ( var_3 in level.players ) + { + if ( isdefined( var_3.connectedpostgame ) || var_3.pers["team"] == "spectator" && !var_3 ismlgspectator() ) + continue; + + if ( level.teambased ) + { + var_3 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( var_0, var_5, var_1 ); + continue; + } + + var_3 thread maps\mp\gametypes\_hud_message::outcomenotify( var_0, var_1 ); + } + + roundendwait( level.roundenddelay, 0 ); + + if ( level.gametype == "ctf" ) + var_0 = "overtime_halftime"; + + if ( isdefined( level.finalkillcam_winner ) && var_6 ) + { + level.finalkillcam_timegameended[level.finalkillcam_winner] = maps\mp\_utility::getsecondspassed(); + + foreach ( var_3 in level.players ) + var_3 notify( "reset_outcome" ); + + level notify( "game_cleanup" ); + waittillfinalkillcamdone(); + + if ( level.gametype == "ctf" ) + { + var_0 = "overtime"; + var_1 = game["end_reason"]["tie"]; + } + + foreach ( var_3 in level.players ) + { + if ( isdefined( var_3.connectedpostgame ) || var_3.pers["team"] == "spectator" && !var_3 ismlgspectator() ) + continue; + + if ( level.teambased ) + { + var_3 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( var_0, 0, var_1 ); + continue; + } + + var_3 thread maps\mp\gametypes\_hud_message::outcomenotify( var_0, var_1 ); + } + + roundendwait( level.halftimeroundenddelay, 0 ); + } + + game["status"] = var_0; + level notify( "restarting" ); + game["state"] = "playing"; + setdvar( "ui_game_state", game["state"] ); + map_restart( 1 ); +} + +endgamehalftime( var_0 ) +{ + setdvar( "bg_compassShowEnemies", 0 ); + var_1 = "halftime"; + var_2 = 1; + + if ( isdefined( level.halftime_switch_sides ) && !level.halftime_switch_sides ) + var_2 = 0; + + if ( var_2 ) + { + game["switchedsides"] = !game["switchedsides"]; + var_3 = game["end_reason"]["switching_sides"]; + } + else + var_3 = var_0; + + freezeallplayers( 1.0, 1 ); + + if ( level.gametype == "ctf" ) + { + var_3 = var_0; + var_1 = "tie"; + + if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] ) + var_1 = "axis"; + + if ( game["teamScores"]["allies"] > game["teamScores"]["axis"] ) + var_1 = "allies"; + } + + foreach ( var_5 in level.players ) + { + var_5.pers["stats"] = var_5.stats; + var_5.pers["segments"] = var_5.segments; + } + + level notify( "round_switch", "halftime" ); + + foreach ( var_5 in level.players ) + { + if ( isdefined( var_5.connectedpostgame ) || var_5.pers["team"] == "spectator" && !var_5 ismlgspectator() ) + continue; + + var_5 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( var_1, 1, var_3 ); + } + + roundendwait( level.roundenddelay, 0 ); + + if ( isdefined( level.finalkillcam_winner ) ) + { + level.finalkillcam_timegameended[level.finalkillcam_winner] = maps\mp\_utility::getsecondspassed(); + + foreach ( var_5 in level.players ) + var_5 notify( "reset_outcome" ); + + level notify( "game_cleanup" ); + waittillfinalkillcamdone(); + var_11 = game["end_reason"]["switching_sides"]; + + if ( !var_2 ) + var_11 = var_3; + + foreach ( var_5 in level.players ) + { + if ( isdefined( var_5.connectedpostgame ) || var_5.pers["team"] == "spectator" && !var_5 ismlgspectator() ) + continue; + + var_5 thread maps\mp\gametypes\_hud_message::teamoutcomenotify( "halftime", 1, var_11 ); + } + + roundendwait( level.halftimeroundenddelay, 0 ); + } + + game["status"] = "halftime"; + level notify( "restarting" ); + game["state"] = "playing"; + setdvar( "ui_game_state", game["state"] ); + map_restart( 1 ); +} + +updategameduration() +{ + level endon( "game_ended" ); + + for (;;) + { + var_0 = getgameduration(); + setomnvar( "ui_game_duration", var_0 * 1000 ); + wait 1.0; + } +} + +getgameduration() +{ + var_0 = maps\mp\_utility::getgametimepassedseconds(); + + if ( isdefined( level.ishorde ) && level.ishorde ) + var_0 = gamedurationclamp( var_0 ); + + return var_0; +} + +gamedurationclamp( var_0 ) +{ + if ( var_0 > 86399 ) + return 86399; + + return var_0; +} + +endgame( var_0, var_1, var_2 ) +{ + if ( !isdefined( var_2 ) ) + var_2 = 0; + + if ( game["state"] == "postgame" || level.gameended ) + return; + + game["state"] = "postgame"; + setdvar( "ui_game_state", "postgame" ); + level.gameendtime = gettime(); + level.gameended = 1; + level.ingraceperiod = 0; + level notify( "game_ended", var_0 ); + maps\mp\_utility::levelflagset( "game_over" ); + maps\mp\_utility::levelflagset( "block_notifies" ); + var_3 = getgameduration(); + setomnvar( "ui_game_duration", var_3 * 1000 ); + waitframe(); + setgameendtime( 0 ); + setmatchdata( "gameLengthSeconds", var_3 ); + setmatchdata( "endTimeUTC", getsystemtime() ); + checkgameendchallenges(); + + if ( isdefined( var_0 ) && isstring( var_0 ) && maps\mp\_utility::isovertimetext( var_0 ) ) + { + level.finalkillcam_winner = "none"; + endgameovertime( var_0, var_1 ); + return; + } + + if ( isdefined( var_0 ) && isstring( var_0 ) && var_0 == "halftime" ) + { + level.finalkillcam_winner = "none"; + endgamehalftime( var_1 ); + return; + } + + if ( isdefined( level.finalkillcam_winner ) ) + level.finalkillcam_timegameended[level.finalkillcam_winner] = maps\mp\_utility::getsecondspassed(); + + game["roundsPlayed"]++; + setomnvar( "ui_current_round", game["roundsPlayed"] ); + + if ( level.teambased ) + { + if ( ( var_0 == "axis" || var_0 == "allies" ) && level.gametype != "ctf" ) + game["roundsWon"][var_0]++; + + maps\mp\gametypes\_gamescore::updateteamscore( "axis" ); + maps\mp\gametypes\_gamescore::updateteamscore( "allies" ); + } + else if ( isdefined( var_0 ) && isplayer( var_0 ) ) + game["roundsWon"][var_0.guid]++; + + maps\mp\gametypes\_gamescore::updateplacement(); + rankedmatchupdates( var_0 ); + + foreach ( var_5 in level.players ) + { + var_5 setclientdvar( "ui_opensummary", 1 ); + + if ( maps\mp\_utility::wasonlyround() || maps\mp\_utility::waslastround() ) + var_5 maps\mp\killstreaks\_killstreaks::clearkillstreaks( 1 ); + } + + setdvar( "g_deadChat", 1 ); + setdvar( "ui_allow_teamchange", 0 ); + setdvar( "bg_compassShowEnemies", 0 ); + freezeallplayers( 1.0, 1 ); + + if ( !maps\mp\_utility::wasonlyround() && !var_2 ) + { + displayroundend( var_0, var_1 ); + + if ( isdefined( level.finalkillcam_winner ) ) + { + foreach ( var_5 in level.players ) + var_5 notify( "reset_outcome" ); + + level notify( "game_cleanup" ); + waittillfinalkillcamdone(); + } + + if ( !maps\mp\_utility::waslastround() ) + { + maps\mp\_utility::levelflagclear( "block_notifies" ); + + if ( checkroundswitch() ) + displayroundswitch(); + + foreach ( var_5 in level.players ) + { + var_5.pers["stats"] = var_5.stats; + var_5.pers["segments"] = var_5.segments; + } + + level notify( "restarting" ); + game["state"] = "playing"; + setdvar( "ui_game_state", "playing" ); + map_restart( 1 ); + return; + } + + if ( !level.forcedend ) + var_1 = updateendreasontext( var_0 ); + } + + if ( !isdefined( game["clientMatchDataDef"] ) ) + { + game["clientMatchDataDef"] = "mp/clientmatchdata.def"; + setclientmatchdatadef( game["clientMatchDataDef"] ); + } + + maps\mp\gametypes\_missions::roundend( var_0 ); + var_0 = getgamewinner( var_0, 1 ); + + if ( level.teambased ) + { + setomnvar( "ui_game_victor", 0 ); + + if ( var_0 == "allies" ) + setomnvar( "ui_game_victor", 2 ); + else if ( var_0 == "axis" ) + setomnvar( "ui_game_victor", 1 ); + } + + displaygameend( var_0, var_1 ); + var_11 = gettime(); + + if ( isdefined( level.finalkillcam_winner ) && maps\mp\_utility::wasonlyround() ) + { + foreach ( var_5 in level.players ) + var_5 notify( "reset_outcome" ); + + level notify( "game_cleanup" ); + waittillfinalkillcamdone(); + } + + maps\mp\_utility::levelflagclear( "block_notifies" ); + level.intermission = 1; + level notify( "spawning_intermission" ); + + foreach ( var_5 in level.players ) + { + var_5 closepopupmenu(); + var_5 closeingamemenu(); + var_5 notify( "reset_outcome" ); + var_5 thread maps\mp\gametypes\_playerlogic::spawnintermission(); + } + + processlobbydata(); + wait 1.0; + checkforpersonalbests(); + updatecombatrecord(); + + if ( level.teambased ) + { + if ( var_0 == "axis" || var_0 == "allies" ) + setmatchdata( "victor", var_0 ); + else + setmatchdata( "victor", "none" ); + + setmatchdata( "alliesScore", game["teamScores"]["allies"] ); + setmatchdata( "axisScore", game["teamScores"]["axis"] ); + tournamentreportwinningteam( var_0 ); + } + else + setmatchdata( "victor", "none" ); + + level maps\mp\_matchdata::endofgamesummarylogger(); + + foreach ( var_5 in level.players ) + { + if ( var_5 maps\mp\_utility::rankingenabled() ) + var_5 maps\mp\_matchdata::logfinalstats(); + + var_5 maps\mp\gametypes\_playerlogic::logplayerstats(); + } + + setmatchdata( "host", maps\mp\gametypes\_playerlogic::truncateplayername( level.hostname ) ); + + if ( maps\mp\_utility::matchmakinggame() ) + { + setmatchdata( "playlistVersion", getplaylistversion() ); + setmatchdata( "playlistID", getplaylistid() ); + setmatchdata( "isDedicated", isdedicatedserver() ); + } + + setmatchdata( "levelMaxClients", level.maxclients ); + sendmatchdata(); + + foreach ( var_5 in level.players ) + { + var_5.pers["stats"] = var_5.stats; + var_5.pers["segments"] = var_5.segments; + } + + tournamentreportendofgame(); + var_20 = 0; + + if ( maps\mp\_utility::practiceroundgame() ) + var_20 = 5.0; + + if ( isdefined( level.endgamewaitfunc ) ) + [[ level.endgamewaitfunc ]]( var_2, level.postgamenotifies, var_20, var_0 ); + else if ( !var_2 && !level.postgamenotifies ) + { + if ( !maps\mp\_utility::wasonlyround() ) + wait(6.0 + var_20); + else + wait(min( 10.0, 4.0 + var_20 + level.postgamenotifies )); + } + else + wait(min( 10.0, 4.0 + var_20 + level.postgamenotifies )); + + var_21 = "_gamelogic.gsc"; + var_22 = "all"; + + if ( level.teambased && isdefined( var_0 ) ) + var_22 = var_0; + + var_23 = "undefined"; + + if ( isdefined( var_1 ) ) + { + switch ( var_1 ) + { + case 1: + var_23 = "MP_SCORE_LIMIT_REACHED"; + break; + case 2: + var_23 = "MP_TIME_LIMIT_REACHED"; + break; + case 3: + var_23 = "MP_PLAYERS_FORFEITED"; + break; + case 4: + var_23 = "MP_TARGET_DESTROYED"; + break; + case 5: + var_23 = "MP_BOMB_DEFUSED"; + break; + case 6: + var_23 = "MP_GHOSTS_ELIMINATED"; + break; + case 7: + var_23 = "MP_FEDERATION_ELIMINATED"; + break; + case 8: + var_23 = "MP_GHOSTS_FORFEITED"; + break; + case 9: + var_23 = "MP_FEDERATION_FORFEITED"; + break; + case 10: + var_23 = "MP_ENEMIES_ELIMINATED"; + break; + case 11: + var_23 = "MP_MATCH_TIE"; + break; + case 12: + var_23 = "GAME_OBJECTIVECOMPLETED"; + break; + case 13: + var_23 = "GAME_OBJECTIVEFAILED"; + break; + case 14: + var_23 = "MP_SWITCHING_SIDES"; + break; + case 15: + var_23 = "MP_ROUND_LIMIT_REACHED"; + break; + case 16: + var_23 = "MP_ENDED_GAME"; + break; + case 17: + var_23 = "MP_HOST_ENDED_GAME"; + break; + default: + break; + } + } + + if ( !isdefined( var_11 ) ) + var_11 = -1; + + var_24 = 15; + var_25 = var_24; + var_26 = getmatchdata( "playerCount" ); + var_27 = getmatchdata( "lifeCount" ); + + if ( !isdefined( level.matchdata ) ) + { + var_28 = 0; + var_29 = 0; + var_30 = 0; + var_31 = 0; + var_32 = 0; + var_33 = 0; + var_34 = 0; + } + else + { + if ( isdefined( level.matchdata["botJoinCount"] ) ) + var_28 = level.matchdata["botJoinCount"]; + else + var_28 = 0; + + if ( isdefined( level.matchdata["deathCount"] ) ) + var_29 = level.matchdata["deathCount"]; + else + var_29 = 0; + + if ( isdefined( level.matchdata["badSpawnDiedTooFastCount"] ) ) + var_30 = level.matchdata["badSpawnDiedTooFastCount"]; + else + var_30 = 0; + + if ( isdefined( level.matchdata["badSpawnKilledTooFastCount"] ) ) + var_31 = level.matchdata["badSpawnKilledTooFastCount"]; + else + var_31 = 0; + + if ( isdefined( level.matchdata["badSpawnDmgDealtCount"] ) ) + var_32 = level.matchdata["badSpawnDmgDealtCount"]; + else + var_32 = 0; + + if ( isdefined( level.matchdata["badSpawnDmgReceivedCount"] ) ) + var_33 = level.matchdata["badSpawnDmgReceivedCount"]; + else + var_33 = 0; + + if ( isdefined( level.matchdata["badSpawnByAnyMeansCount"] ) ) + var_34 = level.matchdata["badSpawnByAnyMeansCount"]; + else + var_34 = 0; + } + + var_35 = 0; + + if ( isdefined( level.spawnsighttracesused_pres1tu ) ) + var_35 += 1; + + if ( isdefined( level.spawnsighttracesused_posts1tu ) ) + var_35 += 2; + + reconevent( "script_mp_match_end: script_file %s, gameTime %d, match_winner %s, win_reason %s, version %d, joinCount %d, botJoinCount %d, spawnCount %d, deathCount %d, badSpawnDiedTooFastCount %d, badSpawnKilledTooFastCount %d, badSpawnDmgDealtCount %d, badSpawnDmgReceivedCount %d, badSpawnByAnyMeansCount %d, sightTraceMethodsUsed %d", var_21, var_11, var_22, var_23, var_25, var_26, var_28, var_27, var_29, var_30, var_31, var_32, var_33, var_34, var_35 ); + + if ( isdefined( level.ishorde ) && level.ishorde ) + { + if ( isdefined( level.zombiescompleted ) && level.zombiescompleted ) + setdvar( "cg_drawCrosshair", 1 ); + } + + level notify( "exitLevel_called" ); + exitlevel( 0 ); +} + +getgamewinner( var_0, var_1 ) +{ + if ( !isstring( var_0 ) ) + return var_0; + + var_2 = var_0; + + if ( level.teambased && ( maps\mp\_utility::isroundbased() || level.gametype == "ctf" ) && level.gameended ) + { + var_3 = "roundsWon"; + + if ( isdefined( level.winbycaptures ) && level.winbycaptures ) + var_3 = "teamScores"; + + if ( game[var_3]["allies"] == game[var_3]["axis"] ) + var_2 = "tie"; + else if ( game[var_3]["axis"] > game[var_3]["allies"] ) + var_2 = "axis"; + else + var_2 = "allies"; + } + + if ( var_1 && ( var_2 == "allies" || var_2 == "axis" ) ) + level.finalkillcam_winner = var_2; + + return var_2; +} + +updateendreasontext( var_0 ) +{ + if ( !level.teambased ) + return 1; + + if ( maps\mp\_utility::hitroundlimit() ) + return game["end_reason"]["round_limit_reached"]; + + if ( maps\mp\_utility::hitwinlimit() ) + return game["end_reason"]["score_limit_reached"]; + + return game["end_reason"]["objective_completed"]; +} + +estimatedtimetillscorelimit( var_0 ) +{ + var_1 = getscoreperminute( var_0 ); + var_2 = getscoreremaining( var_0 ); + var_3 = 999999; + + if ( var_1 ) + var_3 = var_2 / var_1; + + return var_3; +} + +getscoreperminute( var_0 ) +{ + var_1 = maps\mp\_utility::getwatcheddvar( "scorelimit" ); + var_2 = maps\mp\_utility::gettimelimit(); + var_3 = maps\mp\_utility::gettimepassed() / 60000 + 0.0001; + + if ( isplayer( self ) ) + var_4 = self.score / var_3; + else + var_4 = getteamscore( var_0 ) / var_3; + + return var_4; +} + +getscoreremaining( var_0 ) +{ + var_1 = maps\mp\_utility::getwatcheddvar( "scorelimit" ); + + if ( isplayer( self ) ) + var_2 = var_1 - self.score; + else + var_2 = var_1 - getteamscore( var_0 ); + + return var_2; +} + +givelastonteamwarning() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + maps\mp\_utility::waittillrecoveredhealth( 3 ); + thread maps\mp\_utility::teamplayercardsplash( "callout_lastteammemberalive", self, self.pers["team"] ); + + if ( level.multiteambased ) + { + foreach ( var_1 in level.teamnamelist ) + { + if ( self.pers["team"] != var_1 ) + thread maps\mp\_utility::teamplayercardsplash( "callout_lastenemyalive", self, var_1 ); + } + } + else + { + var_3 = maps\mp\_utility::getotherteam( self.pers["team"] ); + thread maps\mp\_utility::teamplayercardsplash( "callout_lastenemyalive", self, var_3 ); + } + + level notify( "last_alive", self ); +} + +processlobbydata() +{ + var_0 = 0; + + foreach ( var_2 in level.players ) + { + if ( !isdefined( var_2 ) ) + continue; + + var_2.clientmatchdataid = var_0; + var_0++; + + if ( isdefined( level.iszombiegame ) && level.iszombiegame ) + var_2.clientmatchdataid = var_2 getentitynumber(); + + setclientmatchdata( "players", var_2.clientmatchdataid, "name", maps\mp\gametypes\_playerlogic::truncateplayername( var_2.name ) ); + setclientmatchdata( "players", var_2.clientmatchdataid, "xuid", var_2.xuid ); + } + + maps\mp\_awards::assignawards(); + maps\mp\_scoreboard::processlobbyscoreboards(); + sendclientmatchdata(); + lootserviceonendgame(); +} + +trackleaderboarddeathstats( var_0, var_1 ) +{ + thread threadedsetweaponstatbyname( var_0, 1, "deaths" ); +} + +trackattackerleaderboarddeathstats( var_0, var_1, var_2 ) +{ + if ( isdefined( self ) && isplayer( self ) ) + { + if ( var_1 != "MOD_FALLING" ) + { + if ( maps\mp\_utility::ismeleemod( var_1 ) && issubstr( var_0, "tactical" ) ) + return; + + if ( maps\mp\_utility::ismeleemod( var_1 ) && !issubstr( var_0, "riotshield" ) && !issubstr( var_0, "combatknife" ) ) + return; + + thread threadedsetweaponstatbyname( var_0, 1, "kills" ); + var_3 = 0; + + if ( isdefined( var_2 ) && isdefined( var_2.firedads ) ) + var_3 = var_2.firedads; + else + var_3 = self playerads(); + + if ( var_3 < 0.2 ) + thread threadedsetweaponstatbyname( var_0, 1, "hipfirekills" ); + } + + if ( var_1 == "MOD_HEAD_SHOT" ) + thread threadedsetweaponstatbyname( var_0, 1, "headShots" ); + } +} + +setweaponstat( var_0, var_1, var_2 ) +{ + if ( !var_1 ) + return; + + var_3 = maps\mp\_utility::getweaponclass( var_0 ); + + if ( var_3 == "killstreak" || var_3 == "other" ) + return; + + if ( maps\mp\_utility::isenvironmentweapon( var_0 ) ) + return; + + if ( maps\mp\_utility::isbombsiteweapon( var_0 ) ) + return; + + if ( var_0 == maps\mp\_grappling_hook::get_grappling_hook_weapon() ) + return; + + if ( var_3 == "weapon_grenade" || var_3 == "weapon_explosive" ) + { + var_4 = maps\mp\_utility::strip_suffix( var_0, "_lefthand" ); + var_4 = maps\mp\_utility::strip_suffix( var_4, "_mp" ); + maps\mp\gametypes\_persistence::incrementweaponstat( var_4, var_2, var_1 ); + maps\mp\_matchdata::logweaponstat( var_4, var_2, var_1 ); + return; + } + + var_5 = maps\mp\gametypes\_weapons::isprimaryorsecondaryprojectileweapon( var_0 ); + + if ( var_2 != "timeInUse" && var_2 != "deaths" && !var_5 ) + { + var_6 = var_0; + var_0 = self getcurrentweapon(); + + if ( var_0 != var_6 && maps\mp\_utility::iskillstreakweapon( var_0 ) ) + return; + } + + if ( !isdefined( self.trackingweaponname ) ) + self.trackingweaponname = var_0; + + if ( var_0 != self.trackingweaponname ) + { + maps\mp\gametypes\_persistence::updateweaponbufferedstats(); + self.trackingweaponname = var_0; + self.currentfirefightshots = 0; + } + + switch ( var_2 ) + { + case "shots": + self.trackingweaponshots++; + self.currentfirefightshots++; + break; + case "hits": + self.trackingweaponhits++; + break; + case "headShots": + self.trackingweaponheadshots++; + self.trackingweaponhits++; + break; + case "kills": + self.trackingweaponkills++; + break; + case "hipfirekills": + self.trackingweaponhipfirekills++; + break; + case "timeInUse": + self.trackingweaponusetime += var_1; + break; + } + + if ( var_2 == "deaths" ) + { + var_7 = maps\mp\_utility::getbaseweaponname( var_0 ); + + if ( !maps\mp\_utility::iscacprimaryweapon( var_7 ) && !maps\mp\_utility::iscacsecondaryweapon( var_7 ) ) + return; + + var_8 = maps\mp\_utility::getweaponattachmentsbasenames( var_0 ); + maps\mp\gametypes\_persistence::incrementweaponstat( var_7, var_2, var_1 ); + maps\mp\_matchdata::logweaponstat( var_7, "deaths", var_1 ); + + foreach ( var_10 in var_8 ) + maps\mp\gametypes\_persistence::incrementattachmentstat( var_10, var_2, var_1 ); + } +} + +setinflictorstat( var_0, var_1, var_2 ) +{ + if ( !isdefined( var_1 ) ) + return; + + if ( !isdefined( var_0 ) ) + { + var_1 setweaponstat( var_2, 1, "hits" ); + return; + } + + if ( !isdefined( var_0.playeraffectedarray ) ) + var_0.playeraffectedarray = []; + + var_3 = 1; + + for ( var_4 = 0; var_4 < var_0.playeraffectedarray.size; var_4++ ) + { + if ( var_0.playeraffectedarray[var_4] == self ) + { + var_3 = 0; + break; + } + } + + if ( var_3 ) + { + var_0.playeraffectedarray[var_0.playeraffectedarray.size] = self; + var_1 setweaponstat( var_2, 1, "hits" ); + } +} + +threadedsetweaponstatbyname( var_0, var_1, var_2 ) +{ + self endon( "disconnect" ); + waittillframeend; + setweaponstat( var_0, var_1, var_2 ); +} + +checkforpersonalbests() +{ + foreach ( var_1 in level.players ) + { + if ( !isdefined( var_1 ) ) + continue; + + if ( var_1 maps\mp\_utility::rankingenabled() ) + { + var_2 = var_1 getcommonplayerdata( "round", "kills" ); + var_3 = var_1 getcommonplayerdata( "round", "deaths" ); + var_4 = var_1.pers["summary"]["xp"]; + var_5 = var_1.score; + var_6 = getroundaccuracy( var_1 ); + var_7 = var_1 getrankedplayerdata( "bestKills" ); + var_8 = var_1 getrankedplayerdata( "mostDeaths" ); + var_9 = var_1 getrankedplayerdata( "mostXp" ); + var_10 = var_1 getrankedplayerdata( "bestScore" ); + var_11 = var_1 getrankedplayerdata( "bestAccuracy" ); + + if ( var_2 > var_7 ) + var_1 setrankedplayerdata( "bestKills", var_2 ); + + if ( var_4 > var_9 ) + var_1 setrankedplayerdata( "mostXp", var_4 ); + + if ( var_3 > var_8 ) + var_1 setrankedplayerdata( "mostDeaths", var_3 ); + + if ( var_5 > var_10 ) + var_1 setrankedplayerdata( "bestScore", var_5 ); + + if ( var_6 > var_11 ) + var_1 setrankedplayerdata( "bestAccuracy", var_6 ); + + var_1 checkforbestweapon(); + var_1 maps\mp\_matchdata::logplayerxp( var_4, "totalXp" ); + var_1 maps\mp\_matchdata::logplayerxp( var_1.pers["summary"]["score"], "scoreXp" ); + var_1 maps\mp\_matchdata::logplayerxp( var_1.pers["summary"]["challenge"], "challengeXp" ); + var_1 maps\mp\_matchdata::logplayerxp( var_1.pers["summary"]["match"], "matchXp" ); + var_1 maps\mp\_matchdata::logplayerxp( var_1.pers["summary"]["misc"], "miscXp" ); + } + + if ( isdefined( var_1.pers["confirmed"] ) ) + var_1 maps\mp\_matchdata::logkillsconfirmed(); + + if ( isdefined( var_1.pers["denied"] ) ) + var_1 maps\mp\_matchdata::logkillsdenied(); + } +} + +getroundaccuracy( var_0 ) +{ + var_1 = float( var_0 getrankedplayerdata( "totalShots" ) - var_0.pers["previous_shots"] ); + + if ( var_1 == 0 ) + return 0; + + var_2 = float( var_0 getrankedplayerdata( "hits" ) - var_0.pers["previous_hits"] ); + var_3 = clamp( var_2 / var_1, 0.0, 1.0 ) * 10000.0; + return int( var_3 ); +} + +checkforbestweapon() +{ + var_0 = maps\mp\_matchdata::buildbaseweaponlist(); + + for ( var_1 = 0; var_1 < var_0.size; var_1++ ) + { + var_2 = var_0[var_1]; + var_2 = maps\mp\_utility::getbaseweaponname( var_2 ); + var_3 = maps\mp\_utility::getweaponclass( var_2 ); + + if ( !maps\mp\_utility::iskillstreakweapon( var_2 ) && var_3 != "killstreak" && var_3 != "other" ) + { + var_4 = self getrankedplayerdata( "bestWeapon", "kills" ); + var_5 = 0; + + if ( isdefined( self.pers["mpWeaponStats"][var_2] ) && isdefined( self.pers["mpWeaponStats"][var_2]["kills"] ) ) + { + var_5 = self.pers["mpWeaponStats"][var_2]["kills"]; + + if ( var_5 > var_4 ) + { + self setrankedplayerdata( "bestWeapon", "kills", var_5 ); + var_6 = 0; + + if ( isdefined( self.pers["mpWeaponStats"][var_2]["shots"] ) ) + var_6 = self.pers["mpWeaponStats"][var_2]["shots"]; + + var_7 = 0; + + if ( isdefined( self.pers["mpWeaponStats"][var_2]["headShots"] ) ) + var_7 = self.pers["mpWeaponStats"][var_2]["headShots"]; + + var_8 = 0; + + if ( isdefined( self.pers["mpWeaponStats"][var_2]["hits"] ) ) + var_8 = self.pers["mpWeaponStats"][var_2]["hits"]; + + var_9 = 0; + + if ( isdefined( self.pers["mpWeaponStats"][var_2]["deaths"] ) ) + var_9 = self.pers["mpWeaponStats"][var_2]["deaths"]; + + self setrankedplayerdata( "bestWeapon", "shots", var_6 ); + self setrankedplayerdata( "bestWeapon", "headShots", var_7 ); + self setrankedplayerdata( "bestWeapon", "hits", var_8 ); + self setrankedplayerdata( "bestWeapon", "deaths", var_9 ); + var_10 = int( tablelookup( "mp/statstable.csv", 4, var_2, 0 ) ); + self setrankedplayerdata( "bestWeaponIndex", var_10 ); + } + } + } + } +} + +updatecombatrecordforplayertrends() +{ + var_0 = 5; + var_1 = self getrankedplayerdata( "combatRecord", "numTrends" ); + var_1++; + + if ( var_1 > var_0 ) + { + var_1 = var_0; + + if ( var_0 > 1 ) + { + for ( var_2 = 0; var_2 < var_0 - 1; var_2++ ) + { + var_3 = self getrankedplayerdata( "combatRecord", "trend", var_2 + 1, "timestamp" ); + var_4 = self getrankedplayerdata( "combatRecord", "trend", var_2 + 1, "kills" ); + var_5 = self getrankedplayerdata( "combatRecord", "trend", var_2 + 1, "deaths" ); + self setrankedplayerdata( "combatRecord", "trend", var_2, "timestamp", var_3 ); + self setrankedplayerdata( "combatRecord", "trend", var_2, "kills", var_4 ); + self setrankedplayerdata( "combatRecord", "trend", var_2, "deaths", var_5 ); + } + } + } + + var_3 = maps\mp\_utility::gettimeutc_for_stat_recording(); + var_4 = self.kills; + var_5 = self.deaths; + self setrankedplayerdata( "combatRecord", "trend", var_1 - 1, "timestamp", var_3 ); + self setrankedplayerdata( "combatRecord", "trend", var_1 - 1, "kills", var_4 ); + self setrankedplayerdata( "combatRecord", "trend", var_1 - 1, "deaths", var_5 ); + self setrankedplayerdata( "combatRecord", "numTrends", var_1 ); +} + +updatecombatrecordcommondata() +{ + var_0 = maps\mp\_utility::gettimeutc_for_stat_recording(); + setcombatrecordstat( "timeStampLastGame", var_0 ); + incrementcombatrecordstat( "numMatches", 1 ); + incrementcombatrecordstat( "timePlayed", self.timeplayed["total"] ); + incrementcombatrecordstat( "kills", self.kills ); + incrementcombatrecordstat( "deaths", self.deaths ); + incrementcombatrecordstat( "xpEarned", self.pers["summary"]["xp"] ); + + if ( isdefined( self.combatrecordwin ) ) + incrementcombatrecordstat( "wins", 1 ); + + if ( isdefined( self.combatrecordtie ) ) + incrementcombatrecordstat( "ties", 1 ); + + var_1 = self getrankedplayerdata( "combatRecord", level.gametype, "timeStampFirstGame" ); + + if ( var_1 == 0 ) + setcombatrecordstat( "timeStampFirstGame", var_0 ); +} + +incrementcombatrecordstat( var_0, var_1 ) +{ + var_2 = self getrankedplayerdata( "combatRecord", level.gametype, var_0 ); + var_2 += var_1; + self setrankedplayerdata( "combatRecord", level.gametype, var_0, var_2 ); +} + +setcombatrecordstat( var_0, var_1 ) +{ + self setrankedplayerdata( "combatRecord", level.gametype, var_0, var_1 ); +} + +setcombatrecordstatifgreater( var_0, var_1 ) +{ + var_2 = self getrankedplayerdata( "combatRecord", level.gametype, var_0 ); + + if ( var_1 > var_2 ) + setcombatrecordstat( var_0, var_1 ); +} + +updatecombatrecordforplayergamemodes() +{ + if ( level.gametype == "war" || level.gametype == "dm" ) + { + updatecombatrecordcommondata(); + var_0 = self.deaths; + + if ( var_0 == 0 ) + var_0 = 1; + + var_1 = int( self.kills / var_0 ) * 1000; + setcombatrecordstatifgreater( "mostkills", self.kills ); + setcombatrecordstatifgreater( "bestkdr", var_1 ); + } + else if ( level.gametype == "ctf" ) + { + updatecombatrecordcommondata(); + var_2 = maps\mp\_utility::getpersstat( "captures" ); + var_3 = maps\mp\_utility::getpersstat( "returns" ); + incrementcombatrecordstat( "captures", var_2 ); + incrementcombatrecordstat( "returns", var_3 ); + setcombatrecordstatifgreater( "mostcaptures", var_2 ); + setcombatrecordstatifgreater( "mostreturns", var_3 ); + } + else if ( level.gametype == "dom" ) + { + updatecombatrecordcommondata(); + var_2 = maps\mp\_utility::getpersstat( "captures" ); + var_4 = maps\mp\_utility::getpersstat( "defends" ); + incrementcombatrecordstat( "captures", var_2 ); + incrementcombatrecordstat( "defends", var_4 ); + setcombatrecordstatifgreater( "mostcaptures", var_2 ); + setcombatrecordstatifgreater( "mostdefends", var_4 ); + } + else if ( level.gametype == "conf" ) + { + updatecombatrecordcommondata(); + var_5 = maps\mp\_utility::getpersstat( "confirmed" ); + var_6 = maps\mp\_utility::getpersstat( "denied" ); + incrementcombatrecordstat( "confirms", var_5 ); + incrementcombatrecordstat( "denies", var_6 ); + setcombatrecordstatifgreater( "mostconfirms", var_5 ); + setcombatrecordstatifgreater( "mostdenies", var_6 ); + } + else if ( level.gametype == "sd" ) + { + updatecombatrecordcommondata(); + var_7 = maps\mp\_utility::getpersstat( "plants" ); + var_8 = maps\mp\_utility::getpersstat( "defuses" ); + var_9 = maps\mp\_utility::getpersstat( "destructions" ); + incrementcombatrecordstat( "plants", var_7 ); + incrementcombatrecordstat( "defuses", var_8 ); + incrementcombatrecordstat( "detonates", var_9 ); + setcombatrecordstatifgreater( "mostplants", var_7 ); + setcombatrecordstatifgreater( "mostdefuses", var_8 ); + setcombatrecordstatifgreater( "mostdetonates", var_9 ); + } + else if ( level.gametype == "hp" ) + { + updatecombatrecordcommondata(); + var_2 = maps\mp\_utility::getpersstat( "captures" ); + var_4 = maps\mp\_utility::getpersstat( "defends" ); + incrementcombatrecordstat( "captures", var_2 ); + incrementcombatrecordstat( "defends", var_4 ); + setcombatrecordstatifgreater( "mostcaptures", var_2 ); + setcombatrecordstatifgreater( "mostdefends", var_4 ); + } + else if ( level.gametype == "sr" ) + { + updatecombatrecordcommondata(); + var_7 = maps\mp\_utility::getpersstat( "plants" ); + var_8 = maps\mp\_utility::getpersstat( "defuses" ); + var_9 = maps\mp\_utility::getpersstat( "destructions" ); + var_5 = maps\mp\_utility::getpersstat( "confirmed" ); + var_6 = maps\mp\_utility::getpersstat( "denied" ); + incrementcombatrecordstat( "plants", var_7 ); + incrementcombatrecordstat( "defuses", var_8 ); + incrementcombatrecordstat( "detonates", var_9 ); + incrementcombatrecordstat( "confirms", var_5 ); + incrementcombatrecordstat( "denies", var_6 ); + setcombatrecordstatifgreater( "mostplants", var_7 ); + setcombatrecordstatifgreater( "mostdefuses", var_8 ); + setcombatrecordstatifgreater( "mostdetonates", var_9 ); + setcombatrecordstatifgreater( "mostconfirms", var_5 ); + setcombatrecordstatifgreater( "mostdenies", var_6 ); + } + else if ( level.gametype == "infect" ) + { + updatecombatrecordcommondata(); + var_10 = maps\mp\_utility::getplayerstat( "contagious" ); + var_11 = self.kills - var_10; + incrementcombatrecordstat( "infectedKills", var_11 ); + incrementcombatrecordstat( "survivorKills", var_10 ); + setcombatrecordstatifgreater( "mostInfectedKills", var_11 ); + setcombatrecordstatifgreater( "mostSurvivorKills", var_10 ); + } + else if ( level.gametype == "gun" ) + { + updatecombatrecordcommondata(); + var_12 = maps\mp\_utility::getplayerstat( "levelup" ); + var_13 = maps\mp\_utility::getplayerstat( "humiliation" ); + incrementcombatrecordstat( "gunPromotions", var_12 ); + incrementcombatrecordstat( "stabs", var_13 ); + setcombatrecordstatifgreater( "mostGunPromotions", var_12 ); + setcombatrecordstatifgreater( "mostStabs", var_13 ); + } + else if ( level.gametype == "ball" ) + { + updatecombatrecordcommondata(); + var_14 = maps\mp\_utility::getplayerstat( "fieldgoal" ) + maps\mp\_utility::getplayerstat( "touchdown" ) * 2; + var_15 = maps\mp\_utility::getplayerstat( "killedBallCarrier" ); + incrementcombatrecordstat( "pointsScored", var_14 ); + incrementcombatrecordstat( "killedBallCarrier", var_15 ); + setcombatrecordstatifgreater( "mostPointsScored", var_14 ); + setcombatrecordstatifgreater( "mostKilledBallCarrier", var_15 ); + } + else if ( level.gametype == "twar" ) + { + updatecombatrecordcommondata(); + var_2 = maps\mp\_utility::getpersstat( "captures" ); + var_16 = maps\mp\_utility::getplayerstat( "kill_while_capture" ); + incrementcombatrecordstat( "captures", var_2 ); + incrementcombatrecordstat( "killWhileCaptures", var_16 ); + setcombatrecordstatifgreater( "mostCaptures", var_2 ); + setcombatrecordstatifgreater( "mostKillWhileCaptures", var_16 ); + } +} + +updatecombatrecordforplayer() +{ + updatecombatrecordforplayertrends(); + updatecombatrecordforplayergamemodes(); +} + +updatecombatrecord() +{ + foreach ( var_1 in level.players ) + { + if ( !isdefined( var_1 ) ) + continue; + + if ( var_1 maps\mp\_utility::rankingenabled() ) + var_1 updatecombatrecordforplayer(); + + level maps\mp\gametypes\_playerlogic::writesegmentdata( var_1 ); + + if ( maps\mp\_utility::practiceroundgame() ) + level maps\mp\gametypes\_playerlogic::checkpracticeroundlockout( var_1 ); + } +} diff --git a/data/maps/mp/gametypes/_playerlogic.gsc b/data/maps/mp/gametypes/_playerlogic.gsc new file mode 100644 index 0000000..bf1c9e7 --- /dev/null +++ b/data/maps/mp/gametypes/_playerlogic.gsc @@ -0,0 +1,2226 @@ +// S1 GSC SOURCE +// Dumped by https://github.com/xensik/gsc-tool + +timeuntilwavespawn( var_0 ) +{ + if ( !self.hasspawned ) + return 0; + + var_1 = gettime() + var_0 * 1000; + var_2 = level.lastwave[self.pers["team"]]; + var_3 = level.wavedelay[self.pers["team"]] * 1000; + var_4 = ( var_1 - var_2 ) / var_3; + var_5 = ceil( var_4 ); + var_6 = var_2 + var_5 * var_3; + + if ( isdefined( self.respawntimerstarttime ) ) + { + var_7 = ( gettime() - self.respawntimerstarttime ) / 1000.0; + + if ( self.respawntimerstarttime < var_2 ) + return 0; + } + + if ( isdefined( self.wavespawnindex ) ) + var_6 += 50 * self.wavespawnindex; + + return ( var_6 - gettime() ) / 1000; +} + +teamkilldelay() +{ + var_0 = self.pers["teamkills"]; + + if ( var_0 <= level.maxallowedteamkills ) + return 0; + + var_1 = var_0 - level.maxallowedteamkills; + return maps\mp\gametypes\_tweakables::gettweakablevalue( "team", "teamkillspawndelay" ) * var_1; +} + +timeuntilspawn( var_0 ) +{ + if ( level.ingraceperiod && !self.hasspawned || level.gameended ) + return 0; + + var_1 = 0; + + if ( self.hasspawned ) + { + var_2 = self [[ level.onrespawndelay ]](); + + if ( isdefined( var_2 ) ) + var_1 = var_2; + else + var_1 = getdvarint( "scr_" + level.gametype + "_playerrespawndelay" ); + + if ( var_0 ) + { + if ( isdefined( self.pers["teamKillPunish"] ) && self.pers["teamKillPunish"] ) + var_1 += teamkilldelay(); + + if ( isdefined( self.pers["suicideSpawnDelay"] ) ) + var_1 += self.pers["suicideSpawnDelay"]; + } + + if ( isdefined( self.respawntimerstarttime ) ) + { + var_3 = ( gettime() - self.respawntimerstarttime ) / 1000.0; + var_1 -= var_3; + + if ( var_1 < 0 ) + var_1 = 0; + } + + if ( isdefined( self.setspawnpoint ) ) + var_1 += level.tispawndelay; + } + + var_4 = getdvarfloat( "scr_" + level.gametype + "_waverespawndelay" ) > 0; + + if ( var_4 ) + return timeuntilwavespawn( var_1 ); + + return var_1; +} + +mayspawn() +{ + if ( maps\mp\_utility::getgametypenumlives() || isdefined( level.disablespawning ) ) + { + if ( isdefined( level.disablespawning ) && level.disablespawning ) + return 0; + + if ( isdefined( self.pers["teamKillPunish"] ) && self.pers["teamKillPunish"] ) + return 0; + + if ( !self.pers["lives"] && maps\mp\_utility::gamehasstarted() ) + return 0; + else if ( maps\mp\_utility::gamehasstarted() ) + { + if ( !level.ingraceperiod && !self.hasspawned && ( isdefined( level.allowlatecomers ) && !level.allowlatecomers ) ) + return 0; + } + + if ( isdefined( level.disablespawningforplayerfunc ) && [[ level.disablespawningforplayerfunc ]]( self ) ) + return 0; + } + + return 1; +} + +spawnclient() +{ + self endon( "becameSpectator" ); + + if ( isdefined( self.clientid ) ) + { + + } + else + { + + } + + if ( isdefined( self.waitingtoselectclass ) && self.waitingtoselectclass ) + self waittill( "notWaitingToSelectClass" ); + + if ( isdefined( self.addtoteam ) ) + { + maps\mp\gametypes\_menus::addtoteam( self.addtoteam ); + self.addtoteam = undefined; + } + + if ( !mayspawn() ) + { + wait 0.05; + self notify( "attempted_spawn" ); + var_0 = self.pers["teamKillPunish"]; + + if ( isdefined( var_0 ) && var_0 ) + { + self.pers["teamkills"] = max( self.pers["teamkills"] - 1, 0 ); + maps\mp\_utility::setlowermessage( "friendly_fire", &"MP_FRIENDLY_FIRE_WILL_NOT" ); + + if ( !self.hasspawned && teamkilldelay() <= 0 ) + self.pers["teamKillPunish"] = 0; + } + else if ( maps\mp\_utility::isroundbased() && !maps\mp\_utility::islastround() ) + { + if ( isdefined( self.tagavailable ) && self.tagavailable ) + maps\mp\_utility::setlowermessage( "spawn_info", game["strings"]["spawn_tag_wait"] ); + else + maps\mp\_utility::setlowermessage( "spawn_info", game["strings"]["spawn_next_round"] ); + + thread removespawnmessageshortly( 3.0 ); + } + + thread spawnspectator(); + return; + } + + if ( self.waitingtospawn ) + return; + + self.waitingtospawn = 1; + waitandspawnclient(); + + if ( isdefined( self ) ) + self.waitingtospawn = 0; +} + +streamprimaryweapons() +{ + if ( maps\mp\_utility::allowclasschoice() && !isai( self ) ) + { + var_0 = []; + var_1 = [ "custom1", "custom2", "custom3", "custom4", "custom5", "class0", "class1", "class2", "class3", "class4" ]; + + foreach ( var_3 in var_1 ) + { + var_4 = maps\mp\gametypes\_class::getloadout( self.team, var_3 ); + var_0[var_0.size] = var_4.primaryname; + } + + self loadweapons( var_0 ); + } +} + +gatherclassweapons( var_0, var_1 ) +{ + var_2 = []; + var_3 = var_1; + + if ( !maps\mp\_utility::isvalidclass( var_3 ) ) + var_3 = self.class; + + if ( maps\mp\_utility::isvalidclass( var_3 ) ) + { + var_4 = maps\mp\gametypes\_class::getloadout( self.team, var_3 ); + var_2[var_2.size] = var_4.primaryname; + + if ( !isdefined( var_0 ) || !var_0 ) + var_2[var_2.size] = var_4.secondaryname; + } + + return var_2; +} + +streamclassweapons( var_0, var_1, var_2 ) +{ + self.classweaponswait = 0; + self notify( "endStreamClassWeapons" ); + self endon( "endStreamClassWeapons" ); + self endon( "death" ); + self endon( "disconnect" ); + + if ( isai( self ) || !isdefined( var_0 ) ) + var_0 = 0; + + var_3 = gatherclassweapons( var_1, var_2 ); + + if ( var_3.size > 0 ) + { + while ( isdefined( self.loadingplayerweapons ) && self.loadingplayerweapons ) + wait 0.05; + + var_0 = !self loadweapons( var_3 ) && var_0; + self onlystreamactiveweapon( 1 ); + + for ( self.classweaponswait = var_0; var_0; var_0 = !self loadweapons( var_3 ) ) + waitframe(); + + self onlystreamactiveweapon( 0 ); + } + + self.classweaponswait = 0; + self notify( "streamClassWeaponsComplete" ); +} + +waitandspawnclient() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + level endon( "game_ended" ); + self notify( "attempted_spawn" ); + + if ( isdefined( self.clientid ) ) + { + + } + else + { + + } + + var_0 = 0; + var_1 = getentarray( "mp_global_intermission", "classname" ); + var_2 = var_1[randomint( var_1.size )]; + var_3 = self.pers["teamKillPunish"]; + + if ( isdefined( var_3 ) && var_3 ) + { + var_4 = teamkilldelay(); + + if ( var_4 > 0 ) + { + maps\mp\_utility::setlowermessage( "friendly_fire", &"MP_FRIENDLY_FIRE_WILL_NOT", var_4, 1, 1 ); + thread respawn_asspectator( var_2.origin, var_2.angles ); + var_0 = 1; + wait(var_4); + maps\mp\_utility::clearlowermessage( "friendly_fire" ); + self.respawntimerstarttime = gettime(); + } + + self.pers["teamKillPunish"] = 0; + } + else if ( teamkilldelay() ) + self.pers["teamkills"] = max( self.pers["teamkills"] - 1, 0 ); + + var_5 = self.pers["suicideSpawnDelay"]; + + if ( isdefined( var_5 ) && var_5 > 0 ) + { + maps\mp\_utility::setlowermessage( "suicidePenalty", &"MP_SUICIDE_PUNISHED", var_5, 1, 1 ); + + if ( !var_0 ) + thread respawn_asspectator( var_2.origin, var_2.angles ); + + var_0 = 1; + wait(var_5); + maps\mp\_utility::clearlowermessage( "suicidePenalty" ); + self.respawntimerstarttime = gettime(); + self.pers["suicideSpawnDelay"] = 0; + } + + if ( maps\mp\_utility::isusingremote() ) + { + self.spawningafterremotedeath = 1; + self.deathposition = self.origin; + self waittill( "stopped_using_remote" ); + } + + if ( !isdefined( self.wavespawnindex ) && isdefined( level.waveplayerspawnindex[self.team] ) ) + { + self.wavespawnindex = level.waveplayerspawnindex[self.team]; + level.waveplayerspawnindex[self.team]++; + } + + var_6 = timeuntilspawn( 0 ); + + if ( var_6 > 0 ) + { + self setclientomnvar( "ui_killcam_time_until_spawn", gettime() + var_6 * 1000 ); + + if ( !var_0 ) + thread respawn_asspectator( var_2.origin, var_2.angles ); + + var_0 = 1; + maps\mp\_utility::waitfortimeornotify( var_6, "force_spawn" ); + self notify( "stop_wait_safe_spawn_button" ); + } + + if ( needsbuttontorespawn() ) + { + maps\mp\_utility::setlowermessage( "spawn_info", game["strings"]["press_to_spawn"], undefined, undefined, undefined, undefined, undefined, undefined, 1 ); + + if ( !var_0 ) + thread respawn_asspectator( var_2.origin, var_2.angles ); + + var_0 = 1; + waitrespawnbutton(); + } + + self.waitingtospawn = 0; + maps\mp\_utility::clearlowermessage( "spawn_info" ); + self.wavespawnindex = undefined; + thread spawnplayer(); +} + +needsbuttontorespawn() +{ + if ( maps\mp\gametypes\_tweakables::gettweakablevalue( "player", "forcerespawn" ) != 0 ) + return 0; + + if ( !self.hasspawned ) + return 0; + + var_0 = getdvarfloat( "scr_" + level.gametype + "_waverespawndelay" ) > 0; + + if ( var_0 ) + return 0; + + if ( self.wantsafespawn ) + return 0; + + return 1; +} + +waitrespawnbutton() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + + for (;;) + { + if ( self usebuttonpressed() ) + break; + + wait 0.05; + } +} + +removespawnmessageshortly( var_0 ) +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + waittillframeend; + self endon( "end_respawn" ); + wait(var_0); + maps\mp\_utility::clearlowermessage( "spawn_info" ); +} + +laststandrespawnplayer() +{ + self laststandrevive(); + + if ( maps\mp\_utility::_hasperk( "specialty_finalstand" ) && !level.diehardmode ) + maps\mp\_utility::_unsetperk( "specialty_finalstand" ); + + if ( level.diehardmode ) + self.headicon = ""; + + self setstance( "crouch" ); + self.revived = 1; + self notify( "revive" ); + + if ( isdefined( self.standardmaxhealth ) ) + self.maxhealth = self.standardmaxhealth; + + self.health = self.maxhealth; + common_scripts\utility::_enableusability(); + + if ( game["state"] == "postgame" ) + maps\mp\gametypes\_gamelogic::freezeplayerforroundend(); +} + +getdeathspawnpoint() +{ + var_0 = spawn( "script_origin", self.origin ); + var_0 hide(); + var_0.angles = self.angles; + return var_0; +} + +showspawnnotifies() +{ + +} + +getspawnorigin( var_0 ) +{ + if ( !positionwouldtelefrag( var_0.origin ) ) + return var_0.origin; + + if ( !isdefined( var_0.alternates ) ) + return var_0.origin; + + foreach ( var_2 in var_0.alternates ) + { + if ( !positionwouldtelefrag( var_2 ) ) + return var_2; + } + + return var_0.origin; +} + +tivalidationcheck() +{ + if ( !isdefined( self.setspawnpoint ) ) + return 0; + + var_0 = getentarray( "care_package", "targetname" ); + + foreach ( var_2 in var_0 ) + { + if ( distancesquared( var_2.origin, self.setspawnpoint.playerspawnpos ) > 4096 ) + continue; + + maps\mp\perks\_perkfunctions::deleteti( self.setspawnpoint ); + return 0; + } + + return 1; +} + +spawningclientthisframereset() +{ + self notify( "spawningClientThisFrameReset" ); + self endon( "spawningClientThisFrameReset" ); + wait 0.05; + level.numplayerswaitingtospawn--; +} + +setuioptionsmenu( var_0 ) +{ + self endon( "disconnect" ); + self endon( "joined_spectators" ); + + while ( self ismlgspectator() && !maps\mp\_utility::invirtuallobby() ) + waitframe(); + + self setclientomnvar( "ui_options_menu", var_0 ); +} + +gather_spawn_weapons() +{ + var_0 = []; + + if ( isdefined( self.loadout ) ) + { + var_0[var_0.size] = maps\mp\_utility::get_spawn_weapon_name( self.loadout ); + + if ( isdefined( self.loadout.secondaryname ) && self.loadout.secondaryname != "none" ) + var_0[var_0.size] = self.loadout.secondaryname; + } + else + { + if ( isdefined( self.primaryweapon ) && self.primaryweapon != "none" ) + var_0[var_0.size] = self.primaryweapon; + + if ( isdefined( self.secondaryweapon ) && self.secondaryweapon != "none" ) + var_0[var_0.size] = self.secondaryweapon; + } + + return var_0; +} + +spawnplayer( var_0, var_1 ) +{ + self endon( "disconnect" ); + self endon( "joined_spectators" ); + self notify( "spawned" ); + self notify( "end_respawn" ); + self notify( "started_spawnPlayer" ); + + if ( isdefined( self.clientid ) ) + { + + } + else + { + + } + + if ( !isdefined( var_0 ) ) + var_0 = 0; + + if ( !isdefined( var_1 ) ) + var_1 = 1; + + if ( var_1 ) + { + self.spawnplayergivingloadout = 1; + thread monitordelayedspawnloadouts(); + } + + self.lifeid = maps\mp\_utility::getnextlifeid(); + self.totallifetime = 0; + var_2 = undefined; + self.ti_spawn = 0; + thread setuioptionsmenu( 0 ); + self setclientomnvar( "ui_hud_shake", 0 ); + self setclientomnvar( "ui_exo_cooldown_in_use", 0 ); + self setdemigod( 0 ); + self disableforcefirstpersonwhenfollowed(); + + if ( !level.ingraceperiod && !self.hasdonecombat ) + { + level.numplayerswaitingtospawn++; + + if ( level.numplayerswaitingtospawn > 1 ) + { + self.waitingtospawnamortize = 1; + wait(0.05 * ( level.numplayerswaitingtospawn - 1 )); + } + + thread spawningclientthisframereset(); + self.waitingtospawnamortize = 0; + } + + if ( var_1 ) + { + var_3 = undefined; + + if ( isdefined( level.iszombiegame ) && level.iszombiegame ) + var_3 = 0; + + maps\mp\gametypes\_class::giveloadout( self.team, self.class, undefined, var_3 ); + var_4 = gather_spawn_weapons(); + self.loadingplayerweapons = 1; + + if ( !self hasloadedcustomizationplayerview( self, var_4 ) ) + { + self.waitingtospawnamortize = 1; + self onlystreamactiveweapon( 1 ); + + for (;;) + { + waitframe(); + var_4 = gather_spawn_weapons(); + + if ( self hasloadedcustomizationplayerview( self, var_4 ) ) + break; + } + + self onlystreamactiveweapon( 0 ); + self.waitingtospawnamortize = 0; + } + + self.loadingplayerweapons = 0; + } + + if ( isdefined( self.forcespawnorigin ) ) + { + var_5 = self.forcespawnorigin; + self.forcespawnorigin = undefined; + + if ( isdefined( self.forcespawnangles ) ) + { + var_6 = self.forcespawnangles; + self.forcespawnangles = undefined; + } + else + var_6 = ( 0, randomfloatrange( 0, 360 ), 0 ); + } + else if ( isdefined( self.setspawnpoint ) && ( isdefined( self.setspawnpoint.notti ) || tivalidationcheck() ) ) + { + var_2 = self.setspawnpoint; + + if ( !isdefined( self.setspawnpoint.notti ) ) + { + self.ti_spawn = 1; + self playlocalsound( "tactical_spawn" ); + + if ( level.multiteambased ) + { + foreach ( var_8 in level.teamnamelist ) + { + if ( var_8 != self.team ) + self playsoundtoteam( "tactical_spawn", var_8 ); + } + } + else if ( level.teambased ) + self playsoundtoteam( "tactical_spawn", level.otherteam[self.team] ); + else + self playsound( "tactical_spawn" ); + } + + foreach ( var_11 in level.ugvs ) + { + if ( distancesquared( var_11.origin, var_2.playerspawnpos ) < 1024 ) + var_11 notify( "damage", 5000, var_11.owner, ( 0, 0, 0 ), ( 0, 0, 0 ), "MOD_EXPLOSIVE", "", "", "", undefined, "killstreak_emp_mp" ); + } + + var_5 = self.setspawnpoint.playerspawnpos; + var_6 = self.setspawnpoint.angles; + + if ( isdefined( self.setspawnpoint.enemytrigger ) ) + self.setspawnpoint.enemytrigger delete(); + + self.setspawnpoint delete(); + var_2 = undefined; + } + else if ( isdefined( self.isspawningonbattlebuddy ) && isdefined( self.battlebuddy ) ) + { + var_5 = undefined; + var_6 = undefined; + var_13 = maps\mp\gametypes\_battlebuddy::checkbuddyspawn(); + + if ( var_13.status == 0 ) + { + var_5 = var_13.origin; + var_6 = var_13.angles; + } + else + { + var_2 = self [[ level.getspawnpoint ]](); + var_5 = var_2.origin; + var_6 = var_2.angles; + } + + maps\mp\gametypes\_battlebuddy::cleanupbuddyspawn(); + self setclientomnvar( "cam_scene_name", "battle_spawn" ); + self setclientomnvar( "cam_scene_lead", self.battlebuddy getentitynumber() ); + self setclientomnvar( "cam_scene_support", self getentitynumber() ); + } + else if ( isdefined( self.helispawning ) && ( !isdefined( self.firstspawn ) || isdefined( self.firstspawn ) && self.firstspawn ) && level.prematchperiod > 0 && self.team == "allies" ) + { + while ( !isdefined( level.allieschopper ) ) + wait 0.1; + + var_5 = level.allieschopper.origin; + var_6 = level.allieschopper.angles; + self.firstspawn = 0; + } + else if ( isdefined( self.helispawning ) && ( !isdefined( self.firstspawn ) || isdefined( self.firstspawn ) && self.firstspawn ) && level.prematchperiod > 0 && self.team == "axis" ) + { + while ( !isdefined( level.axischopper ) ) + wait 0.1; + + var_5 = level.axischopper.origin; + var_6 = level.axischopper.angles; + self.firstspawn = 0; + } + else + { + var_2 = self [[ level.getspawnpoint ]](); + var_5 = var_2.origin; + var_6 = var_2.angles; + } + + setspawnvariables(); + var_14 = self.hasspawned; + self.fauxdead = undefined; + + if ( !var_0 ) + { + self.killsthislife = []; + maps\mp\_utility::updatesessionstate( "playing" ); + maps\mp\_utility::clearkillcamstate(); + self.cancelkillcam = undefined; + self.maxhealth = maps\mp\gametypes\_tweakables::gettweakablevalue( "player", "maxhealth" ); + self.health = self.maxhealth; + self.friendlydamage = undefined; + self.hasspawned = 1; + self.spawntime = gettime(); + self.spawntimedecisecondsfrommatchstart = maps\mp\_utility::gettimepasseddecisecondsincludingrounds(); + self.wasti = !isdefined( var_2 ); + self.afk = 0; + self.damagedplayers = []; + self.killstreakscaler = 1; + self.objectivescaler = 1; + self.clampedhealth = undefined; + self.shielddamage = 0; + self.shieldbullethits = 0; + self.exocount = []; + self.exocount["exo_boost"] = 0; + self.exocount["ground_slam"] = 0; + self.exocount["exo_dodge"] = 0; + self.exocount["exo_slide"] = 0; + self.exomostrecenttimedeciseconds = []; + thread listenforexomoveevent(); + self.exo_shield_on = 0; + self.exo_hover_on = 0; + self.enemyhitcounts = []; + self.currentfirefightshots = 0; + + if ( !isai( self ) ) + thread maps\mp\gametypes\_damage::clearfirefightshotsoninterval(); + + self.scoreatlifestart = self.pers["score"]; + + if ( isdefined( self.pers["summary"] ) && isdefined( self.pers["summary"]["xp"] ) ) + self.xpatlifestart = self.pers["summary"]["xp"]; + } + + self.movespeedscaler = level.baseplayermovescale; + self.inlaststand = 0; + self.laststand = undefined; + self.infinalstand = undefined; + self.disabledweapon = 0; + self.disabledweaponswitch = 0; + self.disabledoffhandweapons = 0; + common_scripts\utility::resetusability(); + self.playerdisableabilitytypes = []; + + if ( !var_0 ) + { + self.avoidkillstreakonspawntimer = 5.0; + var_15 = self.pers["lives"]; + + if ( var_15 == maps\mp\_utility::getgametypenumlives() ) + addtolivescount(); + + if ( var_15 ) + self.pers["lives"]--; + + addtoalivecount(); + + if ( !var_14 || maps\mp\_utility::gamehasstarted() || maps\mp\_utility::gamehasstarted() && level.ingraceperiod && self.hasdonecombat ) + removefromlivescount(); + + if ( !self.wasaliveatmatchstart ) + { + var_16 = 20; + + if ( maps\mp\_utility::gettimelimit() > 0 && var_16 < maps\mp\_utility::gettimelimit() * 60 / 4 ) + var_16 = maps\mp\_utility::gettimelimit() * 60 / 4; + + if ( level.ingraceperiod || maps\mp\_utility::gettimepassed() < var_16 * 1000 ) + self.wasaliveatmatchstart = 1; + } + } + + if ( level.console ) + self setclientdvar( "cg_fov", "65" ); + + resetuidvarsonspawn(); + + if ( isdefined( var_2 ) ) + { + maps\mp\gametypes\_spawnlogic::finalizespawnpointchoice( var_2 ); + var_5 = getspawnorigin( var_2 ); + var_6 = var_2.angles; + } + else + self.lastspawntime = gettime(); + + self.spawnpos = var_5; + self spawn( var_5, var_6 ); + maps\mp\_utility::setdof( level.dofdefault ); + + if ( var_0 && isdefined( self.faux_spawn_stance ) ) + { + self setstance( self.faux_spawn_stance ); + self.faux_spawn_stance = undefined; + } + + [[ level.onspawnplayer ]](); + + if ( !var_0 ) + { + maps\mp\gametypes\_missions::playerspawned(); + + if ( isai( self ) && isdefined( level.bot_funcs ) && isdefined( level.bot_funcs["player_spawned"] ) ) + self [[ level.bot_funcs["player_spawned"] ]](); + } + + maps\mp\gametypes\_class::setclass( self.class ); + + if ( isdefined( level.custom_giveloadout ) ) + self [[ level.custom_giveloadout ]]( var_0 ); + else if ( var_1 ) + { + maps\mp\gametypes\_class::applyloadout(); + self notify( "spawnplayer_giveloadout" ); + } + + if ( getdvarint( "camera_thirdPerson" ) ) + maps\mp\_utility::setthirdpersondof( 1 ); + + if ( !maps\mp\_utility::gameflag( "prematch_done" ) ) + { + maps\mp\_utility::freezecontrolswrapper( 1 ); + self disableammogeneration(); + } + else + { + maps\mp\_utility::freezecontrolswrapper( 0 ); + self enableammogeneration(); + } + + if ( !maps\mp\_utility::gameflag( "prematch_done" ) || !var_14 && game["state"] == "playing" ) + { + var_17 = self.pers["team"]; + + if ( maps\mp\_utility::inovertime() ) + thread maps\mp\gametypes\_hud_message::oldnotifymessage( game["strings"]["overtime"], game["strings"]["overtime_hint"], undefined, ( 1, 0, 0 ), "mp_last_stand" ); + + thread showspawnnotifies(); + } + + if ( maps\mp\_utility::getintproperty( "scr_showperksonspawn", 1 ) == 1 && game["state"] != "postgame" ) + { + + } + + waittillframeend; + self.spawningafterremotedeath = undefined; + self notify( "spawned_player" ); + level notify( "player_spawned", self ); + + if ( game["state"] == "postgame" ) + maps\mp\gametypes\_gamelogic::freezeplayerforroundend(); + + if ( isdefined( level.matchrules_switchteamdisabled ) && level.matchrules_switchteamdisabled ) + self setclientomnvar( "ui_disable_team_change", 1 ); +} + +monitordelayedspawnloadouts() +{ + common_scripts\utility::waittill_any( "disconnected", "joined_spectators", "spawnplayer_giveloadout" ); + self.spawnplayergivingloadout = undefined; +} + +listenforexomoveevent() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for (;;) + { + var_0 = common_scripts\utility::waittill_any_return( "exo_boost", "ground_slam", "exo_dodge", "exo_slide" ); + self.exocount[var_0]++; + self.exomostrecenttimedeciseconds[var_0] = maps\mp\_utility::gettimepasseddecisecondsincludingrounds(); + } +} + +spawnspectator( var_0, var_1 ) +{ + self notify( "spawned" ); + self notify( "end_respawn" ); + self notify( "joined_spectators" ); + in_spawnspectator( var_0, var_1 ); +} + +respawn_asspectator( var_0, var_1 ) +{ + in_spawnspectator( var_0, var_1 ); +} + +in_spawnspectator( var_0, var_1 ) +{ + setspawnvariables(); + var_2 = self.pers["team"]; + + if ( isdefined( var_2 ) && var_2 == "spectator" && !level.gameended ) + maps\mp\_utility::clearlowermessage( "spawn_info" ); + + maps\mp\_utility::updatesessionstate( "spectator" ); + maps\mp\_utility::clearkillcamstate(); + self.friendlydamage = undefined; + self.loadingplayerweapons = undefined; + resetuidvarsonspectate(); + maps\mp\gametypes\_spectating::setspectatepermissions(); + onspawnspectator( var_0, var_1 ); + + if ( level.teambased && !level.splitscreen && !self issplitscreenplayer() ) + self setdepthoffield( 0, 128, 512, 4000, 6, 1.8 ); +} + +getplayerfromclientnum( var_0 ) +{ + if ( var_0 < 0 ) + return undefined; + + for ( var_1 = 0; var_1 < level.players.size; var_1++ ) + { + if ( level.players[var_1] getentitynumber() == var_0 ) + return level.players[var_1]; + } + + return undefined; +} + +getrandomspectatorspawnpoint() +{ + var_0 = "mp_global_intermission"; + var_1 = getentarray( var_0, "classname" ); + var_2 = maps\mp\gametypes\_spawnlogic::getspawnpoint_random( var_1 ); + return var_2; +} + +onspawnspectator( var_0, var_1 ) +{ + if ( isdefined( var_0 ) && isdefined( var_1 ) ) + { + self setspectatedefaults( var_0, var_1 ); + self spawn( var_0, var_1 ); + return; + } + + var_2 = getrandomspectatorspawnpoint(); + self setspectatedefaults( var_2.origin, var_2.angles ); + self spawn( var_2.origin, var_2.angles ); +} + +spawnintermission() +{ + self endon( "disconnect" ); + self notify( "spawned" ); + self notify( "end_respawn" ); + setspawnvariables(); + maps\mp\_utility::clearlowermessages(); + maps\mp\_utility::freezecontrolswrapper( 1 ); + self disableammogeneration(); + self setclientdvar( "cg_everyoneHearsEveryone", 1 ); + var_0 = self.pers["postGameChallenges"]; + + if ( level.rankedmatch && ( self.postgamepromotion || isdefined( var_0 ) && var_0 ) ) + { + if ( self.postgamepromotion ) + self playlocalsound( "mp_level_up" ); + else if ( isdefined( var_0 ) ) + self playlocalsound( "mp_challenge_complete" ); + + if ( self.postgamepromotion > level.postgamenotifies ) + level.postgamenotifies = 1; + + if ( isdefined( var_0 ) && var_0 > level.postgamenotifies ) + level.postgamenotifies = var_0; + + var_1 = 7.0; + + if ( isdefined( var_0 ) ) + var_1 = 4.0 + min( var_0, 3 ); + + while ( var_1 ) + { + wait 0.25; + var_1 -= 0.25; + } + } + + maps\mp\_utility::updatesessionstate( "intermission" ); + maps\mp\_utility::clearkillcamstate(); + self.friendlydamage = undefined; + var_2 = getentarray( "mp_global_intermission", "classname" ); + var_3 = var_2[0]; + self spawn( var_3.origin, var_3.angles ); + self setdepthoffield( 0, 128, 512, 4000, 6, 1.8 ); +} + +spawnendofgame() +{ + if ( 1 ) + { + maps\mp\_utility::freezecontrolswrapper( 1 ); + self disableammogeneration(); + spawnspectator(); + maps\mp\_utility::freezecontrolswrapper( 1 ); + self disableammogeneration(); + return; + } + + self notify( "spawned" ); + self notify( "end_respawn" ); + setspawnvariables(); + maps\mp\_utility::clearlowermessages(); + self setclientdvar( "cg_everyoneHearsEveryone", 1 ); + maps\mp\_utility::updatesessionstate( "dead" ); + maps\mp\_utility::clearkillcamstate(); + self.friendlydamage = undefined; + var_0 = getentarray( "mp_global_intermission", "classname" ); + var_1 = maps\mp\gametypes\_spawnlogic::getspawnpoint_random( var_0 ); + self spawn( var_1.origin, var_1.angles ); + var_1 setmodel( "tag_origin" ); + self playerlinkto( var_1 ); + self playerhide(); + maps\mp\_utility::freezecontrolswrapper( 1 ); + self disableammogeneration(); + self setdepthoffield( 0, 128, 512, 4000, 6, 1.8 ); +} + +setspawnvariables() +{ + self stopshellshock(); + self stoprumble( "damage_heavy" ); + self.deathposition = undefined; +} + +notifyconnecting() +{ + waittillframeend; + + if ( isdefined( self ) ) + level notify( "connecting", self ); +} + +logexostats() +{ + if ( isdefined( self.pers["numberOfTimesCloakingUsed"] ) ) + setmatchdata( "players", self.clientid, "numberOfTimesCloakingUsed", maps\mp\_utility::clamptobyte( self.pers["numberOfTimesCloakingUsed"] ) ); + + if ( isdefined( self.pers["numberOfTimesHoveringUsed"] ) ) + setmatchdata( "players", self.clientid, "numberOfTimesHoveringUsed", maps\mp\_utility::clamptobyte( self.pers["numberOfTimesHoveringUsed"] ) ); + + if ( isdefined( self.pers["numberOfTimesShieldUsed"] ) ) + setmatchdata( "players", self.clientid, "numberOfTimesShieldUsed", maps\mp\_utility::clamptobyte( self.pers["numberOfTimesShieldUsed"] ) ); + + if ( isdefined( self.pers["bulletsBlockedByShield"] ) ) + setmatchdata( "players", self.clientid, "bulletsBlockedByShield", self.pers["bulletsBlockedByShield"] ); +} + +logplayerstats() +{ + logexostats(); + + if ( isdefined( self.pers["totalKillcamsSkipped"] ) ) + setmatchdata( "players", self.clientid, "totalKillcamsSkipped", maps\mp\_utility::clamptobyte( self.pers["totalKillcamsSkipped"] ) ); + + if ( isdefined( self.pers["weaponPickupsCount"] ) ) + setmatchdata( "players", self.clientid, "weaponPickupsCount", maps\mp\_utility::clamptobyte( self.pers["weaponPickupsCount"] ) ); + + if ( isdefined( self.pers["suicides"] ) ) + setmatchdata( "players", self.clientid, "suicidesTotal", maps\mp\_utility::clamptobyte( self.pers["suicides"] ) ); + + if ( isdefined( self.pers["headshots"] ) ) + setmatchdata( "players", self.clientid, "headshotsTotal", maps\mp\_utility::clamptoshort( self.pers["headshots"] ) ); + + if ( isdefined( self.pers["pingAccumulation"] ) && isdefined( self.pers["pingSampleCount"] ) ) + { + if ( self.pers["pingSampleCount"] > 0 ) + { + var_0 = maps\mp\_utility::clamptobyte( self.pers["pingAccumulation"] / self.pers["pingSampleCount"] ); + setmatchdata( "players", self.clientid, "averagePing", var_0 ); + } + } + + if ( maps\mp\_utility::rankingenabled() ) + { + var_1 = 3; + var_2 = 0; + + for ( var_3 = 0; var_3 < var_1; var_3++ ) + { + var_4 = self getrankedplayerdata( "xpMultiplier", var_3 ); + + if ( isdefined( var_4 ) && var_4 > var_2 ) + var_2 = var_4; + } + + if ( var_2 > 0 ) + setmatchdata( "players", self.clientid, "xpMultiplier", var_2 ); + } + + if ( isdefined( self.pers["summary"] ) && isdefined( self.pers["summary"]["clanWarsXP"] ) ) + setmatchdata( "players", self.clientid, "clanWarsXp", self.pers["summary"]["clanWarsXP"] ); + + if ( isdefined( level.ishorde ) && level.ishorde ) + [[ level.hordeupdatetimestats ]]( self ); +} + +callback_playerdisconnect( var_0 ) +{ + if ( !isdefined( self.connected ) ) + return; + + setmatchdata( "players", self.clientid, "disconnectTimeUTC", getsystemtime() ); + setmatchdata( "players", self.clientid, "disconnectReason", var_0 ); + + if ( maps\mp\_utility::rankingenabled() ) + maps\mp\_matchdata::logfinalstats(); + + if ( isdefined( self.pers["confirmed"] ) ) + maps\mp\_matchdata::logkillsconfirmed(); + + if ( isdefined( self.pers["denied"] ) ) + maps\mp\_matchdata::logkillsdenied(); + + logplayerstats(); + + if ( maps\mp\_utility::isroundbased() ) + { + var_1 = game["roundsPlayed"] + 1; + setmatchdata( "players", self.clientid, "playerQuitRoundNumber", var_1 ); + + if ( isdefined( self.team ) && ( self.team == "allies" || self.team == "axis" ) ) + { + if ( self.team == "allies" ) + { + setmatchdata( "players", self.clientid, "playerQuitTeamScore", game["roundsWon"]["allies"] ); + setmatchdata( "players", self.clientid, "playerQuitOpposingTeamScore", game["roundsWon"]["axis"] ); + } + else + { + setmatchdata( "players", self.clientid, "playerQuitTeamScore", game["roundsWon"]["axis"] ); + setmatchdata( "players", self.clientid, "playerQuitOpposingTeamScore", game["roundsWon"]["allies"] ); + } + } + } + else if ( isdefined( self.team ) && ( self.team == "allies" || self.team == "axis" ) && level.teambased ) + { + if ( self.team == "allies" ) + { + setmatchdata( "players", self.clientid, "playerQuitTeamScore", game["teamScores"]["allies"] ); + setmatchdata( "players", self.clientid, "playerQuitOpposingTeamScore", game["teamScores"]["axis"] ); + } + else + { + setmatchdata( "players", self.clientid, "playerQuitTeamScore", game["teamScores"]["axis"] ); + setmatchdata( "players", self.clientid, "playerQuitOpposingTeamScore", game["teamScores"]["allies"] ); + } + } + + removeplayerondisconnect(); + maps\mp\gametypes\_spawnlogic::removefromparticipantsarray(); + maps\mp\gametypes\_spawnlogic::removefromcharactersarray(); + var_2 = self getentitynumber(); + + if ( !level.teambased ) + game["roundsWon"][self.guid] = undefined; + + if ( !level.gameended ) + maps\mp\_utility::logxpgains(); + + if ( level.splitscreen ) + { + var_3 = level.players; + + if ( var_3.size <= 1 ) + level thread maps\mp\gametypes\_gamelogic::forceend(); + } + + if ( isdefined( self.score ) && isdefined( self.pers["team"] ) ) + { + var_4 = self.score; + + if ( maps\mp\_utility::getminutespassed() ) + var_4 = self.score / maps\mp\_utility::getminutespassed(); + + setplayerteamrank( self, self.clientid, int( var_4 ) ); + } + + reconevent( "script_mp_playerquit: player_name %s, player %d, gameTime %d", self.name, self.clientid, gettime() ); + var_5 = self getentitynumber(); + var_6 = self.guid; + logprint( "Q;" + var_6 + ";" + var_5 + ";" + self.name + "\n" ); + thread maps\mp\_events::disconnected(); + + if ( level.gameended ) + maps\mp\gametypes\_gamescore::removedisconnectedplayerfromplacement(); + + if ( isdefined( self.team ) ) + removefromteamcount(); + + if ( self.sessionstate == "playing" && !( isdefined( self.fauxdead ) && self.fauxdead ) ) + removefromalivecount( 1 ); + else if ( self.sessionstate == "spectator" || self.sessionstate == "dead" ) + level thread maps\mp\gametypes\_gamelogic::updategameevents(); +} + +removeplayerondisconnect() +{ + var_0 = 0; + + for ( var_1 = 0; var_1 < level.players.size; var_1++ ) + { + if ( level.players[var_1] == self ) + { + for ( var_0 = 1; var_1 < level.players.size - 1; var_1++ ) + level.players[var_1] = level.players[var_1 + 1]; + + level.players[var_1] = undefined; + break; + } + } +} + +initclientdvarssplitscreenspecific() +{ +} + +initclientdvars() +{ + setdvar( "cg_drawTalk", 1 ); + setdvar( "cg_drawCrosshair", 1 ); + setdvar( "cg_drawCrosshairNames", 1 ); + setdvar( "cg_hudGrenadeIconMaxRangeFrag", 250 ); + + if ( level.hardcoremode ) + { + setdvar( "cg_drawTalk", 3 ); + setdvar( "cg_drawCrosshair", 0 ); + setdvar( "cg_drawCrosshairNames", 1 ); + setdvar( "cg_hudGrenadeIconMaxRangeFrag", 0 ); + } + + if ( isdefined( level.alwaysdrawfriendlynames ) && level.alwaysdrawfriendlynames ) + setdvar( "cg_drawFriendlyNamesAlways", 1 ); + else + setdvar( "cg_drawFriendlyNamesAlways", 0 ); +} + +getlowestavailableclientid() +{ + var_0 = 0; + + for ( var_1 = 0; var_1 < 30; var_1++ ) + { + foreach ( var_3 in level.players ) + { + if ( !isdefined( var_3 ) ) + continue; + + if ( var_3.clientid == var_1 ) + { + var_0 = 1; + break; + } + + var_0 = 0; + } + + if ( !var_0 ) + return var_1; + } +} + +setupsavedactionslots() +{ + self.saved_actionslotdata = []; + + for ( var_0 = 1; var_0 <= 4; var_0++ ) + { + self.saved_actionslotdata[var_0] = spawnstruct(); + self.saved_actionslotdata[var_0].type = ""; + self.saved_actionslotdata[var_0].item = undefined; + } + + if ( !level.console ) + { + for ( var_0 = 5; var_0 <= 8; var_0++ ) + { + self.saved_actionslotdata[var_0] = spawnstruct(); + self.saved_actionslotdata[var_0].type = ""; + self.saved_actionslotdata[var_0].item = undefined; + } + } +} + +logplayerconsoleidandonwifiinmatchdata() +{ + var_0 = getcodanywherecurrentplatform(); + var_1 = self getcommonplayerdata( "consoleIDChunkLow", var_0 ); + var_2 = self getcommonplayerdata( "consoleIDChunkHigh", var_0 ); + + if ( isdefined( var_1 ) && var_1 != 0 ) + setmatchdata( "players", self.clientid, "consoleIDChunkLow", var_1 ); + + if ( isdefined( var_2 ) && var_2 != 0 ) + setmatchdata( "players", self.clientid, "consoleIDChunkHigh", var_2 ); + + var_3 = 3; + var_4 = -1; + + if ( isdefined( var_2 ) && var_2 != 0 && isdefined( var_1 ) && var_1 != 0 ) + { + for ( var_5 = 0; var_5 < var_3; var_5++ ) + { + var_6 = self getcommonplayerdata( "deviceConnectionHistory", var_5, "device_id_high" ); + var_7 = self getcommonplayerdata( "deviceConnectionHistory", var_5, "device_id_low" ); + + if ( var_6 == var_2 && var_7 == var_1 ) + { + var_4 = var_5; + break; + } + } + } + + if ( var_4 == -1 ) + { + var_8 = 0; + + for ( var_5 = 0; var_5 < var_3; var_5++ ) + { + var_9 = self getcommonplayerdata( "deviceConnectionHistory", var_5, "deviceUseFrequency" ); + + if ( var_9 > var_8 ) + { + var_8 = var_9; + var_4 = var_5; + } + } + } + + if ( var_4 == -1 ) + var_4 = 0; + + var_10 = self getcommonplayerdata( "deviceConnectionHistory", var_4, "onWifi" ); + + if ( var_10 ) + setmatchdata( "players", self.clientid, "playingOnWifi", 1 ); +} + +truncateplayername( var_0 ) +{ + if ( level.xb3 && var_0.size > 18 ) + { + var_1 = common_scripts\utility::string_find( var_0, "]" ); + + if ( var_1 >= 0 && common_scripts\utility::string_starts_with( var_0, "[" ) ) + var_0 = getsubstr( var_0, var_1 + 1 ); + } + + return var_0; +} + +callback_playerconnect() +{ + var_0 = getrandomspectatorspawnpoint(); + self setspectatedefaults( var_0.origin, var_0.angles ); + thread notifyconnecting(); + self waittill( "begin" ); + self.connecttime = gettime(); + level notify( "connected", self ); + self.connected = 1; + + if ( self ishost() ) + level.player = self; + + if ( !level.splitscreen && !isdefined( self.pers["score"] ) ) + iprintln( &"MP_CONNECTED", self ); + + self.usingonlinedataoffline = self isusingonlinedataoffline(); + initclientdvars(); + initplayerstats(); + + if ( getdvar( "r_reflectionProbeGenerate" ) == "1" ) + level waittill( "eternity" ); + + self.guid = self getguid(); + self.xuid = self getxuid(); + self.totallifetime = 0; + var_1 = 0; + + if ( !isdefined( self.pers["clientid"] ) ) + { + if ( game["clientid"] >= 30 ) + self.pers["clientid"] = getlowestavailableclientid(); + else + self.pers["clientid"] = game["clientid"]; + + if ( game["clientid"] < 30 ) + game["clientid"]++; + + var_1 = 1; + } + + if ( var_1 && !maps\mp\_utility::invirtuallobby() ) + maps\mp\killstreaks\_killstreaks::resetadrenaline( 1 ); + + if ( maps\mp\_utility::practiceroundgame() && var_1 ) + maps\mp\gametypes\_class::assignpracticeroundclasses(); + + if ( var_1 ) + streamprimaryweapons(); + + self.clientid = self.pers["clientid"]; + self.pers["teamKillPunish"] = 0; + self.pers["suicideSpawnDelay"] = 0; + + if ( var_1 ) + reconevent( "script_mp_playerjoin: player_name %s, player %d, gameTime %d", self.name, self.clientid, gettime() ); + + logprint( "J;" + self.guid + ";" + self getentitynumber() + ";" + self.name + "\n" ); + + if ( game["clientid"] <= 30 && game["clientid"] != getmatchdata( "playerCount" ) ) + { + var_2 = 0; + var_3 = 0; + + if ( !isai( self ) && maps\mp\_utility::matchmakinggame() ) + self registerparty( self.clientid ); + + setmatchdata( "playerCount", game["clientid"] ); + setmatchdata( "players", self.clientid, "playerID", "xuid", self getxuid() ); + setmatchdata( "players", self.clientid, "playerID", "ucdIDHigh", self getucdidhigh() ); + setmatchdata( "players", self.clientid, "playerID", "ucdIDLow", self getucdidlow() ); + setmatchdata( "players", self.clientid, "playerID", "clanIDHigh", self getclanidhigh() ); + setmatchdata( "players", self.clientid, "playerID", "clanIDLow", self getclanidlow() ); + setmatchdata( "players", self.clientid, "gamertag", truncateplayername( self.name ) ); + setmatchdata( "players", self.clientid, "isBot", isai( self ) ); + var_4 = self getentitynumber(); + setmatchdata( "players", self.clientid, "codeClientNum", maps\mp\_utility::clamptobyte( var_4 ) ); + var_5 = getcodanywherecurrentplatform(); + var_3 = self getcommonplayerdata( "connectionIDChunkLow", var_5 ); + var_2 = self getcommonplayerdata( "connectionIDChunkHigh", var_5 ); + setmatchdata( "players", self.clientid, "connectionIDChunkLow", var_3 ); + setmatchdata( "players", self.clientid, "connectionIDChunkHigh", var_2 ); + setmatchclientip( self, self.clientid ); + setmatchdata( "players", self.clientid, "joinType", self getjointype() ); + setmatchdata( "players", self.clientid, "connectTimeUTC", getsystemtime() ); + setmatchdata( "players", self.clientid, "isSplitscreen", issplitscreen() ); + logplayerconsoleidandonwifiinmatchdata(); + + if ( self ishost() ) + setmatchdata( "players", self.clientid, "wasAHost", 1 ); + + if ( maps\mp\_utility::rankingenabled() ) + maps\mp\_matchdata::loginitialstats(); + + if ( istestclient( self ) || isai( self ) ) + var_6 = 1; + else + var_6 = 0; + + if ( maps\mp\_utility::matchmakinggame() && maps\mp\_utility::allowteamchoice() && !var_6 ) + setmatchdata( "players", self.clientid, "team", self.sessionteam ); + + if ( maps\mp\_utility::isaiteamparticipant( self ) ) + { + if ( !isdefined( level.matchdata ) ) + level.matchdata = []; + + if ( !isdefined( level.matchdata["botJoinCount"] ) ) + level.matchdata["botJoinCount"] = 1; + else + level.matchdata["botJoinCount"]++; + } + } + + if ( !level.teambased ) + game["roundsWon"][self.guid] = 0; + + self.leaderdialogqueue = []; + self.leaderdialoglocqueue = []; + self.leaderdialogactive = ""; + self.leaderdialoggroups = []; + self.leaderdialoggroup = ""; + + if ( !isdefined( self.pers["cur_kill_streak"] ) ) + { + self.pers["cur_kill_streak"] = 0; + self.killstreakcount = 0; + } + + if ( !isdefined( self.pers["cur_death_streak"] ) ) + self.pers["cur_death_streak"] = 0; + + if ( !isdefined( self.pers["cur_kill_streak_for_nuke"] ) ) + self.pers["cur_kill_streak_for_nuke"] = 0; + + if ( maps\mp\_utility::rankingenabled() ) + self.kill_streak = maps\mp\gametypes\_persistence::statget( "killStreak" ); + + self.lastgrenadesuicidetime = -1; + self.teamkillsthisround = 0; + self.hasspawned = 0; + self.waitingtospawn = 0; + self.wantsafespawn = 0; + self.wasaliveatmatchstart = 0; + self.movespeedscaler = level.baseplayermovescale; + self.killstreakscaler = 1; + self.objectivescaler = 1; + self.issniper = 0; + setupsavedactionslots(); + level thread monitorplayersegments( self ); + thread maps\mp\_flashgrenades::monitorflash(); + resetuidvarsonconnect(); + maps\mp\_snd_common_mp::snd_mp_player_join(); + waittillframeend; + level.players[level.players.size] = self; + maps\mp\gametypes\_spawnlogic::addtoparticipantsarray(); + maps\mp\gametypes\_spawnlogic::addtocharactersarray(); + + if ( level.teambased ) + self updatescores(); + + if ( game["state"] == "postgame" ) + { + self.connectedpostgame = 1; + spawnintermission(); + } + else + { + if ( isai( self ) && isdefined( level.bot_funcs ) && isdefined( level.bot_funcs["think"] ) ) + self thread [[ level.bot_funcs["think"] ]](); + + level endon( "game_ended" ); + + if ( isdefined( level.hostmigrationtimer ) ) + { + if ( !isdefined( self.hostmigrationcontrolsfrozen ) || self.hostmigrationcontrolsfrozen == 0 ) + { + self.hostmigrationcontrolsfrozen = 0; + thread maps\mp\gametypes\_hostmigration::hostmigrationtimerthink(); + } + } + + if ( isdefined( level.onplayerconnectaudioinit ) ) + [[ level.onplayerconnectaudioinit ]](); + + if ( !isdefined( self.pers["team"] ) ) + { + if ( maps\mp\_utility::matchmakinggame() && self.sessionteam != "none" ) + { + thread spawnspectator(); + + if ( isdefined( level.waitingforplayers ) && level.waitingforplayers ) + maps\mp\_utility::freezecontrolswrapper( 1 ); + + thread maps\mp\gametypes\_menus::setteam( self.sessionteam ); + + if ( maps\mp\_utility::allowclasschoice() ) + thread setuioptionsmenu( 2 ); + + thread kickifdontspawn(); + return; + } + else if ( maps\mp\_utility::allowteamchoice() && !isbot( self ) ) + { + maps\mp\gametypes\_menus::menuspectator(); + thread setuioptionsmenu( 1 ); + } + else + { + thread spawnspectator(); + self [[ level.autoassign ]](); + + if ( maps\mp\_utility::allowclasschoice() ) + thread setuioptionsmenu( 2 ); + + if ( maps\mp\_utility::matchmakinggame() ) + thread kickifdontspawn(); + + return; + } + } + else + { + maps\mp\gametypes\_menus::addtoteam( self.pers["team"], 1 ); + + if ( maps\mp\_utility::isvalidclass( self.pers["class"] ) ) + { + thread spawnclient(); + return; + } + + thread spawnspectator(); + + if ( self.pers["team"] == "spectator" ) + { + if ( maps\mp\_utility::allowteamchoice() ) + { + maps\mp\gametypes\_menus::beginteamchoice(); + return; + } + + self [[ level.autoassign ]](); + return; + return; + } + + maps\mp\gametypes\_menus::beginclasschoice(); + } + } +} + +callback_playermigrated() +{ + if ( isdefined( self.connected ) && self.connected ) + { + maps\mp\_utility::updateobjectivetext(); + maps\mp\_utility::updatemainmenu(); + + if ( level.teambased ) + self updatescores(); + } + + if ( self ishost() ) + { + initclientdvarssplitscreenspecific(); + setmatchdata( "players", self.clientid, "wasAHost", 1 ); + } + + var_0 = 0; + + foreach ( var_2 in level.players ) + { + if ( !isbot( var_2 ) && !istestclient( var_2 ) ) + var_0++; + } + + if ( !isbot( self ) && !istestclient( self ) ) + { + level.hostmigrationreturnedplayercount++; + + if ( level.hostmigrationreturnedplayercount >= var_0 * 2 / 3 ) + level notify( "hostmigration_enoughplayers" ); + + self notify( "player_migrated" ); + } +} + +forcespawn() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "spawned" ); + wait 60.0; + + if ( self.hasspawned ) + return; + + if ( self.pers["team"] == "spectator" ) + return; + + if ( !maps\mp\_utility::isvalidclass( self.pers["class"] ) ) + { + self.pers["class"] = "CLASS_CUSTOM1"; + self.class = self.pers["class"]; + maps\mp\gametypes\_class::clearcopycatloadout(); + } + + thread spawnclient(); +} + +kickifdontspawn() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "spawned" ); + self endon( "attempted_spawn" ); + var_0 = getdvarfloat( "scr_kick_time", 90 ); + var_1 = getdvarfloat( "scr_kick_mintime", 45 ); + var_2 = gettime(); + + if ( self ishost() ) + kickwait( 120 ); + else + kickwait( var_0 ); + + var_3 = ( gettime() - var_2 ) / 1000; + + if ( var_3 < var_0 - 0.1 && var_3 < var_1 ) + return; + + if ( self.hasspawned ) + return; + + if ( self.pers["team"] == "spectator" ) + return; + + kick( self getentitynumber(), "EXE_PLAYERKICKED_INACTIVE" ); + level thread maps\mp\gametypes\_gamelogic::updategameevents(); +} + +kickwait( var_0 ) +{ + level endon( "game_ended" ); + maps\mp\gametypes\_hostmigration::waitlongdurationwithhostmigrationpause( var_0 ); +} + +initplayerstats() +{ + maps\mp\gametypes\_persistence::initbufferedstats(); + self.pers["lives"] = maps\mp\_utility::getgametypenumlives(); + + if ( !isdefined( self.pers["deaths"] ) ) + { + maps\mp\_utility::initpersstat( "deaths" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "deaths", 0 ); + } + + self.deaths = maps\mp\_utility::getpersstat( "deaths" ); + + if ( !isdefined( self.pers["score"] ) ) + { + maps\mp\_utility::initpersstat( "score" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "score", 0 ); + maps\mp\gametypes\_persistence::statsetchildbuffered( "round", "timePlayed", 0 ); + } + + self.score = maps\mp\_utility::getpersstat( "score" ); + self.timeplayed["total"] = maps\mp\gametypes\_persistence::statgetchildbuffered( "round", "timePlayed" ); + + if ( !isdefined( self.pers["suicides"] ) ) + maps\mp\_utility::initpersstat( "suicides" ); + + self.suicides = maps\mp\_utility::getpersstat( "suicides" ); + + if ( !isdefined( self.pers["kills"] ) ) + { + maps\mp\_utility::initpersstat( "kills" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "kills", 0 ); + } + + self.kills = maps\mp\_utility::getpersstat( "kills" ); + + if ( !isdefined( self.pers["headshots"] ) ) + { + maps\mp\_utility::initpersstat( "headshots" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "headshots", 0 ); + } + + self.headshots = maps\mp\_utility::getpersstat( "headshots" ); + + if ( !isdefined( self.pers["assists"] ) ) + { + maps\mp\_utility::initpersstat( "assists" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "assists", 0 ); + } + + self.assists = maps\mp\_utility::getpersstat( "assists" ); + + if ( !isdefined( self.pers["captures"] ) ) + { + maps\mp\_utility::initpersstat( "captures" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "captures", 0 ); + } + + if ( !isdefined( self.pers["returns"] ) ) + { + maps\mp\_utility::initpersstat( "returns" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "returns", 0 ); + } + + self.returns = maps\mp\_utility::getpersstat( "returns" ); + + if ( !isdefined( self.pers["defends"] ) ) + { + maps\mp\_utility::initpersstat( "defends" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "defends", 0 ); + } + + if ( !isdefined( self.pers["plants"] ) ) + { + maps\mp\_utility::initpersstat( "plants" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "plants", 0 ); + } + + if ( !isdefined( self.pers["defuses"] ) ) + { + maps\mp\_utility::initpersstat( "defuses" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "defuses", 0 ); + } + + if ( !isdefined( self.pers["destructions"] ) ) + { + maps\mp\_utility::initpersstat( "destructions" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "destructions", 0 ); + } + + if ( !isdefined( self.pers["confirmed"] ) ) + { + maps\mp\_utility::initpersstat( "confirmed" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "confirmed", 0 ); + } + + if ( !isdefined( self.pers["denied"] ) ) + { + maps\mp\_utility::initpersstat( "denied" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "denied", 0 ); + } + + if ( !isdefined( self.pers["rescues"] ) ) + { + maps\mp\_utility::initpersstat( "rescues" ); + maps\mp\gametypes\_persistence::statsetchild( "round", "rescues", 0 ); + } + + if ( !isdefined( self.pers["teamkills"] ) ) + maps\mp\_utility::initpersstat( "teamkills" ); + + if ( !isdefined( self.pers["totalTeamKills"] ) ) + maps\mp\_utility::initpersstat( "totalTeamKills" ); + + if ( !isdefined( self.pers["extrascore0"] ) ) + maps\mp\_utility::initpersstat( "extrascore0" ); + + if ( !isdefined( self.pers["extrascore1"] ) ) + maps\mp\_utility::initpersstat( "extrascore1" ); + + if ( !isdefined( self.pers["teamKillPunish"] ) ) + self.pers["teamKillPunish"] = 0; + + if ( !isdefined( self.pers["suicideSpawnDelay"] ) ) + self.pers["suicideSpawnDelay"] = 0; + + maps\mp\_utility::initpersstat( "longestStreak" ); + self.pers["lives"] = maps\mp\_utility::getgametypenumlives(); + maps\mp\gametypes\_persistence::statsetchild( "round", "killStreak", 0 ); + maps\mp\gametypes\_persistence::statsetchild( "round", "loss", 0 ); + maps\mp\gametypes\_persistence::statsetchild( "round", "win", 0 ); + maps\mp\gametypes\_persistence::statsetchild( "round", "scoreboardType", "none" ); + + if ( maps\mp\_utility::rankingenabled() ) + { + if ( !isdefined( self.pers["previous_shots"] ) ) + self.pers["previous_shots"] = self getrankedplayerdata( "totalShots" ); + + if ( !isdefined( self.pers["previous_hits"] ) ) + self.pers["previous_hits"] = self getrankedplayerdata( "hits" ); + } + + if ( !isdefined( self.pers["mpWeaponStats"] ) ) + self.pers["mpWeaponStats"] = []; + + if ( !isdefined( self.pers["numberOfTimesCloakingUsed"] ) ) + self.pers["numberOfTimesCloakingUsed"] = 0; + + if ( !isdefined( self.pers["numberOfTimesHoveringUsed"] ) ) + self.pers["numberOfTimesHoveringUsed"] = 0; + + if ( !isdefined( self.pers["numberOfTimesShieldUsed"] ) ) + self.pers["numberOfTimesShieldUsed"] = 0; + + if ( !isdefined( self.pers["bulletsBlockedByShield"] ) ) + self.pers["bulletsBlockedByShield"] = 0; + + if ( !isdefined( self.pers["totalKillcamsSkipped"] ) ) + self.pers["totalKillcamsSkipped"] = 0; + + if ( !isdefined( self.pers["weaponPickupsCount"] ) ) + self.pers["weaponPickupsCount"] = 0; + + if ( !isdefined( self.pers["pingAccumulation"] ) ) + self.pers["pingAccumulation"] = 0; + + if ( !isdefined( self.pers["pingSampleCount"] ) ) + self.pers["pingSampleCount"] = 0; + + if ( !isdefined( self.pers["minPing"] ) ) + self.pers["minPing"] = 32767; + + if ( !isdefined( self.pers["maxPing"] ) ) + self.pers["maxPing"] = 0; + + if ( !isdefined( self.pers["validationInfractions"] ) ) + self.pers["validationInfractions"] = 0; +} + +addtoteamcount() +{ + level.teamcount[self.team]++; + + if ( !isdefined( level.teamlist ) ) + level.teamlist = []; + + if ( !isdefined( level.teamlist[self.team] ) ) + level.teamlist[self.team] = []; + + level.teamlist[self.team][level.teamlist[self.team].size] = self; + maps\mp\gametypes\_gamelogic::updategameevents(); +} + +removefromteamcount() +{ + level.teamcount[self.team]--; + + if ( isdefined( level.teamlist ) && isdefined( level.teamlist[self.team] ) ) + { + var_0 = []; + + foreach ( var_2 in level.teamlist[self.team] ) + { + if ( !isdefined( var_2 ) || var_2 == self ) + continue; + + var_0[var_0.size] = var_2; + } + + level.teamlist[self.team] = var_0; + } +} + +addtoalivecount() +{ + var_0 = self.team; + + if ( !( isdefined( self.alreadyaddedtoalivecount ) && self.alreadyaddedtoalivecount ) ) + { + level.hasspawned[var_0]++; + incrementalivecount( var_0 ); + } + + self.alreadyaddedtoalivecount = undefined; + + if ( level.alivecount["allies"] + level.alivecount["axis"] > level.maxplayercount ) + level.maxplayercount = level.alivecount["allies"] + level.alivecount["axis"]; +} + +incrementalivecount( var_0 ) +{ + level.alivecount[var_0]++; +} + +removefromalivecount( var_0 ) +{ + var_1 = self.team; + + if ( isdefined( self.switching_teams ) && self.switching_teams && isdefined( self.joining_team ) && self.joining_team == self.team ) + var_1 = self.leaving_team; + + if ( isdefined( self.switching_teams ) || isdefined( var_0 ) ) + { + removeallfromlivescount(); + + if ( isdefined( self.switching_teams ) ) + self.pers["lives"] = 0; + } + + decrementalivecount( var_1 ); + return maps\mp\gametypes\_gamelogic::updategameevents(); +} + +decrementalivecount( var_0 ) +{ + level.alivecount[var_0]--; +} + +addtolivescount() +{ + level.livescount[self.team] += self.pers["lives"]; +} + +removefromlivescount() +{ + level.livescount[self.team]--; + level.livescount[self.team] = int( max( 0, level.livescount[self.team] ) ); +} + +removeallfromlivescount() +{ + level.livescount[self.team] -= self.pers["lives"]; + level.livescount[self.team] = int( max( 0, level.livescount[self.team] ) ); +} + +resetuidvarsonspawn() +{ + self setclientomnvar( "ui_carrying_bomb", 0 ); + self setclientomnvar( "ui_capture_icon", 0 ); + self setclientomnvar( "ui_light_armor", 0 ); + self setclientomnvar( "ui_killcam_end_milliseconds", 0 ); + self setclientomnvar( "ui_uplink_can_pass", 0 ); + self setclientomnvar( "ui_light_armor_percent", 0 ); + self setclientomnvar( "ui_killcam_time_until_spawn", 0 ); +} + +resetuidvarsonconnect() +{ + self setclientomnvar( "ui_carrying_bomb", 0 ); + self setclientomnvar( "ui_capture_icon", 0 ); + self setclientomnvar( "ui_light_armor", 0 ); + self setclientomnvar( "ui_killcam_end_milliseconds", 0 ); +} + +resetuidvarsonspectate() +{ + self setclientomnvar( "ui_carrying_bomb", 0 ); + self setclientomnvar( "ui_capture_icon", 0 ); + self setclientomnvar( "ui_light_armor", 0 ); + self setclientomnvar( "ui_killcam_end_milliseconds", 0 ); +} + +resetuidvarsondeath() +{ + +} + +monitorplayersegments( var_0 ) +{ + var_0 endon( "disconnect" ); + level endon( "game_ended" ); + createplayersegmentstats( var_0 ); + + for (;;) + { + var_0 waittill( "spawned_player" ); + recordsegemtdata( var_0 ); + } +} + +createplayersegmentstats( var_0 ) +{ + if ( !isdefined( var_0.pers["segments"] ) ) + var_0.pers["segments"] = []; + + var_0.segments = var_0.pers["segments"]; + + if ( !var_0.segments.size ) + { + var_0.segments["distanceTotal"] = 0; + var_0.segments["movingTotal"] = 0; + var_0.segments["movementUpdateCount"] = 0; + var_0.segments["killDistanceTotal"] = 0; + var_0.segments["killDistanceCount"] = 0; + } +} + +recordsegemtdata( var_0 ) +{ + var_0 endon( "death" ); + + while ( !maps\mp\_utility::gameflag( "prematch_done" ) ) + wait 0.5; + + wait 4; + var_0.savedposition = var_0.origin; + var_0.positionptm = var_0.origin; + + for (;;) + { + wait 1; + + if ( var_0 maps\mp\_utility::isusingremote() ) + { + var_0 waittill( "stopped_using_remote" ); + var_0.savedposition = var_0.origin; + var_0.positionptm = var_0.origin; + continue; + } + + var_0.segments["movementUpdateCount"]++; + var_0.segments["distanceTotal"] += distance2d( var_0.savedposition, var_0.origin ); + var_0.savedposition = var_0.origin; + + if ( var_0.segments["movementUpdateCount"] % 5 == 0 ) + { + var_1 = distance2d( var_0.positionptm, var_0.origin ); + var_0.positionptm = var_0.origin; + + if ( var_1 > 16 ) + var_0.segments["movingTotal"]++; + } + } +} + +writesegmentdata( var_0 ) +{ + if ( level.players.size < 2 ) + return; + + var_0 endon( "disconnect" ); + + if ( var_0.segments["movementUpdateCount"] < 30 || var_0.segments["killDistanceCount"] < 1 ) + return; + + var_1 = var_0.segments["movingTotal"] / int( var_0.segments["movementUpdateCount"] / 5 ) * 100; + var_2 = var_0.segments["distanceTotal"] / var_0.segments["movementUpdateCount"]; + var_3 = var_0.segments["killDistanceTotal"] / var_0.segments["killDistanceCount"]; + var_1 = min( var_1, float( tablelookup( "mp/playerSegments.csv", 0, "MAX", 3 ) ) ); + var_2 = min( var_2, float( tablelookup( "mp/playerSegments.csv", 0, "MAX", 2 ) ) ); + var_3 = min( var_3, float( tablelookup( "mp/playerSegments.csv", 0, "MAX", 4 ) ) ); + var_4 = calculatematchplaystyle( var_1, var_2, var_3 ); + setmatchdata( "players", var_0.clientid, "averageSpeedDuringMatch", var_2 ); + setmatchdata( "players", var_0.clientid, "percentageOfTimeMoving", var_1 ); + setmatchdata( "players", var_0.clientid, "averageKillDistance", var_3 ); + setmatchdata( "players", var_0.clientid, "totalDistanceTravelled", var_0.segments["distanceTotal"] ); + setmatchdata( "players", var_0.clientid, "playstyle", maps\mp\_utility::clamptobyte( var_4 ) ); + + if ( isai( var_0 ) ) + return; + + reconevent( "script_PlayerSegments: percentTimeMoving %f, averageSpeed %f, averageKillDistance %f, playStyle %d, name %s", var_1, var_2, var_3, var_4, var_0.name ); + + if ( !var_0 maps\mp\_utility::rankingenabled() ) + return; + + var_5 = 50; + var_6 = var_0 getrankedplayerdata( "combatRecord", "numPlayStyleTrends" ); + var_6++; + + if ( var_6 > var_5 ) + { + var_6 = var_5; + + if ( var_5 > 1 ) + { + for ( var_7 = 0; var_7 < var_5 - 1; var_7++ ) + { + var_8 = var_0 getrankedplayerdata( "combatRecord", "playStyleTimeStamp", var_7 + 1 ); + var_9 = var_0 getrankedplayerdata( "combatRecord", "playStyle", var_7 + 1 ); + var_0 setrankedplayerdata( "combatRecord", "playStyleTimeStamp", var_7, var_8 ); + var_0 setrankedplayerdata( "combatRecord", "playStyle", var_7, var_9 ); + } + } + } + + var_8 = maps\mp\_utility::gettimeutc_for_stat_recording(); + var_0 setrankedplayerdata( "combatRecord", "playStyleTimeStamp", var_6 - 1, var_8 ); + var_0 setrankedplayerdata( "combatRecord", "playStyle", var_6 - 1, var_4 ); + var_0 setrankedplayerdata( "combatRecord", "numPlayStyleTrends", var_6 ); +} + +calculatematchplaystyle( var_0, var_1, var_2 ) +{ + var_0 = normalizeplayersegment( var_0, float( tablelookup( "mp/playerSegments.csv", 0, "Mean", 3 ) ), float( tablelookup( "mp/playerSegments.csv", 0, "SD", 3 ) ) ); + var_1 = normalizeplayersegment( var_1, float( tablelookup( "mp/playerSegments.csv", 0, "Mean", 2 ) ), float( tablelookup( "mp/playerSegments.csv", 0, "SD", 2 ) ) ); + var_2 = normalizeplayersegment( var_2, float( tablelookup( "mp/playerSegments.csv", 0, "Mean", 4 ) ), float( tablelookup( "mp/playerSegments.csv", 0, "SD", 4 ) ) ); + var_3 = ( var_0, var_1, var_2 ); + var_4 = [ "Camper", "Mobile", "Run", "Sniper", "TacCQ" ]; + var_5 = "Camper"; + var_6 = 1000; + + foreach ( var_8 in var_4 ) + { + var_9 = getcentroiddistance( var_3, var_8 ); + + if ( var_9 < var_6 ) + { + var_5 = var_8; + var_6 = var_9; + } + } + + return int( tablelookup( "mp/playerSegments.csv", 0, var_5, 1 ) ); +} + +normalizeplayersegment( var_0, var_1, var_2 ) +{ + return ( var_0 - var_1 ) / var_2; +} + +getcentroiddistance( var_0, var_1 ) +{ + var_2 = ( float( tablelookup( "mp/playerSegments.csv", 0, var_1, 3 ) ), float( tablelookup( "mp/playerSegments.csv", 0, var_1, 2 ) ), float( tablelookup( "mp/playerSegments.csv", 0, var_1, 4 ) ) ); + return distance( var_0, var_2 ); +} + +clearpracticeroundlockoutdata( var_0, var_1 ) +{ + var_0 setcommonplayerdata( "practiceRoundLockoutTime", 0 ); + + for ( var_2 = 0; var_2 < var_1; var_2++ ) + var_0 setcommonplayerdata( "practiceRoundLockoutMatchTimes", var_2, 0 ); +} + +checkpracticeroundlockout( var_0 ) +{ + if ( isbot( var_0 ) || isagent( var_0 ) ) + return; + + var_1 = 10; + var_2 = 3; + var_3 = 5.0; + var_4 = int( 86400 ); + var_5 = int( 86400 ); + var_6 = var_0 getcommonplayerdata( "practiceRoundLockoutTime" ); + + if ( var_6 > 0 ) + clearpracticeroundlockoutdata( var_0, var_1 ); + + var_7 = var_0 getcommonplayerdata( "round", "kills" ); + var_8 = var_0 getcommonplayerdata( "round", "deaths" ); + var_8 = max( var_8, 1 ); + var_9 = var_7 / var_8; + + if ( var_9 < var_3 ) + { + clearpracticeroundlockoutdata( var_0, var_1 ); + return; + } + else + { + var_10 = maps\mp\_utility::gettimeutc_for_stat_recording(); + var_11 = var_10 - var_4; + var_12 = -1; + var_13 = var_10; + var_14 = 1; + + for ( var_15 = 0; var_15 < var_1; var_15++ ) + { + var_16 = var_0 getcommonplayerdata( "practiceRoundLockoutMatchTimes", var_15 ); + + if ( var_16 < var_13 ) + { + var_13 = var_16; + var_12 = var_15; + } + + if ( var_16 >= var_11 ) + var_14++; + } + + var_0 setcommonplayerdata( "practiceRoundLockoutMatchTimes", var_12, var_10 ); + + if ( var_14 >= var_2 ) + { + var_17 = var_10 + var_5; + var_0 setcommonplayerdata( "practiceRoundLockoutTime", var_17 ); + } + } +} diff --git a/data/maps/mp/gametypes/gun.gsc b/data/maps/mp/gametypes/gun.gsc new file mode 100644 index 0000000..0c90a28 --- /dev/null +++ b/data/maps/mp/gametypes/gun.gsc @@ -0,0 +1,507 @@ +// S1 GSC SOURCE +// Dumped by https://github.com/xensik/gsc-tool + +main() +{ + maps\mp\gametypes\_globallogic::init(); + maps\mp\gametypes\_callbacksetup::setupcallbacks(); + maps\mp\gametypes\_globallogic::setupcallbacks(); + setguns(); + maps\mp\_utility::registertimelimitdvar( level.gametype, 10 ); + setdvar( "scr_gun_scorelimit", level.gun_guns.size ); + maps\mp\_utility::registerscorelimitdvar( level.gametype, level.gun_guns.size ); + level thread reinitializescorelimitonmigration(); + maps\mp\_utility::registerroundlimitdvar( level.gametype, 1 ); + maps\mp\_utility::registerwinlimitdvar( level.gametype, 0 ); + maps\mp\_utility::registernumlivesdvar( level.gametype, 0 ); + maps\mp\_utility::registerhalftimedvar( level.gametype, 0 ); + level.matchrules_randomize = 0; + level.matchrules_damagemultiplier = 0; + level.matchrules_vampirism = 0; + + setspecialloadout(); + level.teambased = 0; + level.doprematch = 1; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.getspawnpoint = ::getspawnpoint; + level.onplayerkilled = ::onplayerkilled; + level.ontimelimit = ::ontimelimit; + level.onplayerscore = ::onplayerscore; + level.bypassclasschoicefunc = ::gungameclass; + level.assists_disabled = 1; + level.setbacklevel = maps\mp\_utility::getintproperty( "scr_setback_levels", 1 ); + level.lastguntimevo = 0; + + if ( level.matchrules_damagemultiplier ) + level.modifyplayerdamage = maps\mp\gametypes\_damage::gamemodemodifyplayerdamage; + + setteammode( "ffa" ); + game["dialog"]["gametype"] = "gg_intro"; + game["dialog"]["defense_obj"] = "gbl_start"; + game["dialog"]["offense_obj"] = "gbl_start"; + game["dialog"]["humiliation"] = "gg_humiliation"; + game["dialog"]["lastgun"] = "at_anr1_gg_lastgun"; + + if ( maps\mp\_utility::isgrapplinghookgamemode() ) + game["dialog"]["gametype"] = "grap_" + game["dialog"]["gametype"]; +} + +initializematchrules() +{ + maps\mp\_utility::setcommonrulesfrommatchrulesdata( 1 ); + level.matchrules_randomize = getmatchrulesdata( "gunData", "randomize" ); + setdvar( "scr_gun_scorelimit", level.gun_guns.size ); + maps\mp\_utility::registerscorelimitdvar( level.gametype, level.gun_guns.size ); + setdvar( "scr_gun_winlimit", 1 ); + maps\mp\_utility::registerwinlimitdvar( "gun", 1 ); + setdvar( "scr_gun_roundlimit", 1 ); + maps\mp\_utility::registerroundlimitdvar( "gun", 1 ); + setdvar( "scr_gun_halftime", 0 ); + maps\mp\_utility::registerhalftimedvar( "gun", 0 ); + setdvar( "scr_gun_playerrespawndelay", 0 ); + setdvar( "scr_gun_waverespawndelay", 0 ); + setdvar( "scr_player_forcerespawn", 1 ); + setdvar( "scr_setback_levels", getmatchrulesdata( "gunData", "setbackLevels" ) ); +} + +reinitializescorelimitonmigration() +{ + setdvar( "scr_gun_scorelimit", level.gun_guns.size ); + maps\mp\_utility::registerscorelimitdvar( level.gametype, level.gun_guns.size ); +} + +onstartgametype() +{ + setclientnamemode( "auto_change" ); + maps\mp\_utility::setobjectivetext( "allies", &"OBJECTIVES_DM" ); + maps\mp\_utility::setobjectivetext( "axis", &"OBJECTIVES_DM" ); + maps\mp\_utility::setobjectivescoretext( "allies", &"OBJECTIVES_DM_SCORE" ); + maps\mp\_utility::setobjectivescoretext( "axis", &"OBJECTIVES_DM_SCORE" ); + maps\mp\_utility::setobjectivehinttext( "allies", &"OBJECTIVES_DM_HINT" ); + maps\mp\_utility::setobjectivehinttext( "axis", &"OBJECTIVES_DM_HINT" ); + initspawns(); + var_0 = []; + maps\mp\gametypes\_gameobjects::main( var_0 ); + level.quickmessagetoall = 1; + level.blockweapondrops = 1; + level thread onplayerconnect(); +} + +initspawns() +{ + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + level.spawn_name = "mp_dm_spawn"; + maps\mp\gametypes\_spawnlogic::addspawnpoints( "allies", level.spawn_name ); + maps\mp\gametypes\_spawnlogic::addspawnpoints( "axis", level.spawn_name ); + level.mapcenter = maps\mp\gametypes\_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); +} + +onplayerconnect() +{ + for (;;) + { + level waittill( "connected", player ); + player.gungamegunindex = 0; + player.gungameprevgunindex = 0; + player.stabs = 0; + player.mysetbacks = 0; + player.lastleveluptime = 0; + player.showsetbacksplash = 0; + + if ( level.matchrules_randomize ) + player.gunlist = common_scripts\utility::array_randomize( level.gun_guns ); + + player thread refillammo(); + player thread refillsinglecountammo(); + player thread watchforhostmigration(); + } +} + +getspawnpoint() +{ + var_0 = maps\mp\gametypes\_spawnlogic::getteamspawnpoints( self.pers["team"] ); + + if ( level.ingraceperiod ) + var_1 = maps\mp\gametypes\_spawnlogic::getspawnpoint_random( var_0 ); + else + var_1 = maps\mp\gametypes\_spawnscoring::getspawnpoint_freeforall( var_0 ); + + maps\mp\gametypes\_spawnlogic::recon_set_spawnpoint( var_1 ); + return var_1; +} + +gungameclass() +{ + self.pers["class"] = "gamemode"; + self.pers["lastClass"] = ""; + self.pers["gamemodeLoadout"] = level.gun_loadout; + self.class = self.pers["class"]; + self.lastclass = self.pers["lastClass"]; + self loadweapons( level.gun_guns[0] ); +} + +onspawnplayer() +{ + thread waitloadoutdone(); +} + +waitloadoutdone() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + level waittill( "player_spawned" ); + givenextgun( 1 ); + + if ( self.showsetbacksplash ) + { + self.showsetbacksplash = 0; + thread maps\mp\_events::decreasegunlevelevent(); + } +} + +watchforhostmigration() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + + for (;;) + { + self waittill( "player_migrated" ); + + if ( self.sessionstate == "spectator" ) + maps\mp\gametypes\_menus::handleclasschoicedisallowed(); + } +} + +onplayerscore( var_0, var_1, var_2 ) +{ + if ( var_0 == "gained_gun_score" ) + { + var_3 = maps\mp\gametypes\_rank::getscoreinfovalue( var_0 ); + var_1 maps\mp\_utility::setextrascore0( var_1.extrascore0 + var_3 ); + var_1 maps\mp\gametypes\_gamescore::updatescorestatsffa( var_1, var_3 ); + return 1; + } + + if ( var_0 == "dropped_gun_score" ) + { + var_4 = min( level.setbacklevel, self.score ); + return int( var_4 * -1 ); + } + + return 0; +} + +onplayerkilled( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 ) +{ + if ( !isdefined( var_1 ) ) + return; + + if ( var_3 == "MOD_TRIGGER_HURT" && !isplayer( var_1 ) ) + var_1 = self; + + if ( var_3 == "MOD_FALLING" || isplayer( var_1 ) ) + { + if ( var_3 == "MOD_FALLING" || var_1 == self || maps\mp\_utility::ismeleemod( var_3 ) && var_4 != "riotshield_mp" || var_4 == "boost_slam_mp" || var_4 == "iw5_dlcgun12loot8_mp" ) + { + self playlocalsound( "mp_war_objective_lost" ); + self.gungameprevgunindex = self.gungamegunindex; + self.gungamegunindex = int( max( 0, self.gungamegunindex - level.setbacklevel ) ); + self.lastkillweapon = undefined; + + if ( self.gungameprevgunindex > self.gungamegunindex ) + { + self.mysetbacks++; + maps\mp\_utility::setextrascore1( self.mysetbacks ); + self.showsetbacksplash = 1; + + if ( maps\mp\_utility::ismeleemod( var_3 ) || var_4 == "boost_slam_mp" || var_4 == "iw5_dlcgun12loot8_mp" ) + { + var_1.stabs++; + var_1.assists = var_1.stabs; + var_1 thread maps\mp\_events::setbackenemygunlevelevent(); + + if ( self.gungameprevgunindex == level.gun_guns.size - 1 ) + { + var_1 thread maps\mp\_events::setbackfirstplayergunlevelevent(); + var_1 maps\mp\_utility::leaderdialogonplayer( "humiliation", "status" ); + } + } + } + } + else if ( var_3 == "MOD_PISTOL_BULLET" || var_3 == "MOD_RIFLE_BULLET" || var_3 == "MOD_HEAD_SHOT" || var_3 == "MOD_PROJECTILE" || var_3 == "MOD_PROJECTILE_SPLASH" || var_3 == "MOD_EXPLOSIVE" || var_3 == "MOD_IMPACT" || var_3 == "MOD_GRENADE" || var_3 == "MOD_GRENADE_SPLASH" || maps\mp\_utility::ismeleemod( var_3 ) && var_4 == "riotshield_mp" ) + { + if ( isdefined( var_1.lastkillweapon ) && var_1.lastkillweapon == var_4 ) + return; + + var_10 = level.gun_guns; + + if ( level.matchrules_randomize ) + var_10 = var_1.gunlist; + + var_11 = var_10[var_1.gungamegunindex]; + + if ( !issubstr( var_4, maps\mp\_utility::getbaseweaponname( var_11 ) ) ) + return; + + var_1.lastkillweapon = var_4; + + if ( var_1.lastleveluptime + 3000 > gettime() ) + var_1 thread maps\mp\_events::quickgunlevelevent(); + + var_1.lastleveluptime = gettime(); + var_1.gungameprevgunindex = var_1.gungamegunindex; + var_1.gungamegunindex++; + var_1 thread maps\mp\_events::increasegunlevelevent(); + + if ( var_1.gungamegunindex == level.gun_guns.size - 1 ) + { + maps\mp\_utility::playsoundonplayers( "mp_enemy_obj_captured" ); + level thread maps\mp\_utility::teamplayercardsplash( "callout_top_gun_rank", var_1 ); + var_12 = gettime(); + + if ( level.lastguntimevo + 4500 < var_12 ) + { + level thread maps\mp\_utility::leaderdialogonplayers( "lastgun", level.players, "status" ); + level.lastguntimevo = var_12; + } + } + + if ( var_1.gungamegunindex < level.gun_guns.size ) + var_1 givenextgun( 0, var_4 ); + } + } +} + +givenextgun( var_0, var_1 ) +{ + self endon( "disconnect" ); + var_2 = getnextgun(); + self.gun_curgun = var_2; + var_2 = addattachments( var_2 ); + + while ( !self loadweapons( var_2 ) ) + waitframe(); + + if ( isdefined( var_1 ) ) + self takeweapon( var_1 ); + else + self takeallweapons(); + + maps\mp\_utility::_giveweapon( var_2 ); + self switchtoweaponimmediate( var_2 ); + + if ( isdefined( var_0 ) && var_0 == 1 ) + self setspawnweapon( var_2 ); + + var_3 = maps\mp\_utility::getbaseweaponname( var_2 ); + self.pers["primaryWeapon"] = var_3; + self.primaryweapon = var_2; + self givestartammo( var_2 ); + self switchtoweapon( var_2 ); + self.gungameprevgunindex = self.gungamegunindex; +} + +getnextgun() +{ + var_0 = level.gun_guns; + var_1 = []; + var_2 = undefined; + + if ( level.matchrules_randomize ) + var_0 = self.gunlist; + + var_2 = var_0[self.gungamegunindex]; + var_1[var_1.size] = var_2; + + if ( self.gungamegunindex + 1 < var_0.size ) + var_1[var_1.size] = var_0[self.gungamegunindex + 1]; + + if ( self.gungamegunindex > 0 ) + var_1[var_1.size] = var_0[self.gungamegunindex - 1]; + + self loadweapons( var_1 ); + return var_2; +} + +addattachments( var_0 ) +{ + if ( getdvarint( "scr_gun_loot_variants", 0 ) == 1 ) + { + var_1 = tablelookup( "mp/statstable.csv", 4, var_0, 40 ); + + if ( isdefined( var_1 ) && var_1 != "" ) + var_2 = maps\mp\gametypes\_class::buildweaponname( var_0, var_1, "none", "none", 0, 0 ); + else + var_2 = maps\mp\gametypes\_class::buildweaponname( var_0, "none", "none", "none", 0, 0 ); + } + else + var_2 = maps\mp\gametypes\_class::buildweaponname( var_0, "none", "none", "none", 0, 0 ); + + return var_2; +} + +ontimelimit() +{ + level.finalkillcam_winner = "none"; + var_0 = gethighestprogressedplayers(); + + if ( !isdefined( var_0 ) || !var_0.size ) + thread maps\mp\gametypes\_gamelogic::endgame( "tie", game["end_reason"]["time_limit_reached"] ); + else if ( var_0.size == 1 ) + thread maps\mp\gametypes\_gamelogic::endgame( var_0[0], game["end_reason"]["time_limit_reached"] ); + else if ( var_0[var_0.size - 1].gungamegunindex > var_0[var_0.size - 2].gungamegunindex ) + thread maps\mp\gametypes\_gamelogic::endgame( var_0[var_0.size - 1], game["end_reason"]["time_limit_reached"] ); + else + thread maps\mp\gametypes\_gamelogic::endgame( "tie", game["end_reason"]["time_limit_reached"] ); +} + +gethighestprogressedplayers() +{ + var_0 = -1; + var_1 = []; + + foreach ( var_3 in level.players ) + { + if ( isdefined( var_3.gungamegunindex ) && var_3.gungamegunindex >= var_0 ) + { + var_0 = var_3.gungamegunindex; + var_1[var_1.size] = var_3; + } + } + + return var_1; +} + +refillammo() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + + for (;;) + { + self waittill( "reload" ); + self givestartammo( self.primaryweapon ); + } +} + +refillsinglecountammo() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + + for (;;) + { + if ( maps\mp\_utility::isreallyalive( self ) && self.team != "spectator" && isdefined( self.primaryweapon ) && self getammocount( self.primaryweapon ) == 0 ) + { + wait 2; + self notify( "reload" ); + wait 1; + continue; + } + + wait 0.05; + } +} + +setguns() +{ + var_0 = getdvarint( "scr_gun_loot_variants", 0 ); + level.gun_guns = []; + level.gun_guns[0] = "iw5_asm1"; + level.gun_guns[1] = "iw5_asaw"; + level.gun_guns[2] = "iw5_himar"; + level.gun_guns[3] = "iw5_kf5"; + level.gun_guns[4] = "iw5_hbra3"; + level.gun_guns[5] = "iw5_mp11"; + level.gun_guns[6] = "iw5_ak12"; + level.gun_guns[7] = "iw5_sn6"; + level.gun_guns[8] = "iw5_arx160"; + level.gun_guns[9] = "iw5_hmr9"; + level.gun_guns[10] = "iw5_maul"; + level.gun_guns[11] = "iw5_dlcgun3"; + level.gun_guns[12] = "iw5_em1"; + level.gun_guns[13] = "iw5_uts19"; + level.gun_guns[14] = "iw5_lsat"; + level.gun_guns[15] = "iw5_rhino"; + level.gun_guns[16] = "iw5_exoxmg"; + level.gun_guns[17] = "iw5_epm3"; + level.gun_guns[18] = "iw5_mors"; + level.gun_guns[19] = "iw5_rw1"; + level.gun_guns[20] = "iw5_vbr"; + level.gun_guns[21] = "iw5_pbw"; + level.gun_guns[22] = "iw5_thor"; + level.gun_guns[23] = "iw5_mahem"; + level.gun_guns[24] = "iw5_exocrossbow"; + + if ( isdefined( var_0 ) && var_0 ) + { + for ( var_1 = 0; var_1 < level.gun_guns.size; var_1++ ) + { + var_2 = level.gun_guns[var_1]; + + if ( maps\mp\_utility::getweaponclass( var_2 ) == "weapon_projectile" || maps\mp\_utility::getweaponclass( var_2 ) == "weapon_sec_special" ) + var_2 = assign_random_loot_variant( var_2, 4 ); + else + var_2 = assign_random_loot_variant( var_2, 10 ); + + level.gun_guns[var_1] = var_2; + } + } +} + +assign_random_loot_variant( var_0, var_1 ) +{ + var_2 = randomint( var_1 ); + + switch ( var_2 ) + { + case 0: + var_0 += "loot0"; + break; + case 1: + var_0 += "loot1"; + break; + case 2: + var_0 += "loot2"; + break; + case 3: + var_0 += "loot3"; + break; + case 4: + var_0 += "loot4"; + break; + case 5: + var_0 += "loot5"; + break; + case 6: + var_0 += "loot6"; + break; + case 7: + var_0 += "loot7"; + break; + case 8: + var_0 += "loot8"; + break; + case 9: + var_0 += "loot9"; + break; + default: + break; + } + + return var_0; +} + +setspecialloadout() +{ + level.gun_loadout = maps\mp\gametypes\_class::getemptyloadout(); + + if ( maps\mp\gametypes\_class::isvalidprimary( level.gun_guns[0] ) ) + level.gun_loadout["loadoutPrimary"] = level.gun_guns[0]; + else if ( maps\mp\gametypes\_class::isvalidsecondary( level.gun_guns[0], 0 ) ) + level.gun_loadout["loadoutSecondary"] = level.gun_guns[0]; +} diff --git a/data/scripts/_team_balance.gsc b/data/scripts/_team_balance.gsc new file mode 100644 index 0000000..6866a9c --- /dev/null +++ b/data/scripts/_team_balance.gsc @@ -0,0 +1,23 @@ +init() +{ + // define onteamselection callback function used in balanceteams() + level.onteamselection = ::set_team; +} + +set_team(team) +{ + if (team != self.pers["team"]) + { + self.switching_teams = true; + self.joining_team = team; + self.leaving_team = self.pers["team"]; + } + + if (self.sessionstate == "playing") + { + self suicide(); + } + + maps\mp\gametypes\_menus::addtoteam(team); + maps\mp\gametypes\_menus::endrespawnnotify(); +} diff --git a/data/ui_scripts/endgame/__init__.lua b/data/ui_scripts/endgame/__init__.lua new file mode 100644 index 0000000..8ee69e5 --- /dev/null +++ b/data/ui_scripts/endgame/__init__.lua @@ -0,0 +1,238 @@ +if (game:issingleplayer() or Engine.InFrontend()) then + return +end + +f0_local0 = function(f1_arg0, f1_arg1) + LUI.FlowManager.RequestLeaveMenu(f1_arg0) +end + +f0_local1 = function(f2_arg0, f2_arg1) + f2_arg0:setText(f2_arg1.message_text) + f2_arg0:dispatchEventToRoot({ + name = "resize_popup" + }) +end + +f0_local2 = function(f3_arg0) + Engine.ExecFirstClient("xpartybackout") + Engine.ExecFirstClient("disconnect") +end + +local f0_local3 = function(f4_arg0) + if Engine.GetDvarBool("squad_match") then + Engine.ExecFirstClient("disconnect") + else + Engine.ExecFirstClient("xpartydisbandafterround") + Engine.ExecFirstClient("disconnect") + end +end + +local f0_local4 = function(f5_arg0) + return Engine.GetOnlineGame() +end + +local f0_local5 = function(f6_arg0) + if f0_local4(f6_arg0) then + Engine.ExecFirstClient("xstopprivateparty") + Engine.ExecFirstClient("disconnect") + Engine.ExecFirstClient("xblive_privatematch 0") + Engine.ExecFirstClient("onlinegame 1") + Engine.ExecFirstClient("xstartprivateparty") + else + Engine.ExecFirstClient("disconnect") + end +end + +local f0_local6 = function(f7_arg0) + local f7_local0 = Engine.GetDvarBool("squad_match") + Engine.ExecFirstClient("xstopprivateparty") + Engine.ExecFirstClient("xpartydisbandafterround") + if f7_local0 then + Engine.ExecFirstClient("disconnect") + Engine.ExecFirstClient("xblive_privatematch 0") + Engine.ExecFirstClient("onlinegame 1") + Engine.ExecFirstClient("xstartprivateparty") + else + Engine.NotifyServer("end_game", 1) + Engine.ExecFirstClient("xstartprivateparty") + end +end + +local f0_local7 = function(f8_arg0, f8_arg1) + local f8_local0 = Engine.GetDvarBool("sv_running") + Game.HandleLeavePauseMenu() + if f8_local0 then + Engine.NotifyServer("end_game", 1) + else + f0_local5(f8_arg0) + end + LUI.FlowManager.RequestCloseAllMenus(f8_arg0) +end + +local f0_local8 = function(f9_arg0, f9_arg1) + LUI.FlowManager.RequestLeaveMenu(f9_arg0) + Game.HandleLeavePauseMenu() + Engine.Exec("onPlayerQuit") + local f9_local0 = Engine.GetDvarBool("sv_running") + if Engine.GetDvarBool("squad_match") then + Squad.PostMatch(0, 0, 0, 0, true) + end + if f9_local0 then + f0_local3(f9_arg0) + else + f0_local2(f9_arg0) + end + LUI.FlowManager.RequestCloseAllMenus(f9_arg0) +end + +local f0_local9 = function(f10_arg0, f10_arg1) + LUI.FlowManager.RequestLeaveMenu(f10_arg0) + Game.HandleLeavePauseMenu() + Engine.Exec("onPlayerQuit") + local f10_local0 = Engine.GetDvarBool("sv_running") + if Engine.GetDvarBool("squad_match") then + Squad.PostMatch(0, 0, 0, 0, true) + end + if f10_local0 then + f0_local6(f10_arg0) + else + f0_local5(f10_arg0) + end + LUI.FlowManager.RequestCloseAllMenus(f10_arg0) +end + +local f0_local10 = function(f11_arg0) + local f11_local0 = Lobby.IsInPrivateParty() + if f11_local0 then + f11_local0 = Lobby.IsPrivatePartyHost() + if f11_local0 then + f11_local0 = not Lobby.IsAloneInPrivateParty() + end + end + return f11_local0 +end + +local f0_local11 = function(f12_arg0, f12_arg1) + if f0_local10(f12_arg0) then + LUI.FlowManager.RequestLeaveMenu(f12_arg0, true) + LUI.FlowManager.RequestAddMenu(f12_arg0, "popup_pull_party", false) + else + Game.HandleLeavePauseMenu() + Engine.Exec("onPlayerQuit") + local f12_local0 = Engine.GetDvarBool("sv_running") + if Engine.GetDvarBool("squad_match") then + Squad.PostMatch(0, 0, 0, 0, true) + end + if f12_local0 then + f0_local6(f12_arg0) + else + f0_local5(f12_arg0) + end + LUI.FlowManager.RequestCloseAllMenus(f12_arg0) + end +end + +local f0_local12 = function() + local self = LUI.UIElement.new() + self.id = "end_game_id" + self:registerAnimationState("default", { + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + rightAnchor = true, + top = 0, + left = 0, + bottom = 0, + right = 0, + alpha = 1 + }) + self:animateToState("default", 0) + LUI.MenuBuilder.BuildAddChild(self, { + type = "generic_yesno_popup", + id = "privateGame_options_list_id", + properties = { + message_text_alignment = LUI.Alignment.Left, + message_text = Engine.Localize("@LUA_MENU_END_GAME_DESC"), + popup_title = Engine.Localize("@LUA_MENU_LEAVE_GAME_TITLE"), + padding_top = 12, + yes_action = f0_local7 + } + }) + local f13_local1 = LUI.UIBindButton.new() + f13_local1.id = "endBackToGameStartButton" + f13_local1:registerEventHandler("button_start", f0_local0) + self:addElement(f13_local1) + return self +end + +local f0_local13 = function() + local self = LUI.UIElement.new() + self.id = "leave_game_id" + self:registerAnimationState("default", { + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + rightAnchor = true, + top = 0, + left = 0, + bottom = 0, + right = 0, + alpha = 1 + }) + self:animateToState("default", 0) + LUI.MenuBuilder.BuildAddChild(self, { + type = "generic_yesno_popup", + id = "publicGame_options_list_id", + properties = { + message_text_alignment = LUI.Alignment.Left, + message_text = Engine.Localize("@LUA_MENU_LEAVE_GAME_DESC"), + popup_title = Engine.Localize("@LUA_MENU_LEAVE_GAME_TITLE"), + padding_top = 12, + yes_action = f0_local11 + } + }) + local f14_local1 = LUI.UIBindButton.new() + f14_local1.id = "leaveBackToGameStartButton" + f14_local1:registerEventHandler("button_start", f0_local0) + self:addElement(f14_local1) + return self +end + +local f0_local14 = function() + local self = LUI.UIElement.new() + self.id = "pull_party_out_id" + self:registerAnimationState("default", { + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + rightAnchor = true, + top = 0, + left = 0, + bottom = 0, + right = 0, + alpha = 1 + }) + self:animateToState("default", 0) + LUI.MenuBuilder.BuildAddChild(self, { + type = "generic_yesno_popup", + id = "party_pullout_list_id", + properties = { + message_text_alignment = LUI.Alignment.Left, + message_text = Engine.Localize("@LUA_MENU_PULL_PARTY_DESC"), + popup_title = Engine.Localize("@LUA_MENU_LEAVE_GAME_TITLE"), + padding_top = 12, + yes_action = f0_local8, + no_action = f0_local9, + cancel_means_no = false + } + }) + local f15_local1 = LUI.UIBindButton.new() + f15_local1.id = "leavePullPartyButton" + f15_local1:registerEventHandler("button_start", f0_local0) + self:addElement(f15_local1) + return self +end + +LUI.MenuBuilder.m_types_build["popup_end_game"] = f0_local12 +LUI.MenuBuilder.m_types_build["popup_leave_game"] = f0_local13 +LUI.MenuBuilder.m_types_build["popup_pull_party"] = f0_local14 diff --git a/data/ui_scripts/hud_info/__init__.lua b/data/ui_scripts/hud_info/__init__.lua new file mode 100644 index 0000000..4b5a89a --- /dev/null +++ b/data/ui_scripts/hud_info/__init__.lua @@ -0,0 +1,6 @@ +if (game:issingleplayer()) then + return +end + +require("settings") +require("hud") diff --git a/data/ui_scripts/hud_info/hud.lua b/data/ui_scripts/hud_info/hud.lua new file mode 100644 index 0000000..d1edab2 --- /dev/null +++ b/data/ui_scripts/hud_info/hud.lua @@ -0,0 +1,163 @@ +local mphud = require("LUI.mp_hud.MPHud") +local barheight = 18 +local textheight = 13 +local textoffsety = barheight / 2 - textheight / 2 + +function createinfobar() + local infobar = LUI.UIElement.new({ + left = 180, + top = 5, + height = barheight, + width = 70, + leftAnchor = true, + topAnchor = true + }) + + infobar:registerAnimationState("hud_on", { + alpha = 1 + }) + + infobar:registerAnimationState("hud_off", { + alpha = 0 + }) + + return infobar +end + +function populateinfobar(infobar) + elementoffset = 0 + + if (Engine.GetDvarBool("cg_infobar_fps")) then + infobar:addElement(infoelement({ + label = "FPS: ", + getvalue = function() + return game:getfps() + end, + width = 70, + interval = 100 + })) + end + + if (Engine.GetDvarBool("cg_infobar_ping")) then + infobar:addElement(infoelement({ + label = "Latency: ", + getvalue = function() + return game:getping() .. " ms" + end, + width = 115, + interval = 100 + })) + end +end + +function infoelement(data) + local container = LUI.UIElement.new({ + bottomAnchor = true, + leftAnchor = true, + topAnchor = true, + width = data.width, + left = elementoffset + }) + + elementoffset = elementoffset + data.width + 10 + + local background = LUI.UIImage.new({ + bottomAnchor = true, + leftAnchor = true, + topAnchor = true, + rightAnchor = true, + color = { + r = 0.3, + g = 0.3, + b = 0.3, + }, + material = RegisterMaterial("distort_hud_bkgnd_ui_blur") + }) + + local labelfont = RegisterFont("fonts/bodyFontBold", textheight) + + local label = LUI.UIText.new({ + left = 5, + top = textoffsety + 1, + font = labelfont, + height = textheight, + leftAnchor = true, + topAnchor = true, + color = { + r = 0.8, + g = 0.8, + b = 0.8, + } + }) + + label:setText(data.label) + + local _, _, left = GetTextDimensions(data.label, labelfont, textheight) + local value = LUI.UIText.new({ + left = left + 5, + top = textoffsety, + font = RegisterFont("fonts/bodyFont", textheight), + height = textheight + 1, + leftAnchor = true, + topAnchor = true, + color = { + r = 0.6, + g = 0.6, + b = 0.6, + } + }) + + value:addElement(LUI.UITimer.new(data.interval, "update")) + value:setText(data.getvalue()) + value:addEventHandler("update", function() + value:setText(data.getvalue()) + end) + + container:addElement(background) + container:addElement(label) + container:addElement(value) + + return container +end + +local updatehudvisibility = mphud.updateHudVisibility +mphud.updateHudVisibility = function(a1, a2) + updatehudvisibility(a1, a2) + + local root = Engine.GetLuiRoot() + local menus = root:AnyActiveMenusInStack() + local infobar = root.infobar + + if (not infobar) then + return + end + + if (menus) then + infobar:animateToState("hud_off") + else + infobar:animateToState("hud_on") + end +end + +local mphud = LUI.MenuBuilder.m_types_build["mp_hud"] +LUI.MenuBuilder.m_types_build["mp_hud"] = function() + local hud = mphud() + + if (Engine.InFrontend()) then + return hud + end + + local infobar = createinfobar() + local root = Engine.GetLuiRoot() + root.infobar = infobar + populateinfobar(infobar) + + root:registerEventHandler("update_hud_infobar_settings", function() + infobar:removeAllChildren() + populateinfobar(infobar) + end) + + hud.static:addElement(infobar) + + return hud +end diff --git a/data/ui_scripts/hud_info/settings.lua b/data/ui_scripts/hud_info/settings.lua new file mode 100644 index 0000000..e439a14 --- /dev/null +++ b/data/ui_scripts/hud_info/settings.lua @@ -0,0 +1,156 @@ +local pcoptions = require("LUI.PCOptions") + +game:addlocalizedstring("LUA_MENU_FPS", "FPS Counter") +game:addlocalizedstring("LUA_MENU_FPS_DESC", "Show FPS Counter") + +game:addlocalizedstring("LUA_MENU_LATENCY", "Server Latency") +game:addlocalizedstring("LUA_MENU_LATENCY_DESC", "Show server latency") + +pcoptions.VideoOptionsFeeder = function() + local items = { + pcoptions.OptionFactory( + "ui_r_displayMode", + "@LUA_MENU_DISPLAY_MODE", + nil, + { + { + text = "@LUA_MENU_MODE_FULLSCREEN", + value = "fullscreen" + }, + { + text = "@LUA_MENU_MODE_WINDOWED_NO_BORDER", + value = "windowed_no_border" + }, + { + text = "@LUA_MENU_MODE_WINDOWED", + value = "windowed" + } + }, + nil, + true + ), + pcoptions.SliderOptionFactory( + "profileMenuOption_blacklevel", + "@MENU_BRIGHTNESS", + "@MENU_BRIGHTNESS_DESC1", + SliderBounds.PCBrightness.Min, + SliderBounds.PCBrightness.Max, + SliderBounds.PCBrightness.Step, + function(element) + element:processEvent({ + name = "brightness_over", + immediate = true + }) + end, + function(element) + element:processEvent({ + name = "brightness_up", + immediate = true + }) + end, + true, + nil, + "brightness_updated" + ), + pcoptions.OptionFactoryProfileData( + "renderColorBlind", + "profile_toggleRenderColorBlind", + "@LUA_MENU_COLORBLIND_FILTER", + "@LUA_MENU_COLOR_BLIND_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + nil, + false + ) + } + + if Engine.IsMultiplayer() and not Engine.IsZombiesMode() then + table.insert(items, pcoptions.OptionFactory( + "cg_paintballFx", + "@LUA_MENU_PAINTBALL", + "@LUA_MENU_PAINTBALL_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + nil, + false, + false + )) + end + + table.insert(items, pcoptions.OptionFactory( + "cg_infobar_ping", + "@LUA_MENU_LATENCY", + "@LUA_MENU_LATENCY_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + function() + Engine.GetLuiRoot():processEvent({ + name = "update_hud_infobar_settings" + }) + end, + false, + false + )) + + table.insert(items, pcoptions.OptionFactory( + "cg_infobar_fps", + "@LUA_MENU_FPS", + "@LUA_MENU_FPS_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + function() + Engine.GetLuiRoot():processEvent({ + name = "update_hud_infobar_settings" + }) + end, + false, + false + )) + + table.insert(items, { + type = "UIGenericButton", + id = "option_advanced_video", + properties = { + style = GenericButtonSettings.Styles.GlassButton, + button_text = Engine.Localize("@LUA_MENU_ADVANCED_VIDEO"), + desc_text = "", + button_action_func = pcoptions.ButtonMenuAction, + text_align_without_content = LUI.Alignment.Left, + menu = "advanced_video" + } + }) + + return items +end diff --git a/data/ui_scripts/lobby/__init__.lua b/data/ui_scripts/lobby/__init__.lua new file mode 100644 index 0000000..761aced --- /dev/null +++ b/data/ui_scripts/lobby/__init__.lua @@ -0,0 +1,6 @@ +if (game:issingleplayer() or not Engine.InFrontend()) then + return +end + +require("menu_xboxlive") +require("menu_xboxlive_lobby") diff --git a/data/ui_scripts/lobby/menu_xboxlive.lua b/data/ui_scripts/lobby/menu_xboxlive.lua new file mode 100644 index 0000000..f69d9ec --- /dev/null +++ b/data/ui_scripts/lobby/menu_xboxlive.lua @@ -0,0 +1,112 @@ +local Lobby = Lobby +local MPLobbyOnline = LUI.mp_menus.MPLobbyOnline +local MenuData = LUI.mp_menus.MenuData +local MPLobbyUtils = LUI.mp_menus.MPLobbyUtils + +game:addlocalizedstring("LUA_MENU_SERVERLIST", "Server List") +game:addlocalizedstring("LUA_MENU_SERVERLIST_DESC", "Browse available servers."); + +LeaveXboxLive = function(f5_arg0) + local f73_local0 = Engine.GetFirstActiveController() + if f73_local0 ~= nil then + Engine.ExecNow("xstopprivateparty", f73_local0) + Cac.NotifyVirtualLobby("leave_lobby", Engine.GetXUIDByController(f73_local0)) + Engine.SetSplitScreen(false) + Engine.ExecNow("forcesplitscreencontrol menu_xboxlive_CLOSE", f73_local0) + else + Engine.Exec("xstopprivateparty") + end +end + +function LeaveLobby(a1) + LUI.MarketingPanel.ClearViewedMessages({ LUI.MarketingLocation.CaC, LUI.MarketingLocation.PlayOnline, + LUI.MarketingLocation.CaO }) + LeaveXboxLive() + LUI.FlowManager.RequestLeaveMenuByName("menu_xboxlive_lobby", nil, true) +end + +function menu_xboxlive(a1, a2) + Engine.SetDvarBool("ui_opensummary", false) + local menu = LUI.MPLobbyBase.new(a1, { + menu_title = "@PLATFORM_UI_HEADER_PLAY_MP_CAPS", + memberListState = Lobby.MemberListStates.Prelobby, + has_new_item_usage_widget = true + }) + + menu:setClass(LUI.MPLobbyOnline) + + menu.handleGamepadButton = MPLobbyOnline.menu_xboxlive_handleGamepadButton + if Engine.IsCoreMode() then + menu:AddNewItemsWidget() + end + + -- server list button + local serverListButton = menu:AddButton("@LUA_MENU_SERVERLIST", function(a1, a2) + LUI.FlowManager.RequestAddMenu(a1, "menu_systemlink_join", true, nil) + end) + serverListButton:setDisabledRefreshRate(500) + + -- private match button + privateMatchButton = menu:AddButton("@MENU_PRIVATE_MATCH", MPLobbyOnline.OnPrivateMatch, + MPLobbyOnline.disablePrivateMatchButton) + privateMatchButton:rename("menu_xboxlive_private_match") + privateMatchButton:setDisabledRefreshRate(500) + + -- combat training button + if Engine.IsCoreMode() then + game:addlocalizedstring("LUA_MENU_COMBAT", "Combat Training"); + game:addlocalizedstring("LUA_MENU_COMBAT_DESC", "Rank up offline with bots."); + + local FindGameButton = menu:AddButton("@LUA_MENU_COMBAT", + MPLobbyOnline.OnPublicMatch, MPLobbyOnline.disablePublicMatchButton) + FindGameButton:rename("menu_xboxlive_find_game") + FindGameButton:setDisabledRefreshRate(500) + end + + if Engine.IsCoreMode() then + menu:AddCACButton() + menu:AddCAOButton() + menu:AddArmoryButton() + end + + if not Engine.IsCoreMode() then + local leaderboardButton = menu:AddButton("@LUA_MENU_LEADERBOARD", "OpLeaderboardMain") + leaderboardButton:rename("OperatorMenu_leaderboard") + end + + if Engine.IsZombiesMode() then + menu:AddButton("@ZOMBIES_MENU_MOVIES", "ZombiesMoviesMenu") + end + + menu:AddOptionsButton() + local natType = Lobby.GetNATType() + if natType then + menu:AddHelp({ + name = "add_button_helper_text", + button_ref = "nat", + helper_text = Engine.Localize("NETWORK_YOURNATTYPE", natType), + side = "left", + clickable = false + }) + end + if Engine.IsZombiesMode() then + menu:AddZombiesStats(true) + end + + menu.isSignInMenu = true + menu:registerEventHandler("gain_focus", LUI.MPLobbyOnline.OnGainFocus) + menu:registerEventHandler("player_joined", Cac.PlayerJoinedEvent) + menu:registerEventHandler("exit_live_lobby", LeaveLobby) + + if PersistentBackground.IsCurrent(PersistentBackground.Variants.AARBackground) then + PersistentBackground.Hide(PersistentBackground.Duration) + end + + if Engine.IsCoreMode() then + Engine.ExecNow("eliteclan_refresh", Engine.GetFirstActiveController()) + end + + return menu +end + +LUI.MenuBuilder.m_types_build["menu_xboxlive"] = menu_xboxlive diff --git a/data/ui_scripts/lobby/menu_xboxlive_lobby.lua b/data/ui_scripts/lobby/menu_xboxlive_lobby.lua new file mode 100644 index 0000000..f4e02bd --- /dev/null +++ b/data/ui_scripts/lobby/menu_xboxlive_lobby.lua @@ -0,0 +1,95 @@ +local MPLobbyPublic = LUI.mp_menus.MPLobbyPublic + +function StartButtonAction(f2_arg0, f2_arg1) + Engine.SetDvarInt("party_minplayers", 1) +end + +function StartButtonText(f5_arg0, f5_arg1) + f5_arg0:processEvent({ + name = "refresh_disabled" + }) + f5_arg0:setText(Engine.Localize("@LUA_MENU_START_GAME")) +end + +function OnLeaveLobby(f6_arg0) + LUI.MarketingPanel.ClearViewedMessages({ + LUI.MarketingLocation.Lobby + }) + LUI.FlowManager.RequestLeaveMenu(f6_arg0) +end + +function OnGameSetup(f10_arg0, f10_arg1) + LUI.FlowManager.RequestAddMenu(f10_arg0, "gamesetup_menu_main", true, f10_arg1.controller, false) +end + +function menu_xboxlive_lobby(f7_arg0, f7_arg1) + local f7_local0 = false + if not Engine.IsZombiesMode() and Engine.GetDvarBool("ui_opensummary") then + f7_local0 = true + end + if Engine.IsZombiesMode() then + ZombiesUpdateMapBkg() + end + local f7_local1 = LUI.MPLobbyBase.new(f7_arg0, { + menu_title = "@PLATFORM_UI_HEADER_PLAY_MP_CAPS", + has_match_summary = true, + has_new_item_usage_widget = true + }, true) + f7_local1:setClass(LUI.MPLobbyPublic) + if Engine.IsMultiplayer() then + f7_local1:AddReadyUpButton("pt_AliensReadyUpPublicInUse", StartButtonAction, false, StartButtonText) + -- f7_local1:AddButton( "@LUA_MENU_GAME_SETUP", OnGameSetup ) -- WIP + end + if Engine.IsCoreMode() then + f7_local1:AddNewItemsWidget() + f7_local1:AddCACButton() + f7_local1:AddCAOButton() + f7_local1:AddArmoryButton() + end + f7_local1:AddOptionsButton() + if not f7_local1:CheckAddMapAndMarketingPanels(f7_local0) then + f7_local1:registerEventHandler("CheckAddMapAndMarketingPanels", function(element, event) + LUI.MPLobbyPublic.CheckAddMapAndMarketingPanels(element, f7_local0) + end) + local self = LUI.UITimer.new(100, "CheckAddMapAndMarketingPanels") + self.id = "MPLobbyPublic_add_map_timer" + f7_local1.mapTimer = self + f7_local1:addElement(self) + end + f7_local1:registerEventHandler("exit_public_lobby", OnLeaveLobby) + f7_local1:registerEventHandler("player_joined", Cac.PlayerJoinedEvent) + f7_local1:registerEventHandler("loadout_request", Cac.PlayerJoinedEvent) + Lobby.EnteredLobby() + if f7_local0 then + LUI.InventoryUtils.ProcessLootExpiration() + end + return f7_local1 +end + +LUI.MenuBuilder.m_types_build["menu_xboxlive_lobby"] = menu_xboxlive_lobby + +LUI.FlowManager.RegisterMenuStack("menu_xboxlive_lobby", function() + if Engine.IsCoreMode() and Playlist.GetPreselectedCategoryClass() ~= 8 then + return { + "mp_main_menu", + "menu_xboxlive", + "FindGameMenu", + "FindGameSubMenu" + } + else + return { + "mp_main_menu", + "menu_xboxlive", + "FindGameMenu" + } + end +end) +VLobby.InitMenuMode("menu_xboxlive_lobby", VirtualLobbyModes.LUI_MODE_LOBBY, function() + if LUI.MPLobbyBase.UseReadyUp then + Lobby.ClearLocalReadyUpFlag() + end + local f10_local0 = PersistentBackground.StackFunc(nil) + f10_local0() +end, LUI.MPLobbyBase.CollectGarbage) + +LUI.FlowManager.RegisterStackResumeBehaviour("menu_xboxlive_lobby", PersistentBackground.StackFunc(nil)) diff --git a/data/ui_scripts/patches/__init__.lua b/data/ui_scripts/patches/__init__.lua new file mode 100644 index 0000000..76790b2 --- /dev/null +++ b/data/ui_scripts/patches/__init__.lua @@ -0,0 +1,19 @@ +if (game:issingleplayer()) then + return +end + +function GetGameModeName() + return Engine.Localize(Engine.TableLookup(GameTypesTable.File, GameTypesTable.Cols.Ref, GameX.GetGameMode(), GameTypesTable.Cols.Name)) +end + +-- Allow players to change teams in game. +function CanChangeTeam() + local f9_local0 = GameX.GetGameMode() + local f9_local1 + if f9_local0 ~= "aliens" and Engine.TableLookup(GameTypesTable.File, GameTypesTable.Cols.Ref, f9_local0, GameTypesTable.Cols.TeamChoice) == "1" then + f9_local1 = not MLG.IsMLGSpectator() + else + f9_local1 = false + end + return f9_local1 +end diff --git a/data/ui_scripts/scoreboard/__init__.lua b/data/ui_scripts/scoreboard/__init__.lua new file mode 100644 index 0000000..f13240e --- /dev/null +++ b/data/ui_scripts/scoreboard/__init__.lua @@ -0,0 +1,30 @@ +if (game:issingleplayer() or Engine.InFrontend()) then + return +end + +function GetPartyMaxPlayers() + return Engine.GetDvarInt("sv_maxclients") +end + +local scoreboard = LUI.mp_hud.Scoreboard + +scoreboard.maxPlayersOnTeam = GetTeamLimitForMaxPlayers(GetPartyMaxPlayers()) + +scoreboard.scoreColumns.ping = { + width = Engine.IsZombiesMode() and 90 or 60, + title = "LUA_MENU_PING", + getter = function(scoreinfo) + return scoreinfo.ping == 0 and "BOT" or tostring(scoreinfo.ping) + end +} + +local getcolumns = scoreboard.getColumnsForCurrentGameMode +scoreboard.getColumnsForCurrentGameMode = function(a1) + local columns = getcolumns(a1) + + if (Engine.IsZombiesMode()) then + table.insert(columns, scoreboard.scoreColumns.ping) + end + + return columns +end diff --git a/data/ui_scripts/server_list/__init__.lua b/data/ui_scripts/server_list/__init__.lua new file mode 100644 index 0000000..f66517b --- /dev/null +++ b/data/ui_scripts/server_list/__init__.lua @@ -0,0 +1,5 @@ +if (game:issingleplayer() or not Engine.InFrontend()) then + return +end + +require("serverlist") diff --git a/data/ui_scripts/server_list/serverlist.lua b/data/ui_scripts/server_list/serverlist.lua new file mode 100644 index 0000000..ca06774 --- /dev/null +++ b/data/ui_scripts/server_list/serverlist.lua @@ -0,0 +1,76 @@ +if (game:issingleplayer() or not Engine.InFrontend()) then + return +end + +local SystemLinkJoinMenu = LUI.mp_menus.SystemLinkJoinMenu + +game:addlocalizedstring("PLATFORM_SYSTEM_LINK_TITLE", "SERVER LIST") +game:addlocalizedstring("MENU_NUMPLAYERS", "Players") +game:addlocalizedstring("MENU_PING", "Ping") + +local offsets = {10, 400, 600, 900, 1075} + +local columns = {"@MENU_HOST_NAME", "@MENU_MAP", "@MENU_TYPE1", "@MENU_NUMPLAYERS", "@MENU_PING"} + +SystemLinkJoinMenu.AddServerButton = function(menu, controller, index) + local serverInformation = nil + local button = menu:AddButton("", SystemLinkJoinMenu.OnJoinGame) + + if index == nil then + button:makeNotFocusable() + serverInformation = function(i) + return Engine.Localize(columns[i]) + end + else + button:makeFocusable() + button.index = index + serverInformation = function(i) + return Lobby.GetServerData(controller, index, i - 1) + end + end + + for size = 1, #offsets do + SystemLinkJoinMenu.MakeText(button, offsets[size], serverInformation(size)) + end + + return button +end + +function menu_systemlink_join(f19_arg0, f19_arg1) + local menu = LUI.MenuTemplate.new(f19_arg0, { + menu_title = "@PLATFORM_SYSTEM_LINK_TITLE", + menu_width = CoD.DesignGridHelper(28) + }) + Lobby.BuildServerList(Engine.GetFirstActiveController()) + Lobby.RefreshServerList(Engine.GetFirstActiveController()) + + SystemLinkJoinMenu.UpdateGameList(menu) + menu:registerEventHandler("updateGameList", SystemLinkJoinMenu.UpdateGameList) + menu:addElement(LUI.UITimer.new(250, "updateGameList")) + + menu:AddHelp({ + name = "add_button_helper_text", + button_ref = "button_alt1", + helper_text = Engine.Localize("@MENU_SB_TOOLTIP_BTN_REFRESH"), + side = "right", + clickable = true, + priority = -1000 + }, function(f10_arg0, f10_arg1) + SystemLinkJoinMenu.RefreshServers(f10_arg0, f10_arg1, menu) + end) + + menu:AddHelp({ + name = "add_button_helper_text", + button_ref = "button_action", + helper_text = Engine.Localize("@MENU_JOIN_GAME1"), + side = "right", + clickable = false, + priority = -1000 + }) + + menu:AddBackButton() + + return menu +end + +LUI.MenuBuilder.m_types_build["menu_systemlink_join"] = menu_systemlink_join diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua new file mode 100644 index 0000000..98b13d4 --- /dev/null +++ b/data/ui_scripts/stats/__init__.lua @@ -0,0 +1,204 @@ +local isclasslocked = Cac.IsCustomClassLocked +Cac.IsCustomClassLocked = function(...) + if (Engine.GetDvarBool("cg_unlockall_classes")) then + return false + end + + return isclasslocked(table.unpack({ ... })) +end + +local isdlcclasslocked = Cac.IsCustomClassDlcLocked +Cac.IsCustomClassDlcLocked = function(...) + if (Engine.GetDvarBool("cg_unlockall_classes")) then + return false + end + + return isdlcclasslocked(table.unpack({ ... })) +end + +if (game:issingleplayer() or not Engine.InFrontend()) then + return +end + +game:addlocalizedstring("LUA_MENU_STATS", "Stats") +game:addlocalizedstring("LUA_MENU_STATS_DESC", "Edit player stats settings.") + +game:addlocalizedstring("LUA_MENU_UNLOCKALL_ITEMS", "Unlock All Items") +game:addlocalizedstring("LUA_MENU_UNLOCKALL_ITEMS_DESC", "Unlock items that are level-locked by the player's stats.") + +game:addlocalizedstring("LUA_MENU_UNLOCKALL_LOOT", "Unlock All Loot") +game:addlocalizedstring("LUA_MENU_UNLOCKALL_LOOT_DESC", "Unlock supply drop loot.") + +game:addlocalizedstring("LUA_MENU_UNLOCKALL_CLASSES", "Unlock All Classes") +game:addlocalizedstring("LUA_MENU_UNLOCKALL_CLASSES_DESC", "Unlock extra class slots.") + +game:addlocalizedstring("LUA_MENU_PRESTIGE", "Prestige") +game:addlocalizedstring("LUA_MENU_PRESTIGE_DESC", "Edit prestige level.") +game:addlocalizedstring("LUA_MENU_RANK", "Rank") +game:addlocalizedstring("LUA_MENU_RANK_DESC", "Edit rank.") + +local armorybutton = LUI.MPLobbyBase.AddArmoryButton +LUI.MPLobbyBase.AddArmoryButton = function(menu) + menu:AddButton("@LUA_MENU_STATS", function(a1, a2) + LUI.FlowManager.RequestAddMenu(a1, "menu_stats", true, nil) + end) +end + +-- button stuff for configuring +function IsEnabled(dvar) + local enabled = Engine.GetDvarBool(dvar) + if enabled then + return Engine.Localize("@LUA_MENU_ENABLED") + end + + return Engine.Localize("@LUA_MENU_DISABLED") +end + +function ToggleEnable(dvar) + local enabled = Engine.GetDvarBool(dvar) + if enabled then + Engine.SetDvarBool(dvar, false) + else + Engine.SetDvarBool(dvar, true) + end +end + +function GoDirection(dvar, direction, callback) + local value = Engine.GetDvarString(dvar) + value = tonumber(value) + + -- get rank data + local max = nil + if (dvar == "ui_rank_level_") then + max = Rank.GetMaxRank(CoD.PlayMode.Core) + elseif (dvar == "ui_prestige_level") then + max = Lobby.GetMaxPrestigeLevel() + end + + local new_value = nil + if (direction == "down") then + new_value = value - 1 + elseif (direction == "up") then + new_value = value + 1 + end + + -- checking to make sure its < 0 or > max + if (new_value < 0) then + new_value = max + elseif (new_value > max) then + new_value = 0 + end + + callback(new_value) + + Engine.SetDvarFromString(dvar, new_value .. "") +end + +LUI.MenuBuilder.registerType("menu_stats", function(a1, a2) + local menu = LUI.MenuTemplate.new(a1, { + menu_title = Engine.ToUpperCase(Engine.Localize("@LUA_MENU_STATS")), + menu_width = GenericMenuDims.menu_right_wide - GenericMenuDims.menu_left, + menu_height = 548 + }) + + menu:setClass(LUI.Options) + menu.controller = a2.exclusiveController + + local itemsbutton = menu:AddButtonVariant(GenericButtonSettings.Variants.Select, + "@LUA_MENU_UNLOCKALL_ITEMS", "@LUA_MENU_UNLOCKALL_ITEMS_DESC", function() + return IsEnabled("cg_unlockall_items") + end, function() + ToggleEnable("cg_unlockall_items") + end, function() + ToggleEnable("cg_unlockall_items") + end) + + local lootbutton = menu:AddButtonVariant(GenericButtonSettings.Variants.Select, + "@LUA_MENU_UNLOCKALL_LOOT", "@LUA_MENU_UNLOCKALL_LOOT_DESC", function() + return IsEnabled("cg_unlockall_loot") + end, function() + ToggleEnable("cg_unlockall_loot") + end, function() + ToggleEnable("cg_unlockall_loot") + end) + + local classesbutton = menu:AddButtonVariant(GenericButtonSettings.Variants.Select, + "@LUA_MENU_UNLOCKALL_CLASSES", "@LUA_MENU_UNLOCKALL_CLASSES_DESC", function() + return IsEnabled("cg_unlockall_classes") + end, function() + ToggleEnable("cg_unlockall_classes") + end, function() + ToggleEnable("cg_unlockall_classes") + end) + + local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0 + local experience = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience") or 0 + local rank = AAR.GetRankForXP(experience, prestige) + + local prestigevalue = prestige + local rankvalue = rank + + -- save changes made + local save_changes = function() + Engine.SetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige", tonumber(prestigevalue)) + + local rank = tonumber(rankvalue) + local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0 + local experience = rank == 0 and 0 or Rank.GetRankMaxXP(tonumber(rankvalue) - 1, prestige) + + Engine.SetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience", experience) + end + + -- back callback + local back = function() + save_changes() + LUI.common_menus.Options.HideOptionsBackground() + LUI.FlowManager.RequestLeaveMenu(menu) + end + + -- create buttons and create callbacks + CreateEditButton(menu, "ui_prestige_level", "@LUA_MENU_PRESTIGE", "@LUA_MENU_PRESTIGE_DESC", function(value) + prestigevalue = value + end) + CreateEditButton(menu, "ui_rank_level_", "@LUA_MENU_RANK", "@LUA_MENU_RANK_DESC", function(value) + rankvalue = value + end) + + menu:AddBottomDescription(menu:InitScrolling()) + menu:AddBackButton(back) + + LUI.common_menus.Options.ShowOptionsBackground() + + return menu +end) + +function CreateEditButton(menu, dvar, name, desc, callback) + local prestige = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "prestige") or 0 + local experience = Engine.GetPlayerDataEx(0, CoD.StatsGroup.Ranked, "experience") or 0 + + local dvarValue = nil + local max = nil + if (dvar == "ui_rank_level_") then + dvarValue = AAR.GetRankForXP(experience, prestige) + max = Rank.GetMaxRank(CoD.PlayMode.Core) + elseif (dvar == "ui_prestige_level") then + dvarValue = prestige + max = Lobby.GetMaxPrestigeLevel() + end + + Engine.SetDvarFromString(dvar, dvarValue .. "") + + menu:AddButtonVariant(GenericButtonSettings.Variants.Select, name, desc, function() + local dvarString = Engine.GetDvarString(dvar) + + if (dvar == "ui_rank_level_") then + dvarString = tonumber(dvarString) + 1 + end + + return tostring(dvarString) + end, function() + GoDirection(dvar, "down", callback) + end, function() + GoDirection(dvar, "up", callback) + end) +end