From 3a6f9681b6fbdf729ebd828f443872736e40ee9d Mon Sep 17 00:00:00 2001 From: diamante0018 Date: Sun, 16 Nov 2025 21:44:07 +0100 Subject: [PATCH] init --- LICENSE | 29 + README.md | 7 + data/gamesettings/mp/gamesettings_escort.cfg | 26 + data/launcher/bigboiii.jpg | Bin 0 -> 14308 bytes data/launcher/main.html | 146 + data/launcher/noise.jpg | Bin 0 -> 58463 bytes data/lookup_tables/dvar_list.txt | 7026 +++++++++++++++++ data/scripts/mp/bots/_bot.gsc | Bin 0 -> 15384 bytes data/scripts/mp/bots/_bot.gsc_raw | 1125 +++ data/scripts/mp/bots/_bot_loadout.gsc | Bin 0 -> 15500 bytes data/scripts/mp/bots/_bot_loadout.gsc_raw | 854 ++ .../mp/gametypes/_globallogic_player.gsc | Bin 0 -> 91376 bytes .../mp/gametypes/_globallogic_player.gsc_raw | 4524 +++++++++++ data/scripts/mp/gametypes/_serversettings.gsc | Bin 0 -> 4612 bytes .../mp/gametypes/_serversettings.gsc_raw | 209 + data/scripts/mp/teams/_teams.gsc | Bin 0 -> 12284 bytes data/scripts/mp/teams/_teams.gsc_raw | 670 ++ .../doubleclick_join_server/__init__.lua | 118 + data/ui_scripts/frontend_menus/__init__.lua | 156 + .../datasources_change_map_categories.lua | 96 + ...datasources_gamesettingsflyout_buttons.lua | 260 + .../datasources_start_menu_tabs.lua | 217 + data/ui_scripts/frontend_menus/utils.lua | 160 + .../ui_scripts/graphics_settings/__init__.lua | 148 + data/ui_scripts/lua_fixes/__init__.lua | 4 + data/ui_scripts/party/__init__.lua | 30 + .../datasources_start_menu_game_options.lua | 75 + data/ui_scripts/playlist/__init__.lua | 34 + ..._playlist_category_match_settings_info.lua | 15 + .../widget_playlist_match_settings_info.lua | 15 + data/ui_scripts/ranked/__init__.lua | 1 + data/ui_scripts/ranked/online_mods_loaded.lua | 23 + data/ui_scripts/server_browser/__init__.lua | 378 + data/ui_scripts/stats/__init__.lua | 421 + 34 files changed, 16767 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 data/gamesettings/mp/gamesettings_escort.cfg create mode 100644 data/launcher/bigboiii.jpg create mode 100644 data/launcher/main.html create mode 100644 data/launcher/noise.jpg create mode 100644 data/lookup_tables/dvar_list.txt create mode 100644 data/scripts/mp/bots/_bot.gsc create mode 100644 data/scripts/mp/bots/_bot.gsc_raw create mode 100644 data/scripts/mp/bots/_bot_loadout.gsc create mode 100644 data/scripts/mp/bots/_bot_loadout.gsc_raw create mode 100644 data/scripts/mp/gametypes/_globallogic_player.gsc create mode 100644 data/scripts/mp/gametypes/_globallogic_player.gsc_raw create mode 100644 data/scripts/mp/gametypes/_serversettings.gsc create mode 100644 data/scripts/mp/gametypes/_serversettings.gsc_raw create mode 100644 data/scripts/mp/teams/_teams.gsc create mode 100644 data/scripts/mp/teams/_teams.gsc_raw create mode 100644 data/ui_scripts/doubleclick_join_server/__init__.lua create mode 100644 data/ui_scripts/frontend_menus/__init__.lua create mode 100644 data/ui_scripts/frontend_menus/datasources_change_map_categories.lua create mode 100644 data/ui_scripts/frontend_menus/datasources_gamesettingsflyout_buttons.lua create mode 100644 data/ui_scripts/frontend_menus/datasources_start_menu_tabs.lua create mode 100644 data/ui_scripts/frontend_menus/utils.lua create mode 100644 data/ui_scripts/graphics_settings/__init__.lua create mode 100644 data/ui_scripts/lua_fixes/__init__.lua create mode 100644 data/ui_scripts/party/__init__.lua create mode 100644 data/ui_scripts/party/datasources_start_menu_game_options.lua create mode 100644 data/ui_scripts/playlist/__init__.lua create mode 100644 data/ui_scripts/playlist/widget_playlist_category_match_settings_info.lua create mode 100644 data/ui_scripts/playlist/widget_playlist_match_settings_info.lua create mode 100644 data/ui_scripts/ranked/__init__.lua create mode 100644 data/ui_scripts/ranked/online_mods_loaded.lua create mode 100644 data/ui_scripts/server_browser/__init__.lua create mode 100644 data/ui_scripts/stats/__init__.lua diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6e58633 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2026, AlterWare +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b67f02 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# T7 Rawfiles +This repo contains the T7 Rawfiles for T7x. + +Contributions are welcome! Please follow the guidelines below: + +- Sign [AlterWare CLA](https://alterware.dev/cla) and send a pull request or email your patch at patches@alterware.dev +- Make sure that PRs have only one commit, and deal with one issue only diff --git a/data/gamesettings/mp/gamesettings_escort.cfg b/data/gamesettings/mp/gamesettings_escort.cfg new file mode 100644 index 0000000..5b713e1 --- /dev/null +++ b/data/gamesettings/mp/gamesettings_escort.cfg @@ -0,0 +1,26 @@ +gametype_setting timelimit 5 +gametype_setting scorelimit 0 +gametype_setting roundscorelimit 1 +gametype_setting roundwinlimit 2 +gametype_setting roundlimit 2 +gametype_setting preroundperiod 10 +gametype_setting teamCount 2 + +gametype_setting shutdownDamage 3 +gametype_setting bootTime 5 +gametype_setting rebootTime 15 +gametype_setting rebootPlayers 0 +gametype_setting movePlayers 1 +gametype_setting robotSpeed 1 +gametype_setting robotShield 0 + + +gametype_setting scoreHeroPowerGainFactor 0.788 //Score earned towards Hero Weapons and Abilities are multiplied by this factor +gametype_setting scoreHeroPowerTimeFactor 0.788 + +gametype_setting spawntraptriggertime 5 + +gametype_setting disableVehicleSpawners 1 + +gametype_setting gameAdvertisementRuleTimeLeft 3.5 +gametype_setting gameAdvertisementRuleRound 3 diff --git a/data/launcher/bigboiii.jpg b/data/launcher/bigboiii.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da49e9fa5a7d0c827a1fa4e52445648d8ac29969 GIT binary patch literal 14308 zcmb8VcUV(f(>NMhXrb3YKx$~AB?f|k(h=z(5TqC&fQB9c1q)4j3j~l*rAS8uNEMYx zOXx^BfT$=zfrCd5qDQga&3V7?d4GTW?sK2JVed7o?3KM{X3fl+ncpkFH$Z~ttZb}6 zEG!@p3-AZ}{g!3L#@zg(lZ&I3jh*FxI_MzaV%GtI!os78F4kspSkDV`$8G<6`2}2w z{9pM0QUddSSw5Z}1X|Gizx4lqHF4tuuLJ;t_JLc82>dwkv7!Jh8vGwv^%(a54{US{ zUyY882F5rY!^HD0<^YTbVAbIN1NQ$v;DAWt@%S8Ij8Rx<%<*p>U&mhz2@H301xha9 zhJmhtTtL^kS<8?_Y06Yh>i95I)1VN7dx2!_~HVCIl$apJUrZ7+}u160SFH-KQA{o zpAa9vfS{m|AP+=XL|9M+fCY~yVL5)2jhzd4QIMCL7ij(edHo&&330LNvg)$2D1can zSlEPEevbeP0I{+Bd;RZfS=rcGKpbFBE}&Oc5X8#L!v4P_*nlytENp)4Lc-1>x~B4? zQT{diNEaF~68fJ>SpIhwpk!fX<6uAj38DYY&-UL=79mz)d0kWI-)kTU(99~tCImVI z`WcJRgB2q95yl>QtyT8#e~FAHnU@tK42vo!EI#R1h>_!DCM=1DB*-g66bY77LWgXD zi6rIDU{%mRc{5wA-*A7quo>Y0@|2ix*fJ&q;EJEq*s!VSE2juV))qO=MyF`TQ@`ko zMhX8G`22Qg`J_TkF4GbfXP7XjpEvVbPWIF4V7>28=?Rn5Si>SV`iD(wE%T}>XTkd2 zEaT0t-fh0kF0=f&y$|oH{E`B3d(#KpqeEUyV3>nC*9=xi7Rv#n8;%Fr{S~wijZjqC zhgRjNYGK)TP(?*o75h!oL0+_>%E3g_Z003MX1?i2R_5MHXyP`hW~E8G{tm1cykF-GPXGgMB}1CKcMHv=DAuZqg9;6CB1syd>RNW$o{U+xIJ$cLtX$ zC(mj*D1O4fy{*~Lk6^rSUzO?=cHi?7=M)zjE&s`b(7<#e^s8(X<_6R51&duVr0A33 z-;|o_C>4w!>2a*8?}Cjo4rG{gf%lwOk`v@#nW(gm9Afky`g8HCc-bOTh?%(e@%>!9LJ%jQrFKSGT$MGgez^ZrtR@zHk1F% z!)y#}=3%6c?^o7DosDYrquC(nU~JI$q%Ixqaq;s}<90N%AZz2_G zM2$UQks18LK1;+?AMMw`1r8+y3pwzN3Ix5!gzFIjEvTmb~2R||7 z&4%x#=;Kqnp)B1{)}2Rk_TS{fte?(@HPdBpzb3(dR9z<|+)P}nNFA@!XU?8>M0XpY zj)!zCUykOWuGG7 zxNRG2o=qgUBRsblPh1?~4hJ^vL8G_K2X9yT&KxiYN*~a#lE}bK@P7ceKfoV@1O89t zpO`tyKk?2Li{m@MmmnA&K{mC0SNxw{lymmuaC&22XqjYr+uMU*)Bu5rd`DadeWRCL*&0-{bYxOR4=%Wge#I+G;LpG*6e*_abi=dMr(J4mt zHgXkJ1iC&RL?jtNC*@#MKgs%eL(E`>nu@zKScyp$;&0G7=!D&Cg{_=-Z2Bqvyzj}% zL->xuXZL7#SUNW*v+l5ZbJ|nDp(1*`Apz9B8!M0(g+Y%Ls(z5&Y<&vCZk>JgBlD)! z*}m>>sOVY_=}Du)MORYa<8A}dwF&^uood~ly!n>h2I4?9fI!sj_WcdAY0Yx?l6fL$yXW;Czrg4Fdy=?*MXikqklo7`0rS=PlA@K z`cs7H@#0tBs`cS();8j2PXEcU0oe{#Z4fEZp^Pa$uP7T4W*F`gt%GU};azTpAud`s9V|{as#FKHDt&CBFC83KyYA{c-UFqjgU`|)1y@?DX4SgmBmk0K)b@?JvLXUBD8$5p zW8$RZuAlhhH|XL~)Z5=6?=Mj?QHPgft?wB;7N7j3%pjo7%Trf+?~EqrpkSt4D6dGLpGL3R^; zalEM)@BflK>0@PezfNiC-|7qU6i{vdCRKX4yq@FbXb?dkeX3|(C(gw5D)9p1q4Olb zM%r3u{r6JeF`~V;P!rbg7_UNe#p8&;Rni8~?qMzG#hK8g;z!#o-@j$+Uw_+afc>*KM_#p*c{U zP+vko+6Ms(8+9iHcZQ&$N&r)Mp*`W<3X^C96`&%GHh|xBuxUU0__L?VP4}}GU5~j+ z+!A1xh9!K`1A4&s!|BYYDiu9BUc~U|(KkDq-}triX7x0y zo@IB2$Bw?){`Q_(`M!#7^l7y!;Yk0K|G{B^vrOer!MInK_Gb0$XG#YjYi~1N&&yOr zRLpMYO*>GI8|W7o$P<-TukC(SlvkqS;$JV21Kh}Tp!U;1yTQmfW09%4I3AoUMai$R zYJK;vyIMO4EwmEV#MrcIl^<(m(ibLI0a|O-sbmeb<@mT;HQwnN$jSAwauka3lp1Ku zHG13)tbZ4It+|EHT*42Oe(`WFm;~O}YA}=mY|(#cl6+kz1za2XUX8 z^E(9&nPq*4@E;U?=BGy2?|aat8|#KJb*1>XgEur{8d5u8MTUz z+L@{4|CO)cDXu1obD zN;?-gHZ#}=M73@MsW|VW9P*PoCC6rZ`r>$i$HXJF?kc*hqR_LM0Tkp52loN4LM#Hz zW%0#6@Eg1>3#gPGR{+NPLO`OMC$hDHck#s^8HTS532%EB@#X~NxqtA0Hfi_od8$zM zqp-VQLT?t}(<`wi<(;<2ivDs|!yZLn_!}}4|9A46u4(@MXm0^*jwmlQ@{>Qy0Y zd>p)=4c6?J_aY)S^-l#I^l0%;S&HMefuD_@-nw`PZr^FMRW)@0h?MM!r+Rju5^j?( zopyC?(B?JTn4VvStwCPu06rVGI>7dW6?&BN0$Iz z>bzzP2;xQN<*g56t<5~>sMWV)jlWWIJ$~{zY6l#3Uj2;!`!}c&ek|d9jEp08^QJ02 zh;gXq{6hS0&yoE_0hbuBpWv8_`bParc<9nqMUTnF%JW|!yTmxxmcL9Z-K`$nY5i${ zjJbFihiat*{|l4LzbYz!8W<()R!#kC+ABMj;WCs{?Z2wde4Y(XIR6{;o$sRd#iP0| z6@ZWEmF};BX?}yOs(c^rcCrx;fQi5L@wEUGEr$78>b0trtyTNKa5VTz0IF6izr7627?}Gs(rm;HL_*Kgbt`_nsuoDH)*x$+dMtX`di$eT_fM@xMGsdp-RnT=b>U8a;J*T;3i-OA^_EqGaq$w~A7F*aCi>D-KzNQ2 zp8O?B=!_F;%6*(Jl>^8f?2^sX1z?|7)xSP%)4H`Y(-6E#L40a|PeKUH!O+Hg= zh-fg@-Uj#}6R20s{K|xv{!jPL;#GLu5%8^6F+wY-CdPY*I=KBeDgSSaH`cufNOOHA z_W&S20J{*NbV)e9p;yV<;uU{GuFFZAD(q2q*8wW_s#F0+ z`P#LQmfM=gmY8P0R1Z^OyG!2kc1XCDW$NOn(LYD{zPvcYs^1{{bJJ;)Oh%N;&}3P0 zIo}-#O{(zFq;zpP`;?ZqI1bvYuOZHJQO-6yh!mJRF`8z}WKhpPF)cxBNM1FfFbj;1 z3=5h)hXHGFolHcPytXI!_dSvyT~#>1uTTd{2ebg~uTl-zjlBSo>wB60ugO!{0P_{J z=Gz}z1}bGe^rbGqcBlgk3&-H9o^)|Q(p5a>dL(a2H3f_YYE@Z9`zM)q6@_ugtE8&3 zgO+eo&s&l+p`Q(DN?;r@B?4 z1>cCkd2n&`$>qISUBG6Dvu!{e%m&%lS9w#m;HCG0BU89d&|J_|uA64KWp_Vtn&R$K z;t%2Irif{=_dx(sBq7+T-Xa*`FTQv~-21wbHhbVX}FJNYT=$vSYF-(@I#qES)bUqlO~Sah-E+81Le9QO(WJk<(L*%yBi@OkO*M5vca!ymy;t zvtU;L1mTccgD^Ub+J4h?C`_ARa($D{v%GL$7hB*>=(E(Jna3(f;&nZBxW9xtjNAR? z>CzbxX@*%)o;ZXwz0$cV;?m_OB9o-*tO{uZc7w94Z%_= zd9>2)=qBNYduB5{xD%H1Vm*+Nl$(t|P+5X{})lq3wRo-swFf2f*P)?i&1u!2?nA}B9pDVv;+djM3y zQR6HJwu;WF2ykQ7_w$MZR`81f?l%6Tmxc=%;?{~n?uxnAN>;EOo@Oke14&)N6@4Y8 zB62dhH0xJ#^YX1m!aY4Z%5kqSJaVe87fK|?e;}QrwfHuFiMzX=3)^Sd{}SCthM+Yt zB_XU%_np8G>Rj$+DuasE@uCx#%SFy5>F!@wq1ewgL_Ec_v@>b27E|;0dZW@(NpmfsKeEWA?4gLRh5;VL+P_3+dHsRnooc6R+~$D zADtSPO?>u#WsLP^`A=e-VMHSgJ00|%h`d>PSsDe0MZ)m2)^>+DSkxFG0#h{S$tV?; zaiBSBT*B1iuh3g8Cz29PweKq2;t)Avd0^Tkw5R$*(LCP|BpT17g~bdfej3D}MpNd> zbl4YCX8w4YaRaNLRI7f;smA)+%m(XQuy$9CS?adxow+43p?&}FTm<@70S_7v zmn}3ac`l7?B;(#wI;tt$Lfk`E-l4rfFHTzKk z^{pke7N!PnsSAz>3pE%#uouU_mK%Avg9}Ur95av-v|?o~g`<833-AsszU?yWP3be8 z0WylYS~pWpKV!XFmKQT-_v0k=3*koRa31D4hEbJw`7407G`mCa)E@UZfHYpw=#CeR zbUx_``^djQ)d6&R+94Dxz@g`MRT`6_j&rGk4K%cGd{ik}xi z>rhV}XUiha)j4JIkJ^K^9F~(Chh-H!1nSB0YBY|!t-p1sr)|LBfin_tYbmo74b7GM z-c`*_+2jmkv$n3u-sj34&c~ro^V{S};-X5*7 zylsnHqWWKWKv_R<nN=>y%>ggnX*q@1d z!Ee%P0{{)&3H=hau(!dHgMM7f35yzv{$;|Vf7j&SExnnzQduv@n)&r2)!C4prQ-}2 z^vN5GzqIF^4HH*LwYPXO_f)Hf{DwY~6Tb)5vHIr7wz?*1I|!)w-ZyG&WRxh2#WnDElcg-PVkAN!yKcI!I zjD8j2b8b~Qk9VAdbt07j4Pg%Y%coLv?ujQ7+o4Li{itk4VH^$R$g>Vh(IgtS=?g#m z(4`c+BGV(}+Ks9gXl_6W6;WZ3j=87EOYaG8cwKiU2vdcf7h4eC2SpB%l zQgL^~z-H*y!_PSLrIh*jedRxmeBvLVcWH)8DGTvbhtGT-rJr$?yT;b7?6c0%<7J;W zY(0R1RQX++oyk%*VN$lkE_Ffp9CVlinYd4j;ZEh3J1wc7$D?cRikY<<2^G#$*s_MI*0WI zH-h>iRH_{)>Po=ysXlV2O8>IEkkN(mXJHiDq6vY8r zNx#hO-i{>v7>$P2tD1S?kn8N-i7RhCr_-j>EpI>ncIt#Y+JCj6*^j4hDKccvmPdGa z##;6MGpWN6V%hqqR^U;ZZ`G^TK6|=Xy*)$AO19A2OSC?Xa1T(RJBmdasN8(NFb+KU z1N?)G^md1ih;&NNaBL>>{J@Ne?jf!4?!+ClcW?;wA*F}+F5g-_@8#_ejWu`q`2)Hz zhd!*)M|%Fap(M;sZXO#PVB{;ot4X?J5n#K&{G7b+{^i7}YDnUo;NKz{*sRxsiHv98 zY=#od^yeMfN?m1n|F~_$a}D;ajHmuoMvU4e@d;-Q)e^HFXS+nJ&sl^?Pmb58TUYV1c9m*qM=IRm?$y!_tDc=SBeqBi=Pr%YoM4$JlFVj z=Oz28j4$EJalMT9uT^SpgvR|tTShs(I86`tpFDdX;Lf`4%uxUACxzH>c|DypzY?wh zOMH(*8ePN?3b{;PN^2Fd_#xS5dcnXl+#<)>OVG!w*nLE-!!7ijc6-)tz-)82dVs=F zeM`SWi>-R$1vTdhH6r@fg?{0b4FHWHwXd6&@Yksib#lp6T?p6c!-cX}pe69Q-t-bRC*IWY>hOyJuG{MywKy@_29(P7gR?nq8A0FDqHW&N z$j-spV0)~T9D%C5OWQ%4`PNPp1ELx6fV2KHSN!zE}I2UYob+IY)QG;M$C7k zvrb|6miVHjO_+{v?G|w9b9b$P-)<`5X%( z_Ce>w?1QdNs{1=aUm1znUqg*2@A_Yqg%qj(O+n|{*{ZVFoWF|%1mOgWx|^ydX|Xx; zo@HlICvTuSJWzDbWkRi}*-zxeUA{}=^M}hdxLNA^6_LHR6)2g%8u##rI@bn2+Yu7) zJv-NMio+XKCB zC=JvR>&BiuW&ALDX?Z>Tdav8wrx^70QxlW4MURjBpCTR{{u9x3Dt3N}!|ncCg3G|-Xp6rbvu$_oo?scyy`$AT#{$;9QFhz%n*NxZ*oNu@_64D@ zGi6lIx3pKnM|PHPX@F0PpQS7}UiU;cXgaXV9aKiWXp_;|fkcp2v?EUqdtu_a8>zcU~t9zg~1c?yS5idFtHc(3AXx z+xl)PuLg2|3BGKkJwM;^#>a~5LnCK@m<&y3;D(HHu&naKjj{=y>w3<~!FAxRU|Dmw zM0lHQ`Fs+}ijN>yM!lNN(d7{dJcTXI#XB>aFiix}jMERf39`jF`WmUTh_!|4;dU!$ zjk@MKe^XVV?5D(nXBKsrbiZE0Eigtt`vUTzT02WSPpi3j-no6J?v1s%c#jnQd(W2p zwlVil$#!qx-IC*VwX;qcj&j^m9K^_yC(dw_&mVfeMTV4qy=YzJ>I)*=?Fkv;bB?Jn zS;E=6`!4M%x2Cw%O4xBnYsHV8k}lTey?e*(4^#fMtzeKSx4p<# zt=V&As+MvNYWYxV(QZQP{JkPCwHTc$WaNw_W}x)vubZIZ3mgw`$!aWW-7F1(o=#4~ zZ&&7ED0epxtW=w-liElIc%n#Ko(-S*BH@Q{p#eTA`-FMwo)}biDrYlA*$Q^vfv)@~ zqF9`MS@vdep^v+O^IX})KZxdl@qt3#o!4(ZymaRZZv}4!ZoITwICEQK2M}yO7bEu5 zc6DNk5jTFW-R%9L(Cc_iyE&i6%&(TQ)tolYpZ>W_wGOZ5d>UTO9=k&gKi{$OqLHRq zc0=|_vRd0E4F-4=11MQlk*xWiFgHExx>~>2LYg%hX+@}&+ zIbxQtbbI*(x-Ij?6nl8iwB@$zIAsv!4$bu*j+&B^S|GPkt*O^${w|6%O#f=HYjhXo z>By$c+f;CTr0G2Gr50?H;bWMj?HO`6-6wZqI-~M>@^!)fKZsXdT{<)8D(AWZBdFiA zL!{}B%eXUt!&aa)0QEW}8t&N&cV-2u#fVN2+@nyc{kd6Epg?q!wIn8j3p0@a3hTv} zP+Pvkv~KWs$8g7d>Ft56O+&_G2({4X~uJk~& zl|6PrWdDn1Q{EatgYo<@jABoY>{55ce&L!9(2)HvdG@cDI466l()wLxWy-E?mrd&l zgiq)=905d;RovNEe)!^tapS^<`DJRjd+4Z*+mS$R@8%}+P<`%s% z+HUfPJ5Oud+Aht^{YuNkpQ`PA=f-O#+sA4JEOZ5l&Dj_7+@L&!rpN|OwsG*^q_34D zWnzG{%!*Ctq*{?{)4M~>>2oD2*M$6w`qI(r%AMSM$*tTK>uvCBg8MGakKnDKDTjUe zje8?TQpIJI4O=zap^}vN%ry>V(Mg_5fEf}fI^i^@d3U+%_TP+QJ=(C{Eg*bt@pS&a zTKy;4q_90eiIrJ)@j+2klraVH(Js*rQv5nKsvO=IO4eWrx=NVQNKGqPo<*L)MS1tu z9CwD)ih*~DLN{Qaw`{u6RWsM;ooE)H<)u%Lo`kR_02w|pDlrvAZZLz`Vks1wMwDCE#t#bF6D7Fhp0#*WUyF+&x!S{k?UFVZDfok(m zPa~(zbL>I6W1@=!f18>HEJNzXbrSsMjY%wetLr8cxd}w>OeX7+?eRI(h!~qtF54-Ikmf2eu|FHl_W}m zr*5zY5Vw67=4mh=>kknMKDk$g_u^)sN=_-4zVoxAU6=x#~LDtF?IWHtSlpeUPoZ>P?Qcfuu%6?9p^kc;uAm|brIcbVOw|6O!5z>G=Z!nnE zUTwCyPMhsdt^Y|pw$%_Y|76~-2o5cM9 z4EW2gII!$*bcX1UgWub|J;TqJ6;L}X8XfAE{3j+)Z79ltr?!n#3>TtSQUSRT=`4ox zUrOFKTS{tm+Iqky-g!Y3P#kijCN+@dn#iP<^pTYmO{*|LnCT1Cj=lF6gvQxW{Uv2X zvvt6E7(3BX?|Rnm86_z(PV~7ny`(^}w?JD_*21Vf=lLs}SJp=4Rd{LriahfQJsqua zvQhZpUpjbFdkXBNc`u)&OIbd={amwtL7s91nHif(LiI=cjl+CSJb0Y!GuquRy3G74 zo47iPN?hg*22qB9{3C80ZfokDI(Ek76ik(P%hWu{1<0;ZOqaaR!3eUtcUyh4co@@< zkS!5ZPANRbacj_77uqCFd^nZgRveF^s^?)1NmapD5}`=VdIk_z8WW~<@dhE9TzM`@ z0pBubYtrxBb;$iwEA?E8Mp8qRst4OO$lFlU_Mjm%4sKzjsH)jSskghRM-r*#*&WYk zZ`f`_c|=tghs-#+M790Qa&>eXKCpZcj2&?blaY%4Wi!%_*@VZUN+3(gV6Qs(byn=8 zS;;mS7nm5Nvp`AhlAO{k)$mL;ssKvmq|1Vv(A1MU3V3{)ek$Lmi-g&i?j7xLr9>Lew@%3m(d-GHJA>&>d0z390F5o>E9uAu5XFx z7MkPEIvUmNC)~FcIiu;tsR>}#eW5j0E@;;@U4WL;gNdEmXYMFs9=u4(VRo+Ksuyy zOIWcCKjK)3lgqQ!JRl|$G*&vLS+0WO4T5VKlzQn-E3BCXP*PFH6zxFpp1lJcu^0`Z z%Jr_0C{5)YtXH)1_?dY-g03ImTmx)hIoHZIqP8^Trs!B9pz~B#uIzE=FF4f|$5PXdG}BM=l%AYUJ;@UzJAde9+B5^d1PI79XP1VpVD4hp^Ed88iZn3R5SU@o z=mH;*T;(0taSOV_AQ? z(9Z)T)``nkB$cp{kgMuYKrsTC6ypSfnZVj70M8M*I0SxdwpTV}_^~X?ZBye`t^bWbcV$IegC|Lsft%9%zTkO+CND zz9KHI#fE8)RDM=E!-naJ3VqwA=M9b`ZlEY*cUS)vS&{RFLz8&#j^`sB2mt-7K!6X) z{;P73v0x~M&`k6rA3=tKo~`MNPMpR;bEmCB9o039?iF#HO^jwzOp4WtSe+IyRZdVB zN*mPNr9o)?2PT0ntMpsOBSrDOD*u-Sld%qxM^#yC=rG26&AP(%f~G_9sa!8EVHyJ` z(VALHYY)L|_JIuLj7S2zFy;EG}ZUYFNNmi>HTblSFNo%mE${ELFtOA@0=qql7@ zMfq{uva8gxXBw881KcU51?h8DrrnW1Ksrn(6Q>|l;SsFbaS{L+dlHCU9G4|0Pg@g{ zZq)zfDHp70z%pUav=slennt8`7~YOrkggCOe||4<6CRfI$l?boA7I{QZ#K2LUn-Gk z4Lx|#I<%>EJZ12jR#(QmHkr+;Y@_QxfP>QF$SqX1k+p=~ExR5j(F+KMaB7ss#&d^T z-=i2YfdDJpoGs_Q^r{kk4Faz9z!vG07q`8|waMq3X8`yp__eqZP<%A&~r}r>S(n{HSHp zqe%}5KkGlYyq@BlyoT2Nmk;JTAB%M8Uf4T(}kRO}8R3~?kL8qi=uSvk2=HANxAZ>6A+;`-P2K5U5e<}tD`RrRmTo@K6Q zVJfFNZl=l($!$pH4r7l5olmf)8sPA%I#0k~nbE3FrI5D?vV4DUG^oFR)8QPWtDg=2 zN_7*%skXAY3SY}Z>~Fl?$$$T_OL6|dB+nSOEcF-`Z@^<<8EWU_o#*UDsuNWd@=z>t zXQDeSLphp;=jrq5bu9iErvFLcz(Ko!*&?E&T9`EdV_|wD*Ms$c%-KXBK+904GW~hP ztt>vWx&u+1WH!Kc-*0ky0>fQhWA_U*nltw>GfwikGV{3zo{SydE40N@)yGt>@-M@$ zo*cd~l?2F0?i+X51}TPgdjQjPnm1Nz#abNPBf`PJF{w#_X~7bYHSkV_#bXEv4}QsF zEP?9!O2upxV>1Dl8T&h;krBg9*CJrq3XTSQ*x z@jAhKsbYQNbr5%DYgn7f&trAWRwOe4S|v%@Q})1xW0#~X26HY8A6(|{w9zcgRw`UY zsE1%n#$-Z-v16qHn1(Adsi?9HgDXbKfwViSzzRc^()qmA7rT_j`rp?TEi-BH24=c^ z;jUg#Y==5#EMs?wFx)n=_&3!GA-s3IiZ9fq3HIxH0Xf?{KzsXI;`(b zCnE#y2I+&~`iA*_b~dyoS~l1Mf>p)>rYxw9&rQ+X5|+iPdgyYYPswyUO(EYB8Q{{< zianb$&)vX67+Pu~cqHxk@-_$`<1^_`r=_N{(mNwj5$T+Kb_wE&|Dw;0cr(8WasQk~ zWu``9%X=cW<XjzWML~j!O>V(b-f!cXOOmMAsq6#t>L=~XkL^x-yREAS=fsPvXuuZ8g-ko(Y zGRiS$qx6^1gEwvo{Fv|6FgItnV3<|yzy#rI)R-l@sAgQa4Q*vzm&c=e2yCmja&;Td z`WBPvOc<4ULKduS?u9T2!;`mu8FVmFdb0Y;fujA$FZmOZ7omJVH`0xeuH?`zx}F+ z5(`Y=Y55v8(kiyJ-2w!pE~IHw|5zOtYSc}Kfpz%yHWS4U+2S!9RMfUe9*=*{#dO%& zMKq^MA7&HXRKufz+0;~jFmE3WlgeuO>XZ({JEd}OZ)T{Pe*S^kC<+EX^7rch1En*7 AmjD0& literal 0 HcmV?d00001 diff --git a/data/launcher/main.html b/data/launcher/main.html new file mode 100644 index 0000000..cbe85e0 --- /dev/null +++ b/data/launcher/main.html @@ -0,0 +1,146 @@ + + + + + + T7x + + + + + +
+ +
+

+ BOIII +

+
Play
+
+ About +
+
+ + + + diff --git a/data/launcher/noise.jpg b/data/launcher/noise.jpg new file mode 100644 index 0000000000000000000000000000000000000000..073a70255814f458f4723cb221a740c3d60baf52 GIT binary patch literal 58463 zcmbTdc{E#H_&=)Efuc%@*4P@`5?W)6QdLvaRM8p|!)q21sn!rRwbVQnEk#i?CDf3F z2#TPpY6wXsro>RQq>8+z{=C2Yz4xwl|GM`+=j^r4T4(Qbp3mB6@BKWV{W*Vs{+;1C zci-5|nB&;7V;uh+9UOmY9EKdnj~)B({2${y$@!n1I&p&YwD z0>?N7j{PNaNO5o+J9*^oe-8hT9Xrl>;^e6#m(K7URluA(a-Wm)_>r?GPnk| z68Gy)zi=uM!3RkXPQ`gYc zx_L|6@Sc&eiK*FrtH)2QZEWozu5Rugo?bBT=l%hKL8#ytQLm$8V&mcy(lg$^%glP8 zol{g?Qd(ACQTeI9p%H_{H8tZqyNKOAy8SDf}G z&C<3{WO6^Uei5BSP*FXgnQ4J#DgL!T12AXiWd28ue?!fXD)E=k(XJUGQyU@uV)kki zrQa=S-zvpb-zSZLub;B%aF4a8Y%LXL(f@L!h8i%E^#(%0Av$4M7A<7N;qZ1p2)0`E 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 M3t45fBmbNDKN6zbSpWb4 literal 0 HcmV?d00001 diff --git a/data/lookup_tables/dvar_list.txt b/data/lookup_tables/dvar_list.txt new file mode 100644 index 0000000..b118711 --- /dev/null +++ b/data/lookup_tables/dvar_list.txt @@ -0,0 +1,7026 @@ +AmmoBoxPickupTime +BotCount +ClickToContinue +GameDescription +HTTPD_CmdFence +HTTPD_Port +HTTPD_StaticRoot +MapName +MaxPlayerCount +ParallaxHUD +ServerName +ServerPassword +ShakeHUD +TestIntervalJitter +UI_enabled +UI_highlightScaledText +UI_safeAreaOverride +UI_showSafeArea +ViewAngleOverride_cameraInputDeadTimeMs +ViewAngleOverride_cameraInputThreshold +accelspeed +actors_walkable +addMapPackFlagsUserInfo +addfavourite +adsZeroSpread +ai_ShowCanSeeChecks +ai_ShowCanshootChecks +ai_accu_player_lateral_speed +ai_accuracyDistScale +ai_accuracy_attackerCountDecrease +ai_accuracy_attackerCountMax +ai_adjustOffMeshNodes +ai_allowCachedConditions +ai_allowFrameLimitedApi +ai_allowLerpedCooldownTimers +ai_angularYawAccelRate +ai_angularYawDecelFactor +ai_angularYawEnabled +ai_arrivalLookaheadDistance +ai_avoidNavBoundaries +ai_avoidOthersAtCloseDist +ai_awarenessEnabled +ai_badPathSpam +ai_clampToNavMeshEnabled +ai_clientFacialCullDist +ai_codeGameskill +ai_corpseCount +ai_coverDistanceOffset +ai_coverFlankCheckRad +ai_coverFlankDistToCover +ai_coverFlankMaxAngle +ai_coverHeightOffset +ai_coverScore_coverType +ai_coverScore_dangerousNode +ai_coverScore_distance +ai_coverScore_engagement +ai_coverScore_flanking +ai_coverScore_nodeAngle +ai_coverScore_playerLos +ai_coverScore_priority +ai_coverScore_targetDir +ai_coverScore_visibility +ai_coverSearchInterval +ai_coverSpacingDistance +ai_debugAccuracy +ai_debugAnimDeltas +ai_debugAnimScripted +ai_debugArrivals +ai_debugCodeBehaviorTree +ai_debugCoverEntityNum +ai_debugCoverSelection +ai_debugCoverTool +ai_debugEntIndex +ai_debugEntLock +ai_debugFindPath +ai_debugFindPathDirect +ai_debugFindPathLock +ai_debugFindPathWidth +ai_debugFlyingPath +ai_debugGrenadeHintArc +ai_debugMayMove +ai_debugMeleeAttackSpots +ai_debugTargets +ai_debugThreatSelection +ai_debugTurnRate +ai_debugVolumeTool +ai_debug_dynamic_nodes +ai_disableSpawn +ai_doNotDamageTeammates +ai_dogMeleeHeight +ai_dogMeleeRange +ai_dogMeleeWidth +ai_enableBadPlaces +ai_eventDistBadPlace +ai_exitLookaheadDistance +ai_findNavExternalFaces +ai_foliageIngoreDist +ai_foliageSeeThroughDist +ai_friendlyFireBlockDuration +ai_friendlySuppression +ai_friendlySuppressionDist +ai_generateNavmeshRegions +ai_instantNoSolidOnDeath +ai_maxAttackerCount +ai_meleeDamage +ai_meleeHeight +ai_meleeRange +ai_meleeWidth +ai_moveOrientMode +ai_navDisplay_Alpha +ai_navDisplay_FontSize +ai_navDisplay_X +ai_navDisplay_Y +ai_navDraw_DepthTest +ai_navDraw_Height +ai_navVolumeLayerIndex +ai_navVolume_Cave +ai_navVolume_fillCells +ai_navVolume_labelCells +ai_navVolume_showCellBorders +ai_navVolume_showEdgeConnections +ai_navVoume_colorCellsRandomly +ai_noDodge +ai_pathChokePointCost +ai_pathMomentum +ai_pathNegotiationOverlapCost +ai_pathRandomPercent +ai_pathSuppressionEnabled +ai_perfInfoSortType +ai_playerFarAccuracy +ai_playerFarRange +ai_playerLOSHalfWidth +ai_playerNearAccuracy +ai_playerNearRange +ai_scaleSightUpdateLatency +ai_secondaryThreats +ai_showClaimedNode +ai_showClearanceCeiling +ai_showCount +ai_showCoverScore +ai_showDodge +ai_showExternalFaceByIndex +ai_showExternalFaceWithEdge +ai_showExternalFaces +ai_showLastKnownEnemyPos +ai_showNavMemory +ai_showNavMesh +ai_showNavMeshBadEdges +ai_showNavMeshRegions +ai_showNavMeshSeeds +ai_showNavMeshSilhouettes +ai_showNavMeshTriggers +ai_showNavPaths +ai_showNavStats +ai_showNavVolume +ai_showNavVolumeStats +ai_showNearestNode +ai_showNodes +ai_showNodesDist +ai_showOffMeshNodes +ai_showPathFindNodes +ai_showPaths +ai_showPerfInfo +ai_showPotentialCoverLocations +ai_showPotentialThreatDir +ai_showSuppression +ai_showVisData +ai_showVisDataDist +ai_showVolume +ai_simplifyExternalEdges +ai_slowdownMaxYawDiff +ai_slowdownMinRate +ai_slowdownMinYawDiff +ai_slowdownRateBlendFactor +ai_stumbleSightFOV +ai_stumbleSightRange +ai_tacticalInfluencersDebug +ai_tacticalInfluencersThreatDebug +ai_testEdgeForCover +ai_testVertexForNearbyFaces +ai_threatUpdateInterval +ai_trim_path_zigzags +ai_useBetterLookahead +ai_useFacingTranslation +ai_useLeanRunAnimations +ai_useTacticalInfluencers +ai_validateBehaviorTree +ai_warnMissingNavVolume +ai_weaponCamoEnabled +aim_DebugTopDownAssist +aim_accel_turnrate_debug +aim_accel_turnrate_enabled +aim_accel_turnrate_lerp +aim_aimAssistRangeScale +aim_alternate_lockon_deflection +aim_alternate_lockon_pitch_strength +aim_alternate_lockon_region_height +aim_alternate_lockon_region_width +aim_alternate_lockon_strength +aim_assist_min_target_distance +aim_assist_script_disable +aim_assist_sniperADS_lock_on +aim_autoAimRangeScale +aim_autoaim_debug +aim_autoaim_enabled +aim_autoaim_lerp +aim_autoaim_region_height +aim_autoaim_region_width +aim_autograpple_lerp +aim_automelee_armblade_lunge_region_height +aim_automelee_armblade_lunge_region_width +aim_automelee_debug +aim_automelee_enabled +aim_automelee_lerp +aim_automelee_move_limit +aim_automelee_move_limit_angle +aim_automelee_move_limit_range +aim_automelee_region_height +aim_automelee_region_width +aim_input_graph_debug +aim_input_graph_enabled +aim_input_graph_index +aim_linkto_autorecenter_delay +aim_linkto_autorecenter_rate +aim_lockon_debug +aim_lockon_deflection +aim_lockon_enabled +aim_lockon_height_change_strength +aim_lockon_pitch_strength +aim_lockon_region_height +aim_lockon_region_width +aim_lockon_strength +aim_scale_view_axis +aim_slowdown_debug +aim_slowdown_enabled +aim_slowdown_pitch_scale +aim_slowdown_pitch_scale_ads +aim_slowdown_region_extended_height +aim_slowdown_region_extended_width +aim_slowdown_region_height +aim_slowdown_region_width +aim_slowdown_yaw_scale +aim_slowdown_yaw_scale_ads +aim_t7_assassinationmode_lerp +aim_t7_strongautomelee_lerp +aim_t7_weakautomelee_lerp +aim_target_actor_min_distance +aim_target_aim_tag_fast_update_interval +aim_target_aim_tag_slow_update_interval +aim_target_alternate_frustum_min_distance +aim_target_closest_first +aim_target_fixed_actor_size +aim_target_frustum_expand_fast_updates +aim_target_frustum_min_distance +aim_target_ignore_team_checking +aim_target_player_enabled +aim_target_sentient_half_height +aim_target_sentient_radius +aim_target_smp +aim_turnrate_pitch +aim_turnrate_pitch_ads +aim_turnrate_yaw +aim_turnrate_yaw_ads +aim_view_sensitivity_component +aim_view_sensitivity_override +airburstAdjustDistance +allClientDvarsEnabled +allCollectiblesUnlocked +allEmblemsPurchased +allEmblemsUnlocked +allItemsPurchased +allItemsUnlocked +all_players_are_connected +allocTracker_log +allocTracker_print +allocTracker_printstack +allocTracker_track +allowAllNAT +allowDLCWeaponsByOwnership +allowGuestSplitScreenOnline +allowHost_matchesHostedRatio +allowHost_matchesHostedStreak +allowHost_matchesPlayedRatio +allowHost_matchesPlayedStreak +allowTaskManagerRSU +allow_weapon_switch_during_swimming +amd_useShaderExtension +animScript_listAnims +anim_debugSpeeds +anim_deltas_debug +anim_intro +anim_visualization_enable +animscript_debug +animscript_xcam_debug +arena_bonusStarStreak +arena_defaultPlaylist +arena_enableArenaChallenges +arena_enableListenHosting +arena_giveBonusStar +arena_lobbyReloadSearchDelayMax +arena_lobbyReloadSearchDelayMin +arena_maintenance +arena_maxPregameCryptoSeconds +arena_minHostSkillRange +arena_minPlayTime +arena_minPregameCryptoSeconds +arena_qosBrodenSkillFrequency +arena_qosBrodenSkillStep +arena_qosSkillStart +arena_seasonOverride +arena_seasonVetChallengeWins +arena_unfairTeamGap +armblade_lunge_region_height +armblade_lunge_region_width +art_review +asm_animDeltaParamsThresh +asm_codeLevel +asm_debugAimLayer +asm_debugLevel +asm_debugPrimaryDeltaLayer +asm_debugShootLayer +asm_disableTransitions +asm_footMatching +asm_useNetworkFrameDelta +assassination +assassination_cinematic +assassination_counter +assassination_debug +assassination_debug_slowmo +assassination_default +assassination_height_limit +assassination_max_height_displacement +assassination_mode +attachment_exclusion_0 +autoExecDemoConfig +autojoin +balances_fakeFail +balances_retry_delay +balances_retry_max +banclient +bandwidth_retry_interval +banuser +beamDrawCurveVerts +beamDrawNodes +beamDrawSlackInfo +beamDrawWaveVerts +beamKillBeam +beamLaunchBeam +beamReset +beast_blur_radius_inner +beast_blur_radius_outer +beast_blur_time_in +beast_blur_time_out +beast_jump_blur_amount +behaviorTrackerVersionNumber +beta_special +betty_activation_delay +betty_damage_cylinder_height +betty_damage_max +betty_damage_min +betty_damage_radius +betty_detect_radius +betty_grace_period +betty_jump_height_onground +betty_jump_height_wall +betty_jump_time +betty_onground_angle_threshold +bgCachePrintValues +bg_ads +bg_aimSpreadMoveSpeedThreshold +bg_allowPlayerRoleTemplateButtonOverrides +bg_anim_blend_angle +bg_anim_blend_anim1 +bg_anim_blend_anim2 +bg_anim_blend_force_time +bg_anim_blend_fudge_time_offset +bg_anim_blend_ratio +bg_anim_blend_set +bg_anim_blend_speed_frac +bg_anim_blend_timing1a +bg_anim_blend_timing1b +bg_anim_blend_timing2a +bg_anim_blend_timing2b +bg_anim_blend_turn_speed +bg_anim_blend_turn_speed_max +bg_anim_blend_use_dvar_timings +bg_aqs +bg_aqsStyle +bg_arenaSlot +bg_blendTimeOverride +bg_bobMax +bg_bobTransTime +bg_bobcycleResetThreshold +bg_bulletPenetrationTreatVoidsAsSolid +bg_chargeShotAutoDischargeDelay +bg_chargeShotAutoFireDelay +bg_chargeShotCenterSpeedReductionPerBullet +bg_chargeShotDamageIncreasePerBullet +bg_chargeShotDischargeWhenQueueReachesMax +bg_chargeShotExponentialAmmoPerChargeLevel +bg_chargeShotMaxBulletQueueOnEMP +bg_chargeShotMaxViewKick +bg_chargeShotMinCenterSpeed +bg_chargeShotPenetrationMultiplier +bg_chargeShotUseOneAmmoForMultipleBullets +bg_chargeShotViewKickIncreasePerBullet +bg_counterMeleeTime +bg_debugNotifies +bg_deferScriptMissileDetonation +bg_disablePaintshopBaseIconTransform +bg_disableWeaponPlantingGroundTrace +bg_disableWeaponPlantingInWater +bg_dog_swim_enabled +bg_dog_swim_water_max +bg_dog_swim_water_min +bg_drawGrenadeInHand +bg_drawProximity +bg_enableIKActiveFix +bg_fallDamageMaxHeight +bg_fallDamageMinHeight +bg_foliagesnd_fastinterval +bg_foliagesnd_maxspeed +bg_foliagesnd_minspeed +bg_foliagesnd_resetinterval +bg_foliagesnd_slowinterval +bg_forceAnimOverrideTimerCheck +bg_forceDurationOverride +bg_forceExplosiveBullets +bg_force_idle_scale +bg_freeCamClipToHeliPatch +bg_friendlyFire +bg_friendlyFireMode +bg_friendlyfireDist +bg_grappleRequiresEquippedWeapon +bg_gravity +bg_grenadeMinimumThrowbackTime +bg_gunXOffset +bg_heavyWeaponsAlwaysPlayFirstRaise +bg_isolateDamageFlash +bg_legYawCrouchTolerance +bg_legYawProneTolerance +bg_legYawTolerance +bg_limitGrenadeImpacts +bg_lowGravity +bg_maxGrenadeIndicatorSpeed +bg_maxWeaponAnimScale +bg_meleePreLungeTime +bg_moonGravity +bg_movingPlatformPitchScale +bg_overridePlayerEmblemIcon +bg_perksCacheTestOld +bg_plantInWaterDepth +bg_playStandToCrouchAnims +bg_playerAnimStanceAllowMovementInteruptTime +bg_proneSwingSpeed +bg_prone_yawcap +bg_scriptCanDisableStances +bg_serverDelayDamageKickForPing +bg_shieldHitEncodeHeightVM +bg_shieldHitEncodeHeightWorld +bg_shieldHitEncodeWidthVM +bg_shieldHitEncodeWidthWorld +bg_slopeFrames +bg_specialOffhandInventoryAllowBallSwitch +bg_specialOffhandInventorySwitch +bg_swingSpeed +bg_t7BlockMeleeUsageTime +bg_t7MeleeControlScheme +bg_t7MeleeHeightCheck +bg_t7MeleeQuadrantMaxAngle +bg_t7MeleeQuadrantMinAngle +bg_t7MeleeUseAssassinationState +bg_teleportAlignTime +bg_ufospeedscale +bg_ufoviewscale +bg_useCharacterTable +bg_useClientDamageKick +bg_useT7Melee +bg_useThrowButtonForDetonatorGrenades +bg_vehicle_gravity +bg_vehicle_ground_max_normal +bg_vehicle_ground_min_normal +bg_vehicle_helicopter_dogfight_roll_control_scale +bg_vehicle_helicopter_focus_target_control_leeway +bg_vehicle_helicopter_focus_target_damping_angle +bg_vehicle_helicopter_focus_target_damping_exponent +bg_vehicle_max_body_pitch +bg_vehicle_max_body_roll +bg_vehicle_max_pitch +bg_vehicle_max_roll +bg_vehicle_overclip +bg_vehicle_pitch_track +bg_vehicle_placement_debug +bg_vehicle_plane_invert_pitch +bg_vehicle_plane_jet_controls +bg_vehicle_plane_turn_assist_decay_rate +bg_vehicle_roll_track +bg_vehicle_slide_min_normal +bg_vehicle_sphere_bounds_offset_z +bg_vehicle_stepsize +bg_vehicle_tangential_clip_max_scale +bg_vehicle_tangential_clip_vel_scale +bg_vehicle_trace_offset +bg_viewBobAmplitudeDtp +bg_viewBobAmplitudeDucked +bg_viewBobAmplitudeDuckedAds +bg_viewBobAmplitudeJuke +bg_viewBobAmplitudeJukeAds +bg_viewBobAmplitudeProne +bg_viewBobAmplitudeRoll +bg_viewBobAmplitudeSlide +bg_viewBobAmplitudeSprinting +bg_viewBobAmplitudeStanding +bg_viewBobAmplitudeStandingAds +bg_viewBobAmplitudeSwimming +bg_viewBobAmplitudeWallRun +bg_viewKickDeflectTime +bg_viewKickDeflectTimeAds +bg_viewKickMax +bg_viewKickMaxAds +bg_viewKickMin +bg_viewKickMinAds +bg_viewKickRandom +bg_viewKickRecoverTime +bg_viewKickRecoverTimeAds +bg_viewKickScale +bg_viewKickScaleAds +bg_viewanglesDebug +bg_vsmode_hud +bg_warmode_version +bg_waterGravity +bg_weaponBobAmplitudeBase +bg_weaponBobFrequencySwimming +bg_weaponButtMeleeCharge +bg_weaponCompatibleIfSharedAmmo +bg_weaponOffscreenReloadScale +bg_weaponSubtractFrameTimeRemainder +bg_weaponSwitchHero +bg_weaponSwitchHeroHoldTime +bg_zm_dlc1_chargeShotMultipleBulletsForFullCharge +bg_zombiePlayerUsesUtilityClip +bgcache_checksum_validation +bgcache_checksum_validation_demo +bgcache_disablewarninghints +bgcache_displaychecksum +bgcache_loaddevitems +bgcache_mark_used_assets +bgcache_skip_mychanges +bind +bind2 +blackboxBandwidthLimited +blackboxHighVolumeProbability +blackboxMode +blurpain +boostcheatBitchHKRatioCoef +boostcheatBitchHKRatioMean +boostcheatBitchHKRatioStddev +boostcheatBitchKillTimestampsAnomalyCoef +boostcheatBitchKillTimestampsAnomalyMean +boostcheatBitchKillTimestampsAnomalyStddev +boostcheatBitchKillsRatioCoef +boostcheatBitchKillsRatioMean +boostcheatBitchKillsRatioStddev +boostcheatBitchKillsTotalCoef +boostcheatBitchKillsTotalMean +boostcheatBitchKillsTotalStddev +boostcheatHeadshotsTotalCoef +boostcheatHeadshotsTotalMean +boostcheatHeadshotsTotalStddev +boostcheatIntercept +boostcheatKillerXAnomalyCoef +boostcheatKillerXAnomalyMean +boostcheatKillerXAnomalyStddev +boostcheatKillerYAnomalyCoef +boostcheatKillerYAnomalyMean +boostcheatKillerYAnomalyStddev +boostcheatMeanBitchLifetimeMillisecondsCoef +boostcheatMeanBitchLifetimeMillisecondsMean +boostcheatMeanBitchLifetimeMillisecondsStddev +boostcheatMeanDistanceBitchTraveledCoef +boostcheatMeanDistanceBitchTraveledMean +boostcheatMeanDistanceBitchTraveledStddev +boostcheatMeanDistanceVictimTraveledCoef +boostcheatMeanDistanceVictimTraveledMean +boostcheatMeanDistanceVictimTraveledStddev +boostcheatVictimXAnomalyCoef +boostcheatVictimXAnomalyMean +boostcheatVictimXAnomalyStddev +boostcheatVictimYAnomalyCoef +boostcheatVictimYAnomalyMean +boostcheatVictimYAnomalyStddev +bot_AllowAiming +bot_AllowAttack +bot_AllowGrenades +bot_AllowHeroGadgets +bot_AllowKillstreaks +bot_AllowMelee +bot_AllowMeleeCharge +bot_AllowMovement +bot_AllowSprint +bot_Debug +bot_DebugX +bot_DebugY +bot_DrawPerks +bot_ForceCrouch +bot_ForceFire +bot_ForceMelee +bot_ForceProne +bot_ForceStand +bot_Fov +bot_FovAds +bot_PitchSensitivity +bot_PitchSpeed +bot_PitchSpeedAds +bot_PredictCorners +bot_PressAttackBtn +bot_PressMeleeBtn +bot_SnapshotDebug +bot_UseFriendNames +bot_YawSensitivity +bot_YawSpeed +bot_YawSpeedAds +bot_difficulty +bot_enableWallrun +bot_enemies +bot_friends +bot_maxAllies +bot_maxAxis +bot_maxFree +bot_maxJumpDistance +bot_maxMantleHeight +bot_maxWaterMantleHeight +bot_recordButtons +bot_recordGoal +bot_recordGoalInfo +bot_recordHealth +bot_recordPathing +bot_recordPlayerFlags +bot_recordThreat +bot_supported +bot_traverseUnderwater +bow_launcher_bounce_max_scale +bow_launcher_charge_snap_percent +bow_launcher_minimum_reticle_scale +bow_launcher_rebound_scale +breadcrumbDistanceImportance +breadcrumbThreshold +breadcrumbTimeImportance +bullet_enterWater +bullet_penetrationEnabled +bullet_penetrationMinFxDist +bullet_ricochetBaseChance +bulletrange +cameraShakeRemoteHelo_Angles +cameraShakeRemoteHelo_Freqs +cameraShakeRemoteHelo_SpeedRange +cameraShakeRemoteMissile_Angles +cameraShakeRemoteMissile_Freqs +cameraShakeRemoteMissile_SpeedRange +cg_BallisticArc_BeginAlpha +cg_BallisticArc_BeginWidth +cg_BallisticArc_Debug +cg_BallisticArc_DrawDelay +cg_BallisticArc_EndAlpha +cg_BallisticArc_EndWidth +cg_BallisticArc_ForceHitIndicator +cg_BallisticArc_ImpactRadius +cg_BallisticArc_MaxBounces +cg_BallisticArc_MinBounces +cg_BallisticArc_Offset +cg_BallisticArc_PerpStep +cg_BallisticArc_VerticalOffset +cg_DrawOnScreenFriendlyAI +cg_DrawOnlyFriendlyPlayerNamesWhileInVehicle +cg_DrawPlayerNamesWhileInVehicle +cg_DrawRemoteVehiclePlayerNames +cg_EnableAdaptiveSkinLodScale +cg_InfraredFadeoutTime +cg_ScoresColor_Free +cg_ScoresColor_Gamertag_0 +cg_ScoresColor_Gamertag_1 +cg_ScoresColor_Gamertag_2 +cg_ScoresColor_Gamertag_3 +cg_ScoresColor_Spectator +cg_ScoresPing_Interval +cg_ScoresPing_MaxBars +cg_VelocityArrow_MaxSegmentLength +cg_VelocityArrow_MinSegmentLength +cg_VelocityArrow_RateOfChange +cg_WeaponButtAttackerCameraShakeDuration +cg_WeaponButtAttackerHitCameraShakeScale +cg_WeaponButtAttackerMissCameraShakeScale +cg_WeaponButtVictimCameraShakeDuration +cg_WeaponButtVictimCameraShakeScale +cg_adsZScaleMax +cg_adsZoomToggleStyle +cg_aggressiveCullRadius +cg_ai_useServerAnims +cg_allPlayerNamesVisible +cg_altDofTrace +cg_animInfoCornerOffset +cg_animMonitorEnt +cg_animMonitorFilter +cg_artilleryKillCamBackDist +cg_artilleryKillCamFov +cg_artilleryKillCamGroundBackDist +cg_artilleryKillCamGroundUpDist +cg_artilleryKillCamUpDist +cg_artilleryKillCamWallOutDist +cg_artilleryKillCamWallSideDist +cg_assignRandomPaintshops +cg_bloodLimit +cg_bloodLimitMsec +cg_blur_time +cg_brass +cg_cameraRollOverride +cg_cameraSpikeEnemyColor +cg_cameraSpikeHighlightBrightness +cg_cameraUnderwaterLens +cg_cameraVehicleExitTweenTime +cg_cameraVzoomToggleTime +cg_cameraWaterClip +cg_canSeeFriendlyFrustumExpand +cg_canSeeFriendlyFrustumMinDistance +cg_canSeeFriendlyFrustumUpdateInterval +cg_cancelChargeShotTime +cg_centertime +cg_chatHeight +cg_cinematicFullscreen +cg_circularMinimapWhenSquare +cg_clampFrameInterpolation +cg_clanNameDebug +cg_clientSideGlassTouch +cg_combatRobotKillCamDistFromEyes +cg_combatRobotKillCamForwardDist +cg_combatRobotKillCamFov +cg_combatRobotKillCamSideDist +cg_combatRobotKillCamUpDist +cg_combatRobotKillMinDistFromTarget +cg_connectionIconSize +cg_constantSizeHeadIcons +cg_corpseHighlightFadeTime +cg_cropFactor +cg_crosshairAlpha +cg_crosshairAlphaMin +cg_crosshairDynamic +cg_crosshairEnemyColor +cg_crosshairVehicleSentientCheck +cg_cullBulletAngle +cg_cullBullets +cg_cursorHints +cg_damageIndicatorAngle +cg_damageIndicatorMinDelay +cg_damageIndicatorShowAfterDeathTime +cg_deathCamAboveWater +cg_deathScreenFadeInTime +cg_deathScreenFadeOutTime +cg_debugCacheEnabled +cg_debugCinematicCamera +cg_debugDrawSafeAreas +cg_debugDynamicLadderSight +cg_debugEllipsesOffset +cg_debugEntCount +cg_debugEvents +cg_debugFace +cg_debugInfoCornerOffset +cg_debugMounting +cg_debugPosition +cg_debugTargetEntNumber +cg_debugThirdPersonCamera +cg_debug_exploders +cg_debug_overlay_viewport +cg_debug_triggers +cg_debugevents +cg_debugposition +cg_descriptiveText +cg_destructibleKillCamCloseXYDist +cg_destructibleKillCamCloseZDist +cg_destructibleKillCamFarBlur +cg_destructibleKillCamFarBlurDist +cg_destructibleKillCamFarBlurStart +cg_destructibleKillCamFov +cg_destructibleKillCamNearBlur +cg_destructibleKillCamNearBlurEnd +cg_destructibleKillCamNearBlurStart +cg_destructibleKillCamRegularHeight +cg_destructibleKillCamZIncrease +cg_destructible_radius_damage_enabled +cg_development +cg_disableearthquake +cg_disableplayernames +cg_dogKillCamDistFromEyes +cg_dogKillCamForwardDist +cg_dogKillCamFov +cg_dogKillCamSideDist +cg_dogKillCamUpDist +cg_dogKillMinDistFromTarget +cg_draw2D +cg_draw2d +cg_drawAnimAttachTags +cg_drawArtFPS +cg_drawBonesEntNum +cg_drawBreathHint +cg_drawBudgets +cg_drawBulletHitPosNormal +cg_drawBulletPenetration +cg_drawCrosshair +cg_drawCrosshairCooker +cg_drawCrosshairNames +cg_drawCrosshairNamesPosX +cg_drawCrosshairNamesPosY +cg_drawDecalSort +cg_drawFPS +cg_drawFPSLabels +cg_drawFPSScale +cg_drawFramePerformanceWarnings +cg_drawFriendlyNames +cg_drawGun +cg_drawHoldBreathHint +cg_drawIdentifierDebug +cg_drawJobsPerf +cg_drawLagometer +cg_drawLightingDebugText +cg_drawMantleHint +cg_drawMaterial +cg_drawMaterialImageName +cg_drawMaterialImageNum +cg_drawMemoryInfo +cg_drawMinimap +cg_drawModelAxis +cg_drawNetTiming +cg_drawPerformanceSweepInfo +cg_drawPerformanceWarnings +cg_drawPhotosensorOverlay +cg_drawRenderFrame +cg_drawRumbleDebug +cg_drawScriptUsage +cg_drawShellshock +cg_drawSnapshot +cg_drawSpectatorMessages +cg_drawTalk +cg_drawThroughWalls +cg_drawVersion +cg_drawVersionX +cg_drawVersionY +cg_drawVisibleCounts +cg_drawWVisDebug +cg_drawWaterTrail +cg_drawXCamInfo +cg_drawYouInKillCamAsWaypoint +cg_drawfps +cg_drawgun +cg_drawlagometer +cg_drawpaused +cg_drawrumbledebug +cg_droneKillCamBackDist +cg_droneKillCamUpDist +cg_dumpAnims +cg_enableHelicopterNoCullLodOut +cg_enemyNameFadeIn +cg_enemyNameFadeOut +cg_errorDecay +cg_explosiveKillCamBackDist +cg_explosiveKillCamGroundBackDist +cg_explosiveKillCamGroundUpDist +cg_explosiveKillCamStopDecelDist +cg_explosiveKillCamStopDist +cg_explosiveKillCamUpDist +cg_explosiveKillCamWallOutDist +cg_explosiveKillCamWallSideDist +cg_fakefireWizbyChance +cg_fastApe +cg_fastFakeApe +cg_fast_lui +cg_firstPersonTracerChance +cg_flareVisionSetFadeDuration +cg_flipTeamVisuals +cg_focalDistance +cg_focalDistanceChangeSpeed +cg_focalLength +cg_footprints +cg_footprintsDebug +cg_footprintsDistortWater +cg_footsteps +cg_forceEmp +cg_forceInfrared +cg_forceInvalidPaintshops +cg_forceNoCullLodOut +cg_fov +cg_fovExtraCam +cg_fovMin +cg_fovScale +cg_fov_comp_max +cg_fov_default +cg_fov_default_nocomp +cg_fov_default_thirdperson +cg_friendlyNameFadeIn +cg_friendlyNameFadeOut +cg_fstop +cg_fullscreenFinalKillcam +cg_gameBoldMessageWidth +cg_gameMessageWidth +cg_gamemessageiconscale +cg_gun_fovcomp_x +cg_gun_fovcomp_y +cg_gun_fovcomp_z +cg_gun_move_f +cg_gun_move_minspeed +cg_gun_move_r +cg_gun_move_rate +cg_gun_move_u +cg_gun_ofs_f +cg_gun_ofs_r +cg_gun_ofs_u +cg_gun_pitch +cg_gun_roll +cg_gun_rot_minspeed +cg_gun_rot_p +cg_gun_rot_r +cg_gun_rot_rate +cg_gun_rot_y +cg_gun_x +cg_gun_y +cg_gun_yaw +cg_gun_z +cg_headIconMinScreenRadius +cg_healthPerBar +cg_heliKillCamFarBlur +cg_heliKillCamFarBlurDist +cg_heliKillCamFarBlurStart +cg_heliKillCamFov +cg_heliKillCamNearBlur +cg_heliKillCamNearBlurEnd +cg_heliKillCamNearBlurStart +cg_hideHighDetail +cg_hideViewmodelInUFOMode +cg_hintFadeTime +cg_hitmarkerFrameSpacing +cg_hudChatIntermissionPosition +cg_hudChatPosition +cg_hudDamageDirectionalIconTime +cg_hudDamageIconHeight +cg_hudDamageIconInScope +cg_hudDamageIconOffset +cg_hudDamageIconTime +cg_hudDamageIconWidth +cg_hudFriendlyIndicatorHeight +cg_hudFriendlyIndicatorWidth +cg_hudGrenadeIconEnabledFlash +cg_hudGrenadeIconHeight +cg_hudGrenadeIconInScope +cg_hudGrenadeIconMaxHeight +cg_hudGrenadeIconMaxRangeFlash +cg_hudGrenadeIconMaxRangeFrag +cg_hudGrenadeIconMaxScale +cg_hudGrenadeIconMaxScaleDistance +cg_hudGrenadeIconMinScale +cg_hudGrenadeIconMinScaleDistance +cg_hudGrenadeIconOffset +cg_hudGrenadeIconWidth +cg_hudGrenadeIndicatorFadeUp +cg_hudGrenadeIndicatorStartColor +cg_hudGrenadeIndicatorTargetColor +cg_hudGrenadePointerHeight +cg_hudGrenadePointerPivot +cg_hudGrenadePointerPulseFreq +cg_hudGrenadePointerPulseMax +cg_hudGrenadePointerPulseMin +cg_hudGrenadePointerWidth +cg_hudLegacySplitscreenScale +cg_hudMapBorderWidth +cg_hudMapFriendlyHeight +cg_hudMapFriendlyWidth +cg_hudMapPlayerHeight +cg_hudMapPlayerWidth +cg_hudMapRadarLineThickness +cg_hudProneY +cg_hudSayPosition +cg_hudSplitscreenBannerScoreboardScale +cg_hudSplitscreenCompassElementScale +cg_hudSplitscreenCompassScale +cg_hudSplitscreenOffsetsUseScale +cg_hudSplitscreenScoreboardScale +cg_hudSplitscreenStanceScale +cg_hudStanceHintPrints +cg_hudVotePosition +cg_infraredBlur +cg_infraredBlurTime +cg_infraredFriendlies +cg_infraredHighlightOffset +cg_infraredHighlightScale +cg_infraredUseDefaultMaterial +cg_ingnoreValidateWeaponOnDeath +cg_inputLagTestAvgThreshold +cg_inputLagTestMaxThreshold +cg_inputLagTestNumRuns +cg_inputLagTestTimePerRun +cg_invalidCmdHintBlinkInterval +cg_invalidCmdHintDelay +cg_invalidCmdHintDuration +cg_isGameplayActive +cg_killcamdebug +cg_lagometer_pos +cg_laserLight +cg_laserSightMaxDistance +cg_lastSpectatorSelectedThirdPerson +cg_latencyTestMode +cg_loadScripts +cg_luiDebug +cg_mapLocationSelectionCursorSpeed +cg_mapLocationSelectionRotationSpeed +cg_marks_ents_player_only +cg_marqueeTimeScale +cg_maxExplosionRadius +cg_maxPlayerHighlightTargetSize +cg_minCullBulletDist +cg_minicon +cg_minimapCorruptionMaskScale +cg_minimapMaskPadding +cg_minimapPadding +cg_minimapPopOutZoom +cg_missile_FOV +cg_noPlayerShadows +cg_objectiveIndicatorColor +cg_objectiveIndicatorFarDist +cg_objectiveIndicatorFarFadeDist +cg_objectiveIndicatorFarScale +cg_objectiveIndicatorNearDist +cg_objectiveIndicatorNearFadeDist +cg_objectiveIndicatorNoDrawDistance +cg_objectiveIndicatorPerkFarFadeDist +cg_objectiveIndicatorSize +cg_objectiveListWrapCountStandard +cg_objectiveListWrapCountWidescreen +cg_oneFriendlyHeadTracePerFrame +cg_onscreenErrors +cg_opticAttachmentViewmodelSwitch +cg_opticCamoHidesShadow +cg_overheadArmorHeight +cg_overheadArmorOffset +cg_overheadHealthDebug +cg_overheadHealthHeight +cg_overheadHealthOffset +cg_overheadHealthWidth +cg_overheadIconSize +cg_overheadNamesDamagedEntityNameRetainTime +cg_overheadNamesDrawOnADS +cg_overheadNamesDrawOnDamage +cg_overheadNamesFarDist +cg_overheadNamesFarScale +cg_overheadNamesFont +cg_overheadNamesGlow +cg_overheadNamesMaxDist +cg_overheadNamesNearDist +cg_overheadNamesSize +cg_overheadNamesTagUpdateInterval +cg_overheadRankSize +cg_overheadiconsize +cg_overheadnamessize +cg_overheadranksize +cg_packetAnalysisClient +cg_packetAnalysisEntTextScale +cg_packetAnalysisEntTextY +cg_packetAnalysisEntityIndex +cg_packetAnalysisEntitySelectionDepth +cg_packetAnalysisEntityTypeIndex +cg_packetAnalysisPaused +cg_packetAnalysisServerMode +cg_packetAnalysisTextScale +cg_packetAnalysisTextY +cg_paintshopCalcTweaks +cg_paintshopEnableCompression +cg_paintshopEnableTweaks +cg_paintshopForceClearDiskCache +cg_paintshopImageHeight +cg_paintshopImagePosition +cg_paintshopImageScale +cg_paintshopImageWidth +cg_paintshopIncreasePlayerRes +cg_paintshopReadDiskCache +cg_paintshopShowGrid +cg_paintshopShowGridEdge +cg_paintshopShowImages +cg_paintshopShowTweaks +cg_paintshopWriteDiskCache +cg_playerBeastGrapHintSizeMax +cg_playerBeastGrapHintSizeMin +cg_playerBeastHintSizeMax +cg_playerBeastHintSizeMin +cg_playerFrustumHalfHeight +cg_playerHighlightBlinkTime +cg_playerHighlightBrightness +cg_playerHighlightEnemyColor +cg_playerHighlightMinFade +cg_playerHighlightPivotLineFlash +cg_playerHighlightPivotLineWidth +cg_playerHighlightPivotScale +cg_playerHighlightSpreadExp +cg_playerHighlightSpreadScale +cg_playerHighlightTargetInner +cg_playerHighlightTargetOuter +cg_playerHighlightTargetScale +cg_playerHighlightTargetSize +cg_playerLockonReticleSize +cg_playerRenderSmp +cg_playerVRGame +cg_playersInViewMinDot +cg_predictItems +cg_profile_physics +cg_proneFeetCollisionHull +cg_rangeFinderActiveColor +cg_rangeFinderActiveHeight +cg_rangeFinderActiveReticleIndex +cg_rangeFinderActiveWidth +cg_rangeFinderColorChangeDelay +cg_rangeFinderDefaultColor +cg_rangeFinderDefaultDisplayStr +cg_rangeFinderDefaultReticleIndex +cg_rangeFinderDiamondIndicator +cg_rangeFinderDiamondSize +cg_rangeFinderMinEnemySpottingDist +cg_rangeFinderPlayerTargetSize +cg_rangeFinderSelectActors +cg_rangeFinderSelectPlayers +cg_rangefinderIndicatorGap +cg_rangefinderIndicatorSize +cg_reflect_impactfx +cg_reflect_impactfx_mindotclamp +cg_resetWeaponPaintshops +cg_retrieveHintTime +cg_retrieveHintTimeStuck +cg_rocketKillCamBackDist +cg_rocketKillCamUpDist +cg_rumble_devgui_duration +cg_rumble_devgui_loop +cg_scoreboardBannerHeight +cg_scoreboardHeight +cg_scoreboardItemHeight +cg_scoreboardPingGraph +cg_scoreboardPingHeight +cg_scoreboardPingText +cg_scoreboardPingWidth +cg_scoreboardQuarterscreenWidth +cg_scoreboardScrollStep +cg_scoreboardSplitscreenWidth +cg_scoreboardWidth +cg_scriptIconSize +cg_scriptedKillCamCloseXYDist +cg_scriptedKillCamCloseZDist +cg_scriptedKillCamFarBlur +cg_scriptedKillCamFarBlurDist +cg_scriptedKillCamFarBlurStart +cg_scriptedKillCamFov +cg_scriptedKillCamNearBlur +cg_scriptedKillCamNearBlurEnd +cg_scriptedKillCamNearBlurStart +cg_scriptmover_useServerAnims +cg_seatHintFadeTime +cg_sensorGrenadeCrouchZOffset +cg_sensorGrenadeExplosionTrackTimeMs +cg_sensorGrenadeLaserActiveTimeMs +cg_sensorGrenadeLaserRadius +cg_sensorGrenadeProneZOffset +cg_sensorGrenadePulsePeriodMs +cg_sensorGrenadeRampAlpha +cg_sensorGrenadeRange +cg_sensorGrenadeZOffset +cg_showLoadedFF +cg_showQosResults +cg_showZombieControls +cg_showZombieMap +cg_showmiss +cg_smp_weapon_visibility +cg_speedBlurScaleBeast +cg_speedBlurScaleDoubleJump +cg_speedBlurScaleGrapple +cg_speedBlurScaleJuke +cg_speedBlurScaleLunge +cg_speedBlurScaleSlam +cg_speedBlurScaleSlide +cg_speedBlurScaleSpeedBurst +cg_splitscreen2pOffset +cg_splitscreenLetterboxSize +cg_splitscreenSpectatorScaleIncrease +cg_sprintMeterDisabledColor +cg_sprintMeterEmptyColor +cg_sprintMeterFullColor +cg_streamLowDetailCamos +cg_subtitleMinTime +cg_subtitleWidthStandard +cg_subtitleWidthWidescreen +cg_t7HealthOverlay +cg_t7HealthOverlay_Threshold1 +cg_t7HealthOverlay_Threshold2 +cg_t7HealthOverlay_Threshold3 +cg_tagCacheEnabled +cg_teamChatsOnly +cg_thirdPerson +cg_thirdPersonAngle +cg_thirdPersonCamLerpScale +cg_thirdPersonCamOffsetUp +cg_thirdPersonFocusDist +cg_thirdPersonFocusOffsetUp +cg_thirdPersonFootstepsFromNotetracks +cg_thirdPersonLastStand +cg_thirdPersonMode +cg_thirdPersonPaintshop +cg_thirdPersonRange +cg_thirdPersonRoll +cg_thirdPersonSideOffset +cg_thirdPersonUpOffset +cg_threatDetectorDebug +cg_threatDetectorRadius +cg_timedDamageDuration +cg_traversalLerpInTime +cg_traversalLerpOutTime +cg_treadmarks +cg_turretBipodOffset +cg_updateScoreboardAfterGameEnded +cg_usNewEventQueueScheme +cg_useNewEventQueueScheme +cg_useSafeSpectatorCam +cg_useWeaponBasedVariableZoom +cg_useWeaponSwitchReloadCancel +cg_use_colored_smoke +cg_usercmdBursting +cg_usingClientScripts +cg_vehNPCThrottleMultiplier +cg_vehicleCamAboveWater +cg_vehicleFocusEntDistanceMax +cg_vehicleFocusEntDistanceMin +cg_vehicleFocusEntFocalLengthMax +cg_vehicleFocusEntFocalLengthMin +cg_vehicleFocusEntFocalLengthSpeedAdjust +cg_vehicleFocusEntFstop +cg_vehicleFocusEntLerpTime +cg_vehicleVRMechGame +cg_vehicle_piece_damagesfx_threshold +cg_viewVehicleInfluenceGunner +cg_viewVehicleInfluenceGunnerFiring +cg_viewVehicleInfluenceGunner_mode +cg_viewZSmoothingMax +cg_viewZSmoothingMin +cg_viewZSmoothingTime +cg_viewmodelAnimatedFalls +cg_viewmodelAnimatedJumps +cg_visionSetLerpMaxDecreasePerFrame +cg_visionSetLerpMaxIncreasePerFrame +cg_voiceIconSize +cg_waterPerturbForceScale +cg_waterPerturbRadiusScale +cg_waterTrailRippleFrequency +cg_waterTrailRippleVariance +cg_watersheeting +cg_weaponCycleDelay +cg_weaponHeat +cg_weaponHintsCoD1Style +cg_weaponSimulateFireAnims +cg_youInKillCamSize +cg_zbarrierStreamAllWeapons +cgprintentities +chain_melee_attack_angle_cosine_limit +chain_melee_chargeThroughVelocity +chain_melee_enabled +chain_melee_endAnimEarlyTime +challenge +challengeResponseResendBackoffInterval +challengeResponseResendInterval +charge_melee_finishCloseThreshold +chatClientEnabled +cheapSpawns +checkEmblemForRank +checkXUIDBeforeStatsUpload +cl_allowDownload +cl_analog_attack_threshold +cl_anglespeedkey +cl_autojoin +cl_avidemo +cl_bitfieldmismatchFatal +cl_bspmismatchFatal +cl_compositeDebugStringMode +cl_connectTimeout +cl_connectionAttempts +cl_dblTapMaxDelayTime +cl_dblTapMaxHoldTime +cl_deathMessageWidth +cl_debugMessageKey +cl_disableHeroRenders +cl_disablePaintshopBaseIconTransform +cl_dpadLeftHeavyWeapon +cl_dtpHoldTime +cl_fakeLagMS +cl_forceavidemo +cl_freelook +cl_gamepadCheatsEnabled +cl_hudDrawsBehindUI +cl_ingame +cl_jqprof_continuous +cl_jqprof_enabled +cl_jqprof_frequency +cl_jqprof_profileCheckpointFrames +cl_jqprof_threshold +cl_maxPing +cl_maxpackets +cl_migrationPingTime +cl_motdString +cl_mouseAccel +cl_nodelta +cl_noprint +cl_packetdup +cl_paused +cl_pitchspeed +cl_playerPrestige +cl_playerRank +cl_profileTextHeight +cl_profileTextY +cl_profileWriteLimiter +cl_rumble +cl_secondaryPlayerMenuControlDisable +cl_serverStatusResendTime +cl_showMouseRate +cl_showSend +cl_showServerCommands +cl_showTimeDelta +cl_shownet +cl_shownuments +cl_smoothSnapInterval +cl_socketpool_enabled +cl_socketpool_size +cl_specialOffhand +cl_specialOffhandDelay +cl_specialOffhandInput +cl_specialOffhandInventorySwitch +cl_splitscreenGamestateHack +cl_sprintOnStick +cl_sprintOnStick_threshold +cl_stanceHoldTime +cl_tacticalHud +cl_timeout +cl_useMapPreloading +cl_userTestBuild +cl_voice +cl_weapNextHoldEnable +cl_weapNextHoldTime +cl_wwwDownload +cl_yawspeed +clanAbbrev +clanAbbrev_IsEliteValidated +clear +clearAllLoadoutSlots +clearAllLoadoutSlotsCPOffline +clearAllLoadoutSlotsMPCustom +clearAllLoadoutSlotsMPOffline +clearAllLoadoutSlotsZMOffline +clearKeyStates +clearLoadoutSlot +clearLoadoutSlotCPOffline +clearLoadoutSlotMPCustom +clearLoadoutSlotMPOffline +clearLoadoutSlotZMOffline +clientkick +climb_cameraAlignmentEaseMode +climb_cameraRotateTimeMs +climb_centerAllowedThreshold +climb_centerTranslateSpeed +climb_ladderMoveDefaultSpeed +climb_ladderMoveScale +climb_ladderSlideDownDefaultSpeed +climb_ladderSlideDownThreshold +climb_pitchDownClamp +climb_pitchUpClamp +climb_yawClamp +cmdlist +com_allowModeSpecificBitFields +com_animCheck +com_clientFieldsDebug +com_cpu_profile +com_desiredMenu +com_developer +com_disable_popups +com_drawFPS_PC +com_enablePaintshopInCP +com_fixedtime +com_fixedtime_float +com_forceSVLockStep +com_freemoveScale +com_introPlayed +com_logfile +com_maxFrameTime +com_maxclients +com_maxfps +com_pauseSupported +com_pgraph_mode +com_profileLoadingForceSend +com_report_syserrors +com_saveSnapshotProfile +com_script_debugger_smoke_test +com_script_error_recovery +com_script_recordeventintervalms +com_script_recordeventprobability_client +com_script_recordeventprobability_server +com_skipMovies +com_smoothFrames +com_sortteamclientsbyname +com_statmon +com_sv_running +com_timescale +com_useEmptyBitFields +com_voip_bandwidth_restricted +com_voip_disable_threshold +com_voip_resume_time +com_waitForInitial +com_waitForInitialFrontend +com_waitForStreamer +com_wideScreen +comerror_enableDelayedComError +comerror_enableTaskCallbackSysError +compass +compassAlwaysShowEnemyVehicles +compassBehaviorAwarenessEnabled +compassClampIcons +compassCloneColor +compassCoords +compassDebug +compassDoubleJumpAlpha +compassDrawHackerPing +compassDrawLastStandIcon +compassECoordCutoff +compassEnableColorBlindPlayerIcons +compassEnemyFootstepEnabled +compassEnemyFootstepMaxRange +compassEnemyFootstepMaxZ +compassEnemyFootstepMinSpeed +compassForcePlayerIcon +compassFriendlyAIColor +compassFriendlyColor +compassFriendlyFogVisionBrightness +compassFriendlyHeight +compassFriendlyWidth +compassGridAlign +compassGridCols +compassGridEnabled +compassGridRows +compassIconOtherVehHeight +compassIconOtherVehWidth +compassIconTankHeight +compassIconTankScale +compassIconTankWidth +compassLocalRadarRadius +compassLocalRadarUpdateTime +compassMaxRange +compassMinRadius +compassMinRange +compassObituaryHeight +compassObituaryWidth +compassObjectiveHeight +compassObjectiveIconHeight +compassObjectiveIconWidth +compassObjectiveMaxHeight +compassObjectiveMaxRange +compassObjectiveMinAlpha +compassObjectiveMinDistRange +compassObjectiveMinHeight +compassObjectiveNearbyDist +compassObjectiveWidth +compassPartialType +compassPingFiringTime +compassPingGunnerFiringTime +compassPlayerColor +compassPlayerHeight +compassPlayerWidth +compassRadarLineThickness +compassRadarPingFadeTime +compassRadarUpdateFastTime +compassRadarUpdateTime +compassRotation +compassSatellitePingFadeTime +compassSatelliteScanTime +compassSatelliteStaticImageFadeTime +compassShowAIWhileFiring +compassShowEnemies +compassSize +compassSoundPingFadeTime +compassSpectatorsSeeEnemies +compassStaticImageUpdateTime +compassmaxrange +comscore_backoff +comscore_debug +comscore_enabled +comscore_eventThreshholdSize +comscore_filtercategories +con_MiniConSplitscreenScale +con_channelhide +con_channelshow +con_default_console_filter +con_echo +con_errormessagetime +con_gameMsgWindow0FadeInTime +con_gameMsgWindow0FadeOutTime +con_gameMsgWindow0Filter +con_gameMsgWindow0LineCount +con_gameMsgWindow0MsgTime +con_gameMsgWindow0ScrollTime +con_gameMsgWindow0SplitscreenScale +con_gameMsgWindow1FadeInTime +con_gameMsgWindow1FadeOutTime +con_gameMsgWindow1Filter +con_gameMsgWindow1LineCount +con_gameMsgWindow1MsgTime +con_gameMsgWindow1ScrollTime +con_gameMsgWindow1SplitscreenScale +con_gameMsgWindow2FadeInTime +con_gameMsgWindow2FadeOutTime +con_gameMsgWindow2Filter +con_gameMsgWindow2LineCount +con_gameMsgWindow2MsgTime +con_gameMsgWindow2ScrollTime +con_gameMsgWindow2SplitscreenScale +con_gameMsgWindow3FadeInTime +con_gameMsgWindow3FadeOutTime +con_gameMsgWindow3Filter +con_gameMsgWindow3LineCount +con_gameMsgWindow3MsgTime +con_gameMsgWindow3ScrollTime +con_gameMsgWindow3SplitscreenScale +con_hidelabel +con_inputBoxColor +con_inputHintBoxColor +con_label_filter_mask +con_labellist +con_matchPrefixOnly +con_miniconlines +con_minicontime +con_outputBarColor +con_outputSliderColor +con_outputWindowColor +con_restricted +con_restricted_access +con_showlabel +con_typewriterColorBase +con_typewriterColorGlowCheckpoint +con_typewriterColorGlowCompleted +con_typewriterColorGlowFailed +con_typewriterColorGlowUpdated +con_typewriterDecayDuration +con_typewriterDecayStartTime +con_typewriterEnabledSounds +con_typewriterPrintSpeed +connect +consoleGame +constBaseline_allow +constBaseline_bigEndian +constBaseline_throwError +content_trialcontentpackbits +contracts_daily_duration +contracts_disable_schedule +contracts_enabled_mp +contracts_now +contracts_rows_in_set +contracts_start_time +contracts_verbose +cookbookDebug +cookbookUseTestData +counterDownloadInterval +counterUploadInterval +cp_queued_level +creditsScrollScale +ctx_cover_ads_walk_speed_scale +ctx_cover_angle_threshold +ctx_cover_control_scheme +ctx_cover_debug +ctx_cover_enable +ctx_cover_ls_engage_threshold +ctx_cover_ls_maintain_threshold +ctx_cover_play3rdPersonAnims +ctx_cover_post_move_pause +ctx_cover_test_high +ctx_cover_test_high_length +ctx_cover_test_low +ctx_cover_test_low_length +ctx_cover_test_radius +ctx_cover_walk_speed_scale +cullGlassShards +currentDifficulty +currentLiveEvent +curveBallBackFactor +curveBallDownFactor +curveBallForwardFactor +curveBallUpFactor +custom_killstreak_mode +cybercom_enabled +cybercom_fastswitch_enabled +daily_contract_cryptokey_reward_count +db_keyserver1 +db_keyserver2 +db_warnformissingasset +db_xassetdebug +db_xassetdebugname +db_xassetdebugtype +dbg_switch_00 +dbg_switch_01 +dbg_switch_02 +dbg_switch_03 +dbg_switch_04 +dbg_switch_05 +dbg_switch_06 +dbg_switch_07 +dcacheSimulateNoHDD +dcache_enabled +ddlAssertOnMismatch +ddlRatDone +debugAnimScript +debugCurves +debugOverlay +debugOverlayClient +debugRenderCollision +debugRenderCollisionDistance +debugRenderMask +debugRenderPlayerCollision +debugSplit +debug_anim_shared +debug_audio +debug_brushClipTintVariation +debug_brushClipTinting +debug_bulletPenetration +debug_color_pallete +debug_crash_type +debug_litBrushes +debug_missileImpactNoDamage +debug_missileStickAngle +debug_mover +debug_physicsGunObjCount +debug_protocol +debug_ragdollSpawnObjCount +debug_reflection +debug_reflection_matte +debug_rope +debug_scene +debug_scene_skip +debug_show_viewpos +debug_trace +debug_triggers +defaultClassSetCount +defaultDamageDuration +defaultDamageInterval +defaultHitDamage +default_emblems_max_count +defragGlassIndices +defragGlassMemory +demigod +demoRenderDuration +demoRenderSizeX +demoRenderSizeY +demo_autoDollyCameraPathFrequency +demo_bookmarkEventThresholdTime +demo_bytesPerSecondMax +demo_bytesPerSecondMin +demo_cameraLensFStop +demo_cameraLensFocalDistance +demo_cameraLensFocalLength +demo_client +demo_debug +demo_desiredClient +demo_desiredTime +demo_desiredclient +demo_desiredtime +demo_dollycamHighlightThreshholdDistance +demo_dollycamLeaveAtPreviousMarker +demo_dollycamMarkerInformationFarDist +demo_dollycamMarkerInformationFarScale +demo_dollycamMarkerInformationNearDist +demo_dollycamMarkerInformationThreshholdDistance +demo_dollycamMarkerTimeScaleMode +demo_dollycamMarkerTimeScaleValue +demo_dollycamTrackWidth +demo_downloadEntireFile +demo_downloadLiveStreamThrottleTime +demo_downloadStreamDataBlockRequestSize +demo_downloadStreamDataBlockThrottleTime +demo_downloadStreamMaxRetryAttemps +demo_downloadStreamRetryWaitTime +demo_downloadStreamThrottleTime +demo_drawdebuginformation +demo_enableAdvancedCameraControls +demo_enableAutoDollyCameraPath +demo_enableCameraLens +demo_enableClipRecordEvent +demo_enableDeferredMatchRecord +demo_enableDollyCam +demo_enableSvBandwidthLimitThrottle +demo_enabled +demo_errormessage +demo_errortitle +demo_extraNetworkProfileData +demo_fileblockWriteRate +demo_filesizeLimit +demo_filmStartInformationScreenStayTime +demo_filmStartInformationScreenStayTime_Freerun +demo_freeCameraLockOnHighlightThreshholdDistance +demo_freeCameraLockOnMissileAllowed +demo_freeCameraLockOnOrbitRadius +demo_freeCameraShowLockableObjectsAlways +demo_freeCameraUseHeliHeightLockAsCeiling +demo_hide3rdPersonPlayerModel +demo_highlightReelGameResultFilter +demo_highlightReelMinimumStarsFilter +demo_highlightReelNumberOfSegments +demo_highlightReelPlayerFilter +demo_highlightReelStylesFilter +demo_highlightReelTransitionFilter +demo_inGameThrottleBandwidthPercent +demo_inLobbyThrottleBandwidthPercent +demo_keyframerate +demo_lightmanMarkerLightAttenuation +demo_lightmanMarkerLightColorB +demo_lightmanMarkerLightColorG +demo_lightmanMarkerLightColorR +demo_lightmanMarkerLightIntensity +demo_lightmanMarkerLightMode +demo_lightmanMarkerLightRange +demo_livestreaming +demo_matchRecordEventOnPlaylists +demo_maxTimeScale +demo_nodeath +demo_oldposInsteadOfMapCenter +demo_packetsPerSecondMax +demo_packetsPerSecondMin +demo_pause +demo_pauseOnNextSnapshot +demo_playbackClientXUID +demo_profiling +demo_recordOfflineMatch +demo_recordPrivateMatch +demo_recordStaticEntityPositions +demo_recordSystemlinkMatch +demo_recordingrate +demo_refreshDollyCamFxEveryFrame +demo_save_smp +demo_selectedSegmentIndex +demo_sendEventOnFailure +demo_skipBuildingDemoSnapshotDuringCinematicPlayback +demo_streamUploadKeepAliveFrequency +demo_streamingAdjustmentFactor +demo_streamingSendSocketBuffSizeForOtherUploads +demo_streamingSendSocketBuffSizeForRecording +demo_summaryReadEnabled +demo_svBandwidthLimitThrottleMaxBytesPercent +demo_svBandwidthLimitThrottleTimeout +demo_useDefaultVehicleDefIndexIfInvalid +demo_useMapNameAsDefaultName +demo_usefilesystem +demo_viewTraceMask +demo_writePaintShopInformation +demoname +dev_timescale +devdlc +developer +devgui_bevelShade +devgui_colorBgnd +devgui_colorBgndGray +devgui_colorBgndGraySel +devgui_colorBgndSel +devgui_colorGraphKnotEditing +devgui_colorGraphKnotNormal +devgui_colorGraphKnotSelected +devgui_colorSliderBgnd +devgui_colorSliderKnob +devgui_colorSliderKnobSel +devgui_colorText +devgui_colorTextGray +devgui_colorTextGraySel +devgui_colorTextSel +devgui_favMenuEnabled +devgui_scale +devgui_showOnlyFavMenu +devgui_warningSpam +devgui_warningSpan +devgui_zoomEnabled +devmap +devmaponline +disableHost_matchesHostedRatio +disableHost_matchesHostedStreak +disableHost_matchesPlayedRatio +disableHost_matchesPlayedStreak +disableLookAtEntityLogic +disable_aivsai_melee +disable_fx +disable_rope +disconnect +disconnected_ctrls +dive_debug +dive_enabled +dive_groundTraceDist +dive_min_distance_ratio +dive_traceForward +dlc2_fix_scripted_looping_linked_animations +dlc2_show_damage_feedback_when_drowning +dlc3_veh_UpdateYawEvenWhileStationary +doAutoExecDevConfig +doAutoExecUserConfig +doMaintenance +dog_MeleeDamage +dog_checkObstaceInPathWhenMoving +dog_checkShouldTurnWhenMoving +dog_repathDistSq +dog_traceMask +dog_turn180_angle +dog_turn90_angle +dog_turn_min_goal_dist +door_breach_weapondrop +doubleJump_accel +doubleJump_accelerationThreshold +doubleJump_ads_enabled +doubleJump_allow_while_swimming +doubleJump_fire_disabled_angles +doubleJump_fire_enabled +doubleJump_frictionMax +doubleJump_frictionMin +doubleJump_frictionScale +doubleJump_fx_enabled +doubleJump_hud_border +doubleJump_hud_is_vertical +doubleJump_maxUpwardsVelocity +doubleJump_minimapClip +doubleJump_minimapFadeTime +doubleJump_minimapRevealEnabled +doubleJump_minimapRevealEnemies +doubleJump_minimapRevealFriendlies +doubleJump_minimapRevealMaxDistance +doubleJump_minimapRevealSelf +doubleJump_minimapRevealSpeed +doubleJump_minimapRevealTime +doubleJump_requirejump +doubleJump_rumble_enabled +doubleJump_shake_duration +doubleJump_shake_duration_ads +doubleJump_shake_duration_ads_spam +doubleJump_shake_duration_spam +doubleJump_shake_enabled +doubleJump_shake_scale +doubleJump_shake_scale_ads +doubleJump_shake_scale_ads_spam +doubleJump_shake_scale_spam +doubleJump_shellshocked_accel +doubleJump_shellshocked_maxUpwardsVelocity +doubleJump_shellshocked_speed +doubleJump_shellshocked_upBoostAccel +doubleJump_speed +doubleJump_tap_enabled +doubleJump_upBoostAccel +doubleJump_viewAngleMaxPitch +doubleJump_viewAngleMaxRoll +doubleJump_viewAnglePitchSpeed +doubleJump_viewAngleRollSpeed +doubleJump_viewMovementEnabled +doubleJump_viewmodel_anim_enabled +doublejump_animCosAngle +doublejump_blur_amount +doublejump_blur_enabled +doublejump_blur_radius_inner +doublejump_blur_radius_outer +doublejump_blur_time_in +doublejump_blur_time_out +doublejump_control_scheme +doublejump_enabled +doublejump_hud +doublejump_rechargeInAir +doublejump_rechargeInWater +doublejump_requirekeyup +doublejump_requirekeyup_in_water +doublejump_time_before_recharge +doublejump_time_before_recharge_emp +doublejump_time_before_recharge_fast +doublescreen +doublesided_raycasts +drawEntityCount +drawEntityCountPos +drawEntityCountSize +drawGlassBBox +drawGlassDebug +drawKillcamData +drawKillcamDataPos +drawKillcamDataSize +drawLagometer +drawServerBandwidth +drawServerBandwidthPos +drawServerBandwidthSize +drawShardOutline +dtp +dtp_debug +dtp_exhaustion_window +dtp_fall_damage_max_height +dtp_fall_damage_min_height +dtp_max_apex_duration +dtp_max_slide_addition +dtp_max_slide_duration +dtp_min_speed +dtp_new_trajectory +dtp_new_trajectory_multiplier +dtp_post_move_pause +dtp_startup_delay +dumpimages +dumpmateriallist +dumpmodels +durangoGame +dvarConfigEnabled +dvarConfigFatal +dvar_maxCallbackTimeMS +dvardump +dvarlist +dvr_enable +dwConsideredConnectedTime +dwFileFetchTryIntervalBase +dwFileFetchTryIntervalMax +dwFileFetchTryMaxAttempts +dwKVSWriteLocally +dwNetMaxWaitMs +dwStreamingSendSocketBuffSize +dwTitle +dw_defaultDTLSAssociationTimeout +dw_popup +dw_sendBufSize +dynEnt_bulletForce +dynEnt_damageRadiusScale +dynEnt_delete_expensive +dynEnt_disable_rb_collision +dynEnt_explodeForce +dynEnt_explodeMaxEnts +dynEnt_explodeMinForce +dynEnt_explodeSpinScale +dynEnt_explodeUpbias +dynEnt_sentientAutoActivate +dynEnt_shouldCullEntitiesForSplitscreen +dynEnt_small_cylinder_dimension +dynEnt_small_cylinder_max_avel +dynEnt_spawnedLimit +dynsnaps_debugspew +emblem +emblemVersion +emblem_scroll_delay_first +emblem_scroll_delay_rest +emblems_enabled +emblems_max_count +enableChallengeResponse +enableDLCWeapons +enableTacticalArrival +enable_camo_materials_tab +enable_cheap_ents +enable_frame_sampling +enable_global_wind +enable_grass_wind +enable_moving_paths +enable_new_prone_check +enable_retail_incentive +enable_season_pass_incentive +enable_sp_exploit_check +enable_weapon_contract +energyShieldActorMagneticAccuracy +energyShieldReflectDamageMultiplier +energyShieldReflectLerpToNormalFrac +entitlementsActive +entitycount +equipClass +equipDefaultClass +equipDefaultClassToProfile +equipDefaultCustomMatchClass +equipDefaultItemToSlot +equipLoadoutSlot +equipLoadoutSlotCPOffline +equipLoadoutSlotMPCustom +equipLoadoutSlotMPOffline +equipLoadoutSlotZMOffline +equipLoadoutWeaponSlot +equipLoadoutWeaponSlotCPOffline +equipLoadoutWeaponSlotMPCustom +equipLoadoutWeaponSlotMPOffline +equipLoadoutWeaponSlotZMOffline +equipmentAltModeEnabled +equipmentAsGadgets +equipmentMods +equipment_enable_threat_detector +excellentPing +exec +facepaintLodDist +fakeEmblemCount +fast_restart +fastfile_allowNoAuth +fastfile_warnMeWhenOutOfSync +ffotdtempfixHostLaunchPump +fileshareAllowDownload +fileshareAllowDownloadingOthersFiles +fileshareAllowEmblemDownload +fileshareAllowPaintjobDownload +fileshareAllowVariantDownload +fileshareRetry +fileshareShowFailure +fileshareXuidOverride +fileshare_enabled +fileshare_fakeFail +fileshare_tier +filterdedicatedserverresults +fire_audio_random_max_duration +fire_audio_repeat_duration +fire_burn_time +fire_debug +fire_world_damage +fire_world_damage_duration +fire_world_damage_rate +firstPersonLegs +firstPersonLegsInWater +firstPersonLegsOffset +firstPersonLegsOffsetMax +firstPersonLegsOffsetMin +firstPersonLegsZmax +firstPersonLegsZmin +firstPersonShadow +fixNegativeLosses +fixedtime +fixedtime_float +flameVar_editingFlameTable +flameVar_lastFlameTable +flame_debug_render +flame_kick_offset +flame_kick_recover_speed +flame_kick_speed +flame_render +flame_team_damage +flame_test +flame_use_new_beam_system +flareDisableEffects +footstep_sounds_cutoff +forceEliteFounder +forceElitePopups +forceEliteSubscription +forceFullScreenMap +forceHost +forceLiveEvent +force_cac +force_no_cac +fpsTool_drawInfo +fpsTool_drawPoints +fpsTool_forceAsyncCompute +fpsTool_headings +fpsTool_includeMapSamplePoints +fpsTool_loadTest +fpsTool_maxSamples +fpsTool_note +fpsTool_randomRotate +fpsTool_receiveSamples +fpsTool_run +fpsTool_showGun")" +fpsTool_showGun +fpsTool_takeScreenshots +frame_sampling_rate +freezeShards +friction +friendlyContentOutlines +friendlyNameFontColor +friendlyNameFontGlowColor +friendlyNameFontObjective +friendlyNameSplitScreenFontSize +friendlyfire_enabled +friendsNewsLastFetchTime +fsShowStreamingGraph +fsSlotEmptyHiddenColor +fsSlotEmptyMainColor +fsSlotEmptyNotSubscribedColor +fsSlotEmptyShowColor +fsSlotEmptyShowColorBg +fsSlotHighlightedColor +fsSlotHighlightedColorNoSel +fsSlotMainColor +fsSlotNumMainColor +fsSlotNumNoSubsribeColor +fsStarAvgColor +fsStarHighlightColor +fs_basegame +fs_basepath +fs_debug +fs_game +fs_homepath +fs_ignoreLocalized +fs_restrict +fs_usedevdir +fshCustomGameName +fshEnableRender +fshFileDebug +fshMtxName +fshOldItemColor +fshRecentsXUID +fshRenderSuccessURL +fshRenderWriteTimeout +fshRetryDelay +fshSearchTaskDelay +fshSkipFileStats +fshStaffXuid +fshSummaryDelay +fshThrottleEnabled +fshThrottleKBytesPerSec +fudgefactor +fx_alphacull_enable +fx_attempt_trail_reconstruction +fx_attempt_trail_reconstruction_debug +fx_attempt_trail_reconstruction_lerp_ratio +fx_attempt_trail_reconstruction_lerp_time_ms +fx_compute_sprites_debug_draw +fx_compute_sprites_enable +fx_compute_sprites_enable_all +fx_compute_sprites_only +fx_compute_sprites_shadow +fx_compute_sprites_show_lmap +fx_count +fx_cull_effect_spawn +fx_cull_elem_draw +fx_cull_elem_spawn +fx_debugBolt +fx_depth_test_bounding_boxes +fx_disable_exclusion_volumes +fx_draw +fx_drawClouds +fx_draw_dvar +fx_draw_exclusion_volumes +fx_draw_weapon_tags +fx_enable +fx_enable_bounding_boxes +fx_enable_portal_culling +fx_force_bounding_boxes +fx_force_portal_culling +fx_freeze +fx_gpufx_debug_enable +fx_gpufx_draw_enable +fx_gpufx_elem_limit +fx_gpufx_library_enable +fx_gpufx_no_water +fx_gpufx_sort_enable +fx_gpufx_sprite_limit +fx_gpufx_update_enable +fx_limit_spawn_workers +fx_liveupdate +fx_liveupdate_kb +fx_liveupdate_verbose +fx_logging +fx_mark_profile +fx_marks +fx_marks_debug_text +fx_marks_draw +fx_marks_draw_impact_axis +fx_marks_ents +fx_marks_forward_vol_marks_enable +fx_marks_grid_debug +fx_marks_grid_enable +fx_marks_range +fx_marks_smodels +fx_max_per_frame_distance +fx_occlusion_max_player_count +fx_occlusion_query_profile +fx_priority_debug +fx_priority_enable +fx_process_clouds +fx_profile +fx_show_bounding_boxes +fx_show_distances +fx_show_names_range +fx_use_ground_entity +fx_visMinTraceDist +fx_warn_on_version +fxfrustumCutoff +g_FactionName_Allies +g_FactionName_Axis +g_FactionName_allies +g_FactionName_axis +g_FactionName_free +g_ScoresColor_Allies +g_ScoresColor_Axis +g_ScoresColor_EnemyTeam +g_ScoresColor_Free +g_ScoresColor_MyTeam +g_ScoresColor_Spectator +g_TeamColor_Allies +g_TeamColor_Axis +g_TeamColor_EnemyTeam +g_TeamColor_EnemyTeamAlt +g_TeamColor_Free +g_TeamColor_MyTeam +g_TeamColor_MyTeamAlt +g_TeamColor_MyTeamAlt_Party +g_TeamColor_Party +g_TeamColor_Spectator +g_TeamIcon_Allies +g_TeamIcon_Axis +g_TeamIcon_Free +g_TeamIcon_Spectator +g_TeamName_Allies +g_TeamName_Axis +g_TeamName_Three +g_TeamName_allies +g_TeamName_axis +g_TeamName_free +g_actorAndVehicleAntilag +g_actorAndVehicleAntilagDebug +g_ai +g_aiEventDump +g_allowLastStandForActiveClients +g_allowVote +g_allowvote +g_animMonitorEnt +g_animMonitorFilter +g_antilag +g_antilagRestoreOnDamage +g_antilagTimeCap +g_avoidEnabled +g_bDebugGrappleTrace +g_bDebugRenderBrushes +g_bDebugRenderBulletCollision +g_bDebugRenderBulletMeshes +g_bDebugRenderCollision +g_bDebugRenderCollisionDistance +g_bDebugRenderColoredPatches +g_bDebugRenderEntityBrushes +g_bDebugRenderMeshType +g_bDebugRenderPatches +g_bDebugRenderStaticModelsBounds +g_banIPs +g_broadcastLocalSound +g_campaign_mode +g_changelevel_time +g_clientSideLinkingEnabled +g_clonePlayerMaxVelocity +g_compassShowEnemies +g_customTeamName_Allies +g_customTeamName_Axis +g_customTeamName_Three +g_deadChat +g_deathDelay +g_deathcameratraceheight +g_debugAccuracy +g_debugBehaviorStateMachine +g_debugBulletDuration +g_debugBulletEntityType +g_debugBullets +g_debugCacheEnabled +g_debugDamage +g_debugHitBrush +g_debugHitSurface +g_debugLocDamage +g_debugLocDamageEntity +g_debugLocHit +g_debugLocHitTime +g_debugPlayerAnimScript +g_debugRankXP +g_debugRenderGjkTraceGeom +g_debugRenderMask +g_debugServerAiming +g_debugWeaponXP +g_destructibleDraw +g_drawDebugInfoVolumes +g_drawDebugInfoVolumesInverse +g_drawGrenadeHints +g_dropForwardSpeed +g_dropHorzSpeedRand +g_dropUpSpeedBase +g_dropUpSpeedRand +g_droppedWeaponPhysics +g_dumpAIEvents +g_dumpAnims +g_dumpAnimsCommands +g_dumpAnimsReduceSpam +g_dumpStaticModels +g_entinfo +g_entinfo_AItext +g_entinfo_maxdist +g_entinfo_scale +g_entinfo_type +g_entsInSnapshot +g_erroronpathsnotconnected +g_fast_devmap +g_fogColorReadOnly +g_fogHalfDistReadOnly +g_fogStartDistReadOnly +g_friendlyNameDist +g_gameEnded +g_gametype +g_knockback +g_lagged_damage_threshold +g_listEntity +g_listEntityCounts +g_loadScripts +g_log +g_logSync +g_logTimeStampInSeconds +g_mantleBlockTimeBuffer +g_maxDroppedWeapons +g_maxEntsInSnapshot +g_minGrenadeDamageSpeed +g_minimumAvgCollisionArea +g_motd +g_oldAnimCmdNetwork +g_password +g_pickupPromptsForDroppedWeapons +g_playerCollisionEjectSpeed +g_playerRespawnTime +g_playerVRGame +g_processDamageAfterFullBullet +g_quadrotorFlyHeight +g_redCrosshairs +g_reviveTime +g_scrDebugHudElems +g_smoothClients +g_spawnai +g_speed +g_synchronousClients +g_tagCacheEnabled +g_teamColor_EnemyTeam +g_teamColor_EnemyTeamAlt +g_teamColor_MyTeam +g_teamColor_MyTeamAlt +g_teamColor_Squad +g_throttleTempEnts +g_turretBipodOffset +g_turretServerPitchMax +g_turretServerPitchMin +g_useholdspawndelay +g_useholdtime +g_validateBehaviorStateMachine +g_vehicleBypassFriendlyFire +g_vehicleDebug +g_vehicleDrawPath +g_vehicleDrawSplines +g_vehiclePlaneCurveTime +g_vehicleVRMechGame +g_voiceChatTalkingDuration +g_voteAbstainWeight +gadgetActivateDuringWeaponChange +gadgetEnabled +gadgetFlickerDurationDefault +gadgetFlickerWhizbyMaxDistance +gadgetPowerInitEmpty +gadgetPowerOverchargePerkScoreFactor +gadgetPowerOverchargePerkTimeFactor +gadgetPowerOverrideFactor +gadgetPowerUnlimited +gadgetPulseOrbShareEnemy +gadgetPulseOrbShareFriendly +gadgetThiefKillFullPowerMultiplier +gadgetThiefKillPowerGain +gadgetThiefRechargeRate +gadgetThiefShutdownFullCharge +gadget_blur_enabled +gadget_castShaderDuration +gadget_flashbackMinimapFudgeFactor +gadget_flashbackResetsWallrunTime +gadget_flashbackUsesPriorAngles +gadget_flashbackWhiteAlphaRatio +gadget_flashbackWhiteFlash +gadget_force_slots +gadget_resurrectHeavyWeaponsFatal +gadget_resurrectHeroWeaponsFatal +gadget_speedBurstBaseGlow +gadget_speedBurstBaseGlowScalar +gadget_speedBurstBlurScalar +gadget_speedBurstDesatClamp +gadget_speedBurstDesatRampSpeed +gadget_speedBurstDoesJuke +gadget_speedBurstGlowPulseDuration +gadget_speedBurstWallRunJumpVelocity +gadget_visionPulseFriendlyMinimap +gadget_visionPulseFriendlyMinimapColor +gadget_visionPulseMinimapFadeTime +gadget_visionPulseRevealsCamo +gamedate +gamename +gamesettings_generateconfig +gametype_setting +geographicalMatchmakingOverride +give +glassBroom +glassCanBreakFromSlide +glassCanBreakFromSprint +glassCanBreakFromWallrun +glassCrackedDamageRateRange +glassDamageMultiplier +glassExtraAngVelocity +glassExtraLinVelocity +glassForceAttenuation +glassForceMultiplier +glassForceOriginMult +glassFreeBuffersDelay +glassLinVelMultiplier +glassLowLodDist +glassMaxShardLife +glassMinVelocityLowest +glassMinVelocityToBreakFromJump +glassMinVelocityToBreakFromSlide +glassMinVelocityToBreakFromSprint +glassMinVelocityToBreakFromWallrun +glassPlayShatterFX +glassPlayerPredictTime +glassPredictTime +god +goodPing +gpad_button_deadzone +gpad_button_lstick_deflect_max +gpad_button_rstick_deflect_max +gpad_debug +gpad_enabled +gpad_fake_vita +gpad_lightbar_test +gpad_menu_scroll_delay_first +gpad_menu_scroll_delay_rest +gpad_stick_deadzone_max +gpad_stick_deadzone_min +gpad_stick_pressed +gpad_stick_pressed_hysteresis +grapple_blur_amount +grapple_blur_radius_inner +grapple_blur_radius_outer +grapple_blur_time_in +grapple_blur_time_out +grapple_early_yank_anim_start_time +grenadeAllowRigidBodyPhysics +grenadeAnimatedFlatCosine +grenadeAnimatedFrictionHigh +grenadeAnimatedFrictionLow +grenadeAnimatedMinDotBeforeRolling +grenadeAnimatedMinDotBeforeRollingOnFlat +grenadeAnimatedRollDegree +grenadeBounceRestitutionMax +grenadeBumpFreq +grenadeBumpMag +grenadeBumpMax +grenadeCurveMax +grenadeFrictionHigh +grenadeFrictionLow +grenadeFrictionMaxThresh +grenadeMinDotBeforeRolling +grenadeParallelBounceOverride +grenadePerpendicularBounceOverride +grenadeRestThreshold +grenadeRollDegree +grenadeRollRadius +grenadeRollingEnabled +grenadeUseRigidBodyPhysics +grenadeVelocityDampFactor +grenadeWaterFrictionHigh +grenadeWaterFrictionLow +grenadeWaterFrictionThresh +grenadeWobbleFreq +grenadeWobbleFwdMag +grenadeWobbleSideDamp +grenadeWobbleSideMag +grenade_indicators_enabled +grenade_waterDebug +grenade_waterEnterRotationScalar +grenade_waterEnterScalar +grenade_waterExitRotationScalar +grenade_waterExitScalar +grenade_waterSpawnRotationScalar +grenade_waterSpawnScalar +groupCountsVisible +groupDownloadInterval +groupUploadInterval +groupZeroCountsVisible +groups_admins_refresh_time +groups_applications_refresh_time +groups_enabled +groups_invites_refresh_time +groups_presence_refresh_time +groups_quickjoin_players_refresh_time +groups_self_groups_refresh_time +groups_service_failure_backoff_time +groups_wait_on_dw +gts_validation_enabled +gunXPGroups +gunsmithVersion +gunsmith_enable_toggle_variant +gunsmith_enabled +gunsmith_totalvariants +h +hackMultiLauncherHorizontalOffset +hackMultiLauncherVerticleOffset +hackerTool_debug +hatch_check_enable +hatch_mantle_fwd +hatch_mantle_up +hiDef +highlightedPlayerName +hkai_actorClampToNavMeshFudgeFactor +hkai_additionalPathfindIterationLimit +hkai_badPlaceEdgeCostMultiplier +hkai_debugActors +hkai_debugAvoidanceCollisionPenalty +hkai_debugAvoidanceDodgingPenalty +hkai_debugAvoidanceGoalDistToleranceScale +hkai_debugAvoidanceLeftTurnRadiusScale +hkai_debugAvoidanceMaxAccel +hkai_debugAvoidanceMaxDecel +hkai_debugAvoidanceMaxNeighbors +hkai_debugAvoidanceMaxSpeed +hkai_debugAvoidanceMinSpeed +hkai_debugAvoidancePenetrationPenalty +hkai_debugAvoidanceRadius +hkai_debugAvoidanceRightTurnRadiusScale +hkai_debugAvoidanceSensorSizeScale +hkai_debugAvoidanceSidednessChangingPenalty +hkai_debugAvoidanceVelocityHysteresis +hkai_debugAvoidanceWallFollowingAngle +hkai_debugBadPlaces +hkai_debugCharacterParameters +hkai_debugCharacters +hkai_debugCornerPredictor +hkai_debugFailedPathFind +hkai_debugManualControl +hkai_debugObstacleSizeScale +hkai_debugObstacles +hkai_debugPointNearBoundary +hkai_debugPositionQuery +hkai_debugPositionqueryPerformance_cellLength +hkai_debugPositionqueryPerformance_faceLength +hkai_debugTurnRate +hkai_debugTurnVelocityScale +hkai_deferredPathfindsEnabled +hkai_dumpMemoryLeaks +hkai_maxClearanceRecalcFaces +hkai_maxPathLengthChecksEnabled +hkai_maxPathLengthMultiplier +hkai_navMeshTriggersEnabled +hkai_navMeshUseHierarchialPathFind +hkai_pathfindIterationLimit +hkai_recordWorldAndPath +hkai_recordWorldAndPathTimeLimit +hkai_repathUsingIncompleteRepathSegments +hkai_resetTimers +hkai_showTimers +hkai_stairsEdgeCostMultiplier +hkai_storeClearanceRecalcStats +hkai_storePathfindResults +hkai_timerTestActive +hkai_warnPathFindFailures +hkai_warningPopupsEnabled +hls_anti_dos_sites +hls_anti_dos_time +hls_audio_volume +hls_debug_draw +hls_quality +hls_quality_autodetected +hls_quality_available +hls_reserved_bandwidth +hls_start_offset +hopper_enabled +hostileNameFontColor +hostileNameFontGlowColor +httpnetfs +hudElemPausedBrightness +hud_deathQuoteFadeTime +hud_enable +hud_fade_ammoDisplay +hud_fade_compass +hud_fade_healthbar +hud_fade_offhand +hud_fade_stance +hud_fade_vehiclecontrols +hud_flash_period_offhand +hud_flash_time_offhand +hud_healthOverlay_phaseEnd_fromAlpha +hud_healthOverlay_phaseEnd_pulseDuration +hud_healthOverlay_phaseEnd_toAlpha +hud_healthOverlay_phaseOne_pulseDuration +hud_healthOverlay_phaseOne_toAlphaAdd +hud_healthOverlay_phaseThree_pulseDuration +hud_healthOverlay_phaseThree_toAlphaMultiplier +hud_healthOverlay_phaseTwo_pulseDuration +hud_healthOverlay_phaseTwo_toAlphaMultiplier +hud_healthOverlay_pulseStart +hud_healthOverlay_pulseStop +hud_healthOverlay_regenPauseTime +hud_health_startpulse_injured +i +ik_ai_hand_get_data +ik_ai_hand_offset_vec +ik_ai_hand_rotation_vec +ik_ai_hand_tuning +ik_ai_pool_size +ik_ai_range_max +ik_debug +ik_dvar_ai_aim_tracking_rate +ik_dvar_lookatentity_eyes_scale +ik_dvar_lookatentity_notorso +ik_dvar_lookatentity_tracking_rate +ik_dvar_lookatpos_eyes_scale +ik_dvar_lookatpos_notorso +ik_dvar_lookatpos_tracking_rate +ik_enable +ik_enable_ai_hand +ik_enable_ai_terrain +ik_enable_player_hand +ik_enable_player_terrain +ik_foot_test +ik_hand_test +ik_left_hand_lerp_test +ik_lookatentity_head_scale +ik_lookatpos_head_scale +ik_paranoid_matrix_checks +ik_pelvis_test +ik_pitch_limit_max +ik_pitch_limit_thresh +ik_right_hand_lerp_test +ik_roll_limit_max +ik_roll_limit_thresh +ik_yaw_limit_max +ik_yaw_limit_thresh +in_mouse +incentive_rare_drop_id +incentive_weapon_drop_id +initial_cod_points_id +interactivePromptAnimLen +interactivePromptNearToDist +interactivePromptNextToDist +inventory_blocking +inventory_enabled +inventory_fakeExtraSlots +inventory_fakeFail +inventory_fetch_cooloff +inventory_itemsPerPage +inventory_maxPages +inventory_retry_delay +inventory_retry_max +inventory_test_button_visible +invited +item_exclusion_0 +join_agreementWindow +join_completionWindow +join_devHostBusyChance +join_devSloMo +join_devSloMoFrame +join_handshakeWindow +join_infoProbeWindow +join_reservationWindow +join_retryCount +join_retryDelay +juke_air_accel +juke_air_enabled +juke_air_frictionMax +juke_air_frictionMin +juke_air_maxUpwardsVelocity +juke_air_speed +juke_air_upBoostAccel +juke_anim_offset +juke_blur_amount +juke_blur_enabled +juke_blur_radius_inner +juke_blur_radius_outer +juke_blur_time_in +juke_blur_time_out +juke_buttonup_jump +juke_buttonup_sprint +juke_clearance_check_dist +juke_clearance_check_radius +juke_cybercom +juke_debug +juke_debug_distance +juke_enabled +juke_forward_no_stick_input +juke_fx_enabled +juke_ms_for_deceleration +juke_ms_to_fullspeed +juke_player_trace_offset +juke_programmatic_animation +juke_rumble_enabled +juke_slide_enabled +juke_snap_angle_backward +juke_snap_angle_forward +juke_snap_angle_side +juke_speed +juke_sprintspeedratio +juke_stick_intensity_threshold +juke_time_ms +juke_wallrun_enabled +juke_weapon_angles_backward +juke_weapon_angles_forward +juke_weapon_angles_left +juke_weapon_angles_right +juke_weapon_side_movement +jump_height +jump_ladderPushVel +jump_max_velocity +jump_slowdownEnable +jump_spreadAdd +jump_stepSize +key_bindsDebug +keyarchiveWriteDelay +kick +kill +killOnlyTrailFX +killserver +ks_emp_ammowidget_maxRadiusMinStatic +ks_emp_ammowidget_maxStaticValue +ks_emp_ammowidget_minRadiusMaxStatic +ks_emp_ammowidget_minStaticValue +ks_emp_fullscreen_maxRadiusMinStatic +ks_emp_fullscreen_maxStaticValue +ks_emp_fullscreen_minRadiusMaxStatic +ks_emp_fullscreen_minStaticValue +ks_emp_minimap_maxRadiusMinStatic +ks_emp_minimap_maxStaticValue +ks_emp_minimap_minRadiusMaxStatic +ks_emp_minimap_minStaticValue +ks_emp_scorewidget_maxRadiusMinStatic +ks_emp_scorewidget_maxStaticValue +ks_emp_scorewidget_minRadiusMaxStatic +ks_emp_scorewidget_minStaticValue +laggedDamageTagThreshold +lagometer_pos +landing_crouchViewDip +language +laserAlpha +laserDebug +laserFadeADS +laserFlarePct +laserForceOn +laserKillImpactDelta +laserLightBeginOffset +laserLightBodyTweak +laserLightEndOffset +laserLightRadius +laserLightRadius_alt +laserLightRangePlayer +laserRadius +laserRadius_alt +lastStandSwayAccel +lastStandSwayMaxDrift +lastStandSwayMaxDriftVel +lastStand_cameraAlignmentEaseMode +lastStand_cameraPitchOffset +lastStand_cameraRotateTimeMs +launchGame +lbTaskDelay +leaveWithPartyEnabled +listallassets +listassetpool +listcustomgametypes +listdefaultassets +liveDedicatedOnly +liveDedicatedonly +liveNeverHostServer +liveNewsMaxCounters +liveSessionTaskTimeoutCreate +liveSessionTaskTimeoutDelete +liveSessionTaskTimeoutSearch +liveSessionTaskTimeoutUpdate +liveVoteErrorBackoff +liveVoteTaskDelay +live_CODPointCheckRequired +live_LPCFFOTDMode +live_allowDisconnectOnSignOut +live_anticheatBoostingPolicy +live_anticheatGlitchingPolicy +live_anticheatLootRecoveryPolicy +live_anticheatOffensiveBehaviorPolicy +live_anticheatOffensiveUGCPolicy +live_anticheatPeripheralsPolicy +live_anticheatPiracyPolicy +live_anticheatThirdPartyPolicy +live_anticheatUnlockableContentPolicy +live_autoEventEnabled +live_autoEventPumpDelay +live_autoEventPumpTime +live_connect_mode +live_connectionStatusChange_timeout +live_debugDailyChallengesDay +live_debugDailyChallengesHour +live_debugDailyChallengesMinute +live_dedicatedLookForPlatformPlaylists +live_disconnected_timeout +live_enableCounters +live_enableDailyChallengeUpdate +live_enableDailyChallengesDebugTimestamp +live_enablePolls +live_exchange_enable +live_exchange_enableErrorMessages +live_exchange_enableExchangeFailureTracking +live_exchange_enableTracking +live_exchange_processProductAttempts +live_exchange_processProductInterval +live_exchange_processProductIntervalMultiplier +live_experimentsEnabled +live_fakeReportConsoleFailure +live_featuredEnabled +live_friends_batch_size +live_friends_enabled +live_friends_features +live_friends_max +live_friends_sort +live_friends_unified +live_friends_update_interval +live_groups_min_task_callback_ms +live_inSyncDDLsRequired +live_leaderboardResetTime +live_leaderboardisRowEmptyCheck +live_motdEnabled +live_newsAddOwnNewsToTicker +live_presence_debug +live_presence_features +live_presence_incremental_fail_delay +live_presence_max_ms_between_updates +live_presence_min_ms_between_updates +live_presence_party +live_presence_platform +live_pubSemaphoreCheckIntervalSeconds +live_pubSemaphoreForceChange +live_pubSemaphoreJitterSeconds +live_pubSemaphoreUserTriggerTime +live_publishervariables_maxupdateattempts +live_readPublisherStorageLocally +live_readSplitFfotd +live_readUserStorageLocally +live_registrationEndURL +live_registrationEndURL_DEV +live_registrationEndURL_RETAIL +live_registrationStartURL +live_registrationStartURL_DEV +live_registrationStartURL_RETAIL +live_social_quickjoin +live_social_quickjoin_cache +live_social_quickjoin_count +live_statscaching +live_steam_server_client_checks_interval +live_steam_server_description +live_steam_server_name +live_steam_server_password +live_store_disable_lang +live_store_disable_region +live_store_enable +live_store_enable_inventory +live_store_entitlementcheck_enable +live_store_show_details +live_systemSurveyCaptureDelta +live_systemsurvey +live_testValue +live_timewarp +live_umbrella_maxUmbrellaLoginAttempts +live_useInGameRegistration +live_useLPC +live_usePublisherVariables +live_useUmbrella +live_useUno +live_username +live_whitelistFatal +livestats_checkNonPrimaryXUIDPS3 +livestats_giveCPXP +livestats_skipFirstTime +livestorage_fakeNoob +livestorage_waitOnContent +livestorage_waitOnContentTimeout +loadoutVersion +loadoutVersionCP +loadoutVersionMP +loadoutVersionZM +lobbyAdvertiseConfig +lobbyAdvertiseDirty +lobbyAdvertiseEmptySlots +lobbyAdvertiseGameType +lobbyAdvertiseGeo1 +lobbyAdvertiseGeo2 +lobbyAdvertiseGeo3 +lobbyAdvertiseGeo4 +lobbyAdvertiseIsEmpty +lobbyAdvertiseLatencyBand +lobbyAdvertiseMap +lobbyAdvertiseMapPacks +lobbyAdvertiseMaxPlayers +lobbyAdvertiseNetcodeVersion +lobbyAdvertiseNumPlayers +lobbyAdvertisePin +lobbyAdvertisePlaylistNumber +lobbyAdvertisePlaylistVersion +lobbyAdvertiseServerLocation +lobbyAdvertiseServerName +lobbyAdvertiseServerType +lobbyAdvertiseShowInMatchmaking +lobbyAdvertiseSkill +lobbyAdvertiseSkip +lobbyAdvertiseTeamSizeMax +lobbyCPTimerStartInterval +lobbyCPZMTimerStartInterval +lobbyDebugLogJoinSuccess +lobbyDebugLogJoins +lobbyDedicatedSearchSkip +lobbyLaunch_fadeToBlackDelay +lobbyLaunch_fadeToBlackDelayOnConnect +lobbyLaunch_gameLaunchDelay +lobbyLaunch_gameLaunchDelayOnConnect +lobbyLaunch_waitForClientAckDelay +lobbyMapVotePrevMapPlayCount +lobbyMergeDedicatedEnabled +lobbyMergeEnabled +lobbyMergeInterval +lobbyMigrate_Enabled +lobbyMigrate_EnabledLAN +lobbyMigrate_considerStreamingForHostMigration +lobbyMigrate_dedicatedOnly +lobbyMigrate_migrateToBestGameHostEnabled +lobbyProbedXuidOverride +lobbySearchBaseSkillRange +lobbySearchDatacenterType +lobbySearchDatacenterTypeGeo +lobbySearchDatacenterTypeOverride +lobbySearchDediUnparkPingLimit +lobbySearchDedicatedGeoMin +lobbySearchDelay +lobbySearchExperimentDatacenter +lobbySearchForceLocation +lobbySearchForceUnparkLobbySize +lobbySearchForceXuid +lobbySearchGameSecurityId +lobbySearchGeo1 +lobbySearchGeo1Weight +lobbySearchGeo2 +lobbySearchGeo2Weight +lobbySearchGeo3 +lobbySearchGeo3Weight +lobbySearchGeo4 +lobbySearchGeo4Weight +lobbySearchGeoMin +lobbySearchIsEmpty +lobbySearchMapPacks +lobbySearchMaxLatencyBandDiff +lobbySearchMinDediSearchClientAdd +lobbySearchMinDediSearchTime +lobbySearchNetcodeVersion +lobbySearchPingBand +lobbySearchPingBandEnabled +lobbySearchPingBandWeight1 +lobbySearchPingBandWeight2 +lobbySearchPingBandWeight3 +lobbySearchPingBandWeight4 +lobbySearchPingBandWeight5 +lobbySearchPlaylistNumber +lobbySearchPlaylistVersion +lobbySearchQueryId +lobbySearchServerLocation1 +lobbySearchServerLocation2 +lobbySearchServerLocation3 +lobbySearchServerLocation4 +lobbySearchServerLocation5 +lobbySearchServerType +lobbySearchShowInMatchmaking +lobbySearchSkill +lobbySearchSkillRangeMultiplier +lobbySearchSkillWeight +lobbySearchSkip +lobbySearchSkipDLCProbability +lobbySearchSkipUnparkProbability +lobbySearchTeamSize +lobbyTimerStartInterval +lobbyTimerStatusBeginInterval +lobbyTimerStatusPostGameInterval +lobbyTimerStatusStartInterval +lobbyTimerStatusVotingInterval +lobbyTimerStatusVotingInterval_Arena +lobbyTimerZMStartInterval +lobby_MatchmakingLoggingChance +lobby_MatchmakingLoggingLevel +lobby_ban +lobby_beginPlay +lobby_clientContentTimeout +lobby_clientEndCooloffTime +lobby_clientEndFakeSendLoss +lobby_clientLoadingIntoUICheck +lobby_clientTimeout +lobby_clientWarnTimeout +lobby_enableLoadoutDataStreamingInGame +lobby_enablePSDataStreamingInGame +lobby_enablePSDataStreamingInLobby +lobby_fillserverlist +lobby_forceLAN +lobby_forceOffline +lobby_hostBots +lobby_hostContentTimeout +lobby_hostIntervalHeartbeat +lobby_hostIntervalState +lobby_hostJoinRequestReject +lobby_hostPSFragmentRetryInterval +lobby_hostTimeout +lobby_ingamePSDataStreamingBW +lobby_kick +lobby_list +lobby_maxLocalPlayers +lobby_moveLobby +lobby_nextmap +lobby_ptptimeout +lobby_readyUpPercentRequired +lobby_setgametype +lobby_setmap +lobby_showSVDebug +lobby_unban +lobbymigrate_HostWaitMS +lobbymigrate_MaxBWPackets +lobbymigrate_MaxPacketWaitTime +lobbymigrate_MinScoreDiff +lobbymigrate_NomineeRecalcInterval +lobbymigrate_NomineeWaitMS +lobbymigrate_TestInterval +lobbymigrate_TestIntervalJitter +lobbymigrate_WirelessLatencyIncrease +lobbymigrate_useStdDev +lobbymsg_prints +lobbyvm_forceGC +loc_availableLanguages +loc_forceEnglish +loc_language +loc_languageSaved +loc_systemLanguage +loc_translate +loc_warnings +loc_warningsAsErrors +local_media_tier +log_append +log_filename +logfile +long_blocking_call +loot_bribeCrate_dwid +loot_burnBatchSize +loot_burnCommonRefund +loot_burnCooloff +loot_burnEpicRefund +loot_burnLegendaryRefund +loot_burnMinMegaRequired +loot_burnMinRareRequired +loot_burnMinUltraRequired +loot_burnRareRefund +loot_burnRefetchOnSuccess +loot_commonCrate_dwid +loot_cryptoCheckDelay +loot_cryptokeyCost +loot_cryptokeySku +loot_earnMax +loot_earnMin +loot_earnPlayThreshold +loot_earnTime +loot_emblems_max_count +loot_enabled +loot_experimentpromo_active +loot_fakeAll +loot_fakeItem +loot_fakeNoBonus +loot_fakeRarity +loot_missedIMChance +loot_mpItemVersions +loot_rareCrate_dwid +loot_recipe_distill_cost +loot_taskMaxAttempts +loot_taskWindow +loot_testAll +loot_testIndex +loot_winBonusPercent +loot_zmItemVersions +lootxp_bonus_multiplier +lootxp_multiplier +lowAmmoWarningPulseFreq +lowAmmoWarningPulseMax +lowAmmoWarningPulseMin +lpc_forceDownloadFiles +lpc_maxattempts +ls_demoauthor +ls_demoduration +ls_demotitle +ls_gametype +ls_maplocation +ls_mapname +ls_status +lua_systemTest +lunge_blur_amount +lunge_blur_enabled +lunge_blur_radius_inner +lunge_blur_radius_outer +lunge_blur_time_in +lunge_blur_time_out +lunge_debug +m_filter +m_forward +m_mouseAcceleration +m_mouseFilter +m_mouseSensitivity +m_pitch +m_side +m_yaw +magic_chest_movable +manifestfs +mantle_adjustment_mp +mantle_check_angle +mantle_check_glass_extra_range +mantle_check_radius +mantle_check_range +mantle_check_range_mp +mantle_debug +mantle_enable +mantle_enabled +mantle_view_yawcap +mantle_weapon_anim_height +mantle_weapon_height +map +map_restart +map_rotate +mapcrc +mapname +marketing_autorefresh +marketing_enabled +marketing_refreshTime +marketing_simulatefakemotd +marketing_waitTimeOnLogin +matchmaking_debug +maxAIGlassHits +maxAttachmentsPerWeapon +maxDailyZMDoubleXP +maxGlassShatters +maxLossesValue +maxMetPlayerListCount +maxShardSplit +maxSplitSizeRatio +maxStatsBackupInterval +maxVoicePacketsPerFrame +melee_allowQueuedMelee +melee_attachmentMultiplier +melee_cameraSway_enabled +melee_debug +melee_debug_fromBehind +melee_fromBehindDebug +melee_fromBehindMaxAngle +melee_fromBehindUseBonesForDirection +melee_maxAutoPitch +melee_maxAutoYaw +melee_victimCamSwayAngle +melee_victimCameraLerpTime +melee_victimEffectDuration +melee_victimMoveScale +melee_victimPitchSpeed +melee_victimTransScale +melee_victimYawSpeed +menuMapMaxRange +metPlayerInGameOnly +metPlayerListCleanupInterval +metPlayerListRemoveFriends +metPlayerListUpdateInterval +metPlayerListUploadInterval +metPlayerPlatformGamertag +metPlayerPlatformPresence +microwave_turret_placement_trace_maxs +microwave_turret_placement_trace_mins +microwave_turretplacement_traceOffset +migrating +migration_blocksperframe +migration_forceHost +migration_limit +migration_minclientcount +migration_msgtimeout +migration_soak +migration_timeBetween +minDelayForOtherPlayerStatsFetch +miniscoreboardhide +missileDebugAttractors +missileDebugDraw +missileDebugText +missileDroneAccelClimb +missileDroneAccelDescend +missileDroneClimbAngleDirect +missileDroneClimbAngleTop +missileDroneClimbCeilingDirect +missileDroneClimbCeilingTop +missileDroneClimbHeightDirect +missileDroneClimbHeightTop +missileDroneClimbMaxDist +missileDroneClimbToOwner +missileDroneDistSqTargetAvoidanceDisabled +missileDroneDistanceAvoidance +missileDroneDistanceAvoidanceSec +missileDroneSpeedLimitClimb +missileDroneSpeedLimitDescend +missileDroneSpeedMin +missileDroneTurnDecel +missileDroneTurnMaxRate +missileDroneTurnMaxRoll +missileDroneTurnMaxRollChange +missileDroneTurnRateAscent +missileDroneTurnRateAvoidance +missileDroneTurnRateDecent +missileDroneTurnRateSmallAdjustments +missileDroneflattenRollRatio +missileHellfireMaxSlope +missileHellfireUpAccel +missileJavAccelClimb +missileJavAccelDescend +missileJavClimbAngleDirect +missileJavClimbAngleTop +missileJavClimbCeilingDirect +missileJavClimbCeilingTop +missileJavClimbHeightDirect +missileJavClimbHeightTop +missileJavClimbToOwner +missileJavSpeedLimitClimb +missileJavSpeedLimitDescend +missileJavTurnDecel +missileJavTurnRateDirect +missileJavTurnRateTop +missileMolotovBlobNum +missileMolotovBlobTime +missilePlantableSize +missileSoftLaunchSpeedScale +missileTVGuidedBoost +missileTVGuidedBoostSpeedDown +missileTVGuidedBoostSpeedUp +missileTVGuidedFlatteningRollAccel +missileTVGuidedMPSpecific +missileTVGuidedMaxRollAngle +missileTVGuidedStickDeadzone +missileTVGuidedTurnRate +missileTVGuidedTurningRollAccel +missingCommandWillError +mlg_active_stream_query_interval +mlg_audio_volume +mlg_client_id +mlg_config_query_interval +mlg_enable +mlg_google_analythics_id +mlg_google_analythics_perc +mlg_google_analythics_url +mlg_inactive_stream_query_interval +mlg_league +mlg_metadata_title_entry +mlg_min_islive_interval +mlg_mixpanel_token +mlg_mixpanel_url +mlg_platform_name +mlg_show_hidden +mm_KeyframeMeterDebug +mm_KeyframeUsageDebug +mm_KeyframeUsageReset +mm_animation_driven_movement +mm_debug +mm_debugKeyframe +mm_doLegYawOffset +mm_enable +mm_inputSet +mm_keyframeInterval +mm_keyframeMeterIsClient +mm_keyframeMeter_clientNum +mm_keyframeMeter_pos +mm_keyframeUsageAnimIndex +mm_keyframeUsage_pos +mm_optimizations +mm_simulateClientPmoves +modPrvAnimDumpInTime +modPrvAnimDumpOutTime +modPrvCurrAndMaxFrameIndexes +modPrvUseAnimDump +mods_DisableStats +mods_SavePlayerBindingsToMod +mods_enabled +modvar +mortarStrikesLeft +motdDelay +motd_enabled +mp_blackjack_consumable_wait +mp_prototype +msg_dumpEnts +msg_hudelemspew +msg_logPredictionPositionErrors +msg_printEntityNums +msg_zlibCompress +msg_zlibCompressOutput +n +name +narrowShardRatio +neo_PTELimit +net_broadcast +net_broadcast_ip +net_debug_server_time_error +net_emu_client +net_emu_jitter +net_emu_latency +net_emu_packet_loss +net_emu_server +net_ip +net_logSnapshotTiming +net_minigraph +net_noudp +net_port +net_profile +net_showprofile +net_socksEnabled +net_socksPassword +net_socksPort +net_socksServer +net_socksUsername +netchan_ackInterval +netchan_debugSpew +netchan_debugSpewChan +netchan_doSwap +netchan_drawGraph +netchan_dropFragChance +netchan_emergencyFreePercent +netchan_fakeLoad +netchan_firstAckWait +netchan_jqprofEnabled +netchan_jqprofThreshold +netchan_logToFile +netchan_mainThreadWaitMs +netchan_msgLifeTime +netchan_nackWaitMs +netchan_statsResetInterval +netfieldchk +netstats_dummy_tracker_data +nextarena +nextmap +noCheapSpawns +noDW +noai +noclip +notarget +nv_textureReleaseFrameDelay +nv_textureReleaseMaxPerFrame +oldShotgunSpread +onlinegame +onlykick +oob_damage_interval_ms +oob_damage_per_interval +oob_max_distance_before_black +oob_time_remaining_before_black +oob_timekeep_ms +oob_timelimit_ms +orbisGame +orbis_PTELimit +orbis_authBypass +orbis_checkpsn_interval +orbis_checkpsplus_interval +orbislive_reduceCheckNetConnection +p +packetDebug +paintjobVersion +partyChatDisallowed +partyMigrate_NomineeRecalcInterval +partyMigrate_TestInterval +partyMigrate_maxBWPackets +partyPrivacyCheckInterval +partyPrivacyEnabled +partyPrivacyPumpEnabled +party_autoteams +party_debug +party_debugMembers +party_maxplayers +party_minplayers +party_reliableMigrate +password +path_alwaysFindNearestNode +path_boundsFudge +path_checkDangerousNodes +path_double_wide_checks +path_minzBias +pc_newversionavailable +pcache_privacy +pclive_updateFriends +penetrationCount +penetrationCount_allies +penetrationCount_axis +perk_armorPiercing +perk_armorVest +perk_armorpiercing +perk_blackbirdShowsGpsJammer +perk_bulletDamage +perk_bulletPenetrationMultiplier +perk_damageKickReduction +perk_deathStreakCountRequired +perk_delayExplosiveTime +perk_directionalfire_clipped_show_direction +perk_disarmExplosiveTime +perk_dogsAttackGhost +perk_extraBreath +perk_fastLadderClimbMultiplier +perk_fireproof +perk_flakJacket +perk_flakJacket_hardcore +perk_gpsjammer_alpha +perk_gpsjammer_fade_time +perk_gpsjammer_graceperiods +perk_gpsjammer_min_distance +perk_gpsjammer_min_speed +perk_gpsjammer_time_period +perk_grenadeDeath +perk_grenadeTossBackTimer +perk_healthRegenMultiplier +perk_interactSpeedMultiplier +perk_killstreakAnteUpResetValue +perk_killstreakDeathPenaltyMultiplier +perk_killstreakMomentumMultiplier +perk_killstreakReduction +perk_mantleReduction +perk_marksmanEnemyNameFadeIn +perk_marksmanEnemyNameFadeOut +perk_nottargetedbyai_graceperiod +perk_nottargetedbyai_min_speed +perk_requireScavengerPerk +perk_scavenger_clip_multiplier +perk_scavenger_lethal_proc +perk_scavenger_tactical_proc +perk_sgjammer_alpha +perk_sgjammer_fade_time +perk_sgjammer_graceperiods +perk_sgjammer_min_distance +perk_sgjammer_min_speed +perk_sgjammer_time_period +perk_shellShockReduction +perk_spawn_ping_duration_ms +perk_speedMultiplier +perk_sprintFireRecoveryMultiplier +perk_sprintMultiplier +perk_sprintMultiplierExtra +perk_sprintRecoveryMultiplier +perk_throwbackInnerRadius +perk_tracker_fx_fly_height +perk_tracker_fx_foot_height +perk_weapAdsMultiplier +perk_weapEquipmentUseMultiplier +perk_weapMeleeMultiplier +perk_weapRateMultiplier +perk_weapReloadMultiplier +perk_weapSpreadMultiplier +perk_weapSwitchMultiplier +perk_weapTossMultiplier +phys_ai_collision_mode +phys_bulletSpinScale +phys_bulletUpBias +phys_buoyancy +phys_buoyancyDistanceCutoff +phys_buoyancyFastComputation +phys_buoyancyFloatHeightOffset +phys_buoyancyRippleFrequency +phys_buoyancyRippleVariance +phys_debugBigQueries +phys_debugCallback +phys_debugDangerousRigidBodies +phys_debugExceededGjkPrims +phys_debugExpensivePushout +phys_disableEntsAndDynEntsCollision +phys_dragAngular +phys_dragLinear +phys_drawCollisionObj +phys_drawConstraints +phys_drawNitrousVehicle +phys_drawNitrousVehicleEffects +phys_drawNitrousVehicleEngine +phys_drawcontacts +phys_entityCollision +phys_floatTimeVariance +phys_fluid +phys_gravity +phys_gravity_dir +phys_impact_distance_cutoff +phys_impact_fx +phys_impact_intensity_limit +phys_impact_max_pfx_per_frame +phys_impact_max_sfx_per_frame +phys_impact_render +phys_impact_silence_window +phys_maxFloatTime +phys_msecStep +phys_piecesSpawnDistanceCutoff +phys_player_collision_adjust_height +phys_player_collision_mode +phys_player_step_on_actors +phys_player_step_on_actors_zm +phys_ragdoll_buoyancy +phys_ragdoll_joint_damp_scale +phys_reeval_frequency +phys_usePhysicsForLocalClientIfPossible +phys_userRigidBodies +phys_vehicleDamageFroceScale +phys_vehicleFriction +phys_vehicleGravityMultiplier +phys_vehicleWheelEntityCollision +phys_verbose +phys_waterDragAngular +phys_waterDragLinear +phys_wind_debug +phys_wind_distance_cutoff +phys_wind_enabled +phys_wind_force_direction +phys_wind_force_speed +phys_wind_vehicle_scale +pickShards +pickupPrints +pitchAccelerationTime +pitchDecelerationThreshold +platformSessionDebugInfo +platformSessionEnabled +platformSessionImg +platformSessionImgPath +platformSessionInviteMessage +platformSessionLaunchInviteJoinProcessDelay +platformSessionName +platformSessionOrbisCreateTimeout +platformSessionOrbisGetInviteInfoTimeout +platformSessionOrbisGetSessionInfoTimeout +platformSessionOrbisImg +platformSessionOrbisImgPath +platformSessionOrbisInviteMessage +platformSessionOrbisInviteTimeout +platformSessionOrbisJoinTimeout +platformSessionOrbisLeaveTimeout +platformSessionOrbisLockFlag +platformSessionOrbisMigrationFlag +platformSessionOrbisName +platformSessionOrbisSearchTimeout +platformSessionOrbisSessionTypeFlag +platformSessionOrbisStatus +platformSessionOrbisUpdateTimeout +platformSessionPartyPrivacy +platformSessionShowErrorCodes +platformSessionStatus +platformSessionUpdateIntervalOrbis +platformSessionsOrbis +platformSessionsOrbisPlayTogetherEnabled +playedWithUpdateInterval +playerCount +playerEnenergy_enabled +playerEnergy_EMPAffectsBoost +playerEnergy_EMPDrain +playerEnergy_boostUpRate +playerEnergy_boostUpRate_emp +playerEnergy_boostUpRate_fast +playerEnergy_doubleJumpCostRatio +playerEnergy_enabled +playerEnergy_jukeCostRatio +playerEnergy_jukeEnergyEnabled +playerEnergy_maxReserve +playerEnergy_minReserve +playerEnergy_rechargeDuringSprint +playerEnergy_restRate +playerEnergy_restRate_emp +playerEnergy_restRate_fast +playerEnergy_restRate_sprint +playerEnergy_restRate_sprintEmp +playerEnergy_restRate_sprintFast +playerEnergy_slideCostRatio +playerEnergy_slideCostRatio_emp +playerEnergy_slideEnergyEnabled +playerEnergy_slowRechargeDuringSprint +playerEnergy_sprintEnergyEnabled +playerEnergy_sprintRate +playerEnergy_sprintRate_emp +playerEnergy_sprintRate_fast +playerEnergy_sprintRechargeDelayMs +playerEnergy_wallRunDelayMs +playerEnergy_wallRunEnergyEnabled +playerEnergy_wallRunRate +playerJetEnergy_boostDownRate +playerJetEnergy_boostUpRate +playerJetEnergy_deployCost +playerJetEnergy_enabled +playerJetEnergy_hoverRate +playerJetEnergy_maxReserve +playerJetEnergy_minReserve +playerJetEnergy_restRate +playerJet_accel +playerJet_downBoostAccel +playerJet_enabled +playerJet_frictionMax +playerJet_frictionMin +playerJet_fx_a +playerJet_fx_b +playerJet_fx_c +playerJet_fx_d +playerJet_hoverAccel +playerJet_initHeight +playerJet_preHoverAccel +playerJet_speed +playerJet_tag_left_back +playerJet_tag_left_front +playerJet_tag_right_back +playerJet_tag_right_front +playerJet_upBoostAccel +playerJet_upSaveBoostAccel +playerPushAmount +playerSounds_rotationAngleThresholdLoop +playerSounds_rotationAngleThresholdStep +playerWeaponRaisePostIGC +player_AimBlend_Back_Low +player_AimBlend_Back_Mid +player_AimBlend_Back_Up +player_AimBlend_Head +player_AimBlend_Neck +player_AimBlend_Pelvis +player_MGUseRadius +player_ProneLaststandFreeMove +player_ProneMinPitchDiff +player_ZVelocityThresholdThirdPerson +player_ZVelocityThreshold_fast +player_ZVelocityThreshold_med +player_ZVelocityThreshold_rapid +player_ZVelocityThreshold_slow +player_adsExitDelay +player_animRunThreshhold +player_animWalkThreshhold +player_armPulseEnabled +player_backSpeedScale +player_bodylights +player_bodylightsCorpseFadeTime +player_bodylightshdr +player_breath_fire_delay +player_breath_gasp_lerp +player_breath_gasp_scale +player_breath_gasp_time +player_breath_hold_lerp +player_breath_hold_time +player_breath_snd_delay +player_breath_snd_lerp +player_chestWaterFrictionScale +player_clipSizeMultiplier +player_deathInvulnerableTime +player_debug +player_debugHeadOffset +player_debugHeadOffsetTolerance +player_debugHealth +player_debugSprint +player_deepWaterWadeScale +player_disableUnderwaterVisionset +player_disableWeaponsInWater +player_disableWeaponsOnVehicle +player_dmgtimer_flinchTime +player_dmgtimer_maxTime +player_dmgtimer_minScale +player_dmgtimer_stumbleTime +player_dmgtimer_timePerPoint +player_dpad_gadget_scheme +player_enableShuffleAnims +player_enduranceSpeedScale +player_fallImpact_camImpact_enabled +player_fallImpact_camLateralTranslateScale +player_fallImpact_camSwingDuration +player_fallImpact_camUpTranslateScale +player_fallImpact_rumble_enabled +player_fallImpact_shake_base_scale +player_fallImpact_shake_duration +player_fallImpact_shake_enabled +player_fallImpact_viewMovementPitch +player_fallImpact_viewMovementRoll +player_fallImpact_viewMovementYaw +player_fallWindZVelocityThreshold +player_fallWindZVelocityThresholdThirdPerson +player_fall_rumble_enabled +player_firstPersonDeaths +player_floatSpeed +player_footstepsThreshhold +player_forceGibs +player_forceRedCrosshair +player_idleToMoveAnimSpeed +player_knockbackMoveThreshhold +player_lastStandBleedoutTime +player_lastStandBleedoutTimeNoRevive +player_lastStandCrawlTransition +player_lastStandDistScale +player_lastStandHealthOverlayTime +player_lastStandSuicideDelay +player_lean_rotate +player_lean_rotate_crouch +player_lean_shift +player_lean_shift_crouch +player_lens_enabled +player_lookAtEntityAllowChildren +player_meleeChargeCancelOnVictimDeath +player_meleeChargeFriction +player_meleeChargeHeightTolerance +player_meleeChargeMaxSpeed +player_meleeChargeMinSpeed +player_meleeHeight +player_meleeHeightChargeAir +player_meleeIdealEndDistance +player_meleeInterruptFrac +player_meleeLungeAcceleration +player_meleeLungeDamageScalar +player_meleeLungeDeviationCutoff +player_meleeLungeSpeedCutoff +player_meleeLungeTimeCutoff +player_meleeLungeUnderwaterSpeedScale +player_meleeRangeChargeAirDefault +player_meleeRangeChargeDefault +player_meleeRangeDefault +player_meleeWidth +player_meleeWidthChargeAir +player_moveSoundThresholdAccel +player_moveSoundThresholdDecel +player_moveSoundThresholdRatio +player_moveThreshhold +player_move_factor_on_torso +player_name +player_revivePlayerListCycleTime +player_reviveTriggerRadius +player_runThreshhold +player_runbkThreshhold +player_scopeExitOnDamage +player_shallowWaterFrictionScale +player_shallowWaterHeightRatio +player_shallowWaterWadeScale +player_slick_accel +player_slick_invspeed +player_slick_wishspeed +player_sliding_friction +player_sliding_velocity_cap +player_sliding_wishspeed +player_slopeAnimAngle +player_spectateSpeedScale +player_sprintCameraBob +player_sprintFallAnim +player_sprintForwardMinimum +player_sprintJumpAnimRate +player_sprintJumpDropWeaponScaler +player_sprintMinTime +player_sprintRechargePause +player_sprintSpeedScale +player_sprintStrafeSpeedScale +player_sprintTime +player_sprintUnlimited +player_standingViewHeight +player_strafeAnimCosAngle +player_strafeSpeedScale +player_sustainAmmo +player_swimAcceleration +player_swimAllowGrenades +player_swimAnimMinSpeed +player_swimCombatOutADSStopAnimRatio +player_swimDamage +player_swimDamagerInterval +player_swimFallOffAngle +player_swimFocalLength +player_swimFootstepWaterDuration +player_swimForwardAnimCatchupMax +player_swimForwardAnimCatchupMin +player_swimForwardMinAngle +player_swimForwardMinSpeed +player_swimForwardSettleTime +player_swimForwardWarmupTime +player_swimFrictionHigh +player_swimFrictionLow +player_swimFrictionVerticalThreshold +player_swimHeightRatio +player_swimLensEnabled +player_swimLensInTransRate +player_swimMaxMovePitchWhileTreading +player_swimMaxSprintPitchWhileTreading +player_swimMaxZ +player_swimMovementShellshockScale +player_swimMovingAnimSpeed +player_swimMovingStopAnimRatio +player_swimSpeed +player_swimSpeedupIdleAnimMinSpeed +player_swimSprintAnimSpeed +player_swimSprintFocalLength +player_swimSprintLensEnabled +player_swimSprintLensInTransRate +player_swimSprintSpeedScale +player_swimSprintStopAnimRatio +player_swimSurfaceSmoothingDepth +player_swimSurfaceSmoothingScalar +player_swimTime +player_swimUnderwaterHeightRatio +player_swimVerticalAcceleration +player_swimVerticalSpeedMax +player_swimViewHeight +player_swimWaterPlaneDistance +player_swimallowshooting +player_swimallowshootingmoving +player_swimcantraverse +player_swimforcesurface +player_swimming_control_scheme +player_swimming_enabled +player_t7MeleeDeathFromAboveRange +player_throwbackInnerRadius +player_throwbackOuterRadius +player_tmodeSightEnabled +player_topDownCursorDist +player_topDownCursorPos +player_turnAnims +player_turnRateScale +player_underwaterWalkJumpHeight +player_underwaterWalkSpeedScale +player_underwaterWalkSprint +player_underwatercantraverse +player_useRadius +player_useRadius_zm +player_useSlopeAnims +player_useTouchScore +player_useWaterFriction +player_useWaterWadeScale +player_viewLockEnt +player_viewRateScale +player_view_pitch_down +player_view_pitch_up +player_view_swim_pitch_down +player_view_swim_pitch_up +player_waistWaterFrictionScale +player_waistWaterWadeScale +player_waterSpeedScale +player_waterWadeScaleUnderwater +player_zombieMeleeHeight +player_zombieMeleeRange +player_zombieMeleeWidth +player_zombieSpeedScale +player_zombieSprintSpeedScale +playgo_profiling +playgo_refreshinterval +playlist_allowdevmaps +playlist_autoEvent +playlist_autoEventsEnabled +playlist_autoevent +playlist_debug +playlist_excludeGametype +playlist_excludeGametypeMap +playlist_excludeMap +playlist_forceEvent +playlist_linearMapCycle +playlist_linearMapCycleRandom +popInLetterFXTime +printCACValidationErrors +printCACValidationSuccesses +printentities +probation_league_dashboardScalar +probation_league_enabled +probation_league_forgiveCount +probation_league_kickScalar +probation_league_kickcalar +probation_league_matchHistoryWindow +probation_league_probationThreshold +probation_league_probationTime +probation_league_quitScalar +probation_league_timeoutScalar +probation_league_warningThreshold +probation_public_enabled +probation_public_forgiveCount +probation_public_kickScalar +probation_public_matchHistoryWindow +probation_public_probationThreshold +probation_public_probationTime +probation_public_quitScalar +probation_public_timeoutScalar +probation_public_warningThreshold +probation_version +prof_disableGameplayGfx +prof_gameplayGfx +prof_selectCameraPosition +prof_selectCameraPositionTeleport +profileDirtyInterval +profileDwUpdateInterval +profileGetInterval +profile_reset +profile_show_loading +prone_bipod_enable +prone_crawlLoopTime +protocol +ps3Game +ps4_swapcirclex +purchasedClassSetCount +qosLocklessQueue +qosMaxAllowedPing +qosPreferredPing +qos_echo_chance +qos_firstUpdateMS +qos_lastUpdateMS +qos_maxProbeWait +qos_minEchoServers +qos_minPercent +qos_minProbes +qos_packetLossPercent +qos_simulateLongQoS +qport +queue_actions_enabled +quit +quit_on_error +r_DFE +r_EOTF1886 +r_EOTFLb +r_EOTFLw +r_EOTFgamma +r_FilmIsoMax +r_FilmIsoMin +r_FilmIsoNoise +r_FilmIsoNoiseEnable +r_LensAbbe +r_LensDistortionGL +r_LensDistortionK1 +r_LensDistortionK2 +r_LensDistortionK3 +r_LensDistortionKS +r_LensOpticalLength +r_MaterialParameterTweak +r_OIT +r_OIT_Debug +r_OIT_MaxEntries +r_POMLODEnd +r_POMLODStart +r_PurkinjeHue +r_PurkinjeMax +r_PurkinjeMin +r_ST2084 +r_ST2084debug +r_ST2084debugWipe +r_ST2084debugWipeWhite +r_ST2084debugWipeWhiteMeasure +r_aaAllowTemporalMultiGpu +r_aaTechnique +r_aberrationFX_enable +r_activeLensID +r_actorShadowCount +r_actorShadowFade +r_addLightWorker +r_adsBloomDownsample +r_adsWorldFocalDistanceMax +r_adsWorldFocalDistanceMin +r_adsWorldFocalDistanceTrackBackScale +r_alphaMap +r_anaglyphFX_enable +r_applyOIT +r_asyncCompute +r_atmosphere_densityM +r_atmosphere_densityR +r_atmosphere_enable +r_atmosphere_groundLevel +r_atmosphere_scatterG +r_atmosphereextinctionstrength +r_atmospherefogcolor +r_atmospherefogdensity +r_atmospherehazebasedist +r_atmospherehazecolor +r_atmospherehazedensity +r_atmospherehazefadedist +r_atmospherehazespread +r_atmosphereinscatterstrength +r_atmospherepbramount +r_atmospheresunstrength +r_autoLodCullRadius +r_autoLodScale +r_autoResolutionControllerIdle +r_autoResolutionScale +r_autoResolutionThreshold +r_autoResolutionTune +r_autoResolutionUIThreshold +r_autoResolutionUITune +r_backBufferCount +r_backendSwapBuffersAssistRelease +r_bc7CompressAsync +r_blinkCullNone +r_blinkForwardSSS +r_blinkGbuffer +r_blinkGbufferDecal +r_blinkGbufferEnt +r_blinkGbufferViewmodel +r_blinkGbufferViewmodelDecal +r_blinkGbufferVolDecal +r_blinkOIT +r_blinkTrans +r_bloomEnable +r_bloomUseLutALT +r_blur +r_blurAndTintEnable +r_blurAndTintLevel +r_brushLimit +r_cachedSpotShadowCopyMode +r_cameraInfo +r_catsEyeAberation +r_catsEyeBlur +r_catsEyeBlurTint +r_catsEyeDecolor +r_catsEyeDistortion +r_catsEyeFX_enable +r_catsEyeNoise +r_catsEyeReset +r_catsEyeTexture +r_chaserFX_enable +r_chkbDiffWeight +r_chkbMode +r_chkbSameWeight +r_chkbTexLodBias +r_circleMaskRadius +r_classifyAsync +r_clear +r_clearAllGBuffers +r_clearColor +r_clearColor2 +r_clearView +r_clothPrimaryTint +r_clothSecondaryTint +r_cmdbuf_worker +r_cmdlistChain +r_codeImageDrawDebug +r_codeImageDrawDebugInfo +r_codeImageDrawImage +r_codeImageDrawImageSize +r_colorMap +r_computeSpritesAsync +r_convergence +r_createLutAsync +r_cubicUpsampleParam +r_cullLightsAsync +r_cullLightsAsyncHighPriority +r_currentMonitor +r_deadOps +r_deadOpsActive +r_debugDisableLocalProbes +r_debugImage +r_debugImageAdvanced +r_debugImageInfo +r_debugMaterial +r_debugMetalStorm +r_debugModel +r_debugShowCoronas +r_debugShowDynamicLights +r_debugShowLightBoundsSelect +r_debugShowPrimaryLights +r_debugShowProbeBlends +r_debugShowProbes +r_debugShowProbesBoundsSelect +r_dedicatedPlayerShadow +r_dedicatedPlayerShadowCull +r_dedicatedPlayerShadowCullAngle +r_dedicatedPlayerSpotOmniShadowResolution +r_dedicatedPlayerSunShadowPenumbraScale +r_dedicatedPlayerSunShadowResolution +r_dedicatedShadowsUmbra +r_deferredBilateralUpsampleSSAO +r_deferredBlurBacklit +r_deferredCullLights +r_deferredDebugDrawAttenuationVolumes +r_deferredDrawPrimaries +r_deferredDrawPrimaryIndex +r_deferredDrawPrimaryOmnis +r_deferredDrawPrimarySpots +r_deferredDrawProbeIndex +r_deferredDrawProbes +r_deferredDrawSceneLights +r_deferredEnableAO +r_deferredForceShadowNeverUpdate +r_deferredIgnoreShadowUpdate +r_deferredMaxVisibleLights +r_deferredMaxVisibleProbes +r_deferredPermuteShowClassification +r_deferredPermuteTiles +r_deferredPermuteTilesSwizzle +r_deferredSSTOptims +r_deferredShowAO +r_deferredShowInfo +r_deferredShowSunVis +r_deferredUseAttenuationVolumes +r_deferredViewmodel +r_depthPrime +r_diffuseProbeDebug +r_disableGenericFilter +r_dobjLimit +r_dofFocusPeaking +r_dofMode +r_dofQuality +r_dofTweak +r_dof_aperture_override +r_dof_enable +r_dof_farBlur +r_dof_farEnd +r_dof_farStart +r_dof_max_override +r_dof_min_override +r_dof_nearBlur +r_dof_nearEnd +r_dof_nearStart +r_dof_showdebug +r_dof_tweak +r_dof_viewModelEnd +r_dof_viewModelStart +r_drawBModels +r_drawBsp +r_drawDebugFogParams +r_drawDynEnts +r_drawFrameDurationGraph +r_drawFxOnProbes +r_drawInfo +r_drawModelsGobo +r_drawPlayersInDynamicProbe +r_drawPrimCap +r_drawPrimFloor +r_drawPrimHistogram +r_drawSModels +r_drawSceneEnts +r_drawSceneModels +r_drawSun +r_drawTerrain +r_drawWorld +r_drawXModels +r_dualPlayEnable +r_dumpRenderTargetFormats +r_dynamicProbeDebugColors +r_dynamicProbeInitBounceCount +r_dynamicProbePrefilter +r_dynamicSceneResolution +r_dynamicSceneResolutionMode +r_eacPathFX_enable +r_eacPath_Posn +r_eacPath_Radius +r_eacPath_Step +r_emulateSlowOrHitchyPresent +r_enableCubicUpsample +r_enableGlassDpvs +r_enableOccluders +r_enablePlayerShadow +r_enableVolDecals +r_ev_distance +r_ev_edgethickness +r_ev_edgewidth +r_ev_geometryrange +r_ev_random_edge +r_ev_random_ground +r_ev_rate +r_ev_screen_scale +r_ev_screen_threshold +r_ev_targetrange +r_ev_targetwidth +r_ev_testenable +r_ev_width +r_expAWB +r_expAuto +r_expCmp +r_expMax +r_expMin +r_expSigma +r_expSigmaAlpha +r_expSigmaBeta +r_expSigmaMax +r_expSigmaMin +r_expandInstancesToDrawIndirect +r_exposureAdaptation +r_exposureAdaptationTweak +r_exposureAsync +r_exposureEyeWeight +r_exposureTweak +r_exposureValue +r_extracamDisable +r_extracam_add_debug_cam +r_extracam_add_debug_cam_width +r_extracam_custom_aspectratio +r_extracam_remove_debug_cam +r_extracam_show_axis +r_extracam_show_render_targets +r_farClip +r_filmLut +r_filmTweakEnable +r_filmTweakLut +r_filmUseTweaks +r_finalShiftX +r_finalShiftY +r_flameFX_FPS +r_flameFX_distortionScaleFactor +r_flameFX_enable +r_flameFX_fadeDuration +r_flameFX_magnitude +r_flameScaler +r_flame_allowed +r_fog +r_fogBaseDist +r_fogBaseHeight +r_fogColor +r_fogHalfDist +r_fogHalfHeight +r_fogIntensity +r_fogOpacity +r_fogSkyHalfHeightOffset +r_fogSunColor +r_fogSunInner +r_fogSunIntensity +r_fogSunOpacity +r_fogSunOuter +r_fogSunPitchOffset +r_fogSunYawOffset +r_fogTweak +r_fog_disable +r_fontResolution +r_font_cache_debug_display +r_forceAdapter +r_forceGbufferVertexOnly +r_forceLod +r_forceMaxTextureSize +r_forceMonitorTV +r_forceTextureAniso +r_forcedModelLods +r_foveaAcuityColorMax +r_foveaAcuityColorMin +r_foveaAcuityVisualMax +r_foveaAcuityVisualMin +r_framesyncThreshold +r_fullHDRrendering +r_fullbright +r_fullscreen +r_fuzzSceneWidth +r_fxShadows +r_fx_backlighting_amount +r_fxaaContrastThreshold +r_fxaaDebug +r_fxaaSubpixelRemoval +r_gbufferDepthSort +r_gbufferDepthSortStaticModels +r_gbufferOccluderMinSize +r_gbufferShowContent +r_genericFilter_enable +r_genericSceneVector0 +r_genericSceneVector1 +r_genericSceneVector2 +r_genericSceneVector3 +r_genericSceneVector_debug +r_glossMap +r_gpuCullingDebugShowDepth +r_gpuCullingDisableDepthTest +r_gpuCullingUseGpuResultForPrimaryLight +r_gpuCullingUseLateDepth +r_gpuCullingUseWorker +r_gpuFrameHistogram +r_gpuTimers +r_graphicContentBlur +r_grassEnable +r_heatPulseFX_enable +r_hotZone_angle1 +r_hotZone_angle2 +r_hotZone_fadedn +r_hotZone_fadeup +r_hotZone_heightlim +r_hotZone_radius1 +r_hotZone_radius2 +r_hotZone_zgradiant +r_hybridPreferDeferred +r_ignore +r_ignorehwgamma +r_instancedVolumeDecals +r_jqprof_capture +r_lateAllocLimit +r_lensAbberation +r_lensApertureAngle +r_lensApertureBlade +r_lensFlaresDebug +r_lightPickerFreeze +r_lightingDebugOverlay +r_lightingDebugOverlayAlpha +r_lightingDebugOverlayScale +r_lightingEnableAggressiveShadowEviction +r_lightingOmniShadowForceSize +r_lightingOmniShadowPenumbraOverride +r_lightingReflectionProbeMipDrop +r_lightingShadowFiltering +r_lightingSpotOmniShadowMaxQuality +r_lightingSpotShadowDropSizeDistance +r_lightingSpotShadowForceSize +r_lightingSpotShadowPenumbraOverride +r_lightingSunShadowCacheDynamicSiegeDistance +r_lightingSunShadowCacheEnable +r_lightingSunShadowCacheEnableUmbra +r_lightingSunShadowCacheEnableUnusedTracking +r_lightingSunShadowCacheForceOff +r_lightingSunShadowCullingToggle +r_lightingSunShadowDebugDrawAABBs +r_lightingSunShadowDisableDynamicDraw +r_lightingSunShadowDobjMovementTracking +r_lightingSunShadowDynamicSplitCount +r_lightingSunShadowDynentMovementTracking +r_lightingSunShadowEnableAsync +r_lightingSunShadowForceSSTOnly +r_lightingSunShadowPenumbraOverride +r_lightingSunShadowSSTMipDrop +r_lightingSunShadowSkipSplits +r_lightingSunShadowSplitScreenEmulate +r_litfog_bank_select +r_litfog_max_visible_volume_count +r_litfog_volume_count +r_litfog_volume_start +r_lockFrameRateTo30Hz +r_lockFrameRateTo30Hz_dynResOff +r_lockFrameRateTo30Hz_enable +r_lockFrameRateTo30Hz_force +r_lockPvs +r_lockPvsInCode +r_lodBiasRigid +r_lodScaleRigid +r_lodThresholdPixelArea +r_lodUseDynamicResolution +r_lowResolutionMode +r_makeDark_enable +r_marksDebugWorldbrushNormal +r_materialLab +r_materialXYZ +r_maxPOMSamples +r_maxSpotShadowUpdates +r_mode +r_modelLimit +r_modelLodBias +r_modelLodLimit +r_modelSkelWorker +r_monitor +r_monitorCalibrate +r_monitorCount +r_monitorTV +r_motionBlurEnable +r_motionBlurMode +r_motionBlurQuality +r_motionBlurStrength +r_motionVectorDebugDisplay +r_motionVectorGenerateEnable +r_motionVectorStaticComputeAsync +r_motionVectorStaticWithMB +r_newLensFlares +r_newLensFlares_offscreen_buffer_size +r_newLensFlares_show_outlines +r_newLensFlares_show_sources +r_norefresh +r_normalMap +r_num_viewports +r_objSpaceViewModelDObj +r_occQueryDebug +r_occlusionMap +r_oit +r_omniShadowRes +r_p4x_capture +r_paperWhite +r_pbgBank +r_pbgFogBank +r_pbrfog_enable +r_picmip +r_pix_material +r_pix_sortkey +r_pixelShaderGPRReallocation +r_poisonFX_blurMax +r_poisonFX_blurMin +r_poisonFX_debug_amount +r_poisonFX_debug_enable +r_poisonFX_dvisionA +r_poisonFX_dvisionX +r_poisonFX_dvisionY +r_poisonFX_pulse +r_poisonFX_warpX +r_poisonFX_warpY +r_polygonOffsetBiasInt +r_polygonOffsetClamp +r_polygonOffsetScale +r_polygonOffsetTweakEnable +r_portalOccluderTest +r_postFxIndex +r_postFxKeylineFrontEnd +r_postFxSubIndex +r_postFxUseTweaks +r_postFxWobble +r_previousFullscreen +r_primaryLightTweakDiffuseStrength +r_primaryLightTweakSpecularStrength +r_primaryLightUseTweaks +r_qrcode_debug_display +r_qrcode_debug_display_size +r_radioactiveBlur +r_radioactiveFX_enable +r_radioactiveIntensity +r_radioactiveSpeed +r_refreshRate +r_removeSystemReservation +r_rendertarget_debug_display +r_resetLightingDebug +r_resolveMethod +r_reviveFX_debug +r_reviveFX_edgeAmount +r_reviveFX_edgeColorTemp +r_reviveFX_edgeContrast +r_reviveFX_edgeMaskAdjust +r_reviveFX_edgeOffset +r_reviveFX_edgeSaturation +r_reviveFX_edgeScale +r_saveDefaultRenderImages +r_scaleViewport +r_sceneGamma +r_sceneResolution +r_sceneResolutionMultiplier +r_shaderDebug +r_shader_constant_set_debug_range +r_shader_constant_set_enable +r_showBModelNamesDist +r_showBounds +r_showCollision +r_showCollisionDepthTest +r_showCollisionDist +r_showCollisionGroups +r_showCollisionPolyType +r_showCullBModels +r_showCullDistDebug +r_showCullSModels +r_showCullXModels +r_showCullXmodelsEntNum +r_showDObjModelNamesDist +r_showDuplicateRenderInfoDist +r_showDynEntModelNames +r_showEntModelNamesDist +r_showExposureZones +r_showForceNoCull +r_showImpactVolDecalDebug +r_showLodInfo +r_showLodInfoMaxDistance +r_showModelNamesPlacement +r_showOccluders +r_showOverdraw +r_showOverdrawAlpha +r_showOverdrawMax +r_showOverdrawNumLayers +r_showPBRCheck +r_showPenetration +r_showSModelNames +r_showSiegeDObjModleNames +r_showSiegeModelNames +r_showSunDirectionDebug +r_showSurfCounts +r_showTextureOverrideInfo +r_showTriCounts +r_showTriDensity +r_showTris +r_showVertCounts +r_showWorldVolDecalDebug +r_siege_debug_scale +r_siege_info +r_siege_notetrack_debug +r_skipDrawTris +r_skipPvs +r_skipXModelZeroSizedBones +r_skyBoxColorIDX +r_skyRotation +r_skyTransition +r_smaa +r_smaaCompute +r_smaaHighQuality +r_smaaQuincunx +r_smodel_combineWorkers +r_smodel_partialSortWorkers +r_smodel_splitWorkers +r_smp_backend +r_smp_worker_threads +r_sortBackToFront +r_sortDrawSurfsBsp +r_sortDrawSurfsStaticModel +r_sortTrans +r_specularGlossMap +r_specularMap +r_speedBlurAmount +r_speedBlurFX_enable +r_splitScreenExpandFull +r_splitscreenBlurEdges +r_spotLightEntityShadows +r_spotLightSModelShadows +r_spotLightShadows +r_spotMeter +r_spotShadowRes +r_ssaoAsync +r_ssaoCompareRefTechnique +r_ssaoEnable +r_ssaoRefTechnique +r_ssaoShowDebug +r_ssaoTechnique +r_ssao_gtaoHigh +r_ssao_gtaoLow +r_ssao_gtaoMid +r_ssao_gtaoStrength +r_ssao_gtaoTweak +r_ssao_hbaoFalloff +r_ssao_hbaoIntensity +r_ssao_hbaoNormalScale +r_ssao_hbaoRadius +r_ssao_hbaoSharpness +r_ssao_hbaoTanAngleBias +r_ssao_hdaoAcceptAngle +r_ssao_hdaoAcceptRadius +r_ssao_hdaoIntensity +r_ssao_hdaoNormalScale +r_ssao_hdaoRadius +r_ssao_hdaoRejectRadius +r_ssao_hdaoSharpness +r_ssao_hemiAOBlurTolerance +r_ssao_hemiAOCombineBeforeBlur +r_ssao_hemiAOCombineResWithMul +r_ssao_hemiAOHierarchyDepth +r_ssao_hemiAONoiseFilterTolerance +r_ssao_hemiAOQuality +r_ssao_hemiAORejectionFalloff +r_ssao_hemiAOSensitivity +r_ssao_hemiAOUpsampleTolerance +r_ssao_ohaoIntensity +r_ssao_ohaoRadius +r_ssao_ohaoSharpness +r_ssao_s1aoDepthScale +r_ssao_s1aoGapFalloff +r_ssao_s1aoGradiantFalloff +r_ssao_s1aoIntensity +r_ssao_s1aoRadius +r_ssao_s1aoSharpness +r_ssao_saoBias +r_ssao_saoEpsilon +r_ssao_saoIntensity +r_ssao_saoRadius +r_ssao_saoSharpness +r_ssao_saov2Bias +r_ssao_saov2Falloff +r_ssao_saov2Intensity +r_ssao_saov2Radius +r_ssao_saov2Sharpness +r_ssao_t7aoFalloff +r_ssao_t7aoIntensity +r_ssao_t7aoRadius +r_ssao_t7aoSelfOcclusion +r_ssao_t7aoSharpness +r_ssao_voaoFalloff +r_ssao_voaoIntensity +r_ssao_voaoRadius +r_ssao_voaoSharpness +r_ssao_voaoThickness +r_sssblurEnable +r_stereo3DAvailable +r_stereo3DEyeSeparation +r_stereo3DEyeSeparationScaler +r_stereo3DMode +r_stereo3DOn +r_stereo3DRightEyeReuseLeftEyeShadows +r_stereoFocusDepth +r_stereoGunShift +r_stereoTurretShift +r_stream +r_streamCheckAabb +r_streamClear +r_streamDistanceMax +r_streamDumpCurrentUsage +r_streamDumpDistance +r_streamDumpImageUsage +r_streamDumpInitial +r_streamDumpSortedImageList +r_streamFreezeState +r_streamHiddenPush +r_streamHidePlayer +r_streamHighPriorityThreshold +r_streamLowDetail +r_streamPaintDiffuse +r_streamProfile +r_streamReadLog +r_streamReflectionProbes +r_streamRemoveHimips +r_streamShowHints +r_streamShowLoadingMaterial +r_streamShowReadSpeeds +r_streamShowVolumes +r_streamTextureMemoryMax +r_streamTouchLookahead +r_submitDoneThreshold +r_sunColor +r_sunFilterInches +r_sunFlareTint +r_sunPitch +r_sunShadowSplitDistance +r_sunStops +r_sunTweak +r_tacScanFX_enable +r_tacScan_Eps +r_tacScan_FadeEnd +r_tacScan_FadeStart +r_tacScan_HotZone +r_tacScan_Layout +r_tacScan_Paths +r_tacScan_Popups +r_tacScan_Scale +r_tacScan_Traces +r_takeScreenShot +r_texFilterQuality +r_textureMipLodBias +r_textureMode +r_tilingHighlight +r_tilingLightCount +r_tilingProbeCount +r_tilingSunShadow +r_tmodeServerActive +r_triDensityPointAlpha +r_triDensityPointOnSmallTris +r_triDensityPointOnTriCenter +r_triDensityPointOnVerts +r_triDensityPointSize +r_triDensityScalePointAlpha +r_triDensityScalePointSize +r_triDensityShowOriginalGeo +r_triDensitySmallTriArea +r_uberResolveAsync +r_uhdMode +r_ui3d_debug_display +r_ui3d_h +r_ui3d_use_debug_values +r_ui3d_w +r_ui3d_x +r_ui3d_y +r_uiHudFX_enable +r_umbraAccurateOcclusionThreshold +r_umbraAllowDatabaseThread +r_umbraDisableForScene +r_umbraDisableForSceneZeroUmbraWork +r_umbraDisableForSpotOmniShadow +r_umbraDistanceScale +r_umbraDrawDebug +r_umbraEnable +r_umbraEnableDebugDisplay +r_umbraEnableParameterVolumes +r_umbraFilter +r_umbraGridHeight +r_umbraGridWidth +r_umbraLightVis +r_umbraMinRelativeContribution +r_umbraNearDistance +r_umbraQueryLocalLights +r_umbraTomeTriggerDebug +r_umbraVerbose +r_umrbaEnableParameterVolumes +r_underwaterAbsorptionRGB +r_underwaterHalfDistance +r_underwaterOutputMix +r_underwaterTweak +r_updateDynamicProbes +r_updateSingleDynamicProbe +r_updateSingleDynamicProbeFace +r_useBindlessMaterialKeyMerge +r_useBindlessTechnique +r_useCachedSpotShadow +r_useDynamicProbeTextures +r_useHidePartbits +r_useLensFov +r_useSimpleDObj +r_useStrict30HzConditions +r_validateCommandBuffers +r_vid_align +r_videoMode +r_viewModelSpotOmniShadowResolution +r_viewModelSunShadowResolution +r_viewmodelSelfShadow +r_viewportBackingColor +r_volumetric_lighting_blur_depth_threshold +r_volumetric_lighting_buffers_size_ratio +r_volumetric_lighting_density_scaler +r_volumetric_lighting_enable_probes +r_volumetric_lighting_enable_spot +r_volumetric_lighting_enable_sun +r_volumetric_lighting_enable_tweaks +r_volumetric_lighting_enabled +r_volumetric_lighting_fog_base_distance +r_volumetric_lighting_fog_base_height +r_volumetric_lighting_fog_half_distance +r_volumetric_lighting_fog_half_height +r_volumetric_lighting_force +r_volumetric_lighting_half_res_apply +r_volumetric_lighting_lights_skip_samples +r_volumetric_lighting_max_lit_omni_spot_fog_distance +r_volumetric_lighting_max_lit_sun_fog_distance +r_volumetric_lighting_max_spot_samples +r_volumetric_lighting_max_sun_samples +r_volumetric_lighting_mode +r_volumetric_lighting_phase_distribution +r_volumetric_lighting_probe_contribution_scaler +r_volumetric_lighting_scattering_albedo +r_volumetric_lighting_sun_intensity_scale +r_volumetric_lighting_sun_skip_samples +r_volumetric_lighting_sun_step_size +r_volumetric_lighting_uber_depth_resolve_enabled +r_volumetric_lighting_upsample_depth_threshold +r_vsync +r_vsync_tear_window_enable +r_vsync_tear_window_lower +r_vsync_tear_window_upper +r_warningRepeatDelay +r_waterFogTest +r_waterSheetingFX_allowed +r_waterSheetingFX_distortionScaleFactor +r_waterSheetingFX_enable +r_waterSheetingFX_magnitude +r_waterSheetingFX_radius +r_watersim_enabled +r_waveWaterActors +r_waveWaterDebugDraw +r_waveWaterDrawOnlyLevel +r_waveWaterFreeze +r_waveWaterGeneratorTweakIndex +r_waveWaterHeightOverride +r_waveWaterHeightOverrideEnable +r_waveWaterPoke +r_waveWaterPokeSize +r_waveWaterPrint +r_waveWaterTweakEnable +r_waveWaterZero +r_worldfogskysize +r_xanim_disableCosmeticBones +r_xanim_disableExtraChannel +r_xanim_drawBones +r_xcamsEnabled +r_xdebug +r_zfar +r_znear_depthhack +r_zombieNameAllowDevList +r_zombieNameAllowFriendsList +r_zombiesShooterSpotted +radius_damage_debug +ragdoll_activationVelocitySq +ragdoll_baselerp_time +ragdoll_bullet_force +ragdoll_bullet_upbias +ragdoll_debug +ragdoll_dump_anims +ragdoll_enable +ragdoll_explode_force +ragdoll_explode_upbias +ragdoll_fps +ragdoll_gravityScale +ragdoll_jitter_scale +ragdoll_jointlerp_time +ragdoll_max_life +ragdoll_max_simulating +ragdoll_musclePowerScale +ragdoll_reactivation_cutoff +ragdoll_rotvel_scale +ragdoll_self_collision_scale +rare_crate_bundle_id +rat_hostdir +rat_instanceid +rat_playback_enabled +rat_testid +rate +rb_drawCullWorkerDebugText +rb_drawSonarDebugText +rcon +rcon_password +reconnect +recordPointsSpent +recorder_bufferSize +recorder_channelAccuracy +recorder_channelAiCode +recorder_channelAiProfile +recorder_channelAlex +recorder_channelAnimation +recorder_channelAnimscript +recorder_channelCover +recorder_channelGrenades +recorder_channelMessaging +recorder_channelNone +recorder_channelPathFind +recorder_channelPerception +recorder_channelPhysics +recorder_channelScript +recorder_channelScriptedAnim +recorder_channelSpawning +recorder_channelSuppression +recorder_channelThreat +recorder_debugMemory +recorder_enableRec +recorder_recordAllVehicles +recorder_streamDObjects +recorder_stringScaleBase +recorder_textScale +recorder_textScaleDistBase +recorder_textScaleDistMax +redactionDisplayTime +redactionFadeDuration +redactionStartStrokeTime +redactionStrokeTime +reliableResendTime +reliableTimeoutTime +remote_missile_boost_acceleration +remote_missile_boost_shake_duration +remote_missile_boost_shake_radius +remote_missile_boost_shake_scale +remote_missile_boost_speed +remote_missile_brake_deceleration +remote_missile_brake_shake_duration +remote_missile_brake_shake_radius +remote_missile_brake_shake_scale +remote_missile_brake_speed +remote_missile_coast_speed +remote_missile_speed +render_actor_collision +render_bpi_env_collision +render_fake_ents +render_player_collision +render_script_movers +reportUserInterval +restrict_attachment +restrict_item +retail_incentive_id +reviveWidgetClampedScale +reviveWidgetEndDistance +reviveWidgetEndScale +reviveWidgetOffset +reviveWidgetRevivingScale +reviveWidgetStartDistance +reviveWidgetStartScale +revive_time_taken +revive_trigger_radius +riotshield_assist_time +riotshield_bullet_damage_scale +riotshield_damage_score_max +riotshield_damage_score_threshold +riotshield_debug +riotshield_deploy_limit_radius +riotshield_deploy_pitch_max +riotshield_deploy_roll_max +riotshield_deploy_zdiff_max +riotshield_deployed_health +riotshield_destroyed_cleanup_time +riotshield_explosive_damage_scale +riotshield_melee_damage_scale +riotshield_placement_foffset +riotshield_placement_maxs +riotshield_projectile_damage_scale +rootMotion_debugMode +s +safeArea_horizontal +safeArea_vertical +saveLocalMatchRecordBinaryFile +saved_gameskill +say +say_team +scene_debug_player +scene_hide_player +scrFatalScriptErrors +scrShowStrUsage +scrShowVarUseage +scrVmEnableScripts +scr_RequiredMapAspectratio +scr_airsupportHeightScale +scr_allies +scr_allow_killstreak_building +scr_axis +scr_codPointsCap +scr_codpointsmatchscale +scr_codpointsperchallenge +scr_codpointsxpscale +scr_coop_friendlyFireDelayTime +scr_coop_hud_showobjicons +scr_coop_score_accolade_infection_score +scr_coop_score_assist_amws_25 +scr_coop_score_assist_amws_50 +scr_coop_score_assist_amws_75 +scr_coop_score_assist_aqu_quadtank_25 +scr_coop_score_assist_aqu_quadtank_50 +scr_coop_score_assist_aqu_quadtank_75 +scr_coop_score_assist_aqu_vtol_25 +scr_coop_score_assist_aqu_vtol_50 +scr_coop_score_assist_aqu_vtol_75 +scr_coop_score_assist_assault_25 +scr_coop_score_assist_assault_50 +scr_coop_score_assist_assault_75 +scr_coop_score_assist_concussion +scr_coop_score_assist_cqb_25 +scr_coop_score_assist_cqb_50 +scr_coop_score_assist_cqb_75 +scr_coop_score_assist_dannyli_25 +scr_coop_score_assist_dannyli_50 +scr_coop_score_assist_dannyli_75 +scr_coop_score_assist_depth_charge_25 +scr_coop_score_assist_depth_charge_50 +scr_coop_score_assist_depth_charge_75 +scr_coop_score_assist_direwolf_25 +scr_coop_score_assist_direwolf_50 +scr_coop_score_assist_direwolf_75 +scr_coop_score_assist_emp +scr_coop_score_assist_flash +scr_coop_score_assist_gomin_25 +scr_coop_score_assist_gomin_50 +scr_coop_score_assist_gomin_75 +scr_coop_score_assist_goxiulan_25 +scr_coop_score_assist_goxiulan_50 +scr_coop_score_assist_goxiulan_75 +scr_coop_score_assist_hunter_25 +scr_coop_score_assist_hunter_50 +scr_coop_score_assist_hunter_75 +scr_coop_score_assist_lotus_gunship_25 +scr_coop_score_assist_lotus_gunship_50 +scr_coop_score_assist_lotus_gunship_75 +scr_coop_score_assist_macv_25 +scr_coop_score_assist_macv_50 +scr_coop_score_assist_macv_75 +scr_coop_score_assist_pamws_25 +scr_coop_score_assist_pamws_50 +scr_coop_score_assist_pamws_75 +scr_coop_score_assist_parasite_25 +scr_coop_score_assist_parasite_50 +scr_coop_score_assist_parasite_75 +scr_coop_score_assist_prologue_robot_25 +scr_coop_score_assist_prologue_robot_50 +scr_coop_score_assist_prologue_robot_75 +scr_coop_score_assist_prologue_vtol_25 +scr_coop_score_assist_prologue_vtol_50 +scr_coop_score_assist_prologue_vtol_75 +scr_coop_score_assist_proximity +scr_coop_score_assist_quadtank_25 +scr_coop_score_assist_quadtank_50 +scr_coop_score_assist_quadtank_75 +scr_coop_score_assist_raps_25 +scr_coop_score_assist_raps_50 +scr_coop_score_assist_raps_75 +scr_coop_score_assist_robotcqb_25 +scr_coop_score_assist_robotcqb_50 +scr_coop_score_assist_robotcqb_75 +scr_coop_score_assist_robotdemo_25 +scr_coop_score_assist_robotdemo_50 +scr_coop_score_assist_robotdemo_75 +scr_coop_score_assist_robotrocketeer_25 +scr_coop_score_assist_robotrocketeer_50 +scr_coop_score_assist_robotrocketeer_75 +scr_coop_score_assist_robotsapper_25 +scr_coop_score_assist_robotsapper_50 +scr_coop_score_assist_robotsapper_75 +scr_coop_score_assist_robotsniper_25 +scr_coop_score_assist_robotsniper_50 +scr_coop_score_assist_robotsniper_75 +scr_coop_score_assist_robotsoldier_25 +scr_coop_score_assist_robotsoldier_50 +scr_coop_score_assist_robotsoldier_75 +scr_coop_score_assist_robotsuppressor_25 +scr_coop_score_assist_robotsuppressor_50 +scr_coop_score_assist_robotsuppressor_75 +scr_coop_score_assist_rocketeer_25 +scr_coop_score_assist_rocketeer_50 +scr_coop_score_assist_rocketeer_75 +scr_coop_score_assist_siegebot_25 +scr_coop_score_assist_siegebot_50 +scr_coop_score_assist_siegebot_75 +scr_coop_score_assist_sniper_25 +scr_coop_score_assist_sniper_50 +scr_coop_score_assist_sniper_75 +scr_coop_score_assist_suppressor_25 +scr_coop_score_assist_suppressor_50 +scr_coop_score_assist_suppressor_75 +scr_coop_score_assist_technical_25 +scr_coop_score_assist_technical_50 +scr_coop_score_assist_technical_75 +scr_coop_score_assist_theia_25 +scr_coop_score_assist_theia_50 +scr_coop_score_assist_theia_75 +scr_coop_score_assist_tiger_tank_25 +scr_coop_score_assist_tiger_tank_50 +scr_coop_score_assist_tiger_tank_75 +scr_coop_score_assist_turret_25 +scr_coop_score_assist_turret_50 +scr_coop_score_assist_turret_75 +scr_coop_score_assist_vtol_25 +scr_coop_score_assist_vtol_50 +scr_coop_score_assist_vtol_75 +scr_coop_score_assist_warlord_25 +scr_coop_score_assist_warlord_50 +scr_coop_score_assist_warlord_75 +scr_coop_score_assist_wasp_25 +scr_coop_score_assist_wasp_50 +scr_coop_score_assist_wasp_75 +scr_coop_score_assist_zombie_25 +scr_coop_score_assist_zombie_50 +scr_coop_score_assist_zombie_75 +scr_coop_score_award_accolade +scr_coop_score_award_calling_card +scr_coop_score_complete_mission_hardened +scr_coop_score_complete_mission_heroic +scr_coop_score_complete_mission_recruit +scr_coop_score_complete_mission_regular +scr_coop_score_complete_mission_veteran +scr_coop_score_completed_match +scr_coop_score_completed_training_sim_rating +scr_coop_score_death +scr_coop_score_debug_give_score +scr_coop_score_kill_amws +scr_coop_score_kill_aqu_quadtank +scr_coop_score_kill_aqu_vtol +scr_coop_score_kill_assault +scr_coop_score_kill_cqb +scr_coop_score_kill_dannyli +scr_coop_score_kill_depth_charge +scr_coop_score_kill_direwolf +scr_coop_score_kill_gomin +scr_coop_score_kill_goxiulan +scr_coop_score_kill_hunter +scr_coop_score_kill_lotus_gunship +scr_coop_score_kill_macv +scr_coop_score_kill_meatball +scr_coop_score_kill_pamws +scr_coop_score_kill_parasite +scr_coop_score_kill_prologue_robot +scr_coop_score_kill_prologue_vtol +scr_coop_score_kill_quadtank +scr_coop_score_kill_raps +scr_coop_score_kill_robotcqb +scr_coop_score_kill_robotdemo +scr_coop_score_kill_robotrocketeer +scr_coop_score_kill_robotsapper +scr_coop_score_kill_robotsniper +scr_coop_score_kill_robotsoldier +scr_coop_score_kill_robotsuppressor +scr_coop_score_kill_rocketeer +scr_coop_score_kill_siegebot +scr_coop_score_kill_sniper +scr_coop_score_kill_spider +scr_coop_score_kill_suppressor +scr_coop_score_kill_technical +scr_coop_score_kill_theia +scr_coop_score_kill_tiger_tank +scr_coop_score_kill_turret +scr_coop_score_kill_vtol +scr_coop_score_kill_warlord +scr_coop_score_kill_wasp +scr_coop_score_kill_zombie +scr_coop_score_killnone +scr_coop_score_melee_kill_amws +scr_coop_score_melee_kill_aqu_quadtank +scr_coop_score_melee_kill_aqu_vtol +scr_coop_score_melee_kill_assault +scr_coop_score_melee_kill_cqb +scr_coop_score_melee_kill_dannyli +scr_coop_score_melee_kill_depth_charge +scr_coop_score_melee_kill_direwolf +scr_coop_score_melee_kill_gomin +scr_coop_score_melee_kill_goxiulan +scr_coop_score_melee_kill_hunter +scr_coop_score_melee_kill_lotus_gunship +scr_coop_score_melee_kill_macv +scr_coop_score_melee_kill_meatball +scr_coop_score_melee_kill_pamws +scr_coop_score_melee_kill_parasite +scr_coop_score_melee_kill_prologue_robot +scr_coop_score_melee_kill_prologue_vtol +scr_coop_score_melee_kill_quadtank +scr_coop_score_melee_kill_raps +scr_coop_score_melee_kill_robotcqb +scr_coop_score_melee_kill_robotdemo +scr_coop_score_melee_kill_robotrocketeer +scr_coop_score_melee_kill_robotsapper +scr_coop_score_melee_kill_robotsniper +scr_coop_score_melee_kill_robotsoldier +scr_coop_score_melee_kill_robotsuppressor +scr_coop_score_melee_kill_rocketeer +scr_coop_score_melee_kill_siegebot +scr_coop_score_melee_kill_sniper +scr_coop_score_melee_kill_suppressor +scr_coop_score_melee_kill_technical +scr_coop_score_melee_kill_theia +scr_coop_score_melee_kill_tiger_tank +scr_coop_score_melee_kill_turret +scr_coop_score_melee_kill_vtol +scr_coop_score_melee_kill_warlord +scr_coop_score_melee_kill_wasp +scr_coop_score_melee_kill_zombie +scr_coop_score_multikill_2 +scr_coop_score_multikill_3 +scr_coop_score_multikill_4 +scr_coop_score_multikill_5 +scr_coop_score_multikill_6 +scr_coop_score_multikill_7 +scr_coop_score_multikill_8 +scr_coop_score_multikill_more_than_8 +scr_coop_score_picked_up_collectible +scr_coop_score_player_did_revived +scr_coop_score_scavenger_assist +scr_coop_score_scavenger_pickup +scr_coop_score_scavenger_streak +scr_coop_score_shield_blocked_damage +scr_coop_score_shield_blocked_damage_reduced +scr_coop_score_suicide +scr_coop_weapon_allowbetty +scr_coop_weapon_allowflash +scr_coop_weapon_allowfrag +scr_coop_weapon_allowrpgs +scr_coop_weapon_allowsatchel +scr_coop_weapon_allowsmoke +scr_csmode +scr_custom_score_assist +scr_debug_heat_wave_traces +scr_debug_leaks +scr_deleteexplosivesonspawn +scr_dirt_enable_explosion +scr_dirt_enable_fall_damage +scr_dirt_enable_gravity_spikes +scr_dirt_enable_slide +scr_disableChallenges +scr_disableSetDStat +scr_disableStatTracking +scr_disable_air_death_ragdoll +scr_disable_team_selection +scr_disable_weapondrop +scr_disableunifiedspawning +scr_drawfriend +scr_dynamic_source_loading +scr_emergency_reserve_timer +scr_emergency_reserve_timer_upgraded +scr_fireflyPartialMovePercent +scr_fireflyPodActivationTime +scr_fireflyPodDetectionRadius +scr_fireflyPodGracePeriod +scr_firefly_attack_attack_speed_scale +scr_firefly_collision_check_interval +scr_firefly_debug +scr_firefly_emit_time +scr_firefly_min_speed +scr_firefly_pod_timeout +scr_firstGumFree +scr_free +scr_game_arcadescoring +scr_game_difficulty +scr_game_friendlyFireDelay +scr_game_medalsenabled +scr_game_pinups +scr_game_rankenabled +scr_gunxpscale +scr_gunxpscaleCP +scr_gunxpscaleMP +scr_gunxpscaleZM +scr_gunxpscalecp +scr_gunxpscalemp +scr_gunxpscalezm +scr_hardcore +scr_hardpoint_allowauto_turret +scr_hardpoint_allowcounteruav +scr_hardpoint_allowdogs +scr_hardpoint_allowhelicopter_comlink +scr_hardpoint_allowradar +scr_hardpoint_allowradardirection +scr_hardpoint_allowrcbomb +scr_hardpoint_allowuav +scr_health_debug +scr_heli_armor +scr_heli_armor_bulletdamage +scr_heli_armored_maxhealth +scr_heli_attract_range +scr_heli_attract_strength +scr_heli_debug +scr_heli_debug_crash +scr_heli_dest_wait +scr_heli_health_degrade +scr_heli_loopmax +scr_heli_maxhealth +scr_heli_missile_friendlycare +scr_heli_missile_max +scr_heli_missile_range +scr_heli_missile_regen_time +scr_heli_missile_reload_time +scr_heli_missile_rof +scr_heli_missile_target_cone +scr_heli_missile_valid_target_cone +scr_heli_protect_pos_time +scr_heli_protect_radius +scr_heli_protect_time +scr_heli_target_recognition +scr_heli_target_spawnprotection +scr_heli_targeting_delay +scr_heli_turretClipSize +scr_heli_turretReloadTime +scr_heli_turret_angle_tan +scr_heli_turret_spinup_delay +scr_heli_turret_target_cone +scr_heli_visual_range +scr_heli_warning_distance +scr_helicopterTurretMaxAngle +scr_hostmigrationtest +scr_incendiaryDamageRadius +scr_incendiaryfireDamage +scr_incendiaryfireDamageHardcore +scr_incendiaryfireDamageTickTime +scr_incendiaryfireDuration +scr_incendiaryfxDuration +scr_killcam +scr_lightningGunKillcamDecelPercent +scr_lightningGunKillcamOffset +scr_lightningGunKillcamTime +scr_mapsize +scr_max_rank +scr_max_simLocks +scr_maxinventory_scorestreaks +scr_min_prestige +scr_minimap_height +scr_missileDudDeleteDelay +scr_mod_enable_devblock +scr_motd +scr_no_checkpoints +scr_numLives +scr_oldschool +scr_playerInvulTimeScale +scr_player_allowrevive +scr_player_sprinttime +scr_proximityChainBoltSpeed +scr_proximityChainDebug +scr_proximityChainGracePeriod +scr_proximityGrenadeActivationTime +scr_proximityGrenadeDOTDamageAmount +scr_proximityGrenadeDOTDamageAmountHardcore +scr_proximityGrenadeDOTDamageInstances +scr_proximityGrenadeDOTDamageTime +scr_proximityGrenadeDetectionRadius +scr_proximityGrenadeDuration +scr_proximityGrenadeGracePeriod +scr_proximityGrenadeProtectedTime +scr_rampagebonusscale +scr_rankXpCap +scr_requiredMapAspectRatio +scr_satchel_detonation_delay +scr_scorestreaks +scr_scorestreaks_maxstacking +scr_selecting_location +scr_showperksonspawn +scr_sideBetTimer +scr_sitrepscan1_enable +scr_sitrepscan1_setdesat +scr_sitrepscan1_setfalloff +scr_sitrepscan1_setlinewidth +scr_sitrepscan1_setoutline +scr_sitrepscan1_setradius +scr_sitrepscan1_setsolid +scr_sitrepscan2_enable +scr_sitrepscan2_setdesat +scr_sitrepscan2_setfalloff +scr_sitrepscan2_setlinewidth +scr_sitrepscan2_setoutline +scr_sitrepscan2_setradius +scr_sitrepscan2_setsolid +scr_skip_devblock +scr_spawn_enemyavoiddist +scr_spawn_enemyavoidweight +scr_spawn_force_unified +scr_tdm_friendlyFireDelayTime +scr_tdm_killstreak_allowcounteruav +scr_tdm_killstreak_allowradar +scr_tdm_killstreak_allowradardirection +scr_tdm_score_aircraft_destruction_assist_25 +scr_tdm_score_aircraft_destruction_assist_50 +scr_tdm_score_aircraft_destruction_assist_75 +scr_tdm_score_aircraft_flare_assist +scr_tdm_score_aitank_kill +scr_tdm_score_annihilator_kill +scr_tdm_score_annihilator_multikill +scr_tdm_score_annihilator_multikill_2 +scr_tdm_score_annihilator_stolen +scr_tdm_score_armblades_kill +scr_tdm_score_armblades_multikill +scr_tdm_score_armblades_multikill_2 +scr_tdm_score_armblades_stolen +scr_tdm_score_assist_25 +scr_tdm_score_assist_50 +scr_tdm_score_assist_75 +scr_tdm_score_assist_concussion +scr_tdm_score_assist_emp +scr_tdm_score_assist_flash +scr_tdm_score_assist_proximity +scr_tdm_score_assisted_suicide +scr_tdm_score_backstabber_kill +scr_tdm_score_ball_capture_assist +scr_tdm_score_ball_capture_carry +scr_tdm_score_ball_capture_throw +scr_tdm_score_ball_intercept +scr_tdm_score_bomb_detonated +scr_tdm_score_bounce_hatchet_kill +scr_tdm_score_bowlauncher_kill +scr_tdm_score_bowlauncher_multikill +scr_tdm_score_bowlauncher_multikill_2 +scr_tdm_score_bowlauncher_stolen +scr_tdm_score_c4_multikill +scr_tdm_score_capture_enemy_crate +scr_tdm_score_clean_assist_collect +scr_tdm_score_clean_enemy_collect +scr_tdm_score_clean_enemy_deposit +scr_tdm_score_clean_friendly_collect +scr_tdm_score_clean_kill_enemy_carrying_tacos +scr_tdm_score_clean_multi_deny_tacos +scr_tdm_score_clean_multi_deposit_big +scr_tdm_score_clean_multi_deposit_normal +scr_tdm_score_clean_own_collect +scr_tdm_score_cleanse_kill +scr_tdm_score_clear_2_attackers +scr_tdm_score_combat_efficiency_bonus_1 +scr_tdm_score_combat_efficiency_bonus_2 +scr_tdm_score_combat_efficiency_bonus_3 +scr_tdm_score_combat_robot_kill +scr_tdm_score_comeback_from_deathstreak +scr_tdm_score_completed_match +scr_tdm_score_counter_uav_assist +scr_tdm_score_dart_kill +scr_tdm_score_death +scr_tdm_score_defend_flag_carrier +scr_tdm_score_defend_hq_last_man_alive +scr_tdm_score_defused_bomb +scr_tdm_score_defused_bomb_last_man_alive +scr_tdm_score_destroyed_aitank +scr_tdm_score_destroyed_bouncingbetty +scr_tdm_score_destroyed_c4 +scr_tdm_score_destroyed_claymore +scr_tdm_score_destroyed_combat_robot +scr_tdm_score_destroyed_counter_uav +scr_tdm_score_destroyed_dart +scr_tdm_score_destroyed_drone_strike +scr_tdm_score_destroyed_emp +scr_tdm_score_destroyed_fireflyhive +scr_tdm_score_destroyed_helicopter_agr_drop +scr_tdm_score_destroyed_helicopter_comlink +scr_tdm_score_destroyed_helicopter_giunit_drop +scr_tdm_score_destroyed_helicopter_supply_drop +scr_tdm_score_destroyed_heliopter_giunit_drop +scr_tdm_score_destroyed_hover_rcxd +scr_tdm_score_destroyed_microwave_turret +scr_tdm_score_destroyed_motion_sensor +scr_tdm_score_destroyed_plane_mortar +scr_tdm_score_destroyed_proxy +scr_tdm_score_destroyed_raps_deployship +scr_tdm_score_destroyed_remote_missile +scr_tdm_score_destroyed_rolling_thunder_all_drones +scr_tdm_score_destroyed_rolling_thunder_drone +scr_tdm_score_destroyed_satellite +scr_tdm_score_destroyed_sentinel +scr_tdm_score_destroyed_sentry_gun +scr_tdm_score_destroyed_shield +scr_tdm_score_destroyed_siegebot +scr_tdm_score_destroyed_siegebot_assist +scr_tdm_score_destroyed_tac_insert +scr_tdm_score_destroyed_trophy_system +scr_tdm_score_destroyed_uav +scr_tdm_score_destroyed_vtol_mothership +scr_tdm_score_disabled_robot +scr_tdm_score_disarm_hacked_care_package +scr_tdm_score_dom_point_neutral_b_secured +scr_tdm_score_dom_point_neutral_secured +scr_tdm_score_dom_point_neutralized_neutralizing +scr_tdm_score_dom_point_secured +scr_tdm_score_dom_point_secured_neutralizing +scr_tdm_score_downed_player +scr_tdm_score_drone_strike_kill +scr_tdm_score_electrified +scr_tdm_score_eliminate_oic +scr_tdm_score_elimination_and_last_player_alive +scr_tdm_score_emp_assist +scr_tdm_score_end_enemy_armblades_attack +scr_tdm_score_end_enemy_gravity_spike_attack +scr_tdm_score_end_enemy_psychosis +scr_tdm_score_end_enemy_specialist_weapon +scr_tdm_score_escort_robot_disable +scr_tdm_score_escort_robot_disable_assist_25 +scr_tdm_score_escort_robot_disable_assist_50 +scr_tdm_score_escort_robot_disable_near_goal +scr_tdm_score_escort_robot_escort +scr_tdm_score_escort_robot_escort_goal +scr_tdm_score_escort_robot_reboot +scr_tdm_score_final_kill_elimination +scr_tdm_score_first_kill +scr_tdm_score_flag_capture +scr_tdm_score_flag_carrier_kill_return_close +scr_tdm_score_flag_grab +scr_tdm_score_flag_return +scr_tdm_score_flamethrower_kill +scr_tdm_score_flamethrower_multikill +scr_tdm_score_flamethrower_multikill_2 +scr_tdm_score_flamethrower_stolen +scr_tdm_score_flashback_kill +scr_tdm_score_focus_earn_multiscorestreak +scr_tdm_score_focus_earn_scorestreak +scr_tdm_score_frag_multikill +scr_tdm_score_gelgun_kill +scr_tdm_score_gelgun_multikill +scr_tdm_score_gelgun_multikill_2 +scr_tdm_score_gelgun_stolen +scr_tdm_score_gravityspikes_kill +scr_tdm_score_gravityspikes_multikill +scr_tdm_score_gravityspikes_multikill_2 +scr_tdm_score_gravityspikes_stolen +scr_tdm_score_hack_3_agrs +scr_tdm_score_hacked +scr_tdm_score_hacked_ai_tank +scr_tdm_score_hacked_autoturret +scr_tdm_score_hacked_combat_robot +scr_tdm_score_hacked_counteruav +scr_tdm_score_hacked_dart +scr_tdm_score_hacked_emp +scr_tdm_score_hacked_helicopter_comlink +scr_tdm_score_hacked_killstreak_protection +scr_tdm_score_hacked_microwaveturret +scr_tdm_score_hacked_mothership +scr_tdm_score_hacked_raps +scr_tdm_score_hacked_rcbomb +scr_tdm_score_hacked_satellite +scr_tdm_score_hacked_sentinel +scr_tdm_score_hacked_supply_drop +scr_tdm_score_hacked_uav +scr_tdm_score_hacker_drone_hacked +scr_tdm_score_hacker_drone_killed +scr_tdm_score_hardpoint_kill +scr_tdm_score_hatchet_kill +scr_tdm_score_headshot +scr_tdm_score_heatwave_kill +scr_tdm_score_helicopter_comlink_kill +scr_tdm_score_hover_rcxd_kill +scr_tdm_score_hpm_suppress +scr_tdm_score_hq_destroyed +scr_tdm_score_hq_secure +scr_tdm_score_humiliation_gun +scr_tdm_score_kill +scr_tdm_score_kill_ball_carrier +scr_tdm_score_kill_confirmed +scr_tdm_score_kill_confirmed_multi +scr_tdm_score_kill_denied +scr_tdm_score_kill_enemies_one_bullet +scr_tdm_score_kill_enemy_after_death +scr_tdm_score_kill_enemy_grenade_throwback +scr_tdm_score_kill_enemy_injuring_teammate +scr_tdm_score_kill_enemy_one_bullet +scr_tdm_score_kill_enemy_that_heatwaved_you +scr_tdm_score_kill_enemy_that_is_in_air +scr_tdm_score_kill_enemy_that_is_using_optic_camo +scr_tdm_score_kill_enemy_that_is_wallrunning +scr_tdm_score_kill_enemy_that_pulsed_you +scr_tdm_score_kill_enemy_that_used_resurrect +scr_tdm_score_kill_enemy_when_injured +scr_tdm_score_kill_enemy_while_both_in_air +scr_tdm_score_kill_enemy_while_capping_dom +scr_tdm_score_kill_enemy_while_capping_hq +scr_tdm_score_kill_enemy_while_carrying_ball +scr_tdm_score_kill_enemy_while_flashbanged +scr_tdm_score_kill_enemy_while_in_air +scr_tdm_score_kill_enemy_while_sliding +scr_tdm_score_kill_enemy_while_stunned +scr_tdm_score_kill_enemy_while_using_psychosis +scr_tdm_score_kill_enemy_while_wallrunning +scr_tdm_score_kill_enemy_who_has_flashbacked +scr_tdm_score_kill_enemy_who_has_full_power +scr_tdm_score_kill_enemy_who_has_high_score +scr_tdm_score_kill_enemy_who_has_powerarmor +scr_tdm_score_kill_enemy_who_is_speedbursting +scr_tdm_score_kill_enemy_who_is_using_focus +scr_tdm_score_kill_enemy_who_killed_teammate +scr_tdm_score_kill_enemy_with_care_package_crush +scr_tdm_score_kill_enemy_with_fists +scr_tdm_score_kill_enemy_with_gunbutt +scr_tdm_score_kill_enemy_with_hacked_care_package +scr_tdm_score_kill_enemy_with_more_ammo_oic +scr_tdm_score_kill_enemy_with_siegebot_crush +scr_tdm_score_kill_enemy_with_their_hero_ability +scr_tdm_score_kill_enemy_with_their_hero_weapon +scr_tdm_score_kill_enemy_with_their_weapon +scr_tdm_score_kill_flag_carrier +scr_tdm_score_kill_gun +scr_tdm_score_kill_hacker +scr_tdm_score_kill_hacker_then_hack +scr_tdm_score_kill_in_3_seconds_gun +scr_tdm_score_kill_sd +scr_tdm_score_kill_underwater_enemy_explosive +scr_tdm_score_kill_x2_score_shrp +scr_tdm_score_killed_annihilator_enemy +scr_tdm_score_killed_armblades_enemy +scr_tdm_score_killed_attacker +scr_tdm_score_killed_bomb_defuser +scr_tdm_score_killed_bomb_planter +scr_tdm_score_killed_bowlauncher_enemy +scr_tdm_score_killed_clone_enemy +scr_tdm_score_killed_defender +scr_tdm_score_killed_dog +scr_tdm_score_killed_dog_assist +scr_tdm_score_killed_enemy_while_carrying_flag +scr_tdm_score_killed_flamethrower_enemy +scr_tdm_score_killed_gelgun_enemy +scr_tdm_score_killed_gravityspikes_enemy +scr_tdm_score_killed_lightninggun_enemy +scr_tdm_score_killed_minigun_enemy +scr_tdm_score_killed_pineapple_enemy +scr_tdm_score_killed_raps +scr_tdm_score_killed_raps_assist +scr_tdm_score_killstreak_10 +scr_tdm_score_killstreak_11 +scr_tdm_score_killstreak_12 +scr_tdm_score_killstreak_13 +scr_tdm_score_killstreak_14 +scr_tdm_score_killstreak_15 +scr_tdm_score_killstreak_16 +scr_tdm_score_killstreak_17 +scr_tdm_score_killstreak_18 +scr_tdm_score_killstreak_19 +scr_tdm_score_killstreak_2 +scr_tdm_score_killstreak_20 +scr_tdm_score_killstreak_21 +scr_tdm_score_killstreak_22 +scr_tdm_score_killstreak_23 +scr_tdm_score_killstreak_24 +scr_tdm_score_killstreak_25 +scr_tdm_score_killstreak_26 +scr_tdm_score_killstreak_27 +scr_tdm_score_killstreak_28 +scr_tdm_score_killstreak_29 +scr_tdm_score_killstreak_3 +scr_tdm_score_killstreak_30 +scr_tdm_score_killstreak_4 +scr_tdm_score_killstreak_5 +scr_tdm_score_killstreak_6 +scr_tdm_score_killstreak_7 +scr_tdm_score_killstreak_8 +scr_tdm_score_killstreak_9 +scr_tdm_score_killstreak_more_than_30 +scr_tdm_score_knife_with_ammo_oic +scr_tdm_score_koth_secure +scr_tdm_score_lightninggun_kill +scr_tdm_score_lightninggun_multikill +scr_tdm_score_lightninggun_multikill_2 +scr_tdm_score_lightninggun_stolen +scr_tdm_score_longshot_kill +scr_tdm_score_melee_kill +scr_tdm_score_melee_leader_gun +scr_tdm_score_microwave_turret_assist +scr_tdm_score_microwave_turret_kill +scr_tdm_score_minigun_kill +scr_tdm_score_minigun_multikill +scr_tdm_score_minigun_multikill_2 +scr_tdm_score_minigun_stolen +scr_tdm_score_most_points_shrp +scr_tdm_score_mothership_assist_kill +scr_tdm_score_multikill_2 +scr_tdm_score_multikill_3 +scr_tdm_score_multikill_4 +scr_tdm_score_multikill_5 +scr_tdm_score_multikill_6 +scr_tdm_score_multikill_7 +scr_tdm_score_multikill_8 +scr_tdm_score_multikill_more_than_8 +scr_tdm_score_optic_camo_capture_objective +scr_tdm_score_optic_camo_kill +scr_tdm_score_pineapple_kill +scr_tdm_score_pineapple_multikill +scr_tdm_score_pineapple_multikill_2 +scr_tdm_score_pineapple_stolen +scr_tdm_score_plane_mortar_kill +scr_tdm_score_planted_bomb +scr_tdm_score_power_armor_kill +scr_tdm_score_quickly_secure_point +scr_tdm_score_raps_kill +scr_tdm_score_reboot_robot +scr_tdm_score_remote_missile_kill +scr_tdm_score_rescue_flag_carrier +scr_tdm_score_resurrect_kill +scr_tdm_score_retrieve_own_tags +scr_tdm_score_revenge_kill +scr_tdm_score_satellite_assist +scr_tdm_score_sentinel_kill +scr_tdm_score_sentry_gun_kill +scr_tdm_score_share_care_package +scr_tdm_score_shield_assist +scr_tdm_score_shield_blocked_damage +scr_tdm_score_shield_blocked_damage_reduced +scr_tdm_score_siegebot_killstreak_5 +scr_tdm_score_speed_burst_kill +scr_tdm_score_stick_explosive_kill +scr_tdm_score_stop_enemy_killstreak +scr_tdm_score_suicide +scr_tdm_score_survivor +scr_tdm_score_team_kill +scr_tdm_score_teammate_kill_confirmed +scr_tdm_score_thief_shutdown_enemy +scr_tdm_score_traversal_kill +scr_tdm_score_trophy_defense +scr_tdm_score_uav_assist +scr_tdm_score_uninterrupted_obit_feed_kills +scr_tdm_score_vision_pulse_kill +scr_tdm_score_vtol_mothership_kill +scr_tdm_score_wager_melee_kill +scr_tdm_score_won_match +scr_tdm_score_x2_score_shrp +scr_tdm_weapon_allowbetty +scr_tdm_weapon_allowflash +scr_tdm_weapon_allowfrag +scr_tdm_weapon_allowrpgs +scr_tdm_weapon_allowsatchel +scr_tdm_weapon_allowsmoke +scr_team_fftype +scr_team_teamkillerplaylistbanpenalty +scr_team_teamkillerplaylistbanquantum +scr_teambalance +scr_timeplayedcap +scr_use_digital_blood_enabled +scr_veh_alive_cleanuptimemax +scr_veh_alive_cleanuptimemin +scr_veh_cleanupabandoned +scr_veh_cleanupdebugprint +scr_veh_cleanupdrifted +scr_veh_cleanupmaxspeedmph +scr_veh_cleanupmindistancefeet +scr_veh_cleanuptime_dmgfactor_deadtread +scr_veh_cleanuptime_dmgfactor_max +scr_veh_cleanuptime_dmgfactor_min +scr_veh_cleanuptime_dmgfraction_curve_begin +scr_veh_cleanuptime_dmgfraction_curve_end +scr_veh_dead_cleanuptimemax +scr_veh_dead_cleanuptimemin +scr_veh_disableoverturndamage +scr_veh_disablerespawn +scr_veh_disappear_maxpreventdistancefeet +scr_veh_disappear_maxpreventvisibilityfeet +scr_veh_disappear_maxwaittime +scr_veh_driversarehidden +scr_veh_driversareinvulnerable +scr_veh_explode_on_cleanup +scr_veh_explosion_doradiusdamage +scr_veh_explosion_husk_forcepointvariance +scr_veh_explosion_husk_horzvelocityvariance +scr_veh_explosion_husk_vertvelocitymax +scr_veh_explosion_husk_vertvelocitymin +scr_veh_explosion_maxdamage +scr_veh_explosion_mindamage +scr_veh_explosion_radius +scr_veh_explosion_spawnfx +scr_veh_health_jeep +scr_veh_health_tank +scr_veh_ondeath_createhusk +scr_veh_ondeath_usevehicleashusk +scr_veh_respawnafterhuskcleanup +scr_veh_respawntimemax +scr_veh_respawntimemin +scr_veh_respawnwait_iterationwaitseconds +scr_veh_respawnwait_maxiterations +scr_veh_waittillstoppedandmindist_maxtime +scr_veh_waittillstoppedandmindist_maxtimeenabledistfeet +scr_vehicle_damage_scalar +scr_vialsAwardedScale +scr_wagerBet +scr_wagerPool +scr_wagerSideBet +scr_wager_firstPayout +scr_wager_firstPlayer +scr_wager_secondPayout +scr_wager_secondPlayer +scr_wager_thirdPayout +scr_wager_thirdPlayer +scr_weapon_allowbetty +scr_weapon_allowc4 +scr_weapon_allowflash +scr_weapon_allowfrags +scr_weapon_allowmines +scr_weapon_allowrpgs +scr_weapon_allowsatchel +scr_weapon_allowsmoke +scr_weaponobject_coneangle +scr_weaponobject_debug +scr_weaponobject_graceperiod +scr_weaponobject_mindist +scr_weaponobject_radius +scr_writeConfigStrings +scr_writeconfigstrings +scr_xpscale +scr_xpscaleCP +scr_xpscaleMP +scr_xpscaleZM +scr_xpscaleZMPromo +scr_xpscalecp +scr_xpscalemp +scr_xpscalezm +scr_zclassic_friendlyFireDelayTime +scr_zclassic_grenadeLauncherDudTime +scr_zclassic_killstreakDelayTime +scr_zclassic_score_alive_at_round_end_1 +scr_zclassic_score_alive_at_round_end_10 +scr_zclassic_score_alive_at_round_end_11 +scr_zclassic_score_alive_at_round_end_12 +scr_zclassic_score_alive_at_round_end_13 +scr_zclassic_score_alive_at_round_end_14 +scr_zclassic_score_alive_at_round_end_15 +scr_zclassic_score_alive_at_round_end_16 +scr_zclassic_score_alive_at_round_end_17 +scr_zclassic_score_alive_at_round_end_18 +scr_zclassic_score_alive_at_round_end_19 +scr_zclassic_score_alive_at_round_end_2 +scr_zclassic_score_alive_at_round_end_20 +scr_zclassic_score_alive_at_round_end_3 +scr_zclassic_score_alive_at_round_end_4 +scr_zclassic_score_alive_at_round_end_5 +scr_zclassic_score_alive_at_round_end_6 +scr_zclassic_score_alive_at_round_end_7 +scr_zclassic_score_alive_at_round_end_8 +scr_zclassic_score_alive_at_round_end_9 +scr_zclassic_score_headshot +scr_zclassic_score_kill +scr_zclassic_score_kill_margwa +scr_zclassic_score_kill_meatball +scr_zclassic_score_kill_mechz +scr_zclassic_score_kill_parasite +scr_zclassic_score_kill_raz +scr_zclassic_score_kill_sentinel +scr_zclassic_score_kill_spider +scr_zclassic_score_kill_thrasher +scr_zclassic_score_main_EE_quest +scr_zclassic_score_main_EE_quest_castle +scr_zclassic_score_main_EE_quest_factory +scr_zclassic_score_main_EE_quest_genesis +scr_zclassic_score_main_EE_quest_island +scr_zclassic_score_main_EE_quest_stalingrad +scr_zclassic_score_main_EE_quest_stalingrad_dragon +scr_zclassic_score_main_ee_quest_all +scr_zclassic_score_main_quest +scr_zclassic_score_melee_kill +scr_zclassic_score_melee_kill_meatball +scr_zclassic_score_melee_kill_parasite +scr_zclassic_score_open_door +scr_zclassic_score_revive_an_ally +scr_zclassic_score_solo_challenge_stalingrad +scr_zclassic_score_team_challenge_stalingrad +scr_zclassic_thrownGrenadeDudTime +scr_zm_enable_bots +scr_zm_use_code_enemy_selection +searchSessionDedicatedGeoMin +searchSessionDedicatedMaxPing +searchSessionGeo1Weight +searchSessionGeo2Weight +searchSessionGeo3Weight +searchSessionGeo4Weight +searchSessionGeoMin +searchSessionIsEmpty +searchSessionMapPackFlags +searchSessionNextTaskDelay +searchSessionSkillWeight +season_pass_incentive_id +season_pass_incentive_max +secondScreenClient +selectedFriendIndex +selectedFriendName +selectedPlayerXuid +sensitivity +serverbrowser_show +serverinfo +sessionSearchMaxAttempts +sessionTaskFailDebug +session_nonblocking +set_gametype +setliveevent +settings_allowGibbing +settings_defaultSubtitles +setviewpos +shardEdgeSize +shardShatterSizeLimitScale +shardSplitDir +shardSplitDir2 +shatterFxMaxDist +shatterFxMinEdgeLength +shieldBlastDamageProtection_120 +shieldBlastDamageProtection_180 +shieldBlastDamageProtection_30 +shieldBlastDamageProtection_60 +shieldDeployShakeDuration +shieldDeployShakeScale +shieldImpactBulletShakeDuration +shieldImpactBulletShakeScale +shieldImpactExplosionHighShakeDuration +shieldImpactExplosionHighShakeScale +shieldImpactExplosionLowShakeDuration +shieldImpactExplosionLowShakeScale +shieldImpactExplosionThreshold +shieldImpactMissileShakeDuration +shieldImpactMissileShakeScale +shieldPlayerBulletProtectionDegrees +shortversion +shoutcastHighlightedClient +shoutcastSelectedClient +showMapErrors +showVisionSetDebugInfo +show_reticle_during_swimming +showdrop +showevents +showpackets +skill_onboardingAdjustOnExit +skill_onboardingEnabled +skill_onboardingEnter +skill_onboardingExit +skill_onboardingGames +skill_onboardingThreshold +skill_scoreBeta +skill_scoreRange +skill_teamBeta +skill_teamRange +skipChunkCheck +skip_contract_rewards +skipto +skipto_complete +skipto_jump +slam_air_accel +slam_air_downward_angle +slam_air_enabled +slam_air_frictionMax +slam_air_frictionMin +slam_air_maxUpwardsVelocity +slam_air_speed +slam_air_upBoostAccel +slam_air_view_delta +slam_blur_amount +slam_blur_enabled +slam_blur_radius_inner +slam_blur_radius_outer +slam_blur_time_in +slam_blur_time_out +slam_clearance_check_dist +slam_clearance_check_radius +slam_debug +slam_enabled +slam_player_trace_offset +slam_time_in_air_timeout_ms +slam_time_ms +slam_wallrun_enabled +slide_allowEarlyMoveTime +slide_allow_hold_for_prone +slide_allow_shooting +slide_angle1 +slide_angle2 +slide_blur_amount +slide_blur_enabled +slide_blur_radius_inner +slide_blur_radius_outer +slide_blur_time_in +slide_blur_time_out +slide_cameraAlignmentEaseMode +slide_cameraClamp +slide_cameraPitchOffset +slide_cameraPitchRate +slide_cameraRotateTimeMs +slide_clearance_check_dist +slide_clearance_check_radius +slide_deadzoneTweek +slide_debug +slide_delayTime +slide_downhillFriction_amount +slide_enable +slide_enable_tweak_left_right +slide_fallDamageReduction +slide_forceBaseSlide +slide_frictionScale +slide_friction_amount +slide_friction_duration_ms +slide_hold_change_stance_time_air_ms +slide_hold_change_stance_time_ms +slide_jetFxDuration +slide_lensInTransRate +slide_lensOutTransRate +slide_maxTime +slide_maxTimeBase +slide_maxTimeReduced +slide_min_continue_velocity +slide_min_required_airVelocity +slide_min_required_velocity +slide_min_sprint_time_ms +slide_outAllowSprint +slide_outShouldScaleSpeed +slide_outSpeedScale +slide_player_trace_offset +slide_required_airAngle +slide_speed +slide_speedBase +slide_speedReduced +slide_subsequentSlideScale +slide_subsequentSlideTime +slide_tap_button_to_slide +slide_to_sprint_friction_time_scale +slide_under_geo_trace_dist +slide_under_geo_trace_radius +slide_uphillFriction_amount +slide_viewMovementEnabled +slide_view_angles +slide_view_anglesTransitionTime +slide_view_bounceAngles +slide_view_bounceAnglesPeriod +slide_view_slide_height +sm_enableViewmodel +sm_fastSunShadow +sm_lightScore_eyeProjectDist +sm_lightScore_spotProjectFrac +sm_showFXShadowmap +sm_showLightShadowmap +sm_showLightShadowmapScale +sm_showSpotAxis +sm_showSunOverlay +sm_showSunOverlayScaleBias +sm_showTris +sm_showViewmodelShadowmap +sm_spotPolygonOffsetBias +sm_spotPolygonOffsetScale +sm_spotShadowLargeRadiusScale +sm_strictCull +sm_sunAlwaysCastsShadow +sm_sunPolygonOffsetBias +sm_sunPolygonOffsetScale +smpDraw2D +smpGlass +smpScanForCrosshairEntity +smpUpdatePlayerNames +snaps +snd_assert_on_animation_prime +snd_assert_on_duck_stop +snd_assert_on_enqueue +snd_assert_on_play +snd_assert_on_stop +snd_autoSim +snd_autosim_window +snd_boat_current_rpm +snd_boat_engine_off +snd_boat_lerp_rpm +snd_boat_pitch_high_max +snd_boat_pitch_high_min +snd_boat_pitch_idle_max +snd_boat_pitch_idle_min +snd_boat_pitch_low_max +snd_boat_pitch_low_min +snd_boat_pitch_med_max +snd_boat_pitch_med_min +snd_boat_rpm_high_fin_end +snd_boat_rpm_high_start +snd_boat_rpm_idle_end +snd_boat_rpm_idle_fout_start +snd_boat_rpm_low_end +snd_boat_rpm_low_fin_end +snd_boat_rpm_low_fout_start +snd_boat_rpm_low_start +snd_boat_rpm_med_end +snd_boat_rpm_med_fin_end +snd_boat_rpm_med_fout_start +snd_boat_rpm_med_start +snd_boat_rpm_scalar +snd_boat_using_lerp_rpm +snd_boat_water_fast_min +snd_boat_water_idle_max +snd_boat_water_pitch_max +snd_boat_water_slow_max +snd_boat_water_slow_min +snd_debug_alias_filter +snd_debug_context_type +snd_debug_context_value +snd_debug_duck +snd_disable_ducks +snd_disable_play_once +snd_dlpf_attenuation +snd_dlpf_max_distance +snd_dlpf_min_distance +snd_dopplerRate +snd_dopplerScale +snd_draw3D +snd_dry_scale +snd_dsp_futz +snd_dsp_meters +snd_earlyverb_force +snd_earlyverb_scale +snd_enable_pitch +snd_farverb_force +snd_farverb_scale +snd_flux_separation +snd_force_pfutz +snd_futz_distance_ratio +snd_futz_force +snd_gfutz_override +snd_global_pitch +snd_isbig_distance +snd_jetgun_loop_start +snd_jetgun_pitch_end +snd_jetgun_pitch_start +snd_levelFadeTime +snd_losOcclusion +snd_master_override +snd_max_ram_voice +snd_max_stream_voice +snd_minigun_loop_start +snd_minigun_pitch_end +snd_minigun_pitch_start +snd_music_stress +snd_mute_alias_substring +snd_nearfar_max +snd_nearfar_min +snd_nearverb_force +snd_nearverb_scale +snd_occlusion_attenuation +snd_occlusion_rate +snd_pitch_timescale +snd_playing_priority_boost +snd_reverb_override +snd_reverb_prefader +snd_skip_muted_sounds +snd_solo_alias_substring +snd_solo_loaded +snd_solo_snapshot_group +snd_solo_streams +snd_speakerConfiguration +snd_start_alias +snd_start_alias_distance +snd_stop_alias +snd_stress +snd_throttle_reduce_vol +snd_throttle_time_held_down +snd_timescale_filter +snd_vo_implementation_mode +snd_voice_duck_override +snd_wet_scale +spawnPingPerkFadeTime +spawnsystem_allow_culling +spawnsystem_allow_non_team_spawns +spawnsystem_badspawn_aggression_delay +spawnsystem_badspawn_damage_delay +spawnsystem_badspawn_force_record +spawnsystem_convert_spawns_to_structs +spawnsystem_danger_time +spawnsystem_debug +spawnsystem_debug_archive +spawnsystem_debug_best_points +spawnsystem_debug_current_player +spawnsystem_debug_explored +spawnsystem_debug_influencer_pulse +spawnsystem_debug_influencer_types +spawnsystem_debug_influencers +spawnsystem_debug_list +spawnsystem_debug_liveedit +spawnsystem_debug_player +spawnsystem_debug_point_weights +spawnsystem_debug_points +spawnsystem_debug_reduced_logging +spawnsystem_debug_showclients +spawnsystem_debug_sideswitched +spawnsystem_debug_team +spawnsystem_debug_visibility +spawnsystem_debug_visibility_time +spawnsystem_demo_enable_parsing +spawnsystem_demo_max_written +spawnsystem_influencer_sight_line +spawnsystem_influencer_sight_line_min_length +spawnsystem_influencer_sight_line_push_through +spawnsystem_influencer_sight_line_update_interval +spawnsystem_old_vis_mask +spawnsystem_pause_weight_update +spawnsystem_player_explored_radius +spawnsystem_score_cull_min_points +spawnsystem_score_cull_percent +spawnsystem_score_cull_time_max +spawnsystem_score_cull_time_min +spawnsystem_sight_check_dual_point +spawnsystem_sight_check_dual_point_radius +spawnsystem_sight_check_max_distance +spawnsystem_sight_check_max_distance_ai +spawnsystem_sight_check_sentient_ai +spawnsystem_sight_check_sentient_players +spawnsystem_sight_height_offset +spawnsystem_sight_use_player_current_view_height +spawnsystem_use_code_point_enabled +spawnsystem_user_selects_spawn +speedburst_blur_amount +speedburst_blur_enabled +speedburst_blur_radius_inner +speedburst_blur_radius_outer +speedburst_blur_time_in +speedburst_blur_time_out +splitscreen +splitscreen_controller +splitscreen_horizontal +splitscreen_playerCount +spmode +sprintLeap_enabled +sprintLeap_forwardVelocityScale +sprintLeap_groundTraceDist +sprintLeap_height +sprintLeap_minSprintTimeMs +sprintLeap_minVolumeTimeMs +sprintLeap_traceForwardIncrament +sprintLeap_traceForwardMax +sprint_allowRechamber +sprint_allowReload +sprint_allowRestore +sprint_capSpeedEnabled +sprint_controlScheme +sprint_focalLength +sprint_fx_enabled +sprint_lensEnabled +sprint_lensInTransRate +sprint_lensOutTransRate +sprint_maxTime +sprint_minTime +sprint_minVelocity +sprint_minVelocitySwimming +sprint_rampIn +sprint_recoveryDelay +sprint_recoveryExtraDelay +sprint_recoveryTime +sprint_rollDeg +sprint_rollEnabled +sprint_rollTransTime +sprint_rumble_enabled +sprint_shake_duration +sprint_shake_enabled +sprint_shake_scale +sprint_stopOnWeaponRest +sprint_weaponScalarEnabled +sprintleap_check_dist +st_LODDistScale +st_forceLOD +standardPrimaryAttachmentCount +standardSecondaryAttachmentCount +stat_version +statsCheckXuidBeforeStatsUpload +statsErrorBackup +statsErrorNormal +statsErrorOtherPlayer +statsErrorStable +statsLocationFatal +statsVersionCP +statsVersionFR +statsVersionMP +statsVersionZM +stats_version_check +status +steamLobby_frameEnable +steamLobby_frameFailInterval +steamLobby_frameInterval +steamLobby_frameKeepAliveInterval +steamP2P_Enable +steamWorkshop_Enable +stopspeed +storage_auto_reset +storage_backoff +storage_maxfailures +storage_offline +storeMapPackMaskToStats +store_item_viewed_timer +streamMBPerSecond +survey_chance +survey_count +sv_FFCheckSums +sv_FFNames +sv_FakeRemoteClient +sv_SnapshotPeek +sv_allowAnonymous +sv_allowDownload +sv_antilagAnim +sv_archiveClientsPositions +sv_assistWorkers +sv_authenticating +sv_bitfieldTracking +sv_botThinkType +sv_botsPressAttackBtn +sv_bullet_range +sv_capture_ping_data +sv_cheats +sv_clientArchive +sv_clientFpsLimit +sv_clientFrameRateFix +sv_clientSideBullets +sv_clientSideVehicles +sv_clientUpdateDistance +sv_clientside +sv_connectTimeout +sv_connectionLogProbability +sv_connectionLogSamplesPerSecond +sv_connecttimeout +sv_debugAntiLagRewind +sv_debugConstantConfigStrings +sv_debugMessageKey +sv_debugPacketContents +sv_debugPacketContentsForClientThisFrame +sv_debugPacketContentsQuick +sv_debugPlayerstate +sv_debugRate +sv_debugReliableCmds +sv_detailedScriptErrors +sv_disableClientConsole +sv_dwlsgerror +sv_dynsnaps +sv_earlyEndSnapshots +sv_endGameIfISuck +sv_endmatch +sv_error_on_baseline_failure +sv_expensive_bullet_time +sv_fakeServerLoad +sv_fakeServerLoadRand +sv_floodProtect +sv_forceUpdateInterval +sv_forcelicensetype +sv_forceunranked +sv_fx_blockMinDist +sv_generateConstBaselines +sv_greedylock +sv_hitFXFrustumCutoff +sv_hostname +sv_ignorePing +sv_iwdNames +sv_iwds +sv_jqprof_continuous +sv_jqprof_enabled +sv_jqprof_frequency +sv_jqprof_profileCheckpointFrames +sv_jqprof_threshold +sv_keywords +sv_kickBanTime +sv_leaderboardwriteInterval +sv_loadMyChanges +sv_mapRotation +sv_mapRotationCurrent +sv_mapSwitch +sv_mapSwitchPerloadFrontendReserveMB +sv_mapSwitchPerloadFrontendReservePagesPerFrame +sv_mapSwitchPerloadFrontendStreamerFrames +sv_mapSwitchPreloadFrontend +sv_mapSwitch_rat +sv_mapcrc +sv_mapname +sv_maprotationcurrent +sv_mapswitch +sv_maxHappyPingTime +sv_maxPhysExplosionSpheres +sv_maxRate +sv_maxclients +sv_maxping +sv_momentumPercent +sv_network_fps +sv_nextmap +sv_noname +sv_onlineHostSnapshotRateThrottled +sv_packet_info +sv_padPackets +sv_paused +sv_penetrationCount +sv_playlistFetchInterval +sv_potm_debug +sv_printMessageSize +sv_privateClients +sv_privateClientsForClients +sv_privatePassword +sv_privateclients +sv_pure +sv_rateBoosting +sv_rateBoostingAllowUnackDeltas +sv_rateBoostingDebugForceSuspend +sv_rateBoostingMaxUploadUsage +sv_rateBoostingMinUploadScale +sv_rateBoostingRecoverTime +sv_rateBoostingSuspendBadFramesCPU +sv_rateBoostingSuspendBadFramesCPUThreshold +sv_rateBoostingSuspendBadFramesCPUTimeout +sv_rateBoostingSuspendedMaxUploadUsage +sv_reconnectlimit +sv_referencedFFCheckSums +sv_referencedFFNames +sv_referencedIwdNames +sv_referencedIwds +sv_restrictedTempEnts +sv_running +sv_saveGameSkipto +sv_sendCmdAngles +sv_serverLogClientPings +sv_showAverageBPS +sv_showCommands +sv_showHuffmanData +sv_showPingSpam +sv_skipto +sv_snapshot_skip_count +sv_timeout +sv_useAnimCulling +sv_useMapPreloading +sv_userCmdLimiter +sv_vac +sv_voice +sv_voiceQuality +sv_writeConfigStrings +sv_wwwBaseURL +sv_wwwDlDisconnected +sv_wwwDownload +sv_zlib_threshold +sv_zombietime +sys_threadWatchdogTimeoutLive +systemUiActive +systeminfo +systemlink +tacticalWalkDirection +take +teamOpsEnabled +teamOpsKillsCountTrigger +teamOpsName +teamOpsPreanounceTime +teamOpsStartDelay +teamsplitter_verbose +tell +tempCPOnline +tempbanclient +tempbanuser +terriblePing +testMissingContentPacks +test_levels_selection +tgraph_debugClearancePointId +tgraph_debugDrawPointNavFace +tgraph_debugDrawPoints +tgraph_debugShowStats +tgraph_debugTargetPointId +tgraph_debugVisMapDrawNonVisible +tgraph_debugVisMapPointId +throwback_enabled +tickerStandardWidth +tickerWidescreenWidth +ticker_menu_context +timeUntilDropRange +timescale +tm_currentErrorPage +tm_failsThreshold +tm_logTimeLimit +tm_pendingeThreshold +tm_startedThreshold +tm_succeedsThreshold +tm_taskManagerDebug +tm_taskTrackerOn +tm_typeToDisplay +totalCoverage_blockFriendlyMinimap +totalCoverage_debug +totalCoverage_enemy_minimap +totalCoverage_friendly_minimap +totalCoverage_higherGroundTest +totalCoverage_offsetToCoverage +totalCoverage_smokeInTime +totalCoverage_smokeOutTime +totalSampleClientTrack +totalSampleRateBlackBox +totalSampleRateQoS +totalSampleRateSurvey +total_paintjobs +tquery_drawQuery +tquery_drawQueryDuration +tracer_debugDraw +tracer_explosiveColor1 +tracer_explosiveColor2 +tracer_explosiveColor3 +tracer_explosiveColor4 +tracer_explosiveColor5 +tracer_explosiveOverride +tracer_explosiveWidth +tracer_firstPersonMaxWidth +tracer_stoppingPowerColor1 +tracer_stoppingPowerColor2 +tracer_stoppingPowerColor3 +tracer_stoppingPowerColor4 +tracer_stoppingPowerColor5 +tracer_stoppingPowerColor6 +tracer_stoppingPowerOverride +tracer_stoppingPowerWidth +tracer_thermalWidthMult +traverse_mode +trm_adsDisablesAutoComplete +trm_alignViewToSurfaceTime +trm_autoCompleteJumpTimeMs +trm_autocomplete_require_jump +trm_checkRadius +trm_checkRange +trm_checkRangeVault +trm_clearanceTraceZEpsilon +trm_clearanceWidthAdd +trm_deadZone +trm_debug +trm_doublejumpPreventReengageTime +trm_doublejump_out_frac_on_high_forward_100 +trm_doublejump_out_frac_on_high_forward_140 +trm_doublejump_out_frac_on_low_forward +trm_doublejump_out_frac_on_low_left +trm_doublejump_out_frac_on_low_right +trm_doublejump_out_frac_on_med_forward +trm_doublejump_out_frac_on_med_left +trm_doublejump_out_frac_on_med_right +trm_doublejump_out_frac_over_high_forward_100 +trm_doublejump_out_frac_over_high_forward_140 +trm_doublejump_out_frac_over_high_forward_75 +trm_doublejump_out_frac_over_low_forward +trm_doublejump_out_frac_over_low_forward_vault +trm_doublejump_out_frac_over_low_left +trm_doublejump_out_frac_over_low_right +trm_doublejump_out_frac_step +trm_enable +trm_enableDoubleJumpOut +trm_enabled +trm_entitiesBlockForwardTrace +trm_fastmantle_scalar +trm_highPitchDegrees +trm_highYawDegrees +trm_initMinForwardMove +trm_initMinSideMove +trm_input +trm_inputRange +trm_inputRangeBack +trm_inputRangeSide +trm_ledgeAngleOffset +trm_ledgeCapsuleRadius +trm_ledgeHeight_onHigh +trm_ledgeHeight_onLow +trm_ledgeHeight_onMed +trm_ledgeHeight_overHigh +trm_ledgeHeight_overLow +trm_ledgeHeight_overMed +trm_ledgeHeight_step +trm_maxBackMantleHeight +trm_maxHurdleDistance +trm_maxSideMantleHeight +trm_maxVerticalityRatio +trm_minFacingRatio +trm_minLedgeHeight +trm_movefrac_on_high_forward_100 +trm_movefrac_on_high_forward_140 +trm_movefrac_on_low_forward +trm_movefrac_on_low_left +trm_movefrac_on_low_right +trm_movefrac_on_med_forward +trm_movefrac_on_med_left +trm_movefrac_on_med_right +trm_movefrac_over_high_forward_100 +trm_movefrac_over_high_forward_140 +trm_movefrac_over_high_forward_75 +trm_movefrac_over_low_forward +trm_movefrac_over_low_forward_vault +trm_movefrac_over_low_left +trm_movefrac_over_low_right +trm_movefrac_step +trm_pitchRecenterTime +trm_safeHurdleZ +trm_stepDistance +trm_step_contact_frac +trm_timescale_on_high_forward_100 +trm_timescale_on_high_forward_140 +trm_timescale_on_low_forward +trm_timescale_on_low_left +trm_timescale_on_low_right +trm_timescale_on_med_forward +trm_timescale_on_med_left +trm_timescale_on_med_right +trm_timescale_over_high_forward_100 +trm_timescale_over_high_forward_140 +trm_timescale_over_high_forward_75 +trm_timescale_over_low_forward +trm_timescale_over_low_forward_vault +trm_timescale_over_low_left +trm_timescale_over_low_right +trm_timescale_step +trm_viewCenterStart +trm_viewCenterTimeMs +trm_weaponRaisedelayMs +tu10_ClearWeapNextHeldInputOnSwitchWeaponCmd +tu10_cleanupRagdollsOnExit +tu10_enableCyclicalDailyChallenges +tu10_enableHighestAvailableDLCEntitlementCheck +tu10_metPlayerClearOnUserSignedOut +tu10_mpSwitchSpecialistWeaponExploitFix +tu10_validationFatal +tu11_AllowIgnoreDisabledWeaponCyclingInActionSlotUsageAllowed +tu11_IgnoreItemsWithPLevel100InIsItemLockedForChallenge +tu11_cleanupRagdollsOnDemoJump +tu11_clearMpVehicleWaterMaterial +tu11_dontUpdateWeaponPosFracWhenLinked +tu11_enableClassicMode +tu11_enableVehicleMode +tu11_fixForMultishotRechamberWeaponSwitchIssue +tu11_lootCryptoAutoRetry +tu11_matchmakingPriorityDOA +tu11_matchmakingPriorityDOAIgnoreTime +tu11_matchmakingPriorityMP +tu11_matchmakingPriorityMPIgnoreTime +tu11_maxQuadCacheAlloc +tu11_mpNewCodCasterKeyline +tu11_mpReconstructTrailsForStationaryEntities +tu11_programaticallyColoredGameFX +tu11_uploadStreamFailureFlag +tu11_useLootXPDueStat +tu12_delayFFOTD +tu12_mpMaintainMissileSpeed +tu12_switchToWeaponImmediateFix +tu12_zmHideLegsWithViewmodel +tu13_recordContentAvailable +tu14_skipPrimaryGroupCheck +tu16_SLFreeStringFix +tu16_physicsPushOutThreshold +tu19_orbis_presence_localizations +tu1_aiPathableMaterials +tu1_build +tu1_pickupParentlessGrenade +tu1_queuedEventInterval +tu1_saveGameAiProximityCheck +tu1_vehicleCollisionCacheSetup +tu1_zombiePaintJobsEnabled +tu2_catchMissingRbEndFrame +tu2_cscGetDStatCP +tu2_disableChallengesForLockedItemsInArena +tu2_forceConnectionStateTransitionSpinnerOn +tu2_logLootToKVS +tu3_lobby_dropRejoiningClients +tu3_onlineSavegameErrorFatal +tu4_burnDuplicates +tu4_enableBonusCryptokeysHint +tu4_enableCodPoints +tu4_enableMeleeWeaponFlourish +tu4_firstValidCurrencyID +tu4_newSysInfo +tu4_newSysInfoUpdateRate +tu4_partyPrivacyLuaCheck +tu4_partyPrivacyUseGlobal +tu4_refetchBalanceOnUpdate +tu4_skipStatStatusCache +tu4_storageClearTargetQueue +tu4_storageControllerSwapProtection +tu4_zmChangePlayerStandOnSentients +tu5_defaultMaxHeroAttachmentsToZero +tu5_dwNetFatalErrors +tu5_enableVialsOwed +tu5_gadgetThiefSupport +tu5_live_friends_signedin_fetch +tu5_partyStatusGetInterval +tu5_recordXuidMismatch +tu5_vialsOwedCheckDelay +tu5_zmChangeOffhandGearWeaponChange +tu5_zmChangeSlamUseWalkable +tu5_zmEnableClipOnlyWeaponFlourish +tu5_zmPathDistanceCheckTolarance +tu6_doublePistolSpreadAmmo +tu6_mpMeleeAttachmentObitIcon +tu6_mpReconstructTrailForOtherPlayers +tu6_mpReconstructTrailForTriboltCrossbow +tu6_mpStackFirePitchChange +tu6_player_shallowWaterHeight +tu7_enableBundles +tu7_mpDoNotSetBallisticAnglesWhenLinked +tu7_mpNoVehicleNeutralTeamTargetHighlight +tu7_mpUseImprovedMissileStickAngles +tu7_mpUseNewBounceMissileMayStopFleshLogic +tu7_zmInAirDisabledTimeoutTime +tu8_ai_enableBTInterruptPriority +tu8_animTimeResetInterval +tu8_enableDurableProductsExchange +tu8_mpChallengesGroupPrereqFix +tu8_mpLootWeaponPurchasedCheckEnabled +tu8_mtx_enabled +tu8_platformSessionOrbisValidateNpEventResult +tu8_trmRestrictionLevel +tu8_yySlideExploitFix +tu9_backupBadDecompress +tu9_backupBadSpace +tu9_canSplitInProgressUnbalancedTeams +tu9_entryExitImpactSurfaceNormalFix +tu9_fileshareCommunityIncludeEmptyDescriptors +tu9_highestAvailableDLC +tu9_hostLaunchCheckMinPlayer +tu9_hostLaunchCheckUnbalancedTeams +tu9_hostPrivateSessions +tu9_jitterModExploitFix +tu9_skipPerlocalClientAllocation +tu9_ui_zmLobbyEEEnabled +tu9_yySlideExploitFix +tu9_zmDisableMeleeChargeJump +turretPlayerAvoidScale +turret_placement_debug +turret_placement_feet_offset +turret_placement_feet_trace_dist_z +turret_placement_trace_dist +turret_placement_trace_dist_wallmount +turret_placement_trace_dist_zm +turret_placement_trace_maxs +turret_placement_trace_min_normal +turret_placement_trace_mins +turret_placement_trace_pitch +turret_placement_trace_radius_canon_safety +turretplacement_traceOffset +turretplacement_useTraceOffset +twitch_app_version +twitch_audio_volume +twitch_client_id +twitch_mixpanel_token +twitch_platform_name +twitch_player_name +twitch_stats_update_interval +typeWriterCod7LetterFXTime +ufo +ui_DSPPromotionInterval +ui_SPReminderPopupInterval +ui_abortKeyboardOnUIChange +ui_allowDisplayContinue +ui_allow_classchange +ui_allow_controlschange +ui_allow_teamchange +ui_allowvote +ui_autoContinue +ui_autoControlledPlayer +ui_badWordMaxTaskWaits +ui_badWordSeverity +ui_bigFont +ui_blocksaves +ui_blurAmount +ui_blurDarkenAmount +ui_blurTime +ui_borderLowLightScale +ui_buildLocation +ui_buildSize +ui_busyBlockIngameMenu +ui_checksum_enabled +ui_cinematicsTimestamp +ui_codexindex_unlocked +ui_combatCurrScrollBarPos +ui_creditSkipTo +ui_creditsScrollScale +ui_currFocusList +ui_currFocusStates +ui_currMenuNameList +ui_currentNetMap +ui_custom_name +ui_customerServiceURL +ui_damage_widget_hide_delay +ui_deadquote +ui_dedicated +ui_demoname +ui_detailedMM +ui_disablePSControlWidgets +ui_disable_blur +ui_disable_lan +ui_display_aar +ui_doa_unlocked +ui_drawBuildNumber +ui_drawCrosshair +ui_drawSpinnerAfterMovie +ui_dropdownListMax +ui_dropdownMax +ui_emblemDisableGroups +ui_enableAllHeroes +ui_enableConnectionMetricGraphs +ui_enableDSPPromotion +ui_enableSPReminderPopup +ui_enableZMHDFeaturedCard +ui_enabled +ui_errorMessage +ui_errorMessageDebug +ui_errorTitle +ui_errorUndefLocals +ui_error_callstack_ship +ui_error_report +ui_error_report_delay +ui_execdemo +ui_execdemo_beta +ui_execdemo_cp +ui_execdemo_e3 +ui_execdemo_gamescom +ui_execdemo_gamescom_host +ui_extraBigFont +ui_fakeCurrentMap +ui_forceQueue +ui_framesBetweenButtonPromptTraces +ui_framesBetweenObjectiveLOSTraces +ui_freeCursorAcceleration +ui_freeCursorParallax +ui_freeCursorSpeed_Focus +ui_freeCursorSpeed_NoFocus +ui_friendlyfire +ui_friendsListOpen +ui_fxFontFalloff +ui_fxFontGlowSize +ui_fxFontOutlineSize +ui_fxFontShadowOffset +ui_fxFontShadowSize +ui_fxFontTweaks +ui_gametype +ui_generic_status_bar +ui_guncycle +ui_heatMapColor +ui_heatMapColorForPlayer +ui_heroExtracamResolution +ui_hideLeaderboards +ui_hideMiniLeaderboards +ui_hostname +ui_hud_hardcore +ui_hud_minimap_hide +ui_hud_obituaries +ui_hud_showobjicons +ui_hud_visible +ui_inGameStoreVisible +ui_isDLCPopupEnabled +ui_keepLoadingScreenUntilAllPlayersConnected +ui_keyboard_dvar_edit +ui_keyboardtitle +ui_levelEra +ui_level_sv +ui_liveEventViewerOpen +ui_lobbyDebugAgreeCountLoc +ui_lobbyDebugAgreementLoc +ui_lobbyDebugBaseX +ui_lobbyDebugBaseY +ui_lobbyDebugClients +ui_lobbyDebugDWSessionLoc +ui_lobbyDebugExtraInfoLoc +ui_lobbyDebugGameClientSessionLoc +ui_lobbyDebugGameHostSessionLoc +ui_lobbyDebugJoinLoc +ui_lobbyDebugLobbyTasksLoc +ui_lobbyDebugMsgLoc +ui_lobbyDebugOverlay +ui_lobbyDebugPlatformSessionLoc +ui_lobbyDebugPrivateClientSessionLoc +ui_lobbyDebugPrivateHostSessionLoc +ui_lobbyDebugResCountLoc +ui_lobbyDebugReservationLoc +ui_lobbyDebugSessionSQJ +ui_lobbyDebugVis +ui_lobbyDebugVoice +ui_lobbyDebugVoiceClientLoc +ui_lobbyDebugVoiceHostLoc +ui_lobbypopup +ui_mapname +ui_menuLvlNotify +ui_motd +ui_mousePitch +ui_mpTheaterEnabled +ui_mpWagerMatchEnabled +ui_netSource +ui_newStartMenu +ui_numTacticalWidgets +ui_options_open +ui_paintshopEditDarkening +ui_playLogoMovie +ui_playerListOpen +ui_playerNemesisColor +ui_playerSquadColor +ui_playlistPopulationRefreshTime +ui_readingSaveDevice +ui_safearea +ui_saveMessageMinTime +ui_scorelimit +ui_scrollSpeed +ui_sessionModeLocation +ui_showFocus +ui_showGameModeHistory +ui_showList +ui_showNewestLeaderboards +ui_showSessionMode +ui_showmap +ui_singlemission +ui_smallFont +ui_smp_hud_models +ui_snapToNearestPixel +ui_splitscreen +ui_storeButtonPressed +ui_supportURL +ui_ten_classes +ui_textPaddingOverride +ui_text_endreason +ui_timelimit +ui_timescale +ui_totalDLCReleased +ui_tu11_splitscreen_scoreboard_snap_check +ui_useloadingmovie +ui_useoutromovie +ui_usingFreeCursor +ui_weakpointIndicatorMedium +ui_weakpointIndicatorNear +ui_weapon_tiers +ui_zm_gamemodegroup +ui_zm_mapstartlocation +uiscript_debug +unbanuser +unbind +unbind2 +unbindall +unbindall2 +unifiedLens_enabled +unifiedLens_minFocalLength +unifiedLens_minVelocityThreshold +unifiedLens_scaleFinal +unifiedLens_scaleInitial +unifiedLens_transTimeIn +unifiedLens_transTimeOut +unsubscriptionCooloffTimer +upload_bps_dedicated +upload_bps_demosystem +upload_bps_perplayer +useClassSets +useFakeEmblems +useFastFile +useForceEliteCmds +useLargeRadius +useMapPreloading +usePaintshopData +useRadius +useSvMapPreloading +useWalkPathnodesMode +vc_LUT +vc_SNAP +vehControlMode +vehGunnerSplashDamage +vehHelicopterAlwaysFaceCamera +vehHelicopterAlwaysFaceCameraRate +vehHelicopterHeadSwayDontSwayTheTurret +vehHelicopterJitterJerkyness +vehLocationalVehicleSeatEntry +vehLockTurretToPlayerView +vehNPCThrottleMultiplier +vehPlaneFakeLiftForce +vehPlaneGravityForce +vehPlaneInvertPitch +vehPlaneJetControls +vehPlaneLiftForce +vehPlaneLowSpeed +vehPlanePitchAccel +vehPlaneRollAccel +vehPlaneRollDeadZone +vehPlaneYawFromRollScale +vehPlaneYawSpeed +vehRecenterDelay +vehanim_debug +vehanim_enable +vehicleMouseExtraTurnSpeed +vehicle_collision_prediction_crash_time +vehicle_collision_prediction_time +vehicle_damage_max_shielding +vehicle_damage_zone_front +vehicle_damage_zone_rear +vehicle_damage_zone_side +vehicle_damage_zone_under +vehicle_destructible_damage_bouncing_betty +vehicle_destructible_damage_bouncing_betty_radius +vehicle_destructible_damage_grenade +vehicle_destructible_damage_grenade_radius +vehicle_destructible_damage_projectile_radius +vehicle_destructible_damage_satchel_charge +vehicle_destructible_damage_satchel_charge_radius +vehicle_destructible_damage_sticky_grenade +vehicle_destructible_damage_sticky_grenade_radius +vehicle_infinite_boost +vehicle_perk_boost_duration_seconds +vehicle_piece_damagesfx_threshold +vehicle_push_during_mantle +vehicle_riding +vehicle_selfCollision +vehicle_sounds_cutoff +vehicle_spline_arrows +vehicle_strafe_control_dead_zone +vehicle_switch_seat_delay +vehicle_useRadius +version +vid_xpos +vid_ypos +viewpos +vm_sendNotifyAndCallbackOnSpawn +voiceDegrade +voice_debug +voice_enabled +vote +waitForInitial +waitForStreamer +waitOnStatsTimeout +walkMove_avoidanceDot +walkMove_avoidanceEnabled +walkMove_avoidanceMinSpeedScale +walkMove_avoidanceProbeDistance +walkMove_avoidanceSpeedDifferentialThreshold +wallRun_avoidanceEnabled +wallRun_avoidanceMinMaintainSpeed +wallRun_avoidanceMinSpeedScale +wallRun_avoidanceProbeDistance +wallRun_beginFallOnDamage +wallRun_cameraAlignmentEaseMode +wallRun_cameraAutoCurveAngleFactor +wallRun_cameraAutoCurveEnabled +wallRun_cameraAutoCurveTimeMs +wallRun_cameraAutoCurveTraceDistance +wallRun_cameraClamp +wallRun_cameraInputDeadTimeMs +wallRun_cameraRollSpeed +wallRun_cameraRotateTimeMs +wallRun_cameraYaw +wallRun_cameraYawOffset +wallRun_cameraYawRate +wallRun_combatEnable +wallRun_debug +wallRun_downStepVelocity +wallRun_enabled +wallRun_exitMoveDampening +wallRun_facingMaxPitch +wallRun_facingMinSin +wallRun_fallGroundPitchMax +wallRun_fallGroundPitchMin +wallRun_fallStageTimeMs +wallRun_fallingRollScalar +wallRun_firingInStateDelay +wallRun_frictionScale +wallRun_handTraceEnable +wallRun_initialAnimDelayMs +wallRun_initialCameraInputDeadTimeMs +wallRun_jumpHeight +wallRun_jumpVelocity +wallRun_maxHeight +wallRun_maxTimeMs +wallRun_minForwardMove +wallRun_minHeightOffGround +wallRun_minJumpHeight +wallRun_minJumpHeightEnable +wallRun_minMaintainSpeed +wallRun_minTriggerSpeed +wallRun_minVelocityAlignment +wallRun_minZVel +wallRun_moveMode +wallRun_normalFacingRatio +wallRun_obtuseSlopeTolerance +wallRun_peakTest +wallRun_peakTest_zm +wallRun_pitchTimeMs +wallRun_rollDeg +wallRun_rollInTimeMs +wallRun_rollOutTimeMs +wallRun_sameSurfaceDelayPeriodMs +wallRun_sameSurfaceWallrun +wallRun_sightTraceDistance +wallRun_speedScale +wallRun_speedScaleADS +wallRun_sweepTraceDistance +wallRun_sweepTraceEnable +wallRun_traceDistance +wallRun_traceMode +wallRun_tracePitch +wallRun_universalRollEnable +wallRun_viewmodelAnimEnable +wallRun_weaponBobFrequency +wallmount_turret_placement_trace_maxs +wallmount_turret_placement_trace_mins +wallrun_additiveWalkAnimScale +wallrun_additiveWalkAnimScaleADS +wallrun_avoidanceDot +wallrun_enabled +wallrun_jumpLateralLimit +wallrun_peakTestMinVelocity +wallrun_slopeQuotient +war_a +war_b +war_c +war_d +war_e +waterbrush_entity +waypointAlphaFractionUnderMinimap +waypointCombatAlpha +waypointDebugDraw +waypointDistFade +waypointDistScaleRangeMax +waypointDistScaleRangeMin +waypointDistScaleSmallest +waypointForceDrawDistance +waypointIconHeight +waypointIconWidth +waypointMaxDrawDist +waypointOffscreenCornerRadius +waypointOffscreenDistanceThresholdAlpha +waypointOffscreenPadBottom +waypointOffscreenPadLeft +waypointOffscreenPadRight +waypointOffscreenPadTop +waypointOffscreenPointerDistance +waypointOffscreenPointerHeight +waypointOffscreenPointerWidth +waypointOffscreenRoundedCorners +waypointOffscreenScaleLength +waypointOffscreenScaleSmallest +waypointPlayerOffsetCrouch +waypointPlayerOffsetProne +waypointPlayerOffsetRevive +waypointPlayerOffsetStand +waypointSplitscreenScale +waypointTimeFade +waypointTweakY +waypointVerticalSeparation +weaponCamoLodDist +weaponClanTagLodDist +weaponClanTagShieldLodDist +weaponEmblemLodDist +weaponEmblemShieldLodDist +weapon_contract_incentive_id +weapon_contract_max +weapon_contract_target_value +weaponrest_check_radius +weaponrest_check_range +weaponrest_debug +weaponrest_enabled +weaponrest_removepitch +weaponrest_updatemsec +webm_encAllowCamera +weekly_contract_blackjack_contract_reward_count +weekly_contract_cryptokey_reward_count +welcome_shown +wideScreen +wiiuGame +wiiuIkEnabled +wind_debug_display +wind_global_hi_altitude +wind_global_low_altitude +wind_global_low_strength_percent +wind_global_vector +wind_grass_gust_distance +wind_grass_gust_radius +wind_grass_gust_speed +wind_grass_gust_strength +wind_grass_gustinterval +wind_grass_scale +wind_grass_tension +wind_leaf_scale +winvoice_loopback +winvoice_mic_mute +winvoice_mic_reclevel +winvoice_mic_scaler +winvoice_save_voice +winvoice_voice_level +xPGroupMask +xPGroups +xanim_debug +xanim_debugNotetracks +xanim_monitorEnt +xanim_monitorFilter +xblive_clanListChanged +xblive_clanmatch +xblive_loggedin +xblive_mappacks +xblive_matchEndingSoon +xblive_privatematch +xblive_rankedmatch +xblive_theater +xblive_wagermatch +xenonGame +xenon_maxVoicePacketsPerSec +xenon_maxVoicePacketsPerSecForServer +xuid +yawAccelerationTime +yawDecelerationThreshold +zero_idle_movement +zero_stats_check +zm_private_rankedmatch +zm_rand_loc +zm_rand_mode +zm_vials_3_id +zm_vials_6_id +zm_vials_9_id +zm_wasp_open_spawning +zombie_cheat +zombie_debug +zombie_devgui +zombie_kill_timer +zombie_kills +zombiemode_debug_zombie_count \ No newline at end of file diff --git a/data/scripts/mp/bots/_bot.gsc b/data/scripts/mp/bots/_bot.gsc new file mode 100644 index 0000000000000000000000000000000000000000..7f793a6890f4ee525ef720aed1be9fc253c0c87c GIT binary patch literal 15384 zcma)D34D`Pw!dGJmbR2o0R<7^%f7EolV)crr4(9hfl}5qP11#?O>EQBoeGKwXaP|W zl}#!j3W|sbh#N8p$ReWXC@{$2f-oqEs0_Swl6*AuP3OJ*xc$!moVzdQo_p@4ZPfS? zy^_eFstpDeP<5>*bVpQE=C1a6HSX$acY`Yey2?CmzrWb+si^5jUQzD%L#{q|w=pW+ zp|WlgSG%h!x)Ieh)P#JM-3V(#<^FC&vwZGgpsKstMx`28l<3;p;sA7*3;uR1aCrii z#qR$shjgyu+E56}|BvZW9;$ZN`KoK&{>~_sLCu|VUB%GfcM{(v@%Vl2s%}Jg*XizL zfvS>jQiZw^czu=sIfXaSjQ}QCpt`eD?y5l9!~Z$6ia@CBKTG@pw>MDRO?EZj*hDeY zPvdfzyFxId{)@c2rZyPtQq#M#h>WhQIuJVtpgCP4)mDXk)wS-rZj17|@9vJf(t87? zca8qt!s`zTbqgWcDp+EWaRy4yxqL*XIc|59UJyD<{2 zvb?6I+~56lsBwpUet&uBzr^rWh03dZcWI`(`UBUMzX96Y{k;4?dbG=G3i;fX(9hvd zY%jP__Y>5lumteqt8y3neUm_KR@Z`htV8Wx6L5nT2*Lz&hXU0EWaTg`F*c)GJh1V( zf-tk(rA(_`RnVieU`WdvBKf=Phjk{b1XN!h$pq-kYM+m|k>T~Zy<|jLAW-8Q;dj^6 zxJFlva##9DXZN_UX)(|fxT8K|xSfL#!|YtBIO7_8)y!gyi4&eiF}Q{qs~BEXGoo4u z##SXdjhG2iUR4K)1Jz&*+!;^o=etp7z9gD3qHZu|XAb{MRD~J|cYFdCNia}e6{-ot zdKgFC^gOsxd0)2sQ2+5)99{s`8)@6rMjaaNhEg zl5$V2KNKCupv&j3xkFb4sw>^h403@1tfWA;%%S0pUpqUI;@W41jQnL&!%ERzRqNFb0AY zLNbK!*@PT~@EU{#5PT4ZL*PS5f^dmN$O#C$A*_Zl4?-n`2@ot0218&&_>m%HKZKVd z%!5z~AqRp6LO%$){Cbe zUxb3P)L@Yidf}Fh6y}ylD@)wJJcN9+AcZa%U6h72{xH4AtjO6sbH+!A-;YU_+A~#)c1yn#crB8ejEcvC$geO@Q}1{^t1Y0*mRbsimHIL- za*=OSoAP&M_c*eIH$+_5T3eX$HeY~zyE9lYmu~BNxY<;R< zB3+Z3w;cJa)h=&*&!%n1?FOgGWB314=GP4#;GBr195_PL`a`+k9Y?@pC(uhEWJ+O-U^+$z9fQ!GQAFqM+~k znWOJ5;c@As0y6d2-TS@B7u#7R1;#`yAQh_S%$()L?~OqI0s)u)Mt564WW_d**ON!@ z*|q`sFX>Zg{)C2lr16L2dBWIWv_l;s4~eGVu`$RWX4f><2Z~KdAIF;l!I5Z=I9aIhtHCk!I>WRzCSLHM^0JHpg`vmzF6> z6%+4I5gB$YeT?Sw+bOijqq{S|5>hEwxEv*y9&I27CVq;9Ozv-aOiOqZB=0#U2nG

1B=tFd^oYd+Sb9Bn_80VbDWW_q-uNS>j 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 literal 0 HcmV?d00001 diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw new file mode 100644 index 0000000..8206b45 --- /dev/null +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -0,0 +1,1125 @@ +#using scripts\codescripts\struct; + +#using scripts\shared\array_shared; +#using scripts\shared\callbacks_shared; +#using scripts\shared\killstreaks_shared; +#using scripts\shared\math_shared; +#using scripts\shared\rank_shared; +#using scripts\shared\system_shared; +#using scripts\shared\util_shared; +#using scripts\shared\weapons_shared; + +#using scripts\shared\weapons\_weapons; + +#using scripts\shared\bots\_bot; +#using scripts\shared\bots\_bot_combat; +#using scripts\shared\bots\bot_buttons; +#using scripts\shared\bots\bot_traversals; + +#using scripts\mp\bots\_bot_ball; +#using scripts\mp\bots\_bot_clean; +#using scripts\mp\bots\_bot_combat; +#using scripts\mp\bots\_bot_conf; +#using scripts\mp\bots\_bot_ctf; +#using scripts\mp\bots\_bot_dem; +#using scripts\mp\bots\_bot_dom; +#using scripts\mp\bots\_bot_escort; +#using scripts\mp\bots\_bot_hq; +#using scripts\mp\bots\_bot_koth; +#using scripts\mp\bots\_bot_loadout; +#using scripts\mp\bots\_bot_sd; + +#using scripts\mp\killstreaks\_ai_tank; +#using scripts\mp\killstreaks\_airsupport; +#using scripts\mp\killstreaks\_combat_robot; +#using scripts\mp\killstreaks\_counteruav; +#using scripts\mp\killstreaks\_dart; +#using scripts\mp\killstreaks\_dogs; +#using scripts\mp\killstreaks\_drone_strike; +#using scripts\mp\killstreaks\_emp; +#using scripts\mp\killstreaks\_flak_drone; +#using scripts\mp\killstreaks\_helicopter; +#using scripts\mp\killstreaks\_helicopter_gunner; +#using scripts\mp\killstreaks\_killstreak_bundles; +#using scripts\mp\killstreaks\_killstreak_detect; +#using scripts\mp\killstreaks\_killstreak_hacking; +#using scripts\mp\killstreaks\_killstreakrules; +#using scripts\mp\killstreaks\_killstreaks; +#using scripts\mp\killstreaks\_microwave_turret; +#using scripts\mp\killstreaks\_planemortar; +#using scripts\mp\killstreaks\_qrdrone; +#using scripts\mp\killstreaks\_raps; +#using scripts\mp\killstreaks\_rcbomb; +#using scripts\mp\killstreaks\_remote_weapons; +#using scripts\mp\killstreaks\_remotemissile; +#using scripts\mp\killstreaks\_satellite; +#using scripts\mp\killstreaks\_sentinel; +#using scripts\mp\killstreaks\_supplydrop; +#using scripts\mp\killstreaks\_turret; +#using scripts\mp\killstreaks\_uav; + +#using scripts\mp\teams\_teams; +#using scripts\mp\_util; + +#insert scripts\shared\shared.gsh; +#insert scripts\mp\bots\_bot.gsh; + +#define MAX_LOCAL_PLAYERS 10 +#define MAX_ONLINE_PLAYERS 18 +#define MAX_ONLINE_PLAYERS_PER_TEAM 6 + +#define RESPAWN_DELAY 0.1 +#define RESPAWN_INTERVAL 0.1 + +#namespace bot; + +#precache("eventstring", "mpl_killstreak_cruisemissile"); +#precache("eventstring", "mpl_killstreak_raps"); + +REGISTER_SYSTEM("bot_mp", &__init__, undefined) + +function __init__() +{ + callback::on_start_gametype(&init); + + level.getBotSettings = &get_bot_settings; + + level.onBotConnect = &on_bot_connect; + level.onBotSpawned = &on_bot_spawned; + level.onBotKilled = &on_bot_killed; + + level.botIdle = &bot_idle; + + level.botThreatLost = &bot_combat::chase_threat; + + level.botPreCombat = &bot_combat::mp_pre_combat; + level.botCombat = &bot_combat::combat_think; + level.botPostCombat = &bot_combat::mp_post_combat; + + level.botIgnoreThreat = &bot_combat::bot_ignore_threat; + + level.enemyEmpActive = &emp::enemyEmpActive; + +/* +/# + level.botDevguiCmd = &bot_devgui_cmd; + level thread system_devgui_gadget_think(); +#/ +*/ + setDvar("bot_enableWallrun", 1); +} + +function init() +{ + level endon("game_ended"); + + level.botSoak = is_bot_soak(); + if (!init_bot_gametype()) + { + return; + } + + wait_for_host(); + + level thread populate_bots(); +} + +// Init Utils +//======================================== + +function is_bot_soak() +{ + return getDvarInt("sv_botsoak", 0); +} + +function wait_for_host() +{ + level endon("game_ended"); + + host = util::getHostPlayerForBots(); + + while (!isdefined(host)) + { + wait(0.25); + host = util::getHostPlayerForBots(); + } +} + +function get_host_team() +{ + host = util::getHostPlayerForBots(); + + if (!isdefined(host) || host.team == "spectator") + { + return "allies"; + } + + return host.team; +} + +function is_bot_comp_stomp() +{ + return false; +} + +// Bot Events +//======================================== + +function on_bot_connect() +{ + self endon("disconnect"); + level endon("game_ended"); + + if (IS_TRUE(level.disableClassSelection)) + { + self set_rank(); + + // Doesn't work if we don't do it in this order + self bot_loadout::pick_hero_gadget(); + self bot_loadout::pick_killstreaks(); + + return; + } + + if (!IS_TRUE(self.pers["bot_loadout"])) + { + self set_rank(); + + // Doesn't work if we don't do it in this order + self bot_loadout::build_classes(); + self bot_loadout::pick_hero_gadget(); + self bot_loadout::pick_killstreaks(); + + self.pers["bot_loadout"] = true; + } + + self bot_loadout::pick_classes(); + self choose_class(); +} + +function on_bot_spawned() +{ + self.bot.goalTag = undefined; +/* +/# + weapon = undefined; + + if (getDvarInt("scr_botsHasPlayerWeapon") != 0) + { + player = util::getHostPlayer(); + weapon = player getCurrentWeapon(); + } + + if (getDvarString("devgui_bot_weapon", "") != "") + { + weapon = getWeapon(getDvarString("devgui_bot_weapon")); + } + + if (isdefined(weapon) && level.weaponNone != weapon) + { + self weapons::detach_all_weapons(); + self takeAllWeapons(); + self giveWeapon(weapon); + self switchToWeapon(weapon); + self setSpawnWeapon(weapon); + + self teams::set_player_model(self.team, weapon); + } +#/ +*/ +} + +function on_bot_killed() +{ + self endon("disconnect"); + level endon("game_ended"); + self endon("spawned"); + self waittill("death_delay_finished"); + + wait RESPAWN_DELAY; + + if (self choose_class() && level.playerForceRespawn) + { + return; + } + + self thread respawn(); +} + +function respawn() +{ + self endon("spawned"); + self endon("disconnect"); + level endon("game_ended"); + + while (1) + { + self bot::tap_use_button(); + + wait RESPAWN_INTERVAL; + } +} + +function bot_idle() +{ + if (self do_supplydrop()) + { + return; + } + + // TODO: Look for an enemy radar blip + // TODO: Get points on navmesh and feed into the spawn system to see if an enemy is likely to spawn there + self bot::navmesh_wander(); + self bot::sprint_to_goal(); +} + +// Crate maxs: 23.1482 +#define CRATE_GOAL_RADIUS 39 +#define CRATE_USE_RADIUS 62 // Wild guess on usable radius + +function do_supplydrop(maxRange = 1400) // A little under minimap width +{ + crates = getEntArray("care_package", "script_noteworthy"); + + maxRangeSq = maxRange * maxRange; + + useRadiusSq = CRATE_USE_RADIUS * CRATE_USE_RADIUS; + + closestCrate = undefined; + closestCrateDistSq = undefined; + + foreach(crate in crates) + { + if (!crate isOnGround()) + { + continue; + } + + crateDistSq = distance2DSquared(self.origin, crate.origin); + + if (crateDistSq > maxRangeSq) + { + continue; + } + + inUse = isdefined(crate.useEnt) && IS_TRUE(crate.useEnt.inUse); + + if (crateDistSq <= useRadiusSq) + { + if (inUse && !self useButtonPressed()) + { + continue; + } + + self bot::press_use_button(); + return true; + } + + if (!self has_minimap() && !self botSightTracePassed(crate)) + { + continue; + } + + if (!isdefined(closestCrate) || crateDistSq < closestCrateDistSq) + { + closestCrate = crate; + closestCrateDistSq = crateDistSq; + } + } + + if (isdefined(closestCrate)) + { + randomAngle = (0, randomInt(360), 0); + randomVec = AnglesToForward(randomAngle); + + point = closestCrate.origin + randomVec * CRATE_GOAL_RADIUS; + + if (self botSetGoal(point)) + { + self thread watch_crate(closestCrate); + return true; + } + } + + return false; +} + +function watch_crate(crate) +{ + self endon("death"); + self endon("bot_goal_reached"); + level endon("game_ended"); + + while (isdefined(crate) && !self bot_combat::has_threat()) + { + wait level.botSettings.thinkInterval; + } + + self botSetGoal(self.origin); +} + +// Bot Team Population +//======================================== + +function populate_bots() +{ + level endon("game_ended"); + + if (level.teambased) + { + maxAllies = getDvarInt("bot_maxAllies", 0); + maxAxis = getDvarInt("bot_maxAxis", 0); + + level thread monitor_bot_team_population(maxAllies, maxAxis); + } + else + { + maxFree = getDvarInt("bot_maxFree", 0); + + level thread monitor_bot_population(maxFree); + } +} + +function monitor_bot_team_population(maxAllies, maxAxis) +{ + level endon("game_ended"); + + if (!maxAllies && !maxAxis) + { + return; + } + + fill_balanced_teams(maxAllies, maxAxis); + + while (1) + { + wait 3; + + // TODO: Get a player count that includes 'CON_CONNECTING' players + allies = getPlayers("allies"); + axis = getPlayers("axis"); + + if (allies.size > maxAllies && + remove_best_bot(allies)) + { + continue; + } + + if (axis.size > maxAxis && + remove_best_bot(axis)) + { + continue; + } + + if (allies.size < maxAllies || axis.size < maxAxis) + { + add_balanced_bot(allies, maxAllies, axis, maxAxis); + } + } +} + +function fill_balanced_teams(maxAllies, maxAxis) +{ + allies = getPlayers("allies"); + axis = getPlayers("axis"); + + while ((allies.size < maxAllies || axis.size < maxAxis) && + add_balanced_bot(allies, maxAllies, axis, maxAxis)) + { + WAIT_SERVER_FRAME; + + allies = getPlayers("allies"); + axis = getPlayers("axis"); + } +} + +function add_balanced_bot(allies, maxAllies, axis, maxAxis) +{ + bot = undefined; + + if (allies.size < maxAllies && + (allies.size <= axis.size || axis.size >= maxAxis)) + { + bot = add_bot("allies"); + } + else if (axis.size < maxAxis) + { + bot = add_bot("axis"); + } + + return isdefined(bot); +} + +function monitor_bot_population(maxFree) +{ + level endon("game_ended"); + + if (!maxFree) + { + return; + } + + // Initial Fill + players = getPlayers(); + while (players.size < maxFree) + { + add_bot(); + WAIT_SERVER_FRAME; + players = getPlayers(); + } + + while (1) + { + wait 3; + + // TODO: Get a player count that includes 'CON_CONNECTING' players + players = getPlayers(); + + if (players.size < maxFree) + { + add_bot(); + } + else if (players.size > maxFree) + { + remove_best_bot(players); + } + } +} + +function remove_best_bot(players) +{ + bots = filter_bots(players); + + if (!bots.size) + { + return false; + } + + // Prefer non-combat bots + bestBots = []; + + foreach(bot in bots) + { + // Don't kick bots in the process of connecting + if (bot.sessionstate == "spectator") + { + continue; + } + + if (bot.sessionstate == "dead" || !bot bot_combat::has_threat()) + { + bestBots[bestBots.size] = bot; + } + } + + if (bestBots.size) + { + remove_bot(bestBots[randomInt(bestBots.size)]); + } + else + { + remove_bot(bots[randomInt(bots.size)]); + } + + return true; +} + +// Bot Loadouts +//======================================== + +function choose_class() +{ + if (IS_TRUE(level.disableClassSelection)) + { + return false; + } + + currClass = self bot_loadout::get_current_class(); + + if (!isdefined(currClass) || randomInt(100) < VAL(level.botSettings.changeClassWeight, 0)) + { + classIndex = randomInt(self.loadoutClasses.size); + className = self.loadoutClasses[classIndex].name; + } + + if (!isdefined(className) || className == currClass) + { + return false; + } + + self notify("menuresponse", MENU_CHANGE_CLASS, className); + + return true; +} + +// Killstreaks +//======================================== + +function use_killstreak() +{ + if (!level.loadoutKillstreaksEnabled || + self emp::enemyEmpActive()) + { + return; + } + + weapons = self getWeaponsList(); + inventoryWeapon = self getInventoryWeapon(); + + foreach(weapon in weapons) + { + killstreak = killstreaks::get_killstreak_for_weapon(weapon); + + if (!isdefined(killstreak)) + { + continue; + } + + if (weapon != inventoryWeapon && !self getWeaponAmmoClip(weapon)) + { + continue; + } + + if (self killstreakrules::isKillstreakAllowed(killstreak, self.team)) + { + useWeapon = weapon; + break; + } + } + + if (!isdefined(useWeapon)) + { + return; + } + + killstreak_ref = killstreaks::get_menu_name(killstreak); + + switch (killstreak_ref) + { + case "killstreak_uav": + case "killstreak_counteruav": + case "killstreak_satellite": + case "killstreak_helicopter_player_gunner": + case "killstreak_raps": + case "killstreak_sentinel": + { + self switchToWeapon(useWeapon); + break; + } + case "killstreak_ai_tank_drop": + { + self use_supply_drop(weapon); + break; + } + case "killstreak_remote_missile": + { + self switchToWeapon(weapon); + self waittill("weapon_change_complete"); + wait 1.5; + self bot::press_attack_button(); + return; + } + } +} + +function get_closest_enemy(origin, on_radar) +{ + enemies = self get_enemies(on_radar); + enemies = arraysort(enemies, origin); + + if (enemies.size) + return enemies[0]; + + return undefined; +} + +function use_supply_drop(weapon) +{ + if (weapon == "inventory_supplydrop_mp" || weapon == "supplydrop_mp") + { + if (gettime() - self.spawntime > 5000) + return; + } + + yaw = (0, self.angles[1], 0); + dir = anglestoforward(yaw); + dir = vectornormalize(dir); + drop_point = self.origin + vectorscale(dir, 384); + end = drop_point + vectorscale((0, 0, 1), 2048.0); + + if (!sighttracepassed(drop_point, end, 0, undefined)) + return; + + if (!sighttracepassed(self.origin, end, 0, undefined)) + return; + + end = drop_point - vectorscale((0, 0, 1), 32.0); + + if (bullettracepassed(drop_point, end, 0, undefined)) + return; + + self addgoal(self.origin, 24, 4, "killstreak"); + + if (weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp") + self lookat(drop_point + vectorscale((0, 0, 1), 384.0)); + else + self lookat(drop_point); + + wait 0.5; + + if (self getCurrentWeapon() != weapon) + { + self thread weapon_switch_failsafe(); + self switchToWeapon(weapon); + + self waittill("weapon_change_complete"); + } + + use_item(weapon); + self switchToWeapon(self.lastnonkillstreakweapon); + self clearlookat(); + self cancelgoal("killstreak"); +} + +function use_item(weapon) +{ + self bot::press_attack_button(); + wait 0.5; + + for (i = 0; i < 10; i++) + { + if (self getCurrentWeapon() == weapon || self getCurrentWeapon() == "none") + self bot::press_attack_button(); + else + return; + + wait 0.5; + } +} + +function killstreak_location(num, weapon) +{ + enemies = get_enemies(); + + if (!enemies.size) + return; + + if (!self switchToWeapon(weapon)) + return; + + self waittill("weapon_change"); + + self util::freeze_player_controls(true); + wait_time = 1; + + while (!isdefined(self.selectinglocation) || self.selectinglocation == 0) + { + wait 0.05; + wait_time -= 0.05; + + if (wait_time <= 0) + { + self util::freeze_player_controls(false); + self switchToWeapon(self.lastnonkillstreakweapon); + return; + } + } + + wait 2; + + for (i = 0; i < num; i++) + { + enemies = get_enemies(); + + if (enemies.size) + { + enemy = randomInt(enemies); + self notify("confirm_location", enemy.origin, 0); + } + + wait 0.25; + } + + self util::freeze_player_controls(false); +} + +function weapon_switch_failsafe() +{ + self endon("death"); + self endon("disconnect"); + self endon("weapon_change_complete"); + wait 10; + self notify("weapon_change_complete"); +} + +function has_radar() +{ + if (level.teambased) + { + return (uav::HasUAV(self.team) || satellite::HasSatellite(self.team)); + } + + return (uav::HasUAV(self.entnum) || satellite::HasSatellite(self.entnum)); +} + +function has_minimap() +{ + if (self IsEmpJammed()) + { + return false; + } + + if (IS_TRUE(level.hardcoreMode)) + { + return self has_radar(); + } + + return true; +} + +function get_enemies(on_radar) +{ + if (!isdefined(on_radar)) + { + on_radar = false; + } + + enemies = self GetEnemies(); + +/* +/# + for (i = 0; i < enemies.size; i++) + { + if (isplayer(enemies[i]) && enemies[i] isInMoveMode("ufo", "noclip")) + { + arrayRemoveIndex(enemies, i); + i--; + } + } +#/ +*/ + + if (on_radar && !self has_radar()) + { + for (i = 0; i < enemies.size; i++) + { + if (!isdefined(enemies[i].lastFireTime)) + { + arrayRemoveIndex(enemies, i); + i--; + } + else if (GetTime() - enemies[i].lastFireTime > 2000) + { + arrayRemoveIndex(enemies, i); + i--; + } + } + } + + return enemies; +} + +function set_rank() +{ + players = getPlayers(); + + ranks = []; + bot_ranks = []; + human_ranks = []; + + for (i = 0; i < players.size; i++) + { + if (players[i] == self) + continue; + + if (isdefined(players[i].pers["rank"])) + { + if (players[i] util::is_bot()) + { + bot_ranks[bot_ranks.size] = players[i].pers["rank"]; + } + else + { + human_ranks[human_ranks.size] = players[i].pers["rank"]; + } + } + } + + if (!human_ranks.size) + human_ranks[human_ranks.size] = 10; + + human_avg = math::array_average(human_ranks); + + while (bot_ranks.size + human_ranks.size < 5) + { + // add some random ranks for better random number distribution + r = human_avg + randomIntRange(-5, 5); + rank = math::clamp(r, 0, level.maxRank); + human_ranks[human_ranks.size] = rank; + } + + ranks = arrayCombine(human_ranks, bot_ranks, true, false); + + avg = math::array_average(ranks); + s = math::array_std_deviation(ranks, avg); + + rank = Int(math::random_normal_distribution(avg, s, 0, level.maxRank)); + + while (!isdefined(self.pers["codpoints"])) + { + wait 0.1; + } + + self.pers["rank"] = rank; + self.pers["rankxp"] = rank::getRankInfoMinXP(rank); + + self setRank(rank); + self rank::syncXPStat(); +} + +function init_bot_gametype() +{ + switch (level.gameType) + { + case "ball": + bot_ball::init(); + return true; + case "conf": + bot_conf::init(); + return true; + case "ctf": + bot_ctf::init(); + return true; + case "dem": + bot_dem::init(); + return true; + case "dm": + return true; + case "dom": + bot_dom::init(); + return true; + case "escort": + bot_escort::init(); + return true; +// case "infect": +// return true; + case "gun": + return true; + case "koth": + bot_koth::init(); + return true; + case "sd": + bot_sd::init(); + return true; + case "clean": + bot_clean::init(); + return true; + case "tdm": + return true; + case "sas": + return true; + case "prop": + return true; + case "sniperonly": + return true; + } + + return false; +} + +function get_bot_settings() +{ + switch (getDvarInt("bot_difficulty", 1)) + { + case 0: + bundleName = "bot_mp_easy"; + break; + + case 1: + bundleName = "bot_mp_normal"; + break; + case 2: + bundleName = "bot_mp_hard"; + break; + case 3: + default: + bundleName = "bot_mp_veteran"; + break; + } + + return struct::get_script_bundle("botsettings", bundleName); +} + +function friend_goal_in_radius(goal_name, origin, radius) +{ + return 0; +} + +function friend_in_radius(goal_name, origin, radius) +{ + return false; +} + +function get_friends() +{ + return[]; +} + +function bot_vehicle_weapon_ammo(weaponName) +{ + return false; +} + +function navmesh_points_visible(origin, point) +{ + return false; +} + +function dive_to_prone(exit_stance) +{ + +} + +/* +/# + +// Devgui +//======================================== + +function bot_devgui_cmd(cmd) +{ + cmdTokens = strtok(cmd, " "); + + if (cmdTokens.size == 0) + { + return false; + } + + host = util::getHostPlayerForBots(); + team = get_host_team(); + + switch (cmdTokens[0]) + { + case "spawn_enemy": + team = util::getotherteam(team); + case "spawn_friendly": + count = 1; + if (cmdTokens.size > 1) + { + count = int(cmdTokens[1]); + } + for (i = 0; i < count; i++) + { + add_bot(team); + } + return true; + case "remove_enemy": + team = util::getotherteam(team); + case "remove_friendly": + remove_bots(undefined, team); + return true; + case "fixed_spawn_enemy": + team = util::getotherteam(team); + case "fixed_spawn_friendly": + bot = add_bot_at_eye_trace(team); + if (isdefined(bot)) + { + bot thread fixed_spawn_override(); + } + return true; + + case "player_weapon": + players = getPlayers(); + foreach(player in players) + { + if (!player util::is_bot()) + { + continue; + } + + weapon = host getCurrentWeapon(); + + player weapons::detach_all_weapons(); + player takeAllWeapons(); + player giveWeapon(weapon); + player switchToWeapon(weapon); + player setSpawnWeapon(weapon); + + player teams::set_player_model(player.team, weapon); + } + return true; + } + + return false; +} + +function system_devgui_gadget_think() +{ + setDvar("devgui_bot_gadget", ""); + + for (;; ) + { + wait(1); + + gadget = getDvarString("devgui_bot_gadget"); + + if (gadget.size == 0) + { + bot_turn_on_gadget(getWeapon(gadget)); + setDvar("devgui_bot_gadget", ""); + } + } +} + +function bot_turn_on_gadget(gadget) +{ + players = getPlayers(); + + foreach(player in players) + { + if (!player util::is_bot()) + { + continue; + } + + host = util::getHostPlayer(); + weapon = host getCurrentWeapon(); + + if (!isdefined(weapon) || weapon == level.weaponNone || weapon == level.weaponNull) + { + weapon = getWeapon("smg_standard"); + } + + player weapons::detach_all_weapons(); + player takeAllWeapons(); + player giveWeapon(weapon); + player switchToWeapon(weapon); + player setSpawnWeapon(weapon); + + player teams::set_player_model(player.team, weapon); + + player giveWeapon(gadget); + slot = player gadgetGetSlot(gadget); + player gadgetPowerSet(slot, 100.0); + player botPressButtonForGadget(gadget); + } +} + +function fixed_spawn_override() +{ + self endon("disconnect"); + + spawnOrigin = self.origin; + spawnAngles = self.angles; + + while (1) + { + self waittill("spawned_player"); + + self setOrigin(spawnOrigin); + self setPlayerAngles(spawnAngles); + } +} + +#/ +*/ diff --git a/data/scripts/mp/bots/_bot_loadout.gsc b/data/scripts/mp/bots/_bot_loadout.gsc new file mode 100644 index 0000000000000000000000000000000000000000..1dce334526baf75b8b04aa93e58387a34dae01fe GIT binary patch literal 15500 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 BP&@zt literal 0 HcmV?d00001 diff --git a/data/scripts/mp/bots/_bot_loadout.gsc_raw b/data/scripts/mp/bots/_bot_loadout.gsc_raw new file mode 100644 index 0000000..3b48b7f --- /dev/null +++ b/data/scripts/mp/bots/_bot_loadout.gsc_raw @@ -0,0 +1,854 @@ +#using scripts\shared\array_shared; +#using scripts\shared\rank_shared; + +#insert scripts\shared\shared.gsh; +#insert scripts\shared\statstable_shared.gsh; + +#using scripts\mp\killstreaks\_killstreaks; + +#using scripts\mp\bots\_bot; + +#define BOT_ALLOCATION_MAX 100 +#define BOT_ALLOCATION_UNLOCK_MAX 3 +#define BOT_RANK_ALL_OPTIONS_AVAILABLE 20 +#define BOT_RANK_OPTIONS_MULTIPLIER 4 + +#namespace bot_loadout; + +// Item Whitelist +//======================================== + +function in_whitelist( itemName ) +{ + if ( !isdefined( itemName ) ) + return false; + + switch( itemName ) + { + // Secondaries + case "WEAPON_KNIFE_LOADOUT": + case "WEAPON_PISTOL_STANDARD": + case "WEAPON_PISTOL_BURST": + case "WEAPON_PISTOL_FULLAUTO": + case "WEAPON_LAUNCHER_STANDARD": + case "WEAPON_LAUNCHER_LOCKONLY": + + // Primaries + case "WEAPON_SMG_STANDARD": + case "WEAPON_SMG_BURST": + case "WEAPON_SMG_FASTFIRE": + case "WEAPON_SMG_LONGRANGE": + case "WEAPON_SMG_VERSATILE": + case "WEAPON_SMG_CAPACITY": + case "WEAPON_AR_STANDARD": + case "WEAPON_AR_ACCURATE": + case "WEAPON_AR_CQB": + case "WEAPON_AR_DAMAGE": + case "WEAPON_AR_FASTBURST": + case "WEAPON_AR_LONGBURST": + case "WEAPON_AR_MARKSMAN": + case "WEAPON_LMG_CQB": + case "WEAPON_LMG_HEAVY": + case "WEAPON_LMG_LIGHT": + case "WEAPON_LMG_SLOWFIRE": + case "WEAPON_SNIPER_FASTBOLT": + case "WEAPON_SNIPER_FASTSEMI": + case "WEAPON_SNIPER_POWERBOLT": + case "WEAPON_SNIPER_CHARGESHOT": + case "WEAPON_SHOTGUN_FULLAUTO": + case "WEAPON_SHOTGUN_PRECISION": + case "WEAPON_SHOTGUN_PUMP": + case "WEAPON_SHOTGUN_SEMIAUTO": + + // Lethals + case "WEAPON_FRAGGRENADE": + case "WEAPON_HATCHET": + case "WEAPON_STICKY_GRENADE": + case "WEAPON_SATCHEL_CHARGE": + case "WEAPON_BOUNCINGBETTY": + case "WEAPON_INCENDIARY_GRENADE": + + // Tacticals + case "WEAPON_WILLY_PETE": + case "WEAPON_STUN_GRENADE": + case "WEAPON_EMPGRENADE": + case "WEAPON_FLASHBANG": + case "WEAPON_PROXIMITY_GRENADE": + case "WEAPON_PDA_HACK": + case "WEAPON_TROPHY_SYSTEM": + + // Killstreaks + //case "KILLSTREAK_RCBOMB": + case "KILLSTREAK_RECON": + case "KILLSTREAK_COUNTER_UAV": + //case "KILLSTREAK_SUPPLY_DROP": + //case "KILLSTREAK_MICROWAVE_TURRET": + case "KILLSTREAK_REMOTE_MISSILE": + //case "KILLSTREAK_PLANEMORTAR": + //case "KILLSTREAK_AUTO_TURRET": + case "KILLSTREAK_AI_TANK_DROP": + //case "KILLSTREAK_HELICOPTER_COMLINK": + case "KILLSTREAK_SATELLITE": + //case "KILLSTREAK_EMP": + //case "KILLSTREAK_HELICOPTER_GUNNER": + case "KILLSTREAK_RAPS": + //case "KILLSTREAK_DRONE_STRIKE": + //case "KILLSTREAK_DART": + case "KILLSTREAK_SENTINEL": + + // TU Something Weapons + case "WEAPON_MELEE_KNUCKLES": + case "WEAPON_MELEE_BUTTERFLY": + case "WEAPON_MELEE_WRENCH": + + // TU 6 Weapons + case "WEAPON_PISTOL_SHOTGUN": + case "WEAPON_AR_GARAND": + case "WEAPON_SPECIAL_CROSSBOW": + case "WEAPON_MELEE_CROWBAR": + case "WEAPON_MELEE_SWORD": + case "WEAPON_MELEE_BOXING": + case "WEAPON_SMG_AK74U": + case "WEAPON_SMG_MP40": + case "WEAPON_SMG_RECHAMBER": + case "WEAPON_SMG_NAILGUN": + case "WEAPON_AR_AN94": + case "WEAPON_AR_FAMAS": + case "WEAPON_SMG_MSMC": + case "WEAPON_LMG_INFINITE": + case "WEAPON_AR_PULSE": + case "WEAPON_AR_M16": + case "WEAPON_SMG_PPSH": + case "WEAPON_LAUNCHER_EX41": + case "WEAPON_SHOTGUN_OLYMPIA": + case "WEAPON_SNIPER_QUICKSCOPE": + case "WEAPON_SNIPER_DOUBLE": + case "WEAPON_SMG_STEN": + case "WEAPON_AR_GALIL": + case "WEAPON_LMG_RPK": + case "WEAPON_AR_M14": + case "WEAPON_SHOTGUN_ENERGY": + case "WEAPON_SPECIAL_CROSSBOW_DW": + case "WEAPON_AR_PEACEKEEPER": + case "WEAPON_MELEE_CHAINSAW": + case "WEAPON_SPECIAL_KNIFE_BALLISTIC": + case "WEAPON_MELEE_CRESCENT": + case "WEAPON_SPECIAL_DISCGUN": + return true; + } + + return false; +} + +// Classes +//======================================== + +function build_classes() +{ + primaryWeapons = self get_available_items( undefined, "primary" ); + secondaryWeapons = self get_available_items( undefined, "secondary" ); + lethals = self get_available_items( undefined, "primarygadget" ); + tacticals = self get_available_items( undefined, "secondarygadget" ); + if ( IS_TRUE( level.perksEnabled ) ) + { + specialties1 = self get_available_items( undefined, "specialty1" ); + specialties2 = self get_available_items( undefined, "specialty2" ); + specialties3 = self get_available_items( undefined, "specialty3" ); + } + + foreach( className, classValue in level.classMap ) + { + if ( !isSubstr( className, "custom" ) ) + { + continue; + } + + classIndex = int( className[className.size-1] ); + + pickedItems = []; + + pick_item( pickedItems, primaryWeapons ); + + if ( RandomInt( 100 ) < 95 ) // 5% chance to be a boxer for Scronce + { + pick_item( pickedItems, secondaryWeapons ); + } + + // Shuffle these selections around a bit so the classes don't all look the same when the allocation is low + otherItems = Array ( lethals, tacticals, specialties1, specialties2, specialties3 ); + otherItems = array::randomize( otherItems ); + + for ( i = 0; i < otherItems.size; i ++ ) + { + pick_item( pickedItems, otherItems[i] ); + } + + // Add items up to the max allocation + for ( i = 0; i < pickedItems.size && i < level.maxAllocation; i++ ) + { + self BotClassAddItem( classIndex, pickedItems[i] ); + } + + // TODO: Pick primary/secondary attachments, extra perks, extra lethal, extra tactical, overkill +/* + primaryWeapon = self GetLoadoutWeapon( classIndex, "primary" ); + + if ( primaryWeapon != level.weaponNone && primaryWeapon.supportedAttachments.size ) + { + attachment = array::random( primaryWeapon.supportedAttachments ); + self BotClassAddAttachment( classIndex, primaryWeapon, attachment, "primary" ); + } + + secondaryWeapon = self GetLoadoutWeapon( classIndex, "secondary" ); + + if ( secondaryWeapon != level.weaponNone && secondaryWeapon.supportedAttachments.size ) + { + attachment = array::random( secondaryWeapon.supportedAttachments ); + self BotClassAddAttachment( classIndex, secondaryWeapon, attachment, "secondary" ); + } +*/ + } +} + +function pick_item( &pickedItems, items ) +{ + if ( !isdefined( items ) || items.size <= 0 ) + { + return; + } + + pickedItems[pickedItems.size] = array::random( items ); +} + +function pick_classes() +{ + self.loadoutClasses = []; + self.launcherClassCount = 0; + + foreach( className, classValue in level.classMap ) + { + if ( isSubstr( className, "custom" ) ) + { + if ( level.disableCAC ) + { + continue; + } + + classIndex = int( className[className.size-1] ); + } + else + { + // Things bots could use better in the default classes: + // C4, Trophy System, Lock on only launcher + classIndex = level.classToClassNum[ classValue ]; + } + + primary = self GetLoadoutWeapon( classIndex, "primary" ); + secondary = self GetLoadoutWeapon( classIndex, "secondary" ); + + botClass = SpawnStruct(); + botClass.name = className; + botClass.index = classIndex; + botClass.value = classValue; + botClass.primary = primary; + botClass.secondary = secondary; + + if ( botClass.secondary.isRocketLauncher ) + { + self.launcherClassCount++; + } + + self.loadoutClasses[ self.loadoutClasses.size ] = botClass; + } +} + +function get_current_class() +{ + currValue = self.pers["class"]; + if ( !isdefined( currValue ) ) + { + return undefined; + } + + foreach( botClass in self.loadoutClasses ) + { + if ( botClass.value == currValue ) + { + return botClass; + } + } + + return undefined; +} + +// Specialists +//======================================== + +function pick_hero_gadget() +{ + if ( RandomInt( 2 ) < 1 || !self pick_hero_ability() ) + { + self pick_hero_weapon(); + } +} + +function pick_hero_weapon() +{ + heroWeaponRef = self GetHeroWeaponName(); + + if ( IsItemRestricted( heroWeaponRef ) ) + { + return false; + } + + heroWeaponName = self get_item_name( heroWeaponRef ); + self BotClassAddItem( 0, heroWeaponName ); + + return true; +} + +function pick_hero_ability() +{ + heroAbilityRef = self GetHeroAbilityName(); + + if ( IsItemRestricted( heroAbilityRef ) ) + { + return false; + } + + heroAbilityName = self get_item_name( heroAbilityRef ); + self BotClassAddItem( 0, heroAbilityName ); + + return true; +} + +// Killstreaks +//======================================== + +function pick_killstreaks() +{ + killstreaks = array::randomize( self get_available_items( "killstreak" ) ); + + for( i = 0; i < 3 && i < killstreaks.size; i++ ) + { + self BotClassAddItem( 0, killstreaks[i] ); + } +} + + +// Get Items +//======================================== + +function get_available_items( filterGroup, filterSlot ) +{ + // Get unlocked and unrestricted items + items = []; + + for( i = 0; i < STATS_TABLE_MAX_ITEMS; i++ ) + { + row = tableLookupRowNum( level.statsTableID, STATS_TABLE_COL_NUMBERING, i ); + + if ( row < 0 ) + { + continue; + } + + name = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_NAME ); + + if ( name == "" || !in_whitelist( name ) ) + { + continue; + } + + allocation = Int( tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_ALLOCATION ) ); + + if ( allocation < 0 ) + { + continue; + } + + ref = tableLookupColumnForRow( level.statsTableId, row, STATS_TABLE_COL_REFERENCE ); + + if ( IsItemRestricted( ref ) ) + { + continue; + } + + number = Int( tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_NUMBERING ) ); +/* + if ( SessionModeIsPrivate() && self IsItemLocked( number ) ) + { + continue; + } +*/ + if ( isdefined( filterGroup ) ) + { + group = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_GROUP ); + + if ( group != filterGroup ) + { + continue; + } + } + + if ( isdefined( filterSlot ) ) + { + slot = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_SLOT ); + + if ( slot != filterSlot ) + { + continue; + } + } + + items[items.size] = name; + } + + return items; +} + +function get_item_name( itemReference ) +{ + for( i = 0; i < STATS_TABLE_MAX_ITEMS; i++ ) + { + row = tableLookupRowNum( level.statsTableID, STATS_TABLE_COL_NUMBERING, i ); + + if ( row < 0 ) + { + continue; + } + + reference = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_REFERENCE ); + + if ( reference != itemReference ) + { + continue; + } + + name = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_NAME ); + + return name; + } + + return undefined; +} + +// Not in use + +function init() +{ + level endon( "game_ended" ); + + level.bot_banned_killstreaks = Array ( "KILLSTREAK_RCBOMB", + "KILLSTREAK_QRDRONE", + /* "KILLSTREAK_REMOTE_MISSILE",*/ + "KILLSTREAK_REMOTE_MORTAR", + "KILLSTREAK_HELICOPTER_GUNNER" ); + for ( ;; ) + { + level waittill( "connected", player ); + + if ( !player IsTestClient() ) + { + continue; + } + + player thread on_bot_connect(); + } +} + +function on_bot_connect() +{ + self endon( "disconnect" ); + + if ( isdefined( self.pers[ "bot_loadout" ] ) ) + { + return; + } + + wait( 0.10 ); + + if ( self GetEntityNumber() % 2 == 0 ) + { + WAIT_SERVER_FRAME; + } + + self bot::set_rank(); + + self BotSetRandomCharacterCustomization(); + + + max_allocation = BOT_ALLOCATION_MAX; +/* + if ( SessionModeIsPrivate() ) + { + for ( i = 1; i <= BOT_ALLOCATION_UNLOCK_MAX; i++ ) + { + if ( self IsItemLocked( rank::GetItemIndex( "feature_allocation_slot_" + i ) ) ) + { + max_allocation--; + } + } + } +*/ + self construct_loadout( max_allocation ); + self.pers[ "bot_loadout" ] = true; +} + +function construct_loadout( allocation_max ) +{ +/* if ( SessionModeIsPrivate() && self IsItemLocked( rank::GetItemIndex( "feature_cac" ) ) ) + { + // cac still locked + return; + } +*/ + pixbeginevent( "bot_construct_loadout" ); + + item_list = build_item_list(); + +// item_list["primary"] = []; +// item_list["primary"][0] = "WEAPON_RIOTSHIELD"; + + construct_class( 0, item_list, allocation_max ); + construct_class( 1, item_list, allocation_max ); + construct_class( 2, item_list, allocation_max ); + construct_class( 3, item_list, allocation_max ); + construct_class( 4, item_list, allocation_max ); + + killstreaks = item_list["killstreak1"]; + + if ( isdefined( item_list["killstreak2"] ) ) + { + killstreaks = ArrayCombine( killstreaks, item_list["killstreak2"], true, false ); + } + + if ( isdefined( item_list["killstreak3"] ) ) + { + killstreaks = ArrayCombine( killstreaks, item_list["killstreak3"], true, false ); + } + + if ( isdefined( killstreaks ) && killstreaks.size ) + { + choose_weapon( 0, killstreaks ); + choose_weapon( 0, killstreaks ); + choose_weapon( 0, killstreaks ); + } + + self.claimed_items = undefined; + pixendevent(); +} + +function construct_class( constructclass, items, allocation_max ) +{ + allocation = 0; + + claimed_count = build_claimed_list( items ); + self.claimed_items = []; + + // primary + weapon = choose_weapon( constructclass, items["primary"] ); + claimed_count["primary"]++; + allocation++; + + // secondary + weapon = choose_weapon( constructclass, items["secondary"] ); + choose_weapon_option( constructclass, "camo", 1 ); +} + +function make_choice( chance, claimed, max_claim ) +{ + return ( claimed < max_claim && RandomInt( 100 ) < chance ); +} + +function chose_action( action1, chance1, action2, chance2, action3, chance3, action4, chance4 ) +{ + chance1 = Int( chance1 / 10 ); + chance2 = Int( chance2 / 10 ); + chance3 = Int( chance3 / 10 ); + chance4 = Int( chance4 / 10 ); + + actions = []; + + for( i = 0; i < chance1; i++ ) + { + actions[ actions.size ] = action1; + } + + for( i = 0; i < chance2; i++ ) + { + actions[ actions.size ] = action2; + } + + for( i = 0; i < chance3; i++ ) + { + actions[ actions.size ] = action3; + } + + for( i = 0; i < chance4; i++ ) + { + actions[ actions.size ] = action4; + } + + return array::random( actions ); +} + +function item_is_claimed( item ) +{ + foreach( claim in self.claimed_items ) + { + if ( claim == item ) + { + return true; + } + } + + return false; +} + +function choose_weapon( weaponclass, items ) +{ + if ( !isdefined( items ) || !items.size ) + { + return undefined; + } + + start = RandomInt( items.size ); + + for( i = 0; i < items.size; i++ ) + { + weapon = items[ start ]; + + if ( !item_is_claimed( weapon ) ) + { + break; + } + + start = ( start + 1 ) % items.size; + } + + self.claimed_items[ self.claimed_items.size ] = weapon; + + self BotClassAddItem( weaponclass, weapon ); + return weapon; +} + +function build_weapon_options_list( optionType ) +{ + level.botWeaponOptionsId[optionType] = []; + level.botWeaponOptionsProb[optionType] = []; + + csv_filename = "gamedata/weapons/common/attachmentTable.csv"; + prob = 0; + for ( row = 0 ; row < 255 ; row++ ) + { + if ( tableLookupColumnForRow( csv_filename, row, ATTACHMENT_TABLE_COL_TYPE ) == optionType ) + { + index = level.botWeaponOptionsId[optionType].size; + level.botWeaponOptionsId[optionType][index] = Int( tableLookupColumnForRow( csv_filename, row, ATTACHMENT_TABLE_COL_NUMBERING ) ); + prob += Int( tableLookupColumnForRow( csv_filename, row, ATTACHMENT_TABLE_COL_BOT_PROB ) ); + level.botWeaponOptionsProb[optionType][index] = prob; + } + } +} + +function choose_weapon_option( weaponclass, optionType, primary ) +{ + if ( !isdefined( level.botWeaponOptionsId ) ) + { + level.botWeaponOptionsId = []; + level.botWeaponOptionsProb = []; + + build_weapon_options_list( "camo" ); + build_weapon_options_list( "reticle" ); + } + + // weapon options cannot be set in local matches + if ( !level.onlineGame && !level.systemLink ) + return; + + // Increase the range of the probability to reduce the chances of picking the option when the bot's level is less than BOT_RANK_ALL_OPTIONS_AVAILABLE + // (in system link all options are available) + numOptions = level.botWeaponOptionsProb[optionType].size; + maxProb = level.botWeaponOptionsProb[optionType][numOptions-1]; + if ( !level.systemLink && self.pers[ "rank" ] < BOT_RANK_ALL_OPTIONS_AVAILABLE ) + maxProb += BOT_RANK_OPTIONS_MULTIPLIER * maxProb * ( ( BOT_RANK_ALL_OPTIONS_AVAILABLE - self.pers[ "rank" ] ) / BOT_RANK_ALL_OPTIONS_AVAILABLE ); + + rnd = RandomInt( Int( maxProb ) ); + for (i=0 ; i rnd ) + { + self BotClassSetWeaponOption( weaponclass, primary, optionType, level.botWeaponOptionsId[optionType][i] ); + break; + } + } +} + +function choose_primary_attachments( weaponclass, weapon, allocation, allocation_max ) +{ + attachments = weapon.supportedAttachments; + remaining = allocation_max - allocation; + + if ( !attachments.size || !remaining ) + { + return 0; + } + + attachment_action = chose_action( "3_attachments", 25, "2_attachments", 65, "1_attachments", 10, "none", 5 ); + + if ( remaining >= 4 && attachment_action == "3_attachments" ) + { + a1 = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a1, "primaryattachment1" ); + count = 1; + + attachments = GetWeaponAttachments( weapon, a1 ); + + if ( attachments.size ) + { + a2 = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a2, "primaryattachment2" ); + count++; + + attachments = GetWeaponAttachments( weapon, a1, a2 ); + + if ( attachments.size ) + { + a3 = array::random( attachments ); + self BotClassAddItem( weaponclass, "BONUSCARD_PRIMARY_GUNFIGHTER" ); + self BotClassAddAttachment( weaponclass, weapon, a3, "primaryattachment3" ); + return 4; + } + } + + return count; + } + else if ( remaining >= 2 && attachment_action == "2_attachments" ) + { + a1 = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a1, "primaryattachment1" ); + + attachments = GetWeaponAttachments( weapon, a1 ); + + if ( attachments.size ) + { + a2 = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a2, "primaryattachment2" ); + return 2; + } + + return 1; + } + else if ( remaining >= 1 && attachment_action == "1_attachments" ) + { + a = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a, "primaryattachment1" ); + return 1; + } + + return 0; +} + +function choose_secondary_attachments( weaponclass, weapon, allocation, allocation_max ) +{ + attachments = weapon.supportedAttachments ; + remaining = allocation_max - allocation; + + if ( !attachments.size || !remaining ) + { + return 0; + } + + attachment_action = chose_action( "2_attachments", 10, "1_attachments", 40, "none", 50, "none", 0 ); + + if ( remaining >= 3 && attachment_action == "2_attachments" ) + { + a1 = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a1, "secondaryattachment1" ); + + attachments = GetWeaponAttachments( weapon, a1 ); + + if ( attachments.size ) + { + a2 = array::random( attachments ); + self BotClassAddItem( weaponclass, "BONUSCARD_SECONDARY_GUNFIGHTER" ); + self BotClassAddAttachment( weaponclass, weapon, a2, "secondaryattachment2" ); + return 3; + } + + return 1; + } + else if ( remaining >= 1 && attachment_action == "1_attachments" ) + { + a = array::random( attachments ); + self BotClassAddAttachment( weaponclass, weapon, a, "secondaryattachment1" ); + return 1; + } + + return 0; +} + +function build_item_list() +{ + items = []; + + for( i = 0; i < STATS_TABLE_MAX_ITEMS; i++ ) + { + row = tableLookupRowNum( level.statsTableID, STATS_TABLE_COL_NUMBERING, i ); + + if ( row > -1 ) + { + slot = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_SLOT ); + + if ( slot == "" ) + { + continue; + } + + number = Int( tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_NUMBERING ) ); +/* + if ( SessionModeIsPrivate() && self IsItemLocked( number ) ) + { + continue; + } +*/ + allocation = Int( tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_ALLOCATION ) ); + + if ( allocation < 0 ) + { + continue; + } + + name = tableLookupColumnForRow( level.statsTableID, row, STATS_TABLE_COL_NAME ); +/* + if ( item_is_banned( slot, name ) ) + { + continue; + } +*/ + if ( !isdefined( items[slot] ) ) + { + items[slot] = []; + } + + items[ slot ][ items[slot].size ] = name; + } + } + + return items; +} + + +function build_claimed_list( items ) +{ + claimed = []; + keys = GetArrayKeys( items ); + + foreach( key in keys ) + { + claimed[ key ] = 0; + } + + return claimed; +} \ No newline at end of file diff --git a/data/scripts/mp/gametypes/_globallogic_player.gsc b/data/scripts/mp/gametypes/_globallogic_player.gsc new file mode 100644 index 0000000000000000000000000000000000000000..b06730520ec037ff3894aa418bc42df0989289f9 GIT binary patch literal 91376 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 player.pers["lastHighestScore"] ) + bestScore = "1"; + + bestKills = "0"; + if ( isdefined( player.pers["lastHighestKills"] ) && killCount > player.pers["lastHighestKills"] ) + bestKills = "1"; + + totalMatchShots = 0; + if ( isdefined( player.totalMatchShots) ) + totalMatchShots = player.totalMatchShots; + + deaths = player.deaths; + if (deaths == 0) + deaths = 1; + kdRatio = player.kills*1000/deaths; + bestKDRatio = "0"; + if ( isdefined( player.pers["lastHighestKDRatio"] ) && kdRatio > player.pers["lastHighestKDRatio"] ) + bestKDRatio = "1"; + + showcaseWeapon = player GetPlayerShowcaseWeapon(); + + RecordComScoreEvent( "end_match", + "match_id", getDemoFileID(), + "game_variant", "mp", + "game_mode", level.gametype, + "private_match", SessionModeIsPrivate(), + "esports_flag", level.leagueMatch, + "ranked_play_flag", level.arenaMatch, + "league_team_id", player getLeagueTeamID(), + "game_map", GetDvarString( "mapname" ), + "player_xuid", player getxuid(true), + "player_ip", player getipaddress(), + "match_kills", killCount, + "match_deaths", player.deaths, + "match_xp", xpEarned, + "match_score", player.score, + "match_streak", player.pers["best_kill_streak"], + "match_captures", player.pers["captures"], + "match_defends", player.pers["defends"], + "match_headshots", player.pers["headshots"], + "match_longshots", player.pers["longshots"], + "match_objtime", player.pers["objtime"], + "match_plants", player.pers["plants"], + "match_defuses", player.pers["defuses"], + "match_throws", player.pers["throws"], + "match_carries", player.pers["carries"], + "match_returns", player.pers["returns"], + "prestige_max", player.pers["plevel"], + "level_max", player.pers["rank"], + "match_result", resultStr, + "match_duration", timePlayed, + "match_shots", totalMatchShots, + "match_hits", hitCount, + "player_gender", player GetPlayerGenderType( CurrentSessionMode() ), + "specialist_kills", player.heroweaponKillCount, + "specialist_used", player GetMpDialogName(), + "season_pass_owned", player HasSeasonPass(0), + "loadout_perks", perkStr, + "loadout_lethal", grenadePrimaryName, + "loadout_tactical", grenadeSecondaryName, + "loadout_scorestreaks", killStreakStr, + "loadout_primary_weapon", primaryWeaponName, + "loadout_secondary_weapon", secondaryWeaponName, + "dlc_owned", player GetDLCAvailable(), + "loadout_primary_attachments", primaryWeaponAttachStr, + "loadout_secondary_attachments",secondaryWeaponAttachStr, + "best_score", bestScore, + "best_kills", bestKills, + "best_kd", bestKDRatio, + "total_kills", totalKills, + "total_deaths", totalDeaths, + "total_wins", totalWins, + "total_xp", totalXP, + "daily_contract_id", dailyContractId, + "daily_contract_target", dailyContractTarget, + "daily_contract_current", dailyContractCurrent, + "daily_contract_completed", dailyContractCompleted, + "weeklyA_contract_id", weeklyAContractId, + "weeklyA_contract_target", weeklyAContractTarget, + "weeklyA_contract_current", weeklyAContractCurrent, + "weeklyA_contract_completed", weeklyAContractCompleted, + "weeklyB_contract_id", weeklyBContractId, + "weeklyB_contract_target", weeklyBContractTarget, + "weeklyB_contract_current", weeklyBContractCurrent, + "weeklyB_contract_completed", weeklyBContractCompleted, + "special_contract_id ", specialContractId, + "special_contract_target", specialContractTarget, + "special_contract_curent", specialContractCurent, + "special_contract_completed", specialContractCompleted, + "specialist_power", player.heroabilityname, + "specialist_head", player GetCharacterHelmetModel(), + "specialist_body", player GetCharacterBodyModel(), + "specialist_taunt", player GetPlayerSelectedTauntName( 0 ), + "specialist_goodgame", player GetPlayerSelectedGestureName( 0 ), + "specialist_threaten", player GetPlayerSelectedGestureName( 1 ), + "specialist_boast", player GetPlayerSelectedGestureName( 2 ), + "specialist_showcase", showcaseWeapon.weapon.name + ); +} + +function player_monitor_travel_dist() +{ + self endon ( "death" ); + self endon ( "disconnect" ); + waitTime = 1; + minimumMoveDistance = 16; + + //Ignore data immediatly after spawn + wait 4; + + prevpos = self.origin; + positionPTM = self.origin; + while( 1 ) + { + wait waitTime; + + if (self util::isUsingRemote()) + { + self waittill ("stopped_using_remote"); + prevpos = self.origin; + positionPTM = self.origin; + continue; + } + + distance = distance( self.origin, prevpos ); + self.pers["total_distance_travelled"] += distance; + self.pers["movement_Update_Count"]++; + prevpos = self.origin; + + if ((self.pers["movement_Update_Count"] % 5) == 0) + { + distanceMoving = distance(self.origin, positionPTM); + positionPTM = self.origin; + if ( distanceMoving > minimumMoveDistance ) + { + self.pers["num_speeds_when_moving_entries"]++; + self.pers["total_speeds_when_moving"] += ( distanceMoving / waitTime ); + self.pers["time_played_moving"] += waitTime; + } + } + + + } +} + +function record_special_move_data_for_life( killer ) +{ + // safe to assume fields on self exist? + if( !isDefined( self.lastSwimmingStartTime) || !isDefined( self.lastWallRunStartTime) || !isDefined( self.lastSlideStartTime) || !isDefined( self.lastDoubleJumpStartTime) || + !isDefined( self.timeSpentSwimmingInLife) || !isDefined( self.timeSpentWallRunningInLife) || !isDefined( self.numberOfDoubleJumpsInLife) || !isDefined( self.numberOfSlidesInLife) ) + { + /# + println( "record_special_move_data_for_life - fields on self not defined!"); + #/ + return; + } + + if( isDefined(killer) ) + { + if( !isDefined( killer.lastSwimmingStartTime) || !isDefined( killer.lastWallRunStartTime) || !isDefined( killer.lastSlideStartTime) || !isDefined( killer.lastDoubleJumpStartTime) ) + { + /# + println( "record_special_move_data_for_life - fields one killer not defined!"); + #/ + return; + } + matchRecordLogSpecialMoveDataForLife( self, self.lastSwimmingStartTime, self.lastWallRunStartTime, self.lastSlideStartTime, self.lastDoubleJumpStartTime, + self.timeSpentSwimmingInLife, self.timeSpentWallRunningInLife, self.numberOfDoubleJumpsInLife, self.numberOfSlidesInLife, + killer, killer.lastSwimmingStartTime, killer.lastWallRunStartTime, killer.lastSlideStartTime, killer.lastDoubleJumpStartTime ); + } + else + { + matchRecordLogSpecialMoveDataForLife( self, self.lastSwimmingStartTime, self.lastWallRunStartTime, self.lastSlideStartTime, self.lastDoubleJumpStartTime, + self.timeSpentSwimmingInLife, self.timeSpentWallRunningInLife, self.numberOfDoubleJumpsInLife, self.numberOfSlidesInLife ); + } + +} + +function player_monitor_wall_run() +{ + self endon ( "disconnect" ); + + // make sure no other stray threads running on this dude + self notify("stop_player_monitor_wall_run"); + self endon("stop_player_monitor_wall_run"); + + self.lastWallRunStartTime = 0; + self.timeSpentWallRunningInLife = 0; + while ( true ) + { + notification = self util::waittill_any_return( "wallrun_begin", "death", "disconnect", "stop_player_monitor_wall_run" ); + if( notification == "death" ) + break; // end thread + + self.lastWallRunStartTime = getTime(); + + notification = self util::waittill_any_return( "wallrun_end", "death", "disconnect", "stop_player_monitor_wall_run" ); + + self.timeSpentWallRunningInLife += (getTime() - self.lastWallRunStartTime); + + if( notification == "death" ) + break; // end thread + + } +} + +function player_monitor_swimming() +{ + self endon ( "disconnect" ); + + // make sure no other stray threads running on this dude + self notify("stop_player_monitor_swimming"); + self endon("stop_player_monitor_swimming"); + + self.lastSwimmingStartTime = 0; + self.timeSpentSwimmingInLife = 0; + while ( true ) + { + notification = self util::waittill_any_return( "swimming_begin", "death", "disconnect", "stop_player_monitor_swimming" ); + if( notification == "death" ) + break; // end thread + + self.lastSwimmingStartTime = getTime(); + + notification = self util::waittill_any_return( "swimming_end", "death", "disconnect", "stop_player_monitor_swimming" ); + + self.timeSpentSwimmingInLife += (getTime() - self.lastSwimmingStartTime); + + if( notification == "death" ) + break; // end thread + + } +} + +function player_monitor_slide() +{ + self endon ( "disconnect" ); + + // make sure no other stray threads running on this dude + self notify("stop_player_monitor_slide"); + self endon("stop_player_monitor_slide"); + + self.lastSlideStartTime = 0; + self.numberOfSlidesInLife = 0; + while ( true ) + { + notification = self util::waittill_any_return( "slide_begin", "death", "disconnect", "stop_player_monitor_slide" ); + if( notification == "death" ) + break; // end thread + + self.lastSlideStartTime = getTime(); + self.numberOfSlidesInLife++; + + notification = self util::waittill_any_return( "slide_end", "death", "disconnect", "stop_player_monitor_slide" ); + + if( notification == "death" ) + break; // end thread + } +} + +function player_monitor_doublejump() +{ + self endon ( "disconnect" ); + + // make sure no other stray threads running on this dude + self notify("stop_player_monitor_doublejump"); + self endon("stop_player_monitor_doublejump"); + + self.lastDoubleJumpStartTime = 0; + self.numberOfDoubleJumpsInLife = 0; + while ( true ) + { + notification = self util::waittill_any_return( "doublejump_begin", "death", "disconnect", "stop_player_monitor_doublejump" ); + if( notification == "death" ) + break; // end thread + + self.lastDoubleJumpStartTime = getTime(); + self.numberOfDoubleJumpsInLife++; + + notification = self util::waittill_any_return( "doublejump_end", "death", "disconnect", "stop_player_monitor_doublejump" ); + + if( notification == "death" ) + break; // end thread + } +} + + +function player_monitor_inactivity() +{ + self endon ( "disconnect" ); + + self notify( "player_monitor_inactivity" ); + self endon( "player_monitor_inactivity" ); + + wait 10; + + while( true ) + { + if ( isdefined( self ) ) + { + if ( self isRemoteControlling() || self util::isUsingRemote() ) + { + self ResetInactivityTimer(); + } + } + wait 5; + } +} + +function Callback_PlayerConnect() +{ + thread notifyConnecting(); + + self.statusicon = "hud_status_connecting"; + self waittill( "begin" ); + + if( isdefined( level.reset_clientdvars ) ) + self [[level.reset_clientdvars]](); + + waittillframeend; + self.statusicon = ""; + + self.guid = self getXuid(); + + self.killstreak = []; + + self.leaderDialogQueue = []; + self.killstreakDialogQueue = []; + + profilelog_begintiming( 4, "ship" ); + + level notify( "connected", self ); + callback::callback( #"on_player_connect" ); + + if ( self IsHost() ) + self thread globallogic::listenForGameEnd(); + + // only print that we connected if we haven't connected in a previous round + if( !level.splitscreen && !isdefined( self.pers["score"] ) ) + { + iPrintLn(&"MP_CONNECTED", self); + } + + if( !isdefined( self.pers["score"] ) ) + { + self thread persistence::adjust_recent_stats(); + self persistence::set_after_action_report_stat( "valid", 0 ); + if ( GameModeIsMode( 3 ) && !( self IsHost() ) ) + self persistence::set_after_action_report_stat( "wagerMatchFailed", 1 ); + else + self persistence::set_after_action_report_stat( "wagerMatchFailed", 0 ); + } + + // track match and hosting stats once per match + if( ( level.rankedMatch || level.wagerMatch || level.leagueMatch ) && !isdefined( self.pers["matchesPlayedStatsTracked"] ) ) + { + gameMode = util::GetCurrentGameMode(); + self globallogic::IncrementMatchCompletionStat( gameMode, "played", "started" ); + + if ( !isdefined( self.pers["matchesHostedStatsTracked"] ) && self IsLocalToHost() ) + { + self globallogic::IncrementMatchCompletionStat( gameMode, "hosted", "started" ); + self.pers["matchesHostedStatsTracked"] = true; + } + + self.pers["matchesPlayedStatsTracked"] = true; + self thread persistence::upload_stats_soon(); + } + + self gamerep::gameRepPlayerConnected(); + + lpselfnum = self getEntityNumber(); + lpGuid = self getXuid(); + lpXuid = self getxuid(true); + + if (self util::is_bot()) + { + lpGuid = "bot0"; + } + + logPrint("J;" + lpGuid + ";" + lpselfnum + ";" + self.name + "\n"); + bbPrint( "global_joins", "name %s client %s xuid %s", self.name, lpselfnum, lpXuid ); + + // needed for cross-referencing into player breadcrumb buffer + // will get out of sync with self.clientId with disconnects/connects + recordPlayerStats( self, "codeClientNum", lpselfnum); + + if( !SessionModeIsZombiesGame() ) // it will be set after intro screen is faded out for zombie + { + self setClientUIVisibilityFlag( "hud_visible", 1 ); + self setClientUIVisibilityFlag( "weapon_hud_visible", 1 ); + } + + self SetClientPlayerSprintTime( level.playerSprintTime ); + self SetClientNumLives( level.numLives ); + + //makeDvarServerInfo( "cg_drawTalk", 1 ); + + if ( level.hardcoreMode ) + { + self SetClientDrawTalk( 3 ); + } + + if( SessionModeIsZombiesGame() ) + { + // initial zombies stats + self [[level.player_stats_init]](); + } + else + { + + self globallogic_score::initPersStat( "score" ); + if ( level.resetPlayerScoreEveryRound ) + { + self.pers["score"] = 0; + } + self.score = self.pers["score"]; + + self globallogic_score::initPersStat( "pointstowin" ); + if ( level.scoreRoundWinBased ) + { + self.pers["pointstowin"] = 0; + } + self.pointstowin = self.pers["pointstowin"]; + + self globallogic_score::initPersStat( "momentum", false ); + self.momentum = self globallogic_score::getPersStat( "momentum" ); + + self globallogic_score::initPersStat( "suicides" ); + self.suicides = self globallogic_score::getPersStat( "suicides" ); + + self globallogic_score::initPersStat( "headshots" ); + self.headshots = self globallogic_score::getPersStat( "headshots" ); + + self globallogic_score::initPersStat( "challenges" ); + self.challenges = self globallogic_score::getPersStat( "challenges" ); + + self globallogic_score::initPersStat( "kills" ); + self.kills = self globallogic_score::getPersStat( "kills" ); + + self globallogic_score::initPersStat( "deaths" ); + self.deaths = self globallogic_score::getPersStat( "deaths" ); + + self globallogic_score::initPersStat( "assists" ); + self.assists = self globallogic_score::getPersStat( "assists" ); + + self globallogic_score::initPersStat( "defends", false ); + self.defends = self globallogic_score::getPersStat( "defends" ); + + self globallogic_score::initPersStat( "offends", false ); + self.offends = self globallogic_score::getPersStat( "offends" ); + + self globallogic_score::initPersStat( "plants", false ); + self.plants = self globallogic_score::getPersStat( "plants" ); + + self globallogic_score::initPersStat( "defuses", false ); + self.defuses = self globallogic_score::getPersStat( "defuses" ); + + self globallogic_score::initPersStat( "returns", false ); + self.returns = self globallogic_score::getPersStat( "returns" ); + + self globallogic_score::initPersStat( "captures", false ); + self.captures = self globallogic_score::getPersStat( "captures" ); + + self globallogic_score::initPersStat( "objtime", false ); + self.objtime = self globallogic_score::getPersStat( "objtime" ); + + self globallogic_score::initPersStat( "carries", false ); + self.carries = self globallogic_score::getPersStat( "carries" ); + + self globallogic_score::initPersStat( "throws", false ); + self.throws = self globallogic_score::getPersStat( "throws" ); + + self globallogic_score::initPersStat( "destructions", false ); + self.destructions = self globallogic_score::getPersStat( "destructions" ); + + self globallogic_score::initPersStat( "disables", false ); + self.disables = self globallogic_score::getPersStat( "disables" ); + + self globallogic_score::initPersStat( "escorts", false ); + self.escorts = self globallogic_score::getPersStat( "escorts" ); + + self globallogic_score::initPersStat( "infects", false ); + self.infects = self globallogic_score::getPersStat( "infects" ); + + self globallogic_score::initPersStat( "sbtimeplayed", false ); + self.sbtimeplayed = self globallogic_score::getPersStat( "sbtimeplayed" ); + + self globallogic_score::initPersStat( "backstabs", false ); + self.backstabs = self globallogic_score::getPersStat( "backstabs" ); + + self globallogic_score::initPersStat( "longshots", false ); + self.longshots = self globallogic_score::getPersStat( "longshots" ); + + self globallogic_score::initPersStat( "survived", false ); + self.survived = self globallogic_score::getPersStat( "survived" ); + + self globallogic_score::initPersStat( "stabs", false ); + self.stabs = self globallogic_score::getPersStat( "stabs" ); + + self globallogic_score::initPersStat( "tomahawks", false ); + self.tomahawks = self globallogic_score::getPersStat( "tomahawks" ); + + self globallogic_score::initPersStat( "humiliated", false ); + self.humiliated = self globallogic_score::getPersStat( "humiliated" ); + + self globallogic_score::initPersStat( "x2score", false ); + self.x2score = self globallogic_score::getPersStat( "x2score" ); + + self globallogic_score::initPersStat( "agrkills", false ); + self.x2score = self globallogic_score::getPersStat( "agrkills" ); + + self globallogic_score::initPersStat( "hacks", false ); + self.x2score = self globallogic_score::getPersStat( "hacks" ); + + self globallogic_score::initPersStat( "killsconfirmed", false ); + self.killsconfirmed = self globallogic_score::getPersStat( "killsconfirmed" ); + + self globallogic_score::initPersStat( "killsdenied", false ); + self.killsdenied = self globallogic_score::getPersStat( "killsdenied" ); + + self globallogic_score::initPersStat( "rescues", false ); + self.rescues = self globallogic_score::getPersStat( "rescues" ); + + self globallogic_score::initPersStat( "shotsfired", false ); + self.shotsfired = self globallogic_score::getPersStat( "shotsfired" ); + + self globallogic_score::initPersStat( "shotshit", false ); + self.shotshit = self globallogic_score::getPersStat( "shotshit" ); + + self globallogic_score::initPersStat( "shotsmissed", false ); + self.shotsmissed = self globallogic_score::getPersStat( "shotsmissed" ); + + self globallogic_score::initPersStat( "cleandeposits", false ); + self.cleandeposits = self globallogic_score::getPersStat( "cleandeposits" ); + + self globallogic_score::initPersStat( "cleandenies", false ); + self.cleandenies = self globallogic_score::getPersStat( "cleandenies" ); + + self globallogic_score::initPersStat( "victory", false ); + self.victory = self globallogic_score::getPersStat( "victory" ); + + self globallogic_score::initPersStat( "sessionbans", false ); + self.sessionbans = self globallogic_score::getPersStat( "sessionbans" ); + self globallogic_score::initPersStat( "gametypeban", false ); + self globallogic_score::initPersStat( "time_played_total", false ); + self globallogic_score::initPersStat( "time_played_alive", false ); + + self globallogic_score::initPersStat( "teamkills", false ); + self globallogic_score::initPersStat( "teamkills_nostats", false ); + + // used by match recorder for analyzing play styles + self globallogic_score::initPersStat( "kill_distances", false ); + self globallogic_score::initPersStat( "num_kill_distance_entries", false ); + self globallogic_score::initPersStat( "time_played_moving", false ); + self globallogic_score::initPersStat( "total_speeds_when_moving", false ); + self globallogic_score::initPersStat( "num_speeds_when_moving_entries", false ); + self globallogic_score::initPersStat( "total_distance_travelled", false ); + self globallogic_score::initPersStat( "movement_Update_Count", false ); + + self.teamKillPunish = false; + if ( level.minimumAllowedTeamKills >= 0 && self.pers["teamkills_nostats"] > level.minimumAllowedTeamKills ) + self thread reduceTeamKillsOverTime(); + + self behaviorTracker::Initialize(); + } + + self.killedPlayersCurrent = []; + + if ( !isdefined( self.pers["totalTimePlayed"] ) ) + { + self setEnterTime( getTime() ); + self.pers["totalTimePlayed"] = 0; + } + + if ( !isdefined( self.pers["totalMatchBonus"] ) ) + { + self.pers["totalMatchBonus"] = 0; + } + + if( !isdefined( self.pers["best_kill_streak"] ) ) + { + self.pers["killed_players"] = []; + self.pers["killed_by"] = []; + self.pers["nemesis_tracking"] = []; + self.pers["artillery_kills"] = 0; + self.pers["dog_kills"] = 0; + self.pers["nemesis_name"] = ""; + self.pers["nemesis_rank"] = 0; + self.pers["nemesis_rankIcon"] = 0; + self.pers["nemesis_xp"] = 0; + self.pers["nemesis_xuid"] = ""; + self.pers["killed_players_with_specialist"] = []; + + /*self.killstreakKills["artillery"] = 0; + self.killstreakKills["dogs"] = 0; + self.killstreaksUsed["radar"] = 0; + self.killstreaksUsed["artillery"] = 0; + self.killstreaksUsed["dogs"] = 0;*/ + self.pers["best_kill_streak"] = 0; + } + +// Adding Music tracking per player CDC + if( !isdefined( self.pers["music"] ) ) + { + self.pers["music"] = spawnstruct(); + self.pers["music"].spawn = false; + self.pers["music"].inque = false; + self.pers["music"].currentState = "SILENT"; + self.pers["music"].previousState = "SILENT"; + self.pers["music"].nextstate = "UNDERSCORE"; + self.pers["music"].returnState = "UNDERSCORE"; + + } + + if ( self.team != "spectator" ) + { + self thread globallogic_audio::set_music_on_player( "spawnPreLoop" ); + } + + if ( !isdefined( self.pers["cur_kill_streak"] ) ) + { + self.pers["cur_kill_streak"] = 0; + } + + if ( !isdefined( self.pers["cur_total_kill_streak"] ) ) + { + self.pers["cur_total_kill_streak"] = 0; + self setplayercurrentstreak( 0 ); + } + + if ( !isdefined( self.pers["totalKillstreakCount"] ) ) + self.pers["totalKillstreakCount"] = 0; + + //Keep track of how many killstreaks have been earned in the current streak + if ( !isdefined( self.pers["killstreaksEarnedThisKillstreak"] ) ) + self.pers["killstreaksEarnedThisKillstreak"] = 0; + + if ( isdefined( level.usingScoreStreaks ) && level.usingScoreStreaks && !isdefined( self.pers["killstreak_quantity"] ) ) + self.pers["killstreak_quantity"] = []; + + if ( isdefined( level.usingScoreStreaks ) && level.usingScoreStreaks && !isdefined( self.pers["held_killstreak_ammo_count"] ) ) + self.pers["held_killstreak_ammo_count"] = []; + + if ( IsDefined( level.usingScoreStreaks ) && level.usingScoreStreaks && !IsDefined( self.pers["held_killstreak_clip_count"] ) ) + self.pers["held_killstreak_clip_count"] = []; + + if( !isDefined( self.pers["changed_class"] ) ) + self.pers["changed_class"] = false; + + if( !isDefined( self.pers["lastroundscore"] ) ) + self.pers["lastroundscore"] = 0; + + self.lastKillTime = 0; + + self.cur_death_streak = 0; + self disabledeathstreak(); + self.death_streak = 0; + self.kill_streak = 0; + self.gametype_kill_streak = 0; + self.spawnQueueIndex = -1; + self.deathTime = 0; + + self.aliveTimes = []; + for( index = 0; index < level.aliveTimeMaxCount; index++ ) + { + self.aliveTimes[index] = 0; + } + + self.aliveTimeCurrentIndex = 0; + + if ( level.onlineGame && !( isdefined( level.freerun ) && level.freerun ) ) + { + self.death_streak = self getDStat( "HighestStats", "death_streak" ); + self.kill_streak = self getDStat( "HighestStats", "kill_streak" ); + self.gametype_kill_streak = self persistence::stat_get_with_gametype( "kill_streak" ); + } + + self.lastGrenadeSuicideTime = -1; + + self.teamkillsThisRound = 0; + + if ( !isdefined( level.livesDoNotReset ) || !level.livesDoNotReset || !isdefined( self.pers["lives"] ) ) + { + self.pers["lives"] = level.numLives; + } + + // multi round FFA games in custom game mode should maintain team in-between rounds + if ( !level.teamBased ) + { + self.pers["team"] = undefined; + } + + self.hasSpawned = false; + self.waitingToSpawn = false; + self.wantSafeSpawn = false; + self.deathCount = 0; + + self.wasAliveAtMatchStart = false; + + level.players[level.players.size] = self; + + if( level.splitscreen ) + SetDvar( "splitscreen_playerNum", level.players.size ); + // removed underscore for debug CDC + // When joining a game in progress, if the game is at the post game state (scoreboard) the connecting player should spawn into intermission + if ( game["state"] == "postgame" ) + { + self.pers["needteam"] = 1; + self.pers["team"] = "spectator"; + self.team = self.sessionteam; + + self setClientUIVisibilityFlag( "hud_visible", 0 ); + + self [[level.spawnIntermission]](); + self closeInGameMenu(); + profilelog_endtiming( 4, "gs=" + game["state"] + " zom=" + SessionModeIsZombiesGame() ); + return; + } + + // don't count losses for CTF and S&D and War at each round. + if ( ( level.rankedMatch || level.wagerMatch || level.leagueMatch ) && !isdefined( self.pers["lossAlreadyReported"] ) ) + { + if ( level.leagueMatch ) + { + self recordLeaguePreLoser(); + } + + globallogic_score::updateLossStats( self ); + + self.pers["lossAlreadyReported"] = true; + } + if ((level.rankedMatch || level.leagueMatch) && !isDefined( self.pers["lateJoin"] ) ) + { + if (game["state"] == "playing" && !level.inPrematchPeriod ) + { + self.pers["lateJoin"] = true; + } + else + { + self.pers["lateJoin"] = false; + } + } + + // don't redo winstreak save to pers array for each round of round based games. + if ( !isdefined( self.pers["winstreakAlreadyCleared"] ) ) + { + self globallogic_score::backupAndClearWinStreaks(); + self.pers["winstreakAlreadyCleared"] = true; + } + + if( self istestclient() ) + { + self.pers[ "isBot" ] = true; + recordPlayerStats( self, "isBot", true); + } + + if ( level.rankedMatch || level.leagueMatch ) + { + self persistence::set_after_action_report_stat( "demoFileID", "0" ); + } + + level endon( "game_ended" ); + + if ( isdefined( level.hostMigrationTimer ) ) + self thread hostmigration::hostMigrationTimerThink(); + + if ( isdefined( self.pers["team"] ) ) + self.team = self.pers["team"]; + + if ( isdefined( self.pers["class"] ) ) + self.curClass = self.pers["class"]; + + if ( !isdefined( self.pers["team"] ) || isdefined( self.pers["needteam"] ) ) + { + // Don't set .sessionteam until we've gotten the assigned team from code, + // because it overrides the assigned team. + self.pers["needteam"] = undefined; + self.pers["team"] = "spectator"; + self.team = "spectator"; + self.sessionstate = "dead"; + + self globallogic_ui::updateObjectiveText(); + + [[level.spawnSpectator]](); + + [[level.autoassign]]( false ); + if ( level.rankedMatch || level.leagueMatch ) + { + self thread globallogic_spawn::kickIfDontSpawn(); + } + + if ( self.pers["team"] == "spectator" ) + { + self.sessionteam = "spectator"; + self thread spectate_player_watcher(); + } + + if ( level.teamBased ) + { + // set team and spectate permissions so the map shows waypoint info on connect + self.sessionteam = self.pers["team"]; + if ( !isAlive( self ) ) + self.statusicon = "hud_status_dead"; + self thread spectating::set_permissions(); + } + } + else if ( self.pers["team"] == "spectator" ) + { + self SetClientScriptMainMenu( game[ "menu_start_menu" ] ); + [[level.spawnSpectator]](); + self.sessionteam = "spectator"; + self.sessionstate = "spectator"; + self thread spectate_player_watcher(); + } + else + { + self.sessionteam = self.pers["team"]; + self.sessionstate = "dead"; + + self globallogic_ui::updateObjectiveText(); + + [[level.spawnSpectator]](); + + if ( globallogic_utils::isValidClass( self.pers["class"] ) || util::IsPropHuntGametype() ) + { + if ( !globallogic_utils::isValidClass( self.pers["class"] ) ) + { + self.pers["class"] = level.defaultClass; + self.curClass = level.defaultClass; + self SetClientScriptMainMenu( game[ "menu_start_menu" ] ); + } + self thread [[level.spawnClient]](); + } + else + { + self globallogic_ui::showMainMenuForTeam(); + } + + self thread spectating::set_permissions(); + } + + if ( self.sessionteam != "spectator" ) + { + self thread spawning::onSpawnPlayer(true); + } + + if ( level.forceRadar == 1 ) // radar always sweeping + { + self.pers["hasRadar"] = true; + self.hasSpyplane = true; + + if ( level.teambased ) + { + level.activeUAVs[self.team]++; + } + else + { + level.activeUAVs[self getEntityNumber()]++; + } + + level.activePlayerUAVs[self getEntityNumber()]++; + } + + if ( level.forceRadar == 2 ) // radar constant + { + self setClientUIVisibilityFlag( "g_compassShowEnemies", level.forceRadar ); + } + else + { + self SetClientUIVisibilityFlag( "g_compassShowEnemies", 0 ); + } + + profilelog_endtiming( 4, "gs=" + game["state"] + " zom=" + SessionModeIsZombiesGame() ); + + if ( isdefined( self.pers["isBot"] ) ) + return; + + self record_global_mp_stats_for_player_at_match_start(); + + //T7 - moved from load_shared to make sure this doesn't get set on CP until level.players is ready + num_con = getnumconnectedplayers(); + num_exp = getnumexpectedplayers(); + /#println( "all_players_connected(): getnumconnectedplayers=", num_con, "getnumexpectedplayers=", num_exp );#/ + + if(num_con == num_exp && (num_exp != 0)) + { + level flag::set( "all_players_connected" ); + // CODER_MOD: GMJ (08/28/08): Setting dvar for use by code + SetDvar( "all_players_are_connected", "1" ); + } + + globallogic_score::updateWeaponContractStart( self ); +} + +function record_global_mp_stats_for_player_at_match_start() +{ + // not sure if we even want/need this test + // if ( level.onlinegame && !SessionModeIsPrivate() ) ? + // if ( level.rankedMatch ) ? + // + // just copy from mp_stats, and it will do what it's supposed to + // (i.e. return something or 0) + + if( isdefined( level.disableStatTracking ) && level.disableStatTracking == true ) + { + return; + } + + startKills = self GetDStat( "playerstatslist", "kills", "statValue" ); + startDeaths = self GetDStat( "playerstatslist", "deaths", "statValue" ); + startWins = self GetDStat( "playerstatslist", "wins", "statValue" ); + startLosses = self GetDStat( "playerstatslist", "losses", "statValue" ); + startHits = self GetDStat( "playerstatslist", "hits", "statValue" ); + startMisses = self GetDStat( "playerstatslist", "misses", "statValue" ); + startTimePlayedTotal = self GetDStat( "playerstatslist", "time_played_total", "statValue" ); + startScore = self GetDStat( "playerstatslist", "score", "statValue" ); + startPrestige = self GetDStat( "playerstatslist", "plevel", "statValue" ); + startUnlockPoints = self GetDStat( "unlocks", 0); + + ties = self GetDStat( "playerstatslist", "ties", "statValue" ); + startGamesPlayed = startWins + startLosses + ties; + + self.startKills = startKills; + self.startHits = startHits; + self.totalMatchShots = 0; + + // note: xp_start - already exists - written in code - reads RANKXP + + recordPlayerStats( self, "startKills", startKills ); + recordPlayerStats( self, "startDeaths", startDeaths ); + recordPlayerStats( self, "startWins", startWins ); + recordPlayerStats( self, "startLosses", startLosses ); + recordPlayerStats( self, "startHits", startHits ); + recordPlayerStats( self, "startMisses", startMisses ); + recordPlayerStats( self, "startTimePlayedTotal", startTimePlayedTotal ); + recordPlayerStats( self, "startScore", startScore ); + recordPlayerStats( self, "startPrestige", startPrestige ); + recordPlayerStats( self, "startUnlockPoints", startUnlockPoints ); + recordPlayerStats( self, "startGamesPlayed", startGamesPlayed ); + + // temp commenting out; the getdstat calls here fail + lootXPBeforeMatch = self GetDStat( "AfterActionReportStats", "lootXPBeforeMatch" ); + cryptoKeysBeforeMatch = self GetDStat( "AfterActionReportStats", "cryptoKeysBeforeMatch" ); + recordPlayerStats( self, "lootXPBeforeMatch", lootXPBeforeMatch ); + recordPlayerStats( self, "cryptoKeysBeforeMatch", cryptoKeysBeforeMatch ); + +} + +function record_global_mp_stats_for_player_at_match_end() +{ + if( isdefined( level.disableStatTracking ) && level.disableStatTracking == true ) + { + return; + } + + endKills = self GetDStat( "playerstatslist", "kills", "statValue" ); + endDeaths = self GetDStat( "playerstatslist", "deaths", "statValue" ); + endWins = self GetDStat( "playerstatslist", "wins", "statValue" ); + endLosses = self GetDStat( "playerstatslist", "losses", "statValue" ); + endHits = self GetDStat( "playerstatslist", "hits", "statValue" ); + endMisses = self GetDStat( "playerstatslist", "misses", "statValue" ); + endTimePlayedTotal = self GetDStat( "playerstatslist", "time_played_total", "statValue" ); + endScore = self GetDStat( "playerstatslist", "score", "statValue" ); + endPrestige = self GetDStat( "playerstatslist", "plevel", "statValue" ); + endUnlockPoints = self GetDStat( "unlocks", 0); + + ties = self GetDStat( "playerstatslist", "ties", "statValue" ); + endGamesPlayed = endWins + endLosses + ties; + + // note: xp_end - already exists - written in code - reads RANKXP + + recordPlayerStats( self, "endKills", endKills ); + recordPlayerStats( self, "endDeaths", endDeaths ); + recordPlayerStats( self, "endWins", endWins ); + recordPlayerStats( self, "endLosses", endLosses ); + recordPlayerStats( self, "endHits", endHits ); + recordPlayerStats( self, "endMisses", endMisses ); + recordPlayerStats( self, "endTimePlayedTotal", endTimePlayedTotal ); + recordPlayerStats( self, "endScore", endScore ); + recordPlayerStats( self, "endPrestige", endPrestige ); + recordPlayerStats( self, "endUnlockPoints", endUnlockPoints ); + recordPlayerStats( self, "endGamesPlayed", endGamesPlayed ); + +} + +function record_misc_player_stats() +{ + if( isdefined( level.disableStatTracking ) && level.disableStatTracking == true ) + { + return; + } + + // common either for match end or on disconnect + recordPlayerStats( self, "UTCEndTimeSeconds", getUTC() ); + if( isdefined( self.weaponPickupsCount ) ) + { + recordPlayerStats( self, "weaponPickupsCount", self.weaponPickupsCount ); + } + if( isdefined( self.killcamsSkipped) ) + { + recordPlayerStats( self, "totalKillcamsSkipped", self.killcamsSkipped ); + } + if( isdefined( self.matchBonus) ) + { + recordPlayerStats( self, "matchXp", self.matchBonus ); + } + if( isdefined( self.killsdenied ) ) + { + recordPlayerStats( self, "killsDenied", self.killsdenied ); + } + if( isdefined( self.killsconfirmed ) ) + { + recordPlayerStats( self, "killsConfirmed", self.killsconfirmed ); + } + if( self IsSplitscreen() ) + { + recordPlayerStats( self, "isSplitscreen", true ); + } + if( self.objtime ) + { + recordPlayerStats( self, "objectiveTime", self.objtime ); + } + if( self.escorts ) + { + recordPlayerStats( self, "escortTime", self.escorts ); + } +} + +function spectate_player_watcher() +{ + self endon( "disconnect" ); + + // Setup the perks hud elem for the spectator if its not yet initalized + // We have to do it here, since the perk hudelem is generally initalized only on spawn, and the spectator will not able able to + // look at the perk loadout of some player. + if ( !level.splitscreen && !level.hardcoreMode && GetDvarint( "scr_showperksonspawn" ) == 1 && game["state"] != "postgame" && !isdefined( self.perkHudelem ) ) + { + if ( level.perksEnabled == 1 ) + { + self hud::showPerks( ); + } + } + + self.watchingActiveClient = true; + self.waitingForPlayersText = undefined; + + while ( 1 ) + { + if ( self.pers["team"] != "spectator" || level.gameEnded ) + { + self hud_message::clearShoutcasterWaitingMessage(); + if ( !( isdefined( level.inPrematchPeriod ) && level.inPrematchPeriod ) ) + { + self FreezeControls( false ); + } + self.watchingActiveClient = false; + break; + } + else + { + count = 0; + for ( i = 0; i < level.players.size; i++ ) + { + if ( level.players[i].team != "spectator" ) + { + count++; + break; + } + } + + if ( count > 0 ) + { + if ( !self.watchingActiveClient ) + { + self hud_message::clearShoutcasterWaitingMessage(); + self FreezeControls( false ); + + // Make sure that the player spawned notify happens when we start watching a player. + self LUINotifyEvent( &"player_spawned", 0 ); + } + + self.watchingActiveClient = true; + } + else + { + if ( self.watchingActiveClient ) + { + [[level.onSpawnSpectator]](); + self FreezeControls( true ); + self hud_message::setShoutcasterWaitingMessage(); + } + + self.watchingActiveClient = false; + } + + wait( 0.5 ); + } + } +} + +function Callback_PlayerMigrated() +{ +/# println( "Player " + self.name + " finished migrating at time " + gettime() ); #/ + + if ( isdefined( self.connected ) && self.connected ) + { + self globallogic_ui::updateObjectiveText(); +// self globallogic_ui::updateObjectiveText(); +// self updateMainMenu(); + +// if ( level.teambased ) +// self updateScores(); + } + + level.hostMigrationReturnedPlayerCount++; + if ( level.hostMigrationReturnedPlayerCount >= level.players.size * 2 / 3 ) + { + /# println( "2/3 of players have finished migrating" ); #/ + level notify( "hostmigration_enoughplayers" ); + } +} + +function Callback_PlayerDisconnect() +{ + profilelog_begintiming( 5, "ship" ); + + if ( game["state"] != "postgame" && !level.gameEnded ) + { + gameLength = game["timepassed"]; + self globallogic::bbPlayerMatchEnd( gameLength, "MP_PLAYER_DISCONNECT", 0 ); + + if( util::isRoundBased() ) + { + recordPlayerStats( self, "playerQuitRoundNumber", game["roundsplayed"] + 1 ); + } + + if( level.teambased ) + { + ourTeam = self.team; // only expecting: "allies" or "axis" + if( ourTeam == "allies" || ourTeam == "axis" ) + { + theirTeam = ""; + if( ourTeam == "allies" ) + { + theirTeam = "axis"; + } + else if( ourTeam == "axis" ) + { + theirTeam = "allies"; + } + recordPlayerStats( self, "playerQuitTeamScore", getTeamScore( ourTeam ) ); + recordPlayerStats( self, "playerQuitOpposingTeamScore", getTeamScore( theirTeam ) ); + } + } + + recordEndGameComScoreEventForPlayer( self, "disconnect" ); + + } + + self behaviorTracker::Finalize(); + + ArrayRemoveValue( level.players, self ); + + if ( level.splitscreen ) + { + players = level.players; + + if ( players.size <= 1 ) + level thread globallogic::forceEnd(); + + // passing number of players to menus in splitscreen to display leave or end game option + SetDvar( "splitscreen_playerNum", players.size ); + } + + if ( isdefined( self.score ) && isdefined( self.pers["team"] ) ) + { + /#print( "team: score " + self.pers["team"] + ":" + self.score );#/ + level.dropTeam += 1; + } + + [[level.onPlayerDisconnect]](); + + lpselfnum = self getEntityNumber(); + lpGuid = self getXuid(); + + if (self util::is_bot()) + { + lpGuid = "bot0"; + } + + logPrint("Q;" + lpGuid + ";" + lpselfnum + ";" + self.name + "\n"); + + self record_global_mp_stats_for_player_at_match_end(); + self record_special_move_data_for_life( undefined ); + + self record_misc_player_stats(); + + self gamerep::gameRepPlayerDisconnected(); + + for ( entry = 0; entry < level.players.size; entry++ ) + { + if ( level.players[entry] == self ) + { + while ( entry < level.players.size-1 ) + { + level.players[entry] = level.players[entry+1]; + entry++; + } + level.players[entry] = undefined; + break; + } + } + for ( entry = 0; entry < level.players.size; entry++ ) + { + if ( isdefined( level.players[entry].pers["killed_players"][self.name] ) ) + level.players[entry].pers["killed_players"][self.name] = undefined; + + if ( isdefined( level.players[entry].pers["killed_players_with_specialist"][self.name] ) ) + level.players[entry].pers["killed_players_with_specialist"][self.name] = undefined; + + if ( isdefined( level.players[entry].killedPlayersCurrent[self.name] ) ) + level.players[entry].killedPlayersCurrent[self.name] = undefined; + + if ( isdefined( level.players[entry].pers["killed_by"][self.name] ) ) + level.players[entry].pers["killed_by"][self.name] = undefined; + + if ( isdefined( level.players[entry].pers["nemesis_tracking"][self.name] ) ) + level.players[entry].pers["nemesis_tracking"][self.name] = undefined; + + // player that disconnected was our nemesis + if ( level.players[entry].pers["nemesis_name"] == self.name ) + { + level.players[entry] chooseNextBestNemesis(); + } + } + + if ( level.gameEnded ) + self globallogic::removeDisconnectedPlayerFromPlacement(); + + level thread globallogic::updateTeamStatus(); + level thread globallogic::updateAllAliveTimes(); + + profilelog_endtiming( 5, "gs=" + game["state"] + " zom=" + SessionModeIsZombiesGame() ); +} + +function Callback_PlayerMelee( eAttacker, iDamage, weapon, vOrigin, vDir, boneIndex, shieldHit, fromBehind ) +{ + hit = true; + + if ( level.teamBased && self.team == eAttacker.team ) + { + if ( level.friendlyfire == 0 ) // no one takes damage + { + hit = false; + } + } + + self finishMeleeHit( eAttacker, weapon, vOrigin, vDir, boneIndex, shieldHit, hit, fromBehind ); +} + +function chooseNextBestNemesis() +{ + nemesisArray = self.pers["nemesis_tracking"]; + nemesisArrayKeys = getArrayKeys( nemesisArray ); + nemesisAmount = 0; + nemesisName = ""; + + if ( nemesisArrayKeys.size > 0 ) + { + for ( i = 0; i < nemesisArrayKeys.size; i++ ) + { + nemesisArrayKey = nemesisArrayKeys[i]; + if ( nemesisArray[nemesisArrayKey] > nemesisAmount ) + { + nemesisName = nemesisArrayKey; + nemesisAmount = nemesisArray[nemesisArrayKey]; + } + + } + } + + self.pers["nemesis_name"] = nemesisName; + + if ( nemesisName != "" ) + { + playerIndex = 0; + for( ; playerIndex < level.players.size; playerIndex++ ) + { + if ( level.players[playerIndex].name == nemesisName ) + { + nemesisPlayer = level.players[playerIndex]; + self.pers["nemesis_rank"] = nemesisPlayer.pers["rank"]; + self.pers["nemesis_rankIcon"] = nemesisPlayer.pers["rankxp"]; + self.pers["nemesis_xp"] = nemesisPlayer.pers["prestige"]; + self.pers["nemesis_xuid"] = nemesisPlayer GetXUID(); + break; + } + } + } + else + { + self.pers["nemesis_xuid"] = ""; + } +} + +function custom_gamemodes_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, weapon, eInflictor, sHitLoc ) +{ + // regular public matches should early out + if ( level.onlinegame && !SessionModeIsPrivate() ) + { + return iDamage; + } + + if( isdefined( eAttacker) && isdefined( eAttacker.damageModifier ) ) + { + iDamage *= eAttacker.damageModifier; + } + if ( ( sMeansOfDeath == "MOD_PISTOL_BULLET" ) || ( sMeansOfDeath == "MOD_RIFLE_BULLET" ) ) + { + iDamage = int( iDamage * level.bulletDamageScalar ); + } + + return iDamage; +} + +function figure_out_attacker( eAttacker ) +{ + if ( isdefined(eAttacker) ) + { + if( isai(eAttacker) && isdefined( eAttacker.script_owner ) ) + { + team = self.team; + + if ( eAttacker.script_owner.team != team ) + eAttacker = eAttacker.script_owner; + } + + if( eAttacker.classname == "script_vehicle" && isdefined( eAttacker.owner ) ) + eAttacker = eAttacker.owner; + else if( eAttacker.classname == "auto_turret" && isdefined( eAttacker.owner ) ) + eAttacker = eAttacker.owner; + else if( eAttacker.classname == "actor_spawner_bo3_robot_grunt_assault_mp" && isdefined( eAttacker.owner ) ) + eAttacker = eAttacker.owner; + } + + return eAttacker; +} + +function player_damage_figure_out_weapon( weapon, eInflictor ) +{ + // explosive barrel/car detection + if ( weapon == level.weaponNone && isdefined( eInflictor ) ) + { + if ( isdefined( eInflictor.targetname ) && eInflictor.targetname == "explodable_barrel" ) + { + weapon = GetWeapon( "explodable_barrel" ); + } + else if ( isdefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) ) + { + weapon = GetWeapon( "destructible_car" ); + } + else if( isdefined( eInflictor.scriptvehicletype ) ) + { + veh_weapon = GetWeapon( eInflictor.scriptvehicletype ); + if( isdefined( veh_weapon ) ) + { + weapon = veh_weapon; + } + } + } + + if ( isdefined( eInflictor ) && isdefined( eInflictor.script_noteworthy ) ) + { + if ( IsDefined( level.overrideWeaponFunc ) ) + { + weapon = [[level.overrideWeaponFunc]]( weapon, eInflictor.script_noteworthy ); + } + } + + return weapon; +} + +function figure_out_friendly_fire( victim ) +{ + if ( level.hardcoreMode && level.friendlyfire > 0 && isdefined( victim ) && victim.is_capturing_own_supply_drop === true ) + { + return 2; // FF 2 = reflect; design wants reflect friendly fire whenever a player is capturing their own supply drop + } + + if ( killstreaks::is_ricochet_protected( victim ) ) + { + return 2; + } + + // note, keep, non-gametype specific friendly fire logic above this line + + if ( isdefined( level.figure_out_gametype_friendly_fire ) ) + { + return [[ level.figure_out_gametype_friendly_fire ]]( victim ); + } + + return level.friendlyfire; +} + +function isPlayerImmuneToKillstreak( eAttacker, weapon ) +{ + if ( level.hardcoreMode ) + return false; + + if ( !isdefined( eAttacker ) ) + return false; + + if ( self != eAttacker ) + return false; + + return weapon.doNotDamageOwner; +} + + +function should_do_player_damage( eAttacker, weapon, sMeansOfDeath, iDFlags ) +{ + if ( game["state"] == "postgame" ) + return false; + + if ( self.sessionteam == "spectator" ) + return false; + + if ( isdefined( self.canDoCombat ) && !self.canDoCombat ) + return false; + + if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isdefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat ) + return false; + + if ( isdefined( level.hostMigrationTimer ) ) + return false; + + if ( level.onlyHeadShots ) + { + if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" ) + return false; + } + + // Make all vehicle drivers invulnerable to bullets + if ( self vehicle::player_is_occupant_invulnerable( sMeansOfDeath ) ) + return false; + + if ( weapon.isSupplyDropWeapon && !weapon.isGrenadeWeapon && ( smeansofdeath != "MOD_TRIGGER_HURT" ) ) + return false; + + if ( self.scene_takedamage === false ) + return false; + + // prevent spawn kill wall bangs + if ( (iDFlags & 8) && self player::is_spawn_protected() ) + return false; + +return true; +} + +function apply_damage_to_armor( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, sHitLoc, friendlyFire, ignore_round_start_friendly_fire ) +{ + victim = self; + + if ( friendlyFire && !player_damage_does_friendly_fire_damage_victim( ignore_round_start_friendly_fire ) ) + return iDamage; + + // Handle armor damage + if( IsDefined( victim.lightArmorHP ) ) + { + if ( weapon.ignoresLightArmor && sMeansOfDeath != "MOD_MELEE" ) + { + return iDamage; + } + else if ( weapon.meleeIgnoresLightArmor && sMeansOfDeath == "MOD_MELEE" ) + { + return iDamage; + } + // anything stuck to the player does health damage + else if( IsDefined( eInflictor ) && IsDefined( eInflictor.stuckToPlayer ) && eInflictor.stuckToPlayer == victim ) + { + iDamage = victim.health; + } + else + { + // Handle Armor Damage + // no armor damage in case of falling, melee, fmj or head shots + if ( sMeansOfDeath != "MOD_FALLING" + && !weapon_utils::isMeleeMOD( sMeansOfDeath ) + && !globallogic_utils::isHeadShot( weapon, sHitLoc, sMeansOfDeath, eAttacker ) + ) + { + victim armor::setLightArmorHP( victim.lightArmorHP - ( iDamage ) ); + + iDamage = 0; + if ( victim.lightArmorHP <= 0 ) + { + // since the light armor is gone, adjust the damage to be the excess damage that happens after the light armor hp is reduced + iDamage = abs( victim.lightArmorHP ); + armor::unsetLightArmor(); + } + } + } + } + + return iDamage; +} + +function make_sure_damage_is_not_zero( iDamage ) +{ + // Make sure at least one point of damage is done & give back 1 health because of this if you have power armor + if ( iDamage < 1 ) + { + if( ( self ability_util::gadget_power_armor_on() ) && isDefined( self.maxHealth ) && ( self.health < self.maxHealth ) ) + { + self.health += 1; + } + iDamage = 1; + } + + return int(iDamage); +} + +function modify_player_damage_friendlyfire( iDamage ) +{ + friendlyfire = [[ level.figure_out_friendly_fire ]]( self ); + + // half damage + if ( friendlyfire == 2 || friendlyfire == 3 ) + { + iDamage = int(iDamage * .5); + } + + return iDamage; +} + +function modify_player_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ) +{ + if ( isdefined( self.overridePlayerDamage ) ) + { + iDamage = self [[self.overridePlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ); + } + else if ( isdefined( level.overridePlayerDamage ) ) + { + iDamage = self [[level.overridePlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ); + } + + assert(isdefined(iDamage), "You must return a value from a damage override function."); + + if ( isdefined( eAttacker ) ) + { + iDamage = loadout::cac_modified_damage( self, eAttacker, iDamage, sMeansOfDeath, weapon, eInflictor, sHitLoc ); + + if( isdefined( eAttacker.pickup_damage_scale ) && eAttacker.pickup_damage_scale_time > GetTime() ) + { + iDamage = iDamage * eAttacker.pickup_damage_scale; + } + } + iDamage = custom_gamemodes_modified_damage( self, eAttacker, iDamage, sMeansOfDeath, weapon, eInflictor, sHitLoc ); + + if ( level.onPlayerDamage != &globallogic::blank ) + { + modifiedDamage = [[level.onPlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime ); + + if ( isdefined( modifiedDamage ) ) + { + if ( modifiedDamage <= 0 ) + return; + + iDamage = modifiedDamage; + } + } + + if ( level.onlyHeadShots ) + { + if ( sMeansOfDeath == "MOD_HEAD_SHOT" ) + iDamage = 150; + } + + if ( weapon.damageAlwaysKillsPlayer ) + { + iDamage = self.maxHealth + 1; + } + + if ( sHitLoc == "riotshield" ) + { + if ( iDFlags & 32 ) + { + if ( !(iDFlags & 64) ) + { + iDamage *= 0.0; + } + } + else if ( iDFlags & 128 ) + { + if ( isdefined( eInflictor ) && isdefined( eInflictor.stuckToPlayer ) && eInflictor.stuckToPlayer == self ) + { + //does enough damage to shield carrier to ensure death + iDamage = self.maxhealth + 1; + } + } + } + + return int(iDamage); +} + +function modify_player_damage_meansofdeath( eInflictor, eAttacker, sMeansOfDeath, weapon, sHitLoc ) +{ + if ( globallogic_utils::isHeadShot( weapon, sHitLoc, sMeansOfDeath, eInflictor ) && isPlayer(eAttacker) && !weapon_utils::ismeleemod( sMeansOfDeath ) ) + { + sMeansOfDeath = "MOD_HEAD_SHOT"; + } + + if ( isdefined( eInflictor ) && isdefined( eInflictor.script_noteworthy ) ) + { + if ( eInflictor.script_noteworthy == "ragdoll_now" ) + { + sMeansOfDeath = "MOD_FALLING"; + } + } + + return sMeansOfDeath; +} + +function player_damage_update_attacker( eInflictor, eAttacker, sMeansOfDeath ) +{ + if ( isdefined( eInflictor ) && isPlayer( eAttacker ) && eAttacker == eInflictor ) + { + if ( sMeansOfDeath == "MOD_HEAD_SHOT" || sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" ) + { + //if ( isPlayer( eAttacker ) ) already tested for above + { + eAttacker.hits++; + } + } + } + + if ( isPlayer( eAttacker ) ) + eAttacker.pers["participation"]++; +} + +function player_is_spawn_protected_from_explosive( eInflictor, weapon, sMeansOfDeath ) +{ + if ( !self player::is_spawn_protected() ) + return false; + + // if we are using this as a impact damage only projectile then no protection + // we should probably add a bool to the weapon to indicate that it spawn protects + if ( weapon.explosionradius == 0 ) + return false; + + distSqr = ( ( isdefined( eInflictor ) && isdefined( self.lastSpawnPoint ) ) ? DistanceSquared( eInflictor.origin, self.lastSpawnPoint.origin ) : 0 ); + + // protect players from spawnkill grenades, tabun and incendiary + if ( distSqr < ( (250) * (250) ) ) + { + if ( sMeansOfDeath == "MOD_GRENADE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" ) + { + return true; + } + + if ( sMeansOfDeath == "MOD_PROJECTILE" || sMeansOfDeath == "MOD_PROJECTILE_SPLASH" ) + { + return true; + } + + if ( sMeansOfDeath == "MOD_EXPLOSIVE" ) + { + return true; + } + } + + if ( killstreaks::is_killstreak_weapon( weapon ) ) + { + return true; + } + + return false; +} + +function player_damage_update_explosive_info( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ) +{ + is_explosive_damage = loadout::isExplosiveDamage( sMeansOfDeath ); + + if ( is_explosive_damage ) + { + // protect players from spawnkill grenades, tabun, incendiaries, and scorestreaks + if ( self player_is_spawn_protected_from_explosive( eInflictor, weapon, sMeansOfDeath ) ) + { + return false; + } + + // protect players from their own non-player controlled killstreaks + if ( self isPlayerImmuneToKillstreak( eAttacker, weapon ) ) + { + return false; + } + } + + if ( isdefined( eInflictor ) && ( sMeansOfDeath == "MOD_GAS" || is_explosive_damage ) ) + { + self.explosiveInfo = []; + self.explosiveInfo["damageTime"] = getTime(); + self.explosiveInfo["damageId"] = eInflictor getEntityNumber(); + self.explosiveInfo["originalOwnerKill"] = false; + self.explosiveInfo["bulletPenetrationKill"] = false; + self.explosiveInfo["chainKill"] = false; + self.explosiveInfo["damageExplosiveKill"] = false; + self.explosiveInfo["chainKill"] = false; + self.explosiveInfo["cookedKill"] = false; + self.explosiveInfo["weapon"] = weapon; + self.explosiveInfo["originalowner"] = eInflictor.originalowner; + + isFrag = ( weapon.rootweapon.name == "frag_grenade" ); + + if ( isdefined( eAttacker ) && eAttacker != self ) + { + if ( isdefined( eAttacker ) && isdefined( eInflictor.owner ) && (weapon.name == "satchel_charge" || weapon.name == "claymore" || weapon.name == "bouncingbetty") ) + { + self.explosiveInfo["originalOwnerKill"] = (eInflictor.owner == self); + self.explosiveInfo["damageExplosiveKill"] = isdefined( eInflictor.wasDamaged ); + self.explosiveInfo["chainKill"] = isdefined( eInflictor.wasChained ); + self.explosiveInfo["wasJustPlanted"] = isdefined( eInflictor.wasJustPlanted ); + self.explosiveInfo["bulletPenetrationKill"] = isdefined( eInflictor.wasDamagedFromBulletPenetration ); + self.explosiveInfo["cookedKill"] = false; + } + if ( isdefined( eInflictor ) && isdefined( eInflictor.stuckToPlayer ) && weapon.projExplosionType == "grenade" ) + { + self.explosiveInfo["stuckToPlayer"] = eInflictor.stuckToPlayer; + } + if ( weapon.doStun ) + { + self.lastStunnedBy = eAttacker; + self.lastStunnedTime = self.iDFlagsTime; + } + if ( isdefined( eAttacker.lastGrenadeSuicideTime ) && eAttacker.lastGrenadeSuicideTime >= gettime() - 50 && isFrag ) + { + self.explosiveInfo["suicideGrenadeKill"] = true; + } + else + { + self.explosiveInfo["suicideGrenadeKill"] = false; + } + } + + if ( isFrag ) + { + self.explosiveInfo["cookedKill"] = isdefined( eInflictor.isCooked ); + self.explosiveInfo["throwbackKill"] = isdefined( eInflictor.threwBack ); + } + + if( isdefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker != self ) + { + self globallogic_score::setInflictorStat( eInflictor, eAttacker, weapon ); + } + } + + if( sMeansOfDeath == "MOD_IMPACT" && isdefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker != self ) + { + if ( weapon != level.weaponBallisticKnife ) + { + self globallogic_score::setInflictorStat( eInflictor, eAttacker, weapon ); + } + + if ( weapon.rootweapon.name == "hatchet" && isdefined( eInflictor ) ) + { + self.explosiveInfo["projectile_bounced"] = isdefined( eInflictor.bounced ); + } + } + + return true; +} + +function player_damage_is_friendly_fire_at_round_start() +{ + //check for friendly fire at the begining of the match. apply the damage to the attacker only + if( level.friendlyFireDelay && level.friendlyFireDelayTime >= ( ( ( gettime() - level.startTime ) - level.discardTime ) / 1000 ) ) + { + return true; + } + + return false; +} + +function player_damage_does_friendly_fire_damage_attacker( eAttacker, ignore_round_start_friendly_fire ) +{ + if ( !IsAlive( eAttacker ) ) + return false; + + friendlyfire = [[ level.figure_out_friendly_fire ]]( self ); + + if ( friendlyfire == 1 ) // the friendly takes damage + { + //check for friendly fire at the begining of the match. apply the damage to the attacker only + if ( player_damage_is_friendly_fire_at_round_start() && ( ignore_round_start_friendly_fire == false ) ) + { + return true; + } + } + + if ( friendlyfire == 2 ) // only the attacker takes damage + { + return true; + } + + if ( friendlyfire == 3 ) // both friendly and attacker take damage + { + return true; + } + + return false; +} + +function player_damage_does_friendly_fire_damage_victim( ignore_round_start_friendly_fire ) +{ + friendlyfire = [[ level.figure_out_friendly_fire ]]( self ); + + if ( friendlyfire == 1 ) // the friendly takes damage + { + //check for friendly fire at the begining of the match. apply the damage to the attacker only + if ( player_damage_is_friendly_fire_at_round_start() && ( ignore_round_start_friendly_fire == false ) ) + { + return false; + } + + return true; + } + + if ( friendlyfire == 3 ) // both friendly and attacker take damage + { + return true; + } + + return false; +} + +function player_damage_riotshield_hit( eAttacker, iDamage, sMeansOfDeath, weapon, attackerIsHittingTeammate) +{ + if (( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" ) && + ( !killstreaks::is_killstreak_weapon( weapon )) && + ( !attackerIsHittingTeammate ) ) + { + if ( self.hasRiotShieldEquipped ) + { + if ( isPlayer( eAttacker )) + { + eAttacker.lastAttackedShieldPlayer = self; + eAttacker.lastAttackedShieldTime = getTime(); + } + + previous_shield_damage = self.shieldDamageBlocked; + self.shieldDamageBlocked += iDamage; + + if (( self.shieldDamageBlocked % 400 /*riotshield_damage_score_threshold*/ ) < ( previous_shield_damage % 400 /*riotshield_damage_score_threshold*/ )) + { + score_event = "shield_blocked_damage"; + + if (( self.shieldDamageBlocked > 2000 /*riotshield_damage_score_max*/ )) + { + score_event = "shield_blocked_damage_reduced"; + } + + if ( isdefined( level.scoreInfo[ score_event ]["value"] ) ) + { + // need to get the actual riot shield weapon here + self AddWeaponStat( level.weaponRiotshield, "score_from_blocked_damage", level.scoreInfo[ score_event ]["value"] ); + } + + scoreevents::processScoreEvent( score_event, self ); + } + } + } + +} + +function does_player_completely_avoid_damage(iDFlags, sHitLoc, weapon, friendlyFire, attackerIsHittingSelf, sMeansOfDeath ) +{ + if( iDFlags & 2048 ) + return true; + + if ( friendlyFire && level.friendlyfire == 0 ) + return true; + + if ( sHitLoc == "riotshield" ) + { + if ( !(iDFlags & (32|128)) ) + return true; + } + + + if( weapon.isEmp && sMeansOfDeath == "MOD_GRENADE_SPLASH" ) + { + if( self hasperk("specialty_immuneemp") ) + return true; + } + + if ( isdefined( level.playerAvoidDamageGameMode ) && self [[ level.playerAvoidDamageGameMode ]]( iDFlags, sHitLoc, weapon, friendlyFire, attackerIsHittingSelf, sMeansOfDeath ) ) + return true; + + return false; +} + +function player_damage_log( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ) +{ + pixbeginevent( "PlayerDamage log" ); + +/# + // Do debug print if it's enabled + if(GetDvarint( "g_debugDamage")) + println("client:" + self getEntityNumber() + " health:" + self.health + " attacker:" + eAttacker.clientid + " inflictor is player:" + isPlayer(eInflictor) + " damage:" + iDamage + " hitLoc:" + sHitLoc); +#/ + + if(self.sessionstate != "dead") + { + lpselfnum = self getEntityNumber(); + lpselfname = self.name; + lpselfteam = self.team; + lpselfGuid = self getXuid(); + + if (self util::is_bot()) + { + lpselfGuid = "bot0"; + } + + lpattackerteam = ""; + lpattackerorigin = ( 0, 0, 0 ); + + if(isPlayer(eAttacker)) + { + lpattacknum = eAttacker getEntityNumber(); + lpattackGuid = eAttacker getXuid(); + + if (eAttacker util::is_bot()) + { + lpattackGuid = "bot0"; + } + + lpattackname = eAttacker.name; + lpattackerteam = eAttacker.team; + lpattackerorigin = eAttacker.origin; + isusingheropower = 0; + + if ( eAttacker ability_player::is_using_any_gadget() ) + isusingheropower = 1; + + bbPrint( "mpattacks", "gametime %d attackerspawnid %d attackerweapon %s attackerx %d attackery %d attackerz %d victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d isusingheropower %d", + gettime(), getplayerspawnid( eAttacker ), weapon.name, lpattackerorigin, getplayerspawnid( self ), self.origin, iDamage, sMeansOfDeath, sHitLoc, 0, isusingheropower ); + } + else + { + lpattacknum = -1; + lpattackGuid = ""; + lpattackname = ""; + lpattackerteam = "world"; + bbPrint( "mpattacks", "gametime %d attackerweapon %s victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d isusingheropower %d", + gettime(), weapon.name, getplayerspawnid( self ), self.origin, iDamage, sMeansOfDeath, sHitLoc, 0, 0 ); + } + logPrint("D;" + lpselfGuid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + weapon.name + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n"); + } + + pixendevent(); // "END: PlayerDamage log" +} + +function should_allow_postgame_damage( sMeansOfDeath ) +{ + if ( sMeansOfDeath == "MOD_TRIGGER_HURT" || sMeansOfDeath == "MOD_CRUSH" ) + return true; + + return false; +} + +function do_post_game_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal ) +{ + if ( game["state"] != "postgame" ) + return; + + if ( !should_allow_postgame_damage( sMeansOfDeath ) ) + return; + + // just pass it along + self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, "MOD_POST_GAME", weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal ); +} + +function Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal ) +{ + profilelog_begintiming( 6, "ship" ); + + do_post_game_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal ); + + if ( sMeansOfDeath == "MOD_CRUSH" && isdefined( eInflictor ) && ( eInflictor.deal_no_crush_damage === true ) ) + { + return; + } + + if ( isdefined( eInflictor ) && eInflictor.killstreakType === "siegebot" ) + { + if ( eInflictor.team === "neutral" ) + return; + } + + self.iDFlags = iDFlags; + self.iDFlagsTime = getTime(); + + // determine if we should treat owner damage as friendly fire + if ( !IsPlayer( eAttacker ) && isdefined( eAttacker ) && eAttacker.owner === self ) + { + treat_self_damage_as_friendly_fire = eAttacker.treat_owner_damage_as_friendly_fire; + } + + // determine if we should ignore_round_start_friendly_fire + ignore_round_start_friendly_fire = ( isdefined( eInflictor ) && ( sMeansOfDeath == "MOD_CRUSH" ) || sMeansOfDeath == "MOD_HIT_BY_OBJECT" ); + + eAttacker = figure_out_attacker( eAttacker ); + + // no damage from people who have dropped into laststand + if ( IsPlayer( eAttacker ) && ( isdefined( eAttacker.laststand ) && eAttacker.laststand ) ) + { + return; + } + + sMeansOfDeath = modify_player_damage_meansofdeath( eInflictor, eAttacker, sMeansOfDeath, weapon, sHitLoc ); + + if ( !(self should_do_player_damage( eAttacker, weapon, sMeansOfDeath, iDFlags )) ) + return; + + player_damage_update_attacker( eInflictor, eAttacker, sMeansOfDeath ); + + weapon = player_damage_figure_out_weapon( weapon, eInflictor ); + + pixbeginevent( "PlayerDamage flags/tweaks" ); + + // Don't do knockback if the damage direction was not specified + if( !isdefined( vDir ) ) + iDFlags |= 4; + + attackerIsHittingTeammate = isPlayer( eAttacker ) && ( self util::IsEnemyPlayer( eAttacker ) == false ); + attackerIsHittingSelf = IsPlayer( eAttacker ) && (self == eAttacker); + + friendlyFire = ( ( attackerIsHittingSelf && treat_self_damage_as_friendly_fire === true ) // some killstreaks treak owner damage as friendly-fire + || ( level.teamBased && !attackerIsHittingSelf && attackerIsHittingTeammate ) ); // teammates are always friendly-fire, but self is handled above + + pixendevent(); // "END: PlayerDamage flags/tweaks" + + iDamage = modify_player_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ); + if ( friendlyFire ) + { + iDamage = modify_player_damage_friendlyfire( iDamage ); + } + + if( ( isdefined( self.power_armor_took_damage ) && self.power_armor_took_damage ) ) + { + iDFlags |= 1024; + } + + if ( sHitLoc == "riotshield" ) + { + // do we want all of the damage modifiers that get applied for the player to get applied to this damage? + // or friendly fire? + player_damage_riotshield_hit( eAttacker, iDamage, sMeansOfDeath, weapon, attackerIsHittingTeammate); + } + + // check for completely getting out of the damage + if ( self does_player_completely_avoid_damage(iDFlags, sHitLoc, weapon, friendlyFire, attackerIsHittingSelf, sMeansOfDeath ) ) + { + return; + } + + // do we want this called pre or post damage application? + self callback::callback( #"on_player_damage" ); + + armor = self armor::getArmor(); + + iDamage = apply_damage_to_armor( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, sHitLoc, friendlyFire, ignore_round_start_friendly_fire ); + iDamage = make_sure_damage_is_not_zero( iDamage ); + + armor_damaged = (armor != self armor::getArmor()); + + // this must be below the damage modification functions as they use this to determine riotshield hits + if ( sHitLoc == "riotshield" ) + { + sHitLoc = "none"; // code ignores any damage to a "shield" bodypart. + } + + if ( !player_damage_update_explosive_info( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ) ) + return; + + prevHealthRatio = self.health / self.maxhealth; + + if ( friendlyFire ) + { + pixmarker( "BEGIN: PlayerDamage player" ); // profs automatically end when the function returns + + if ( player_damage_does_friendly_fire_damage_victim( ignore_round_start_friendly_fire ) ) + { + self.lastDamageWasFromEnemy = false; + + self finishPlayerDamageWrapper(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal); + } + else if ( weapon.forceDamageShellshockAndRumble ) + { + self damageShellshockAndRumble( eAttacker, eInflictor, weapon, sMeansOfDeath, iDamage ); + } + + if ( player_damage_does_friendly_fire_damage_attacker( eAttacker, ignore_round_start_friendly_fire ) ) + { + eAttacker.lastDamageWasFromEnemy = false; + + eAttacker.friendlydamage = true; + eAttacker finishPlayerDamageWrapper(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal); + eAttacker.friendlydamage = undefined; + } + + pixmarker( "END: PlayerDamage player" ); + } + else + { + behaviorTracker::UpdatePlayerDamage( eAttacker, self, iDamage ); + + self.lastAttackWeapon = weapon; + + giveAttackerAndInflictorOwnerAssist( eAttacker, eInflictor, iDamage, sMeansOfDeath, weapon ); + + if ( isdefined( eAttacker ) ) + level.lastLegitimateAttacker = eAttacker; + + if ( ( sMeansOfDeath == "MOD_GRENADE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" ) && isdefined( eInflictor ) && isdefined( eInflictor.isCooked ) ) + self.wasCooked = getTime(); + else + self.wasCooked = undefined; + + self.lastDamageWasFromEnemy = (isdefined( eAttacker ) && (eAttacker != self)); + + if ( self.lastDamageWasFromEnemy ) + { + if ( isplayer( eAttacker ) ) + { + if ( isdefined ( eAttacker.damagedPlayers[ self.clientId ] ) == false ) + eAttacker.damagedPlayers[ self.clientId ] = spawnstruct(); + + eAttacker.damagedPlayers[ self.clientId ].time = getTime(); + eAttacker.damagedPlayers[ self.clientId ].entity = self; + } + } + + if( isPlayer( eAttacker ) && isDefined(weapon.gadget_type) && weapon.gadget_type == 14 ) + { + if( isDefined(eAttacker.heroweaponHits) ) + { + eAttacker.heroweaponHits++; + } + } + + self finishPlayerDamageWrapper(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal); + } + + if ( isdefined( eAttacker ) && !attackerIsHittingSelf ) + { + if ( damagefeedback::doDamageFeedback( weapon, eInflictor, iDamage, sMeansOfDeath ) ) + { + // the perk feedback should be shown only if the enemy is damaged and not killed. + if ( iDamage > 0 && self.health > 0 ) + { + perkFeedback = doPerkFeedBack( self, weapon, sMeansOfDeath, eInflictor, armor_damaged ); + } + + eAttacker thread damagefeedback::update( sMeansOfDeath, eInflictor, perkFeedback, weapon, self, psOffsetTime, sHitLoc ); + } + } + + if( !isdefined(eAttacker) || !friendlyFire || ( isdefined( level.hardcoreMode ) && level.hardcoreMode ) ) + { + if ( isdefined( level.customPlayPainSound ) ) + self [[ level.customPlayPainSound ]]( sMeansOfDeath ); + else + self battlechatter::pain_vox( sMeansOfDeath ); + } + + self.hasDoneCombat = true; + + if( weapon.isEmp && sMeansOfDeath == "MOD_GRENADE_SPLASH" ) + { + if( !self hasperk("specialty_immuneemp") ) + { + self notify( "emp_grenaded", eAttacker, vPoint ); + } + } + + if ( isdefined( eAttacker ) && eAttacker != self && !friendlyFire ) + level.useStartSpawns = false; + + player_damage_log( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ); + + profilelog_endtiming( 6, "gs=" + game["state"] + " zom=" + SessionModeIsZombiesGame() ); +} + +function resetAttackerList() +{ + self.attackers = []; + self.attackerData = []; + self.attackerDamage = []; + self.firstTimeDamaged = 0; +} + +function resetAttackersThisSpawnList() +{ + self.attackersThisSpawn = []; +} + +function doPerkFeedBack( player, weapon, sMeansOfDeath, eInflictor, armor_damaged ) +{ + perkFeedback = undefined; + hasTacticalMask = loadout::hasTacticalMask( player ); + hasFlakJacket = ( player HasPerk( "specialty_flakjacket" ) ); + isExplosiveDamage = loadout::isExplosiveDamage( sMeansOfDeath ); + isFlashOrStunDamage = weapon_utils::isFlashOrStunDamage( weapon, sMeansOfDeath ); + + if ( isFlashOrStunDamage && hasTacticalMask ) + { + perkFeedback = "tacticalMask"; + } + else if ( player HasPerk( "specialty_fireproof" ) && loadout::isFireDamage( weapon, sMeansOfDeath ) ) + { + perkFeedback = "flakjacket"; + } + else if ( isExplosiveDamage && hasFlakJacket && !weapon.ignoresFlakJacket && ( !isAIKillstreakDamage( weapon, eInflictor ) ) ) + { + perkFeedback = "flakjacket"; + } + else if ( armor_damaged ) + { + perkFeedback = "armor"; + } + + return perkFeedback; +} + +function isAIKillstreakDamage( weapon, eInflictor ) +{ + if ( weapon.isAIKillstreakDamage ) + { + if ( weapon.name != "ai_tank_drone_rocket" || isdefined( eInflictor.firedByAI ) ) + { + return true; + } + } + + return false; +} + +function finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal ) +{ + pixbeginevent("finishPlayerDamageWrapper"); + + if( !level.console && iDFlags & 8 && isplayer ( eAttacker ) ) + { + /# + println("penetrated:" + self getEntityNumber() + " health:" + self.health + " attacker:" + eAttacker.clientid + " inflictor is player:" + isPlayer(eInflictor) + " damage:" + iDamage + " hitLoc:" + sHitLoc); + #/ + eAttacker AddPlayerStat( "penetration_shots", 1 ); + } + + if ( GetDvarString( "scr_csmode" ) != "" ) + self shellShock( "damage_mp", 0.2 ); + + if ( isdefined( level.customDamageShellshockAndRumble ) ) + self [[ level.customDamageShellshockAndRumble ]]( eAttacker, eInflictor, weapon, sMeansOfDeath, iDamage, vPoint ); + else + self damageShellshockAndRumble( eAttacker, eInflictor, weapon, sMeansOfDeath, iDamage ); + + self ability_power::power_loss_event_took_damage( eAttacker, eInflictor, weapon, sMeansOfDeath, iDamage ); + + if( isPlayer( eAttacker) ) + { + self.lastShotBy = eAttacker.clientid; + } + + if ( sMeansOfDeath == "MOD_BURNED" ) + { + self burnplayer::TakingBurnDamage( eAttacker, weapon, sMeansOfDeath ); + } + + self.gadget_was_active_last_damage = self GadgetIsActive( 0 ); + + self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal ); + + pixendevent(); +} + +function allowedAssistWeapon( weapon ) +{ + if ( !killstreaks::is_killstreak_weapon( weapon ) ) + return true; + + if (killstreaks::is_killstreak_weapon_assist_allowed( weapon ) ) + return true; + + return false; +} + +function PlayerKilled_Killstreaks( attacker, weapon ) +{ + if( !isdefined( self.switching_teams ) ) + { + // if team killed we reset kill streak, but dont count death and death streak + if ( isPlayer( attacker ) && level.teamBased && ( attacker != self ) && ( self.team == attacker.team ) ) + { + + self.pers["cur_kill_streak"] = 0; + self.pers["cur_total_kill_streak"] = 0; + self.pers["totalKillstreakCount"] = 0; + self.pers["killstreaksEarnedThisKillstreak"] = 0; + self setplayercurrentstreak( 0 ); + } + else + { + self globallogic_score::incPersStat( "deaths", 1, true, true ); + self.deaths = self globallogic_score::getPersStat( "deaths" ); + self UpdateStatRatio( "kdratio", "kills", "deaths" ); + + if( self.pers["cur_kill_streak"] > self.pers["best_kill_streak"] ) + self.pers["best_kill_streak"] = self.pers["cur_kill_streak"]; + + // need to keep the current killstreak to see if this was a buzzkill later + self.pers["kill_streak_before_death"] = self.pers["cur_kill_streak"]; + + + self.pers["cur_kill_streak"] = 0; + self.pers["cur_total_kill_streak"] = 0; + self.pers["totalKillstreakCount"] = 0; + self.pers["killstreaksEarnedThisKillstreak"] = 0; + self setplayercurrentstreak( 0 ); + + self.cur_death_streak++; + + if ( self.cur_death_streak > self.death_streak ) + { + if ( level.rankedMatch && !level.disableStatTracking ) + { + self setDStat( "HighestStats", "death_streak", self.cur_death_streak ); + } + self.death_streak = self.cur_death_streak; + } + + if( self.cur_death_streak >= GetDvarint( "perk_deathStreakCountRequired" ) ) + { + self enabledeathstreak(); + } + } + } + else + { + self.pers["totalKillstreakCount"] = 0; + self.pers["killstreaksEarnedThisKillstreak"] = 0; + } + + if ( !SessionModeIsZombiesGame() && killstreaks::is_killstreak_weapon( weapon ) ) + { + level.globalKillstreaksDeathsFrom++; + } +} + +function PlayerKilled_WeaponStats( attacker, weapon, sMeansOfDeath, wasInLastStand, lastWeaponBeforeDroppingIntoLastStand, inflictor ) +{ + // Don't increment weapon stats for team kills or deaths + if ( isPlayer( attacker ) && attacker != self && ( !level.teamBased || ( level.teamBased && self.team != attacker.team ) ) ) + { + attackerWeaponPickedUp = false; + if( isdefined( attacker.pickedUpWeapons ) && isdefined( attacker.pickedUpWeapons[weapon] ) ) + { + attackerWeaponPickedUp = true; + } + self AddWeaponStat( weapon, "deaths", 1, self.class_num, attackerWeaponPickedUp, undefined, self.primaryLoadoutGunSmithVariantIndex, self.secondaryLoadoutGunSmithVariantIndex ); + + if ( wasInLastStand && isdefined( lastWeaponBeforeDroppingIntoLastStand ) ) + victim_weapon = lastWeaponBeforeDroppingIntoLastStand; + else + victim_weapon = self.lastdroppableweapon; + + if ( isdefined( victim_weapon ) ) + { + victimWeaponPickedUp = false; + if( isdefined( self.pickedUpWeapons ) && isdefined( self.pickedUpWeapons[victim_weapon] ) ) + { + victimWeaponPickedUp = true; + } + self AddWeaponStat( victim_weapon, "deathsDuringUse", 1, self.class_num, victimWeaponPickedUp, undefined, self.primaryLoadoutGunSmithVariantIndex, self.secondaryLoadoutGunSmithVariantIndex ); + } + + + recordWeaponStatKills = true; + if ( ( attacker.isThief === true ) && isdefined( weapon ) && ( weapon.isHeroWeapon === true ) ) + { + recordWeaponStatKills = false; // Blackjack's Rogue kills are tracked as specialiststats[9].stats.kills_weapon + } + + if ( sMeansOfDeath != "MOD_FALLING" && recordWeaponStatKills ) + { + if ( weapon.name == "explosive_bolt" && IsDefined( inflictor ) && IsDefined( inflictor.ownerWeaponAtLaunch ) && inflictor.ownerAdsAtLaunch ) + { + inflictorOwnerWeaponAtLaunchPickedUp = false; + if( isdefined( attacker.pickedUpWeapons ) && isdefined( attacker.pickedUpWeapons[inflictor.ownerWeaponAtLaunch] ) ) + { + inflictorOwnerWeaponAtLaunchPickedUp = true; // ever the case? + } + attacker AddWeaponStat( inflictor.ownerWeaponAtLaunch, "kills", 1, attacker.class_num, inflictorOwnerWeaponAtLaunchPickedUp, true, attacker.primaryLoadoutGunSmithVariantIndex, attacker.secondaryLoadoutGunSmithVariantIndex ); + } + else + { + if ( isdefined( attacker ) && isdefined( attacker.class_num ) ) + attacker AddWeaponStat( weapon, "kills", 1, attacker.class_num, attackerWeaponPickedUp, undefined, attacker.primaryLoadoutGunSmithVariantIndex, attacker.secondaryLoadoutGunSmithVariantIndex ); + } + } + + if ( sMeansOfDeath == "MOD_HEAD_SHOT" ) + { + attacker AddWeaponStat( weapon, "headshots", 1, attacker.class_num, attackerWeaponPickedUp, undefined, attacker.primaryLoadoutGunSmithVariantIndex, attacker.secondaryLoadoutGunSmithVariantIndex ); + } + + if ( sMeansOfDeath == "MOD_PROJECTILE" || ( ( sMeansOfDeath == "MOD_GRENADE" || sMeansOfDeath == "MOD_IMPACT" ) && weapon.rootWeapon.statIndex == level.weaponLauncherEx41.statIndex ) ) + { + attacker AddWeaponStat( weapon, "direct_hit_kills", 1 ); + } + + victimIsRoulette = ( self.isRoulette === true ); + if ( self ability_player::gadget_CheckHeroAbilityKill( attacker ) && !victimIsRoulette ) + { + attacker AddWeaponStat( attacker.heroAbility, "kills_while_active", 1 ); + } + } +} + +function PlayerKilled_Obituary( attacker, eInflictor, weapon, sMeansOfDeath ) +{ + if ( !isplayer( attacker ) || ( self util::IsEnemyPlayer( attacker ) == false ) || ( isdefined ( weapon ) && killstreaks::is_killstreak_weapon( weapon ) ) ) + { + level notify( "reset_obituary_count" ); + level.lastObituaryPlayerCount = 0; + level.lastObituaryPlayer = undefined; + } + else + { + if ( isdefined( level.lastObituaryPlayer ) && level.lastObituaryPlayer == attacker ) + { + level.lastObituaryPlayerCount++; + } + else + { + level notify( "reset_obituary_count" ); + level.lastObituaryPlayer = attacker; + level.lastObituaryPlayerCount = 1; + } + + level thread scoreevents::decrementLastObituaryPlayerCountAfterFade(); + + if ( level.lastObituaryPlayerCount >= 4 ) + { + level notify( "reset_obituary_count" ); + level.lastObituaryPlayerCount = 0; + level.lastObituaryPlayer = undefined; + self thread scoreevents::uninterruptedObitFeedKills( attacker, weapon ); + } + } + + if ( !isplayer( attacker ) || ( isdefined( weapon ) && !killstreaks::is_killstreak_weapon( weapon ) ) ) + { + behaviorTracker::UpdatePlayerKilled( attacker, self ); + } + + overrideEntityCamera = killstreaks::should_override_entity_camera_in_demo( attacker, weapon ); + + if( isdefined( eInflictor ) && ( eInflictor.archetype === "robot" ) ) + { + if( sMeansOfDeath == "MOD_HIT_BY_OBJECT" ) + weapon = GetWeapon( "combat_robot_marker" ); + sMeansOfDeath = "MOD_RIFLE_BULLET"; + } + // send out an obituary message to all clients about the kill + if( level.teamBased && isdefined( attacker.pers ) && self.team == attacker.team && sMeansOfDeath == "MOD_GRENADE" && level.friendlyfire == 0 ) + { + obituary(self, self, weapon, sMeansOfDeath); + demo::bookmark( "kill", gettime(), self, self, 0, eInflictor, overrideEntityCamera ); + } + else + { + obituary(self, attacker, weapon, sMeansOfDeath); + demo::bookmark( "kill", gettime(), attacker, self, 0, eInflictor, overrideEntityCamera ); + } +} + +function PlayerKilled_Suicide( eInflictor, attacker, sMeansOfDeath, weapon, sHitLoc ) +{ + awardAssists = false; + self.suicide = false; + + // switching teams + if ( isdefined( self.switching_teams ) ) + { + + if ( !level.teamBased && ( isdefined( level.teams[ self.leaving_team ] ) && isdefined( level.teams[ self.joining_team ] ) && level.teams[ self.leaving_team ] != level.teams[ self.joining_team ] ) ) + { + playerCounts = self teams::count_players(); + playerCounts[self.leaving_team]--; + playerCounts[self.joining_team]++; + + if( (playerCounts[self.joining_team] - playerCounts[self.leaving_team]) > 1 ) + { + scoreevents::processScoreEvent( "suicide", self ); + self thread rank::giveRankXP( "suicide" ); + self globallogic_score::incPersStat( "suicides", 1 ); + self.suicides = self globallogic_score::getPersStat( "suicides" ); + self.suicide = true; + } + } + } + else + { + scoreevents::processScoreEvent( "suicide", self ); + self globallogic_score::incPersStat( "suicides", 1 ); + self.suicides = self globallogic_score::getPersStat( "suicides" ); + + if ( sMeansOfDeath == "MOD_SUICIDE" && sHitLoc == "none" && self.throwingGrenade ) + { + self.lastGrenadeSuicideTime = gettime(); + } + + if ( level.maxSuicidesBeforeKick > 0 && level.maxSuicidesBeforeKick <= self.suicides ) + { + // should change "teamKillKicked" to just kicked for the next game + self notify( "teamKillKicked" ); + self SuicideKick(); + } + + //Check for player death related battlechatter + thread battlechatter::on_player_suicide_or_team_kill( self, "suicide" ); //Play suicide battlechatter + + //check if assist points should be awarded + awardAssists = true; + self.suicide = true; + } + + if( isdefined( self.friendlydamage ) ) + { + self iPrintLn(&"MP_FRIENDLY_FIRE_WILL_NOT"); + if ( level.teamKillPointLoss ) + { + scoreSub = self [[level.getTeamKillScore]]( eInflictor, attacker, sMeansOfDeath, weapon); + + score = globallogic_score::_getPlayerScore( attacker ) - scoreSub; + + if ( score < 0 ) + score = 0; + + globallogic_score::_setPlayerScore( attacker, score ); + } + } + + return awardAssists; +} + +function PlayerKilled_TeamKill( eInflictor, attacker, sMeansOfDeath, weapon, sHitLoc ) +{ + scoreevents::processScoreEvent( "team_kill", attacker ); + + self.teamKilled = true; + + if ( !IgnoreTeamKills( weapon, sMeansOfDeath, eInflictor ) ) + { + teamkill_penalty = self [[level.getTeamKillPenalty]]( eInflictor, attacker, sMeansOfDeath, weapon); + + attacker globallogic_score::incPersStat( "teamkills_nostats", teamkill_penalty, false ); + attacker globallogic_score::incPersStat( "teamkills", 1 ); //save team kills to player stats + attacker.teamkillsThisRound++; + + if ( level.teamKillPointLoss ) + { + scoreSub = self [[level.getTeamKillScore]]( eInflictor, attacker, sMeansOfDeath, weapon); + + score = globallogic_score::_getPlayerScore( attacker ) - scoreSub; + + if ( score < 0 ) + { + score = 0; + } + + globallogic_score::_setPlayerScore( attacker, score ); + } + + if ( globallogic_utils::getTimePassed() < 5000 ) + teamKillDelay = 1; + else if ( attacker.pers["teamkills_nostats"] > 1 && globallogic_utils::getTimePassed() < (8000 + (attacker.pers["teamkills_nostats"] * 1000)) ) + teamKillDelay = 1; + else + teamKillDelay = attacker TeamKillDelay(); + + if ( teamKillDelay > 0 ) + { + attacker.teamKillPunish = true; + attacker thread wait_and_suicide(); // can't eject the teamkilling player same frame bc it purges EV_FIRE_WEAPON fx + + if ( attacker ShouldTeamKillKick(teamKillDelay) ) + { + // should change "teamKillKicked" to just kicked for the next game + attacker notify( "teamKillKicked" ); + attacker thread TeamKillKick(); + } + + attacker thread reduceTeamKillsOverTime(); + } + + //Play teamkill battlechatter + if( isPlayer( attacker ) ) + thread battlechatter::on_player_suicide_or_team_kill( attacker, "teamkill" ); + } +} + +function wait_and_suicide() // self == player +{ + self endon( "disconnect" ); + self util::freeze_player_controls( true ); + + wait .25; + + self suicide(); +} + +function PlayerKilled_AwardAssists( eInflictor, attacker, weapon, lpattackteam ) +{ + pixbeginevent( "PlayerKilled assists" ); + + if ( isdefined( self.attackers ) ) + { + for ( j = 0; j < self.attackers.size; j++ ) + { + player = self.attackers[j]; + + if ( !isdefined( player ) ) + continue; + + if ( player == attacker ) + continue; + + if ( player.team != lpattackteam ) + continue; + + damage_done = self.attackerDamage[player.clientId].damage; + player thread globallogic_score::processAssist( self, damage_done, self.attackerDamage[player.clientId].weapon ); + } + } + + if ( level.teamBased ) + { + self globallogic_score::processKillstreakAssists( attacker, eInflictor, weapon ); + } + + if ( isdefined( self.lastAttackedShieldPlayer ) && isdefined( self.lastAttackedShieldTime ) && self.lastAttackedShieldPlayer != attacker ) + { + if ( gettime() - self.lastAttackedShieldTime < 4000 ) + { + self.lastAttackedShieldPlayer thread globallogic_score::processShieldAssist( self ); + } + } + + pixendevent(); //"END: PlayerKilled assists" +} + +function PlayerKilled_Kill( eInflictor, attacker, sMeansOfDeath, weapon, sHitLoc ) +{ + if( !isdefined( killstreaks::get_killstreak_for_weapon( weapon ) ) || ( isdefined( level.killstreaksGiveGameScore ) && level.killstreaksGiveGameScore ) ) + globallogic_score::incTotalKills(attacker.team); + + if( GetDvarInt( "teamOpsEnabled" ) == 1 ) + { + if( isdefined( eInflictor ) && ( isdefined( eInflictor.teamops ) && eInflictor.teamops ) ) + { + if( !isdefined( killstreaks::get_killstreak_for_weapon( weapon ) ) || ( isdefined( level.killstreaksGiveGameScore ) && level.killstreaksGiveGameScore ) ) + globallogic_score::giveTeamScore( "kill", attacker.team, undefined, self ); + return; + } + } + + attacker thread globallogic_score::giveKillStats( sMeansOfDeath, weapon, self ); + + + if ( isAlive( attacker ) ) + { + pixbeginevent("killstreak"); + + if ( !isdefined( eInflictor ) || !isdefined( eInflictor.requiredDeathCount ) || attacker.deathCount == eInflictor.requiredDeathCount ) + { + shouldGiveKillstreak = killstreaks::should_give_killstreak( weapon ); + //attacker thread _properks::earnedAKill(); + + if ( shouldGiveKillstreak ) + { + attacker killstreaks::add_to_killstreak_count( weapon ); + } + + attacker.pers["cur_total_kill_streak"]++; + attacker setplayercurrentstreak( attacker.pers["cur_total_kill_streak"] ); + + //Kills gotten through killstreak weapons should not the players killstreak + if ( isdefined( level.killstreaks ) && shouldGiveKillstreak ) + { + attacker.pers["cur_kill_streak"]++; + + if ( attacker.pers["cur_kill_streak"] >= 2 ) + { + if ( attacker.pers["cur_kill_streak"] == 10 ) + { + attacker challenges::killstreakTen(); + } + if ( attacker.pers["cur_kill_streak"] <= 30 ) + { + scoreevents::processScoreEvent( "killstreak_" + attacker.pers["cur_kill_streak"], attacker, self, weapon ); + + if ( attacker.pers["cur_kill_streak"] == 30 ) + { + attacker challenges::killstreak_30_noscorestreaks(); + } + } + else + { + scoreevents::processScoreEvent( "killstreak_more_than_30", attacker, self, weapon ); + } + } + + if ( !isdefined( level.usingMomentum ) || !level.usingMomentum ) + { + if( GetDvarInt( "teamOpsEnabled" ) == 0 ) + attacker thread killstreaks::give_for_streak(); + } + } + } + + pixendevent(); // "killstreak" + } + + if ( attacker.pers["cur_kill_streak"] > attacker.kill_streak ) + { + if ( level.rankedMatch && !level.disableStatTracking ) + { + attacker setDStat( "HighestStats", "kill_streak", attacker.pers["totalKillstreakCount"] ); + } + attacker.kill_streak = attacker.pers["cur_kill_streak"]; + } + + + if ( attacker.pers["cur_kill_streak"] > attacker.gametype_kill_streak ) + { + attacker persistence::stat_set_with_gametype( "kill_streak", attacker.pers["cur_kill_streak"] ); + attacker.gametype_kill_streak = attacker.pers["cur_kill_streak"]; + } + + killstreak = killstreaks::get_killstreak_for_weapon( weapon ); + + if ( isdefined( killstreak ) ) + { + if ( scoreevents::isRegisteredEvent( killstreak ) ) + { + scoreevents::processScoreEvent( killstreak, attacker, self, weapon ); + } + + if( isdefined( eInflictor ) && ( killstreak == "dart" || killstreak == "inventory_dart" ) ) + { + eInflictor notify( "veh_collision" ); + } + } + else + { + scoreevents::processScoreEvent( "kill", attacker, self, weapon ); + + // if ( sMeansOfDeath == "MOD_HEAD_SHOT" || ( sMeansOfDeath == "MOD_IMPACT" && sHitLoc == "head" ) ) // TODO: add back when applicable LOOT6 weapon is ready + if ( sMeansOfDeath == "MOD_HEAD_SHOT" ) + { + scoreevents::processScoreEvent( "headshot", attacker, self, weapon ); + attacker util::player_contract_event( "headshot" ); + } + else if ( weapon_utils::isMeleeMOD( sMeansOfDeath ) ) + { + scoreevents::processScoreEvent( "melee_kill", attacker, self, weapon ); + } + } + + attacker thread globallogic_score::trackAttackerKill( self.name, self.pers["rank"], self.pers["rankxp"], self.pers["prestige"], self getXuid(), weapon ); + + attackerName = attacker.name; + self thread globallogic_score::trackAttackeeDeath( attackerName, attacker.pers["rank"], attacker.pers["rankxp"], attacker.pers["prestige"], attacker getXuid() ); + self thread medals::setLastKilledBy( attacker ); + + attacker thread globallogic_score::incKillstreakTracker( weapon ); + + // to prevent spectator gain score for team-spectator after throwing a granade and killing someone before he switched + if ( level.teamBased && attacker.team != "spectator") + { + if( !isdefined( killstreak ) || ( isdefined( level.killstreaksGiveGameScore ) && level.killstreaksGiveGameScore ) ) + globallogic_score::giveTeamScore( "kill", attacker.team, attacker, self ); + } + + scoreSub = level.deathPointLoss; + if ( scoreSub != 0 ) + { + globallogic_score::_setPlayerScore( self, globallogic_score::_getPlayerScore( self ) - scoreSub ); + } + + level thread playKillBattleChatter( attacker, weapon, self, eInflictor ); +} + +function should_allow_postgame_death( sMeansOfDeath ) +{ + if ( sMeansOfDeath == "MOD_POST_GAME" ) + return true; + + return false; +} + +function do_post_game_death(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration) +{ + if ( !should_allow_postgame_death( sMeansOfDeath ) ) + return; + + self weapons::detach_carry_object_model(); + + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + + clone_weapon = weapon; + + // we do not want the weapon death fx to play if this is not a melee weapon and its a melee attack + // ideally the mod be passed to the client side and let it decide but this is post ship t7 and this is safest + if ( weapon_utils::isMeleeMOD(sMeansOfDeath) && clone_weapon.type != "melee" ) + { + clone_weapon = level.weaponNone; + } + body = self clonePlayer( deathAnimDuration, clone_weapon, attacker ); + + if ( isdefined( body ) ) + { + self createDeadBody( attacker, iDamage, sMeansOfDeath, weapon, sHitLoc, vDir, (0,0,0), deathAnimDuration, eInflictor, body ); + } +} + +function Callback_PlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, enteredResurrect = false) +{ + profilelog_begintiming( 7, "ship" ); + + self endon( "spawned" ); + + + if ( game["state"] == "postgame" ) + { + do_post_game_death(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration); + return; + } + + if ( self.sessionteam == "spectator" ) + return; + + self notify( "killed_player" ); + self callback::callback( #"on_player_killed" ); + + self needsRevive( false ); + + if ( isdefined( self.burning ) && self.burning == true ) + { + self setburn( 0 ); + } + + self.suicide = false; + self.teamKilled = false; + + if ( isdefined( level.takeLivesOnDeath ) && ( level.takeLivesOnDeath == true ) ) + { + if ( self.pers["lives"] ) + { + self.pers["lives"]--; + if ( self.pers["lives"] == 0 ) + { + level notify( "player_eliminated" ); + self notify( "player_eliminated" ); + } + } + if ( game[self.team + "_lives"] ) + { + game[self.team + "_lives"]--; + if ( game[self.team + "_lives"] == 0 ) + { + level notify( "player_eliminated" ); + self notify( "player_eliminated" ); + } + } + } + + self thread globallogic_audio::flush_leader_dialog_key_on_player( "equipmentDestroyed" ); + //self thread globallogic_audio::flush_leader_dialog_key_on_player( "equipmentHacked" ); + + weapon = updateWeapon( eInflictor, weapon ); + + pixbeginevent( "PlayerKilled pre constants" ); + + wasInLastStand = false; + bledOut = false; + deathTimeOffset = 0; + lastWeaponBeforeDroppingIntoLastStand = undefined; + attackerStance = undefined; + self.lastStandThisLife = undefined; + self.vAttackerOrigin = undefined; + + // need to get this before changing the sessionstate + weapon_at_time_of_death = self GetCurrentWeapon(); + + if ( isdefined( self.useLastStandParams ) && enteredResurrect == false ) + { + self.useLastStandParams = undefined; + + assert( isdefined( self.lastStandParams ) ); + if ( !level.teamBased || ( !isdefined( attacker ) || !isplayer( attacker ) || attacker.team != self.team || attacker == self ) ) + { + eInflictor = self.lastStandParams.eInflictor; + attacker = self.lastStandParams.attacker; + attackerStance = self.lastStandParams.attackerStance; + iDamage = self.lastStandParams.iDamage; + sMeansOfDeath = self.lastStandParams.sMeansOfDeath; + weapon = self.lastStandParams.sWeapon; + vDir = self.lastStandParams.vDir; + sHitLoc = self.lastStandParams.sHitLoc; + self.vAttackerOrigin = self.lastStandParams.vAttackerOrigin; + self.killcam_entity_info_cached = self.lastStandParams.killcam_entity_info_cached; + deathTimeOffset = (gettime() - self.lastStandParams.lastStandStartTime) / 1000; + bledOut = true; + if ( isdefined( self.previousPrimary ) ) + { + wasInLastStand = true; + lastWeaponBeforeDroppingIntoLastStand = self.previousPrimary; + } + } + self.lastStandParams = undefined; + } + + self StopSounds(); + + bestPlayer = undefined; + bestPlayerMeansOfDeath = undefined; + obituaryMeansOfDeath = undefined; + bestPlayerWeapon = undefined; + obituaryWeapon = weapon; + assistedSuicide = false; + + if ( isdefined( level.gameModeAssistedSuicide ) ) + { + result = self [[ level.gameModeAssistedSuicide ]]( attacker, sMeansOfDeath, weapon ); + if ( isdefined( result ) ) + { + bestPlayer = result["bestPlayer"]; + bestPlayerMeansOfDeath = result["bestPlayerMeansOfDeath"]; + bestPlayerWeapon = result["bestPlayerWeapon"]; + } + } + + if ( (!isdefined( attacker ) || attacker.classname == "trigger_hurt" || attacker.classname == "worldspawn" || ( isdefined( attacker.isMagicBullet ) && attacker.isMagicBullet == true ) || attacker == self ) && isdefined( self.attackers ) && !self IsPlayerUnderwater() ) + { + if ( !isdefined(bestPlayer) ) + { + for ( i = 0; i < self.attackers.size; i++ ) + { + player = self.attackers[i]; + if ( !isdefined( player ) ) + continue; + + if (!isdefined( self.attackerDamage[ player.clientId ] ) || ! isdefined( self.attackerDamage[ player.clientId ].damage ) ) + continue; + + if ( player == self || (level.teamBased && player.team == self.team ) ) + continue; + + if ( self.attackerDamage[ player.clientId ].lasttimedamaged + 2500 < getTime() ) + continue; + + if ( !allowedAssistWeapon( self.attackerDamage[ player.clientId ].weapon ) ) + continue; + + if ( self.attackerDamage[ player.clientId ].damage > 1 && ! isdefined( bestPlayer ) ) + { + bestPlayer = player; + bestPlayerMeansOfDeath = self.attackerDamage[ player.clientId ].meansOfDeath; + bestPlayerWeapon = self.attackerDamage[ player.clientId ].weapon; + } + else if ( isdefined( bestPlayer ) && self.attackerDamage[ player.clientId ].damage > self.attackerDamage[ bestPlayer.clientId ].damage ) + { + bestPlayer = player; + bestPlayerMeansOfDeath = self.attackerDamage[ player.clientId ].meansOfDeath; + bestPlayerWeapon = self.attackerDamage[ player.clientId ].weapon; + } + } + } + if ( isdefined ( bestPlayer ) ) + { + scoreevents::processScoreEvent( "assisted_suicide", bestPlayer, self, weapon ); + self RecordKillModifier("assistedsuicide"); + assistedSuicide = true; + } + } + + if ( isdefined ( bestPlayer ) ) + { + attacker = bestPlayer; + obituaryMeansOfDeath = bestPlayerMeansOfDeath; + obituaryWeapon = bestPlayerWeapon; + if ( isdefined( bestPlayerWeapon ) ) + { + weapon = bestPlayerWeapon; + } + } + + if ( isplayer( attacker ) && isdefined( attacker.damagedPlayers ) ) + attacker.damagedPlayers[self.clientid] = undefined; + + if ( enteredResurrect == false ) + { + globallogic::DoWeaponSpecificKillEffects(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime); + } + + self.deathTime = getTime(); + + if ( attacker != self && (!level.teamBased || attacker.team != self.team )) + { + assert( IsDefined( self.lastspawntime ) ); + self.aliveTimes[self.aliveTimeCurrentIndex] = self.deathTime - self.lastspawntime; + self.aliveTimeCurrentIndex = (self.aliveTimeCurrentIndex + 1) % level.aliveTimeMaxCount; + } + + attacker = updateAttacker( attacker, weapon ); + eInflictor = updateInflictor( eInflictor ); + + sMeansOfDeath = self PlayerKilled_UpdateMeansOfDeath( attacker, eInflictor, weapon, sMeansOfDeath, sHitLoc ); + + if ( !isdefined( obituaryMeansOfDeath ) ) + obituaryMeansOfDeath = sMeansOfDeath; + + self.hasRiotShield = false; + self.hasRiotShieldEquipped = false; + + self thread updateGlobalBotKilledCounter(); + + self PlayerKilled_WeaponStats( attacker, weapon, sMeansOfDeath, wasInLastStand, lastWeaponBeforeDroppingIntoLastStand, eInflictor ); + + if ( bledOut == false ) + { + if( GetDvarInt( "teamOpsEnabled" ) == 1 && ( isdefined( eInflictor ) && ( isdefined( eInflictor.teamops ) && eInflictor.teamops ) ) ) + { + self PlayerKilled_Obituary( eInflictor, eInflictor, obituaryWeapon, obituaryMeansOfDeath ); + } + else + { + self PlayerKilled_Obituary( attacker, eInflictor, obituaryWeapon, obituaryMeansOfDeath ); + } + } + + if ( enteredResurrect == false ) + { +// spawnlogic::death_occured(self, attacker); + + self.sessionstate = "dead"; + self.statusicon = "hud_status_dead"; + } + + self.pers["weapon"] = undefined; + + self.killedPlayersCurrent = []; + + self.deathCount++; + +/# + println( "players("+self.clientId+") death count ++: " + self.deathCount ); +#/ + + if ( bledout == false ) + { + self PlayerKilled_Killstreaks( attacker, weapon ); + } + + lpselfnum = self getEntityNumber(); + lpselfname = self.name; + lpattackGuid = ""; + lpattackname = ""; + lpselfteam = self.team; + lpselfguid = self getXuid(); + + if (self util::is_bot()) + { + lpselfGuid = "bot0"; + } + + lpattackteam = ""; + lpattackorigin = ( 0, 0, 0 ); + + lpattacknum = -1; + + //check if we should award assist points + awardAssists = false; + wasTeamKill = false; + wasSuicide = false; + + pixendevent(); // "PlayerKilled pre constants" ); + + scoreevents::processScoreEvent( "death", self, self, weapon ); + self.pers["resetMomentumOnSpawn"] = level.scoreResetOnDeath; + + + if( isPlayer( attacker ) ) + { + lpattackGuid = attacker getXuid(); + + if (attacker util::is_bot()) + { + lpattackGuid = "bot0"; + } + + lpattackname = attacker.name; + lpattackteam = attacker.team; + lpattackorigin = attacker.origin; + + if ( attacker == self || assistedSuicide == true ) // killed himself + { + doKillcam = false; + wasSuicide = true; + + awardAssists = self PlayerKilled_Suicide( eInflictor, attacker, sMeansOfDeath, weapon, sHitLoc ); + if( assistedSuicide == true ) + attacker thread globallogic_score::giveKillStats( sMeansOfDeath, weapon, self ); + } + else + { + pixbeginevent( "PlayerKilled attacker" ); + + lpattacknum = attacker getEntityNumber(); + + doKillcam = true; + + if ( level.teamBased && self.team == attacker.team && sMeansOfDeath == "MOD_GRENADE" && level.friendlyfire == 0 ) + { + } + else if ( level.teamBased && self.team == attacker.team ) // killed by a friendly + { + wasTeamKill = true; + + self PlayerKilled_TeamKill( eInflictor, attacker, sMeansOfDeath, weapon, sHitLoc ); + } + else + { + if ( bledOut == false ) + { + self PlayerKilled_Kill( eInflictor, attacker, sMeansOfDeath, weapon, sHitLoc ); + + if ( level.teamBased ) + { + //check if assist points should be awarded + awardAssists = true; + } + } + } + + pixendevent(); //"PlayerKilled attacker" + } + } + else if ( isdefined( attacker ) && ( attacker.classname == "trigger_hurt" || attacker.classname == "worldspawn" ) ) + { + doKillcam = false; + + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackteam = "world"; + + scoreevents::processScoreEvent( "suicide", self ); + self globallogic_score::incPersStat( "suicides", 1 ); + self.suicides = self globallogic_score::getPersStat( "suicides" ); + + self.suicide = true; + + //Check for player death related battlechatter + thread battlechatter::on_player_suicide_or_team_kill( self, "suicide" ); //Play suicide battlechatter + + //check if assist points should be awarded + awardAssists = true; + + if ( level.maxSuicidesBeforeKick > 0 && level.maxSuicidesBeforeKick <= self.suicides ) + { + // should change "teamKillKicked" to just kicked for the next game + self notify( "teamKillKicked" ); + self SuicideKick(); + } + } + else + { + doKillcam = false; + + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackteam = "world"; + + wasSuicide = true; + + // we may have a killcam on an world entity like the rocket in cosmodrome + if ( isdefined( eInflictor ) && isdefined( eInflictor.killCamEnt ) ) + { + doKillcam = true; + lpattacknum = self getEntityNumber(); + wasSuicide = false; + } + + // even if the attacker isn't a player, it might be on a team + if ( isdefined( attacker ) && isdefined( attacker.team ) && ( isdefined( level.teams[attacker.team] ) ) ) + { + if ( attacker.team != self.team ) + { + if ( level.teamBased ) + { + if( !isdefined( killstreaks::get_killstreak_for_weapon( weapon ) ) || ( isdefined( level.killstreaksGiveGameScore ) && level.killstreaksGiveGameScore ) ) + globallogic_score::giveTeamScore( "kill", attacker.team, attacker, self ); + } + + wasSuicide = false; + } + } + + //check if assist points should be awarded + awardAssists = true; + } + + if ( !level.inGracePeriod && enteredResurrect == false ) + { + if ( sMeansOfDeath != "MOD_GRENADE" && sMeansOfDeath != "MOD_GRENADE_SPLASH" && sMeansOfDeath != "MOD_EXPLOSIVE" && sMeansOfDeath != "MOD_EXPLOSIVE_SPLASH" && sMeansOfDeath != "MOD_PROJECTILE_SPLASH" && sMeansOfDeath != "MOD_FALLING" ) + { + if ( weapon.name != "incendiary_fire" ) + { + self weapons::drop_scavenger_for_death( attacker ); + } + } + + if ( should_drop_weapon_on_death( wasTeamkill, wasSuicide, weapon_at_time_of_death, sMeansOfDeath ) ) + { + self weapons::drop_for_death( attacker, weapon, sMeansOfDeath ); + } + } + + //award assist points if needed + if( awardAssists ) + { + self PlayerKilled_AwardAssists( eInflictor, attacker, weapon, lpattackteam ); + } + + pixbeginevent( "PlayerKilled post constants" ); + + self.lastAttacker = attacker; + self.lastDeathPos = self.origin; + + if ( isdefined( attacker ) && isPlayer( attacker ) && attacker != self && (!level.teambased || attacker.team != self.team) ) + { + attacker notify( "killed_enemy_player", self, weapon ); + if( isDefined( attacker.gadget_thief_kill_callback ) ) + { + attacker [[attacker.gadget_thief_kill_callback]]( self, weapon ); + } + self thread challenges::playerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, sHitLoc, attackerStance, bledOut ); + } + else + { + + self notify("playerKilledChallengesProcessed"); + } + + if ( isdefined ( self.attackers )) + self.attackers = []; + + + // minimize repeat checks of things like isPlayer + killerHeroPowerActive = 0; + killer = undefined; + killerLoadoutIndex = -1; + killerWasADS = false; + killerInVictimFOV = false; + victimInKillerFOV = false; + + if( isPlayer( attacker ) ) + { + attacker.lastKillTime = gettime(); + + killer = attacker; + if ( isdefined( attacker.class_num ) ) + killerLoadoutIndex = attacker.class_num; + killerWasADS = attacker playerADS() >= 1; + + killerInVictimFOV = util::within_fov( self.origin, self.angles, attacker.origin, self.fovcosine ); + victimInKillerFOV = util::within_fov( attacker.origin, attacker.angles, self.origin, attacker.fovcosine ); + + if ( attacker ability_player::is_using_any_gadget() ) + killerHeroPowerActive = 1; + + if( killstreaks::is_killstreak_weapon( weapon ) ) + { + killstreak = killstreaks::get_killstreak_for_weapon_for_stats( weapon ); + + bbPrint( "mpattacks", "gametime %d attackerspawnid %d attackerweapon %s attackerx %d attackery %d attackerz %d victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d isusingheropower %d killstreak %s", + gettime(), getplayerspawnid( attacker ), weapon.name, lpattackorigin, getplayerspawnid( self ), self.origin, iDamage, sMeansOfDeath, sHitLoc, 1, killerHeroPowerActive, killstreak ); + } + else + { + bbPrint( "mpattacks", "gametime %d attackerspawnid %d attackerweapon %s attackerx %d attackery %d attackerz %d victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d isusingheropower %d", + gettime(), getplayerspawnid( attacker ), weapon.name, lpattackorigin, getplayerspawnid( self ), self.origin, iDamage, sMeansOfDeath, sHitLoc, 1, killerHeroPowerActive ); + } + + attacker thread weapons::bestweapon_kill( weapon ); + } + else + { + bbPrint( "mpattacks", "gametime %d attackerweapon %s victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d isusingheropower %d", + gettime(), weapon.name, getplayerspawnid( self ), self.origin, iDamage, sMeansOfDeath, sHitLoc, 1, 0 ); + } + + victimWeapon = undefined; + victimWeaponPickedUp = false; + victimKillstreakWeaponIndex = 0; + if( isdefined( weapon_at_time_of_death ) ) + { + victimWeapon = weapon_at_time_of_death; + if( isdefined( self.pickedUpWeapons ) && isdefined( self.pickedUpWeapons[victimWeapon] ) ) + { + victimWeaponPickedUp = true; + } + + if( killstreaks::is_killstreak_weapon( victimWeapon ) ) + { + killstreak = killstreaks::get_killstreak_for_weapon_for_stats( victimWeapon ); + if( isdefined( level.killstreaks[killstreak].menuname ) ) + { + victimKillstreakWeaponIndex = level.killstreakindices[level.killstreaks[killstreak].menuname]; + } + } + } + victimWasADS = self playerADS() >= 1; + victimHeroPowerActive = self ability_player::is_using_any_gadget(); + + killerWeaponPickedUp = false; + killerKillstreakWeaponIndex = 0; + killerKillstreakEventIndex = 125; // 125 = not a killstreak + if( isdefined( weapon ) ) + { + if( isdefined( killer ) && isdefined( killer.pickedUpWeapons ) && isdefined( killer.pickedUpWeapons[weapon] ) ) + { + killerWeaponPickedUp = true; + } + + if( killstreaks::is_killstreak_weapon( weapon ) ) + { + killstreak = killstreaks::get_killstreak_for_weapon_for_stats( weapon ); + if( isdefined( level.killstreaks[killstreak].menuname ) ) + { + killerKillstreakWeaponIndex = level.killstreakindices[level.killstreaks[killstreak].menuname]; + + if( isdefined( killer.killstreakEvents ) && isdefined( killer.killstreakEvents[ killerkillstreakweaponindex ] ) ) + { + killerKillstreakEventIndex = killer.killstreakEvents[killerkillstreakweaponindex]; + } + else + { + killerkillstreakeventindex = 126; // 126 = was a killstreak but no event index + } + } + } + } + + // + // Log additional stuff in match record on death. + // Mostly values we can't easily access in the existing MatchRecordDeath function in code. + // + + matchRecordLogAdditionalDeathInfo( self, killer, victimWeapon, weapon, + self.class_num, victimWeaponPickedUp, victimWasADS, + killerLoadoutIndex, killerWeaponPickedUp, killerWasADS, + victimHeroPowerActive, killerHeroPowerActive, + victimInKillerFOV, killerInVictimFOV, + killerKillstreakWeaponIndex, victimKillstreakWeaponIndex, + killerkillstreakeventindex); + + + self record_special_move_data_for_life( killer ); + + self.pickedUpWeapons = []; // reset on each death + + + logPrint( "K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackteam + ";" + lpattackname + ";" + weapon.name + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" ); + attackerString = "none"; + if ( isPlayer( attacker ) ) // attacker can be the worldspawn if it's not a player + attackerString = attacker getXuid() + "(" + lpattackname + ")"; + /#print( "d " + sMeansOfDeath + "(" + weapon.name + ") a:" + attackerString + " d:" + iDamage + " l:" + sHitLoc + " @ " + int( self.origin[0] ) + " " + int( self.origin[1] ) + " " + int( self.origin[2] ) );#/ + + // for cod caster update the top scorers + if ( !level.rankedMatch && !level.teambased ) + { + level thread update_ffa_top_scorers(); + } + + level thread globallogic::updateTeamStatus(); + level thread globallogic::updateAliveTimes(self.team); + + if ( isdefined( self.killcam_entity_info_cached ) ) + { + killcam_entity_info = self.killcam_entity_info_cached; + self.killcam_entity_info_cached = undefined; + } + else + { + killcam_entity_info = killcam::get_killcam_entity_info( attacker, eInflictor, weapon ); + } + + + // no killcam if the player is still involved with a killstreak + if ( isdefined( self.killstreak_delay_killcam ) ) + doKillcam = false; + + self weapons::detach_carry_object_model(); + + pixendevent(); //"END: PlayerKilled post constants" + + pixbeginevent( "PlayerKilled body and gibbing" ); + vAttackerOrigin = undefined; + if ( isdefined( attacker ) ) + { + vAttackerOrigin = attacker.origin; + } + + if ( enteredResurrect == false ) + { + clone_weapon = weapon; + + // we do not want the weapon death fx to play if this is not a melee weapon and its a melee attack + // ideally the mod be passed to the client side and let it decide but this is post ship t7 and this is safest + if ( weapon_utils::isMeleeMOD(sMeansOfDeath) && clone_weapon.type != "melee" ) + { + clone_weapon = level.weaponNone; + } + body = self clonePlayer( deathAnimDuration, clone_weapon, attacker ); + + if ( isdefined( body ) ) + { + self createDeadBody( attacker, iDamage, sMeansOfDeath, weapon, sHitLoc, vDir, vAttackerOrigin, deathAnimDuration, eInflictor, body ); + + if ( isdefined( level.customPlayDeathSound ) ) + self [[ level.customPlayDeathSound ]]( body, attacker, weapon, sMeansOfDeath ); + else + self battlechatter::play_death_vox( body, attacker, weapon, sMeansOfDeath ); + + globallogic::DoWeaponSpecificCorpseEffects(body, eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime); + } + } + + + pixendevent();// "END: PlayerKilled body and gibbing" + + if ( enteredResurrect ) + { + thread globallogic_spawn::spawnQueuedClient( self.team, attacker ); + } + + self.switching_teams = undefined; + self.joining_team = undefined; + self.leaving_team = undefined; + + if ( bledOut == false ) // handled in PlayerLastStand + { + self thread [[level.onPlayerKilled]](eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration); + } + + if ( isdefined( level.teamopsOnPlayerKilled ) ) + { + self [[level.teamopsOnPlayerKilled]]( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration); + } + + for ( iCB = 0; iCB < level.onPlayerKilledExtraUnthreadedCBs.size; iCB++ ) + { + self [[ level.onPlayerKilledExtraUnthreadedCBs[ iCB ] ]]( + eInflictor, + attacker, + iDamage, + sMeansOfDeath, + weapon, + vDir, + sHitLoc, + psOffsetTime, + deathAnimDuration ); + } + + self.wantSafeSpawn = false; + perks = []; + // perks = globallogic::getPerks( attacker ); + killstreaks = globallogic::getKillstreaks( attacker ); + + if( !isdefined( self.killstreak_delay_killcam ) ) + { + // start the prediction now so the client gets updates while waiting to spawn + self thread [[level.spawnPlayerPrediction]](); + } + + profilelog_endtiming( 7, "gs=" + game["state"] + " zom=" + SessionModeIsZombiesGame() ); + + // record the kill cam values for the final kill cam + if ( wasTeamKill == false && assistedSuicide == false && sMeansOfDeath != "MOD_SUICIDE" && !( !isdefined( attacker ) || attacker.classname == "trigger_hurt" || attacker.classname == "worldspawn" || attacker == self || isdefined ( attacker.disableFinalKillcam ) ) ) + { + level thread killcam::record_settings( lpattacknum, self getEntityNumber(), weapon, sMeansOfDeath, self.deathTime, deathTimeOffset, psOffsetTime, killcam_entity_info, perks, killstreaks, attacker ); + } + if ( enteredResurrect ) + { + return; + } + + // let the player watch themselves die + wait ( 0.25 ); + + //check if killed by a sniper + weaponClass = util::getWeaponClass( weapon ); + if( isdefined( weaponClass ) && weaponClass == "weapon_sniper" ) + { + self thread battlechatter::killed_by_sniper( attacker ); + } + else + { + self thread battlechatter::player_killed( attacker, killstreak ); + } + self.cancelKillcam = false; + self thread killcam::cancel_on_use(); + + // initial death cam + self playerkilled_watch_death(weapon, sMeansOfDeath, deathAnimDuration); + + // killcam +/# + if ( GetDvarint( "scr_forcekillcam" ) != 0 ) + { + doKillcam = true; + + if ( lpattacknum < 0 ) + lpattacknum = self getEntityNumber(); + } +#/ + + if ( game["state"] != "playing" ) + { + return; + } + + self.respawnTimerStartTime = gettime(); + keep_deathcam = false; + if ( isdefined( self.overridePlayerDeadStatus ) ) + { + keep_deathcam = self [[ self.overridePlayerDeadStatus ]](); + } + + if ( !self.cancelKillcam && doKillcam && level.killcam && ( wasTeamKill == false ) ) + { + livesLeft = !(level.numLives && !self.pers["lives"]) && !(level.numTeamLives && !game[self.team+"_lives"]); + timeUntilSpawn = globallogic_spawn::TimeUntilSpawn( true ); + willRespawnImmediately = livesLeft && (timeUntilSpawn <= 0) && !level.playerQueuedRespawn; + + self killcam::killcam( lpattacknum, self getEntityNumber(), killcam_entity_info, weapon, sMeansOfDeath, self.deathTime, deathTimeOffset, psOffsetTime, willRespawnImmediately, globallogic_utils::timeUntilRoundEnd(), perks, killstreaks, attacker, keep_deathcam ); + } + else if( self.cancelKillcam ) + { + // copy of code from wait_skip_killcam_button + // because fast button mashers (not hard to do) will "skip" the killcam + // before it even starts + if( isdefined( self.killcamsSkipped) ) + { + self.killcamsSkipped++; + } + else + { + self.killcamsSkipped = 1; + } + } + + // secondary deathcam for resurrection + + secondary_deathcam = 0.0; + + timeUntilSpawn = globallogic_spawn::TimeUntilSpawn( true ); + shouldDoSecondDeathCam = timeUntilSpawn > 0; + + if ( shouldDoSecondDeathCam && IsDefined(self.secondaryDeathCamTime) ) + { + secondary_deathcam = self [[self.secondaryDeathCamTime]](); + } + + if ( secondary_deathcam > 0.0 && !self.cancelKillcam ) + { + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.spectatekillcam = false; + globallogic_utils::waitForTimeOrNotify( secondary_deathcam, "end_death_delay" ); + self notify ( "death_delay_finished" ); + } + + // secondary deathcam is complete + + if ( !self.cancelKillcam && doKillcam && level.killcam && keep_deathcam ) + { + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.spectatekillcam = false; + } + + if ( game["state"] != "playing" ) + { + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamtargetentity = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.spectatekillcam = false; + return; + } + + WaitTillKillStreakDone(); + useRespawnTime = true; + if( isDefined( level.hostMigrationTimer ) ) + { + useRespawnTime = false; + } + hostmigration::waittillHostMigrationCountDown(); + //if ( isDefined( level.hostMigrationTimer ) ) + //return; + + // class may be undefined if we have changed teams + if ( globallogic_utils::isValidClass( self.curClass ) ) + { + timePassed = undefined; + + if ( isdefined( self.respawnTimerStartTime ) && useRespawnTime ) + { + timePassed = (gettime() - self.respawnTimerStartTime) / 1000; + } + + self thread [[level.spawnClient]]( timePassed ); + self.respawnTimerStartTime = undefined; + } +} + +function update_ffa_top_scorers() +{ + waittillframeend; + + if ( !level.players.size || level.gameEnded ) + return; + + placement = []; + foreach ( player in level.players ) + { + if ( player.team != "spectator" ) + placement[placement.size] = player; + } + + for ( i = 1; i < placement.size; i++ ) + { + player = placement[i]; + playerScore = player.pointstowin; + for ( j = i - 1; j >= 0 && (playerScore > placement[j].pointstowin || (playerScore == placement[j].pointstowin && player.deaths < placement[j].deaths) || (playerScore == placement[j].pointstowin && player.deaths == placement[j].deaths && player.lastKillTime > placement[j].lastKillTime)); j-- ) + placement[j + 1] = placement[j]; + placement[j + 1] = player; + } + + ClearTopScorers(); + for ( i = 0; i < placement.size && i < 3; i++ ) + { + SetTopScorer( i, placement[i], 0, 0, 0, 0, level.weaponNone ); + } +} + +function playerkilled_watch_death(weapon, sMeansOfDeath, deathAnimDuration) +{ + defaultPlayerDeathWatchTime = 1.75; + if ( sMeansOfDeath == "MOD_MELEE_ASSASSINATE" || 0 > weapon.deathCamTime ) + { + defaultPlayerDeathWatchTime = (deathAnimDuration * 0.001) + 0.5; + } + else if ( 0 < weapon.deathCamTime ) + { + defaultPlayerDeathWatchTime = weapon.deathCamTime; + } + + if ( isdefined ( level.overridePlayerDeathWatchTimer ) ) + { + defaultPlayerDeathWatchTime = [[level.overridePlayerDeathWatchTimer]]( defaultPlayerDeathWatchTime ); + } + + globallogic_utils::waitForTimeOrNotify( defaultPlayerDeathWatchTime, "end_death_delay" ); + + self notify ( "death_delay_finished" ); +} + +function should_drop_weapon_on_death( wasTeamKill, wasSuicide, current_weapon, sMeansOfDeath ) +{ + // to avoid exploits dont allow weapon drops on suicide or teamkills. + if ( wasTeamKill ) + return false; + + if ( wasSuicide ) + return false; + + // assuming this means that they are in a death trigger out of bounds and falling + if ( sMeansOfDeath == "MOD_TRIGGER_HURT" && !self IsOnGround()) + return false; + + // dont drop any weapon if they were holding a hero weapon + if ( IsDefined(current_weapon) && current_weapon.isHeroWeapon ) + return false; + + return true; +} + +function updateGlobalBotKilledCounter() +{ + if ( isdefined( self.pers["isBot"] ) ) + { + level.globalLarrysKilled++; + } +} + + +function WaitTillKillStreakDone() +{ + if( isdefined( self.killstreak_delay_killcam ) ) + { + while( isdefined( self.killstreak_delay_killcam ) ) + { + wait( 0.1 ); + } + + //Plus a small amount so we can see our dead body + wait( 2.0 ); + + self killstreaks::reset_killstreak_delay_killcam(); + } +} + +function SuicideKick() +{ + self globallogic_score::incPersStat( "sessionbans", 1 ); + + self endon("disconnect"); + waittillframeend; + + globallogic::gameHistoryPlayerKicked(); + + ban( self getentitynumber() ); + globallogic_audio::leader_dialog( "gamePlayerKicked" ); +} + +function TeamKillKick() +{ + self globallogic_score::incPersStat( "sessionbans", 1 ); + + self endon("disconnect"); + waittillframeend; + + //for test purposes lets lock them out of certain game type for 2mins + + playlistbanquantum = tweakables::getTweakableValue( "team", "teamkillerplaylistbanquantum" ); + playlistbanpenalty = tweakables::getTweakableValue( "team", "teamkillerplaylistbanpenalty" ); + if ( playlistbanquantum > 0 && playlistbanpenalty > 0 ) + { + timeplayedtotal = self GetDStat( "playerstatslist", "time_played_total", "StatValue" ); + minutesplayed = timeplayedtotal / 60; + + freebees = 2; + + banallowance = int( floor(minutesplayed / playlistbanquantum) ) + freebees; + + if ( self.sessionbans > banallowance ) + { + self SetDStat( "playerstatslist", "gametypeban", "StatValue", timeplayedtotal + (playlistbanpenalty * 60) ); + } + } + + globallogic::gameHistoryPlayerKicked(); + + ban( self getentitynumber() ); + globallogic_audio::leader_dialog( "gamePlayerKicked" ); +} + +function TeamKillDelay() +{ + teamkills = self.pers["teamkills_nostats"]; + if ( level.minimumAllowedTeamKills < 0 || teamkills <= level.minimumAllowedTeamKills ) + return 0; + + exceeded = (teamkills - level.minimumAllowedTeamKills); + return level.teamKillSpawnDelay * exceeded; +} + + +function ShouldTeamKillKick(teamKillDelay) +{ + if ( teamKillDelay && ( level.minimumAllowedTeamKills >= 0 ) ) + { + // if its more then 5 seconds into the match and we have a delay then just kick them + if ( globallogic_utils::getTimePassed() >= 5000 ) + { + return true; + } + + // if its under 5 seconds into the match only kick them if they have killed more then one players so far + if ( self.pers["teamkills_nostats"] > 1 ) + { + return true; + } + } + + return false; +} + +function reduceTeamKillsOverTime() +{ + timePerOneTeamkillReduction = 20.0; + reductionPerSecond = 1.0 / timePerOneTeamkillReduction; + + while(1) + { + if ( isAlive( self ) ) + { + self.pers["teamkills_nostats"] -= reductionPerSecond; + if ( self.pers["teamkills_nostats"] < level.minimumAllowedTeamKills ) + { + self.pers["teamkills_nostats"] = level.minimumAllowedTeamKills; + break; + } + } + wait 1; + } +} + + +function IgnoreTeamKills( weapon, sMeansOfDeath, eInflictor ) +{ + if ( weapon_utils::isMeleeMOD( sMeansOfDeath ) ) + return false; + + if ( weapon.ignoreTeamKills ) + return true; + + if ( isdefined( eInflictor ) && eInflictor.ignore_team_kills === true ) + return true; + + if( isDefined( eInflictor ) && isDefined( eInflictor.destroyedBy ) && isDefined( eInflictor.owner ) && eInflictor.destroyedBy != eInflictor.owner ) + return true; + + if ( isDefined( eInflictor ) && eInflictor.classname == "worldspawn" ) + return true; + + return false; +} + + +function Callback_PlayerLastStand( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ) +{ + laststand::PlayerLastStand( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ); +} + +function damageShellshockAndRumble( eAttacker, eInflictor, weapon, sMeansOfDeath, iDamage ) +{ + self thread weapons::on_damage( eAttacker, eInflictor, weapon, sMeansOfDeath, iDamage ); + + if ( !self util::isUsingRemote() ) + { + self PlayRumbleOnEntity( "damage_heavy" ); + } +} + + +function createDeadBody( attacker, iDamage, sMeansOfDeath, weapon, sHitLoc, vDir, vAttackerOrigin, deathAnimDuration, eInflictor, body ) +{ + if ( sMeansOfDeath == "MOD_HIT_BY_OBJECT" && self GetStance() == "prone" ) + { + self.body = body; + if ( !isdefined( self.switching_teams ) ) + thread deathicons::add( body, self, self.team, 5.0 ); + + return; + } + + ragdoll_now = false; + if( isdefined(self.usingvehicle) && self.usingvehicle && isdefined(self.vehicleposition) && self.vehicleposition == 1 ) + { + ragdoll_now = true; + } + + if ( isdefined( level.ragdoll_override ) && self [[level.ragdoll_override]]( iDamage, sMeansOfDeath, weapon, sHitLoc, vDir, vAttackerOrigin, deathAnimDuration, eInflictor, ragdoll_now, body ) ) + { + return; + } + + if ( ( ragdoll_now ) || self isOnLadder() || self isMantling() || sMeansOfDeath == "MOD_CRUSH" || sMeansOfDeath == "MOD_HIT_BY_OBJECT" ) + body startRagDoll(); + + if ( !self IsOnGround() && sMeansOfDeath != "MOD_FALLING" ) + { + if ( GetDvarint( "scr_disable_air_death_ragdoll" ) == 0 ) + { + body startRagDoll(); + } + } + + if( sMeansOfDeath == "MOD_MELEE_ASSASSINATE" && !attacker isOnGround() ) + { + body start_death_from_above_ragdoll( vDir ); + } + + if ( self is_explosive_ragdoll( weapon, eInflictor ) ) + { + body start_explosive_ragdoll( vDir, weapon ); + } + + thread delayStartRagdoll( body, sHitLoc, vDir, weapon, eInflictor, sMeansOfDeath ); + + if ( sMeansOfDeath == "MOD_CRUSH" ) + { + body globallogic_vehicle::vehicleCrush(); + } + + self.body = body; + if ( !isdefined( self.switching_teams ) ) + thread deathicons::add( body, self, self.team, 5.0 ); +} + +function is_explosive_ragdoll( weapon, inflictor ) +{ + if ( !isdefined( weapon ) ) + { + return false; + } + + // destructible explosives + if ( weapon.name == "destructible_car" || weapon.name == "explodable_barrel" ) + { + return true; + } + + // special explosive weapons + if ( weapon.projExplosionType == "grenade" ) + { + if ( isdefined( inflictor ) && isdefined( inflictor.stuckToPlayer ) ) + { + if ( inflictor.stuckToPlayer == self ) + { + return true; + } + } + } + + return false; +} + +function start_explosive_ragdoll( dir, weapon ) +{ + if ( !isdefined( self ) ) + { + return; + } + + x = RandomIntRange( 50, 100 ); + y = RandomIntRange( 50, 100 ); + z = RandomIntRange( 10, 20 ); + + if ( isdefined( weapon ) && (weapon.name == "sticky_grenade" || weapon.name == "explosive_bolt") ) + { + if ( isdefined( dir ) && LengthSquared( dir ) > 0 ) + { + x = dir[0] * x; + y = dir[1] * y; + } + } + else + { + if ( math::cointoss() ) + { + x = x * -1; + } + if ( math::cointoss() ) + { + y = y * -1; + } + } + + self StartRagdoll(); + self LaunchRagdoll( ( x, y, z ) ); +} + +function start_death_from_above_ragdoll( dir ) +{ + if ( !isdefined( self ) ) + { + return; + } + + self StartRagdoll(); + self LaunchRagdoll( ( 0, 0, -100 ) ); +} + + +function notifyConnecting() +{ + waittillframeend; + + if( isdefined( self ) ) + { + level notify( "connecting", self ); + } + + callback::callback( #"on_player_connecting" ); +} + + +function delayStartRagdoll( ent, sHitLoc, vDir, weapon, eInflictor, sMeansOfDeath ) +{ + if ( isdefined( ent ) ) + { + deathAnim = ent getcorpseanim(); + if ( animhasnotetrack( deathAnim, "ignore_ragdoll" ) ) + return; + } + + waittillframeend; + + if ( !isdefined( ent ) ) + return; + + if ( ent isRagDoll() ) + return; + + deathAnim = ent getcorpseanim(); + + startFrac = 0.35; + + if ( animhasnotetrack( deathAnim, "start_ragdoll" ) ) + { + times = getnotetracktimes( deathAnim, "start_ragdoll" ); + if ( isdefined( times ) ) + startFrac = times[0]; + } + + waitTime = startFrac * getanimlength( deathAnim ); + + //waitTime -= 0.2; // account for the wait above + if( waitTime > 0 ) + wait( waitTime ); + + if ( isdefined( ent ) ) + { + ent startragdoll(); + } +} + +function trackAttackerDamage( eAttacker, iDamage, sMeansOfDeath, weapon ) +{ + if( !IsDefined( eAttacker ) ) + return; + + if ( !IsPlayer( eAttacker ) ) + return; + + if ( self.attackerData.size == 0 ) + { + self.firstTimeDamaged = getTime(); + } + if ( !isdefined( self.attackerData[eAttacker.clientid] ) ) + { + self.attackerDamage[eAttacker.clientid] = spawnstruct(); + self.attackerDamage[eAttacker.clientid].damage = iDamage; + self.attackerDamage[eAttacker.clientid].meansOfDeath = sMeansOfDeath; + self.attackerDamage[eAttacker.clientid].weapon = weapon; + self.attackerDamage[eAttacker.clientid].time = getTime(); + + self.attackers[ self.attackers.size ] = eAttacker; + + // we keep an array of attackers by their client ID so we can easily tell + // if they're already one of the existing attackers in the above if(). + // we store in this array data that is useful for other things, like challenges + self.attackerData[eAttacker.clientid] = false; + } + else + { + self.attackerDamage[eAttacker.clientid].damage += iDamage; + self.attackerDamage[eAttacker.clientid].meansOfDeath = sMeansOfDeath; + self.attackerDamage[eAttacker.clientid].weapon = weapon; + if ( !isdefined( self.attackerDamage[eAttacker.clientid].time ) ) + self.attackerDamage[eAttacker.clientid].time = getTime(); + } + + if ( IsArray( self.attackersThisSpawn ) ) + { + self.attackersThisSpawn[ eAttacker.clientid ] = eAttacker; + } + + self.attackerDamage[eAttacker.clientid].lasttimedamaged = getTime(); + if ( weapons::is_primary_weapon( weapon ) ) + self.attackerData[eAttacker.clientid] = true; +} + +function giveAttackerAndInflictorOwnerAssist( eAttacker, eInflictor, iDamage, sMeansOfDeath, weapon ) +{ + if ( !allowedAssistWeapon( weapon ) ) + return; + + self trackAttackerDamage( eAttacker, iDamage, sMeansOfDeath, weapon ); + + if ( !isdefined( eInflictor ) ) + return; + + if ( !isdefined( eInflictor.owner ) ) + return; + + if ( !isdefined( eInflictor.ownerGetsAssist ) ) + return; + + if ( !eInflictor.ownerGetsAssist ) + return; + + // if attacker and inflictor owner are the same no additional points + // I dont ever know if they are different + if ( isdefined( eAttacker ) && eAttacker == eInflictor.owner ) + return; + + self trackAttackerDamage( eInflictor.owner, iDamage, sMeansOfDeath, weapon ); +} + +function PlayerKilled_UpdateMeansOfDeath( attacker, eInflictor, weapon, sMeansOfDeath, sHitLoc ) +{ + if( globallogic_utils::isHeadShot( weapon, sHitLoc, sMeansOfDeath, eInflictor ) && isPlayer( attacker ) && !weapon_utils::ismeleemod( sMeansOfDeath ) ) + { + return "MOD_HEAD_SHOT"; + } + + // we do not want the melee icon to show up for dog attacks + switch( weapon.name ) + { + case "dog_bite": + sMeansOfDeath = "MOD_PISTOL_BULLET"; + break; + case "destructible_car": + sMeansOfDeath = "MOD_EXPLOSIVE"; + break; + case "explodable_barrel": + sMeansOfDeath = "MOD_EXPLOSIVE"; + break; + } + + return sMeansOfDeath; +} + +function updateAttacker( attacker, weapon ) +{ + if( isai(attacker) && isdefined( attacker.script_owner ) ) + { + // if the person who called the dogs in switched teams make sure they don't + // get penalized for the kill + if ( !level.teambased || attacker.script_owner.team != self.team ) + attacker = attacker.script_owner; + } + + if( attacker.classname == "script_vehicle" && isdefined( attacker.owner ) ) + { + attacker notify("killed",self); + + attacker = attacker.owner; + } + + if( isai(attacker) ) + attacker notify("killed",self); + + if ( ( isdefined ( self.capturingLastFlag ) ) && ( self.capturingLastFlag == true ) ) + { + attacker.lastCapKiller = true; + } + + if( isdefined( attacker ) && attacker != self && isdefined( weapon ) ) + { + if ( weapon.name == "planemortar" ) + { + if(!isdefined(attacker.planeMortarBda))attacker.planeMortarBda=0; + attacker.planeMortarBda++; + } + else if( weapon.name == "dart" || + weapon.name == "dart_turret" ) + { + if(!isdefined(attacker.dartBda))attacker.dartBda=0; + attacker.dartBda++; + } + else if( weapon.name == "straferun_rockets" || weapon.name == "straferun_gun") + { + if( isdefined( attacker.strafeRunbda ) ) + { + attacker.strafeRunbda++; + } + } + else if ( weapon.name == "remote_missile_missile" || weapon.name == "remote_missile_bomblet" ) + { + if(!isdefined(attacker.remotemissileBda))attacker.remotemissileBda=0; + attacker.remotemissileBda++; + } + } + + return attacker; +} + +function updateInflictor( eInflictor ) +{ + if( isdefined( eInflictor ) && eInflictor.classname == "script_vehicle" ) + { + eInflictor notify("killed",self); + + if ( isdefined( eInflictor.bda ) ) + { + eInflictor.bda++; + } + } + + return eInflictor; +} + +function updateWeapon( eInflictor, weapon ) +{ + // explosive barrel/car detection + if ( weapon == level.weaponNone && isdefined( eInflictor ) ) + { + if ( isdefined( eInflictor.targetname ) && eInflictor.targetname == "explodable_barrel" ) + weapon = GetWeapon( "explodable_barrel" ); + else if ( isdefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) ) + weapon = GetWeapon( "destructible_car" ); + } + + return weapon; +} + +function playKillBattleChatter( attacker, weapon, victim, eInflictor ) +{ + if( IsPlayer( attacker ) ) + { + if ( !killstreaks::is_killstreak_weapon( weapon ) ) + { + level thread battlechatter::say_kill_battle_chatter( attacker, weapon, victim, eInflictor ); + } + } + + if( isdefined( eInflictor ) ) + { + eInflictor notify( "bhtn_action_notify", "attack_kill" ); + } +} diff --git a/data/scripts/mp/gametypes/_serversettings.gsc b/data/scripts/mp/gametypes/_serversettings.gsc new file mode 100644 index 0000000000000000000000000000000000000000..bf3985aab646d5b010b7fea76bcc9567366f1d51 GIT binary patch literal 4612 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 A;Q#;t literal 0 HcmV?d00001 diff --git a/data/scripts/mp/gametypes/_serversettings.gsc_raw b/data/scripts/mp/gametypes/_serversettings.gsc_raw new file mode 100644 index 0000000..e420ca3 --- /dev/null +++ b/data/scripts/mp/gametypes/_serversettings.gsc_raw @@ -0,0 +1,209 @@ +#using scripts\codescripts\struct; + +#using scripts\shared\callbacks_shared; +#using scripts\shared\system_shared; + +#namespace serversettings; + +function autoexec __init__sytem__() { system::register("serversettings",&__init__,undefined,undefined); } + +function __init__() +{ + callback::on_start_gametype( &init ); +} + +function init() +{ + level.hostname = GetDvarString( "sv_hostname"); + if(level.hostname == "") + level.hostname = "CoDHost"; + SetDvar("sv_hostname", level.hostname); + SetDvar("ui_hostname", level.hostname); + //makeDvarServerInfo("ui_hostname", "CoDHost"); + + level.motd = GetDvarString( "scr_motd" ); + if(level.motd == "") + level.motd = ""; + SetDvar("scr_motd", level.motd); + SetDvar("ui_motd", level.motd); + //makeDvarServerInfo("ui_motd", ""); + + level.allowvote = GetDvarString( "g_allowvote" ); + if(level.allowvote == "") + level.allowvote = "1"; + SetDvar("g_allowvote", level.allowvote); + SetDvar("ui_allowvote", level.allowvote); + //makeDvarServerInfo("ui_allowvote", "1"); + + level.allow_teamchange = "1"; + SetDvar("ui_allow_teamchange", level.allow_teamchange); + + level.friendlyfire = GetGametypeSetting( "friendlyfiretype" ); + + SetDvar("ui_friendlyfire", level.friendlyfire); + //makeDvarServerInfo("ui_friendlyfire", "0"); + + if(GetDvarString( "scr_mapsize") == "") + SetDvar("scr_mapsize", "64"); + else if(GetDvarfloat( "scr_mapsize") >= 64) + SetDvar("scr_mapsize", "64"); + else if(GetDvarfloat( "scr_mapsize") >= 32) + SetDvar("scr_mapsize", "32"); + else if(GetDvarfloat( "scr_mapsize") >= 16) + SetDvar("scr_mapsize", "16"); + else + SetDvar("scr_mapsize", "8"); + level.mapsize = GetDvarfloat( "scr_mapsize"); + + constrain_gametype(GetDvarString( "g_gametype")); + constrain_map_size(level.mapsize); + + thread setup_callbacks(); + + for(;;) + { + update(); + wait 5; + } +} + +function update() +{ + sv_hostname = GetDvarString( "sv_hostname"); + if(level.hostname != sv_hostname) + { + level.hostname = sv_hostname; + SetDvar("ui_hostname", level.hostname); + } + + scr_motd = GetDvarString( "scr_motd"); + if(level.motd != scr_motd) + { + level.motd = scr_motd; + SetDvar("ui_motd", level.motd); + } + + g_allowvote = GetDvarString( "g_allowvote" ); + if(level.allowvote != g_allowvote) + { + level.allowvote = g_allowvote; + SetDvar("ui_allowvote", level.allowvote); + } + + scr_friendlyfire = GetGametypeSetting( "friendlyfiretype" ); + if(level.friendlyfire != scr_friendlyfire) + { + level.friendlyfire = scr_friendlyfire; + SetDvar("ui_friendlyfire", level.friendlyfire); + } +} + +function constrain_gametype(gametype) +{ + entities = getentarray(); + for(i = 0; i < entities.size; i++) + { + entity = entities[i]; + + if(gametype == "dm") + { + if(isdefined(entity.script_gametype_dm) && entity.script_gametype_dm != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "tdm") + { + if(isdefined(entity.script_gametype_tdm) && entity.script_gametype_tdm != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "ctf") + { + if(isdefined(entity.script_gametype_ctf) && entity.script_gametype_ctf != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "hq") + { + if(isdefined(entity.script_gametype_hq) && entity.script_gametype_hq != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "sd") + { + if(isdefined(entity.script_gametype_sd) && entity.script_gametype_sd != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "koth") + { + if(isdefined(entity.script_gametype_koth) && entity.script_gametype_koth != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + } +} + +function constrain_map_size(mapsize) +{ + entities = getentarray(); + for(i = 0; i < entities.size; i++) + { + entity = entities[i]; + + if(int(mapsize) == 8) + { + if(isdefined(entity.script_mapsize_08) && entity.script_mapsize_08 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + else if(int(mapsize) == 16) + { + if(isdefined(entity.script_mapsize_16) && entity.script_mapsize_16 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + else if(int(mapsize) == 32) + { + if(isdefined(entity.script_mapsize_32) && entity.script_mapsize_32 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + else if(int(mapsize) == 64) + { + if(isdefined(entity.script_mapsize_64) && entity.script_mapsize_64 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + } +} + +function setup_callbacks() +{ + level.onForfeit = &default_onForfeit; +} + +function default_onForfeit() +{ + level.gameForfeited = false; +} \ No newline at end of file diff --git a/data/scripts/mp/teams/_teams.gsc b/data/scripts/mp/teams/_teams.gsc new file mode 100644 index 0000000000000000000000000000000000000000..bb53019a4c6f7f0da902752f6d9a0c1b16c48cff GIT binary patch literal 12284 zcmZ{K34ByV(s;d@$zc{^RzXlv-n=>A-1qg~%n*(QFb4@q2q7WY}RgOhbL>7-lR#|sNaalk_M8pF`U6j8ElCNr#r;-2f8)?&Zbai!ib#-<1 z>&=`xZfFXO%Dp3Xf*=PFO#m|n{vNaf6sQ3fY5}fdoyrd^z-Xi!VHC^&`Y9k8WYAJQ zryMQ5eM6A`7(P&j=_3W1Ne#G_kSk0W4hL+Zvrs|si zgQKMb$&LR9v8}ZsdOfKzX05AitZD6t)wEd4>!Qt7s6%sILv?vu!!OFHQ{7tG z+R#)tn4z4cLu*ZCV+-KuklF&3ZLK7)67_}bDdp*f1-WC>v(j_MO(@UFokp$8se!}- zwtiGYV@)ht*-;azu8e`*XS2n{79bj0n_DZRRGSiKfZ91VHPGBzUo!_PqYZNh7@+l@ z$~iEnxveSE(k}^Bs%)(R0^)jCwf@ox42-9F4z$H0$ki{pzdPhA@0U;x)IHv z7O1YAGpD0`5MowyLsLy8zAg}HXsK>)YQp7)0rW3(g^N63)@U5@Rkz05v{>p|szJp7 z$gq5Xo8UDpo3Px6r5ejbERo7QPbU72|Aw-u>=W7>LPm8~tUX2Jxp4ds%ZP9yWbSgI z5UmHw1XmRC zd)kU)V>NUCPH@0k)JgRt>IGURug&tws6#(Yx2CZ~qu)^W5p@ps`+`5yIX3>cy*7Y< z|Hu2XJH@!$mdcj-D-j;6g?TzLD>UuEoz2v4o6l{$8}WMnakCmy*|nBf{Tzf>2JH^w zUoJqqGpf_?U3pWK_!%*kRa(mC$|y=VTgNrSR~@`}}w>O5}Gqq#qkoFzOIbhPWNi%Q(bsqDw9dF|I`CtV@<9|mZy@@8ly*e;~9D{N(%%TGN2F43{Q7&UbG&ipR*8-hvy zef-A`27qpqCdId?pCrs}MBsTH+LQfVa6aRPGJB-X7Rnx<`qZa{pQuY?YYk?B>hvSNQ-(uc@ZS{})0%G$a-JN* z4|k@q#+>2~s?%>MyDVrzJu_{M-Fk$#1Wbh<{JYIy%P3s@)A%#iVUF*3sD~Mgi5=#v zQ`xBf0VUjBm|L4uq`TAiCZ0xUhoLmK@-CyD>hv4R?y)SzHNWDj)RLT9e;S+RDHi*w z0B6jKwpr}T5KQRoT6=zf19)l+qW1^Xz&SN}Ic-OwUZvdG9f+*bz8Bo)b3|97tZ~NN z29j0E=c{~%VQ|#5B}n)dLrE*)zwv2oUj^reHN8)MYB4fug>{>aX}QU8vs&i87`&{M z&4}oCb0Oe0GJmJQz}H(?4Z@yHt;!GdDYwcC%>sZa)+bD zC+eX`<&ec{b&3AHedlyvsw;}0!hW^7oLb`99Uc*|a%rAz@$u>#2{&C?;wuj}3Of;Z zRarENaE}^C1j-B*?mdWW(iyV}XANpyPSz=mfn4`J=MT+2qnWCD3F-6ouj$iZl&j3| zo&E~KDei}PA6sO-1vV*nsV0X>#&}P2gk&_iZ*q65gpC!Hr z^;xm|eNVVwu%?0|)SmLsx3Yqz>Ri|PzB0o zlOKvY^OhZ*6c2N9EW^-OXF6$K69Vn=`43wc3tt-bkm;VMBmK(!V%BF!A1Q1K-2|)c zv@UamkemAd+8Y*!+Ke%P-f&CcRmat9X>7gS(JtBLa+AWD_4k{50DWhsd(Q(<9`Syd z{KB(P9gKRqc6#~j2Tr$J7iF~hyF`h$wZ}@x937*kgtfCDn&hxwm zgp4AN{dZd;oK-X9a}0Yhx?|Hvh)lD_c7p)? zmmX@z_=dPjRAX_6zKDi9TTQs5p@}MR#NBM|xtpW8r29zRmrK#7?lQ(|h^N*%E(9}X zn^niOdx)+RtBj=IX7#I%DSf}5KW0sGS9~94Wb=vlojD9uV)crg$%TMU^{-#7aRFD* zv1;Vq7XW?g&qME+0rT3Mjiu*?13J-@|Ixn++EjKcUzYh_oa47uAXffpq%#=L!TI9q zsxf5`*^)tv9(B8a-AfN^=E*#4hmUOP9Wf!8uKvWFpf@XLyAmh6Y-iPp^YT?2gsV_! zOl;~D64L#l&6XsM#k$FpSp9l9!M-K@qekJ@*mzA+dB|vT(RwBe+u8l#aM3yOxVZ%9 ziT)d@q_bp)Cuw@7TbWCIhwUHh0UfbXd1Mvo=kS0?j#xT>=9>hIT!!&9pVa9Of9v^^ z2I78Lc(v}&#NU68rLtdoa*ZT=iI^0=!k3nj?4Q*bHT1jVT1h^hBj}C&cS-WoU4b!a zD1V5pjRo|_n{L^BJIM{8k5U*7j>McJK85qgYiljV9b~VIOpV})Jpv`?ko?7{l9LXAA(}BO&Zs8n*JI4 zE;ON&WHaurxF6f&s4XDboK~wMpDfA6an(Dbxeb!s3$Bt@8rL6GOPw$`td_<#-+IDK zdvva^CBE-Z=$Ery@o{W&^^akOpXkY4ejW95LXRhN_bjc{55_xHJ+X>nsh^oTc}`m> zm0fR;*KRUBW&wR;(WDBu@$l`pecwNisqFnWd3Ks-s>+4>D8#Wmc&AU6#yQ;SVN=U4 z&3r;1jcai(7;Yv#%KVW^(qp_Q&qI1V!=Do&Gb<+PfmTCdqFK@dPmHb!zO6jQD9xxHpI0l6oTWdtoZF96ML9%FeDW% zwOvxmI`6kJd6(T=JdnB6zt7QWO>)YEG?wo?6MV~c(0 zmKU>#C(k|8yiC<(q&d*)`hDa#zI`f;5@Lh>;!ySlKk0qS)!^L2JEL?~ID+qMNbirm z-3~hIHAz^k7jjZuxGv1} zbOwxm;w8VhF|&r@*(c^blV_W|GO{IpjCFW)fe~rFce2%a)OI4DVrIB$j@ykB(0djP zil0*1sp9ii@{i~mt2Qm%zKF*ACs(zF;<`tai zli@+Vp(FCsf=@TN)tS~?}Y-!$Fg2Z*Il4x``E!aY*EF|J#%-4)Zn zbwJ^7uB2}V>%f>XI(Cb%|NM$tKMnN^I=>cKWJWsgAY5AZ{FP~Mg8c*amO!NLQS5ss zYYWlYwo$i4yU(>k{}|%F=dx=F*Pz-VGMvFoZ82698rgptKlX!vx%vhN-1Ui>3G6cm z%eB|%h@uh{csi3<6gd-(-zyBErq%L zePlR}xwNpyQXB7MkqAXMI~bkQ6%*2Jm3I-(8S830jcugxrHHHNqI##zXs15*_#@t4 zH&j;We+a7k_UowsuY%evqCL!ac!>AAkf)g71*YR_TGx*QW0bF2OmMSKY$N(*{e(`U z9}P7bseLY<5d^Q``)xak->Dv}ONOzUjfO-^BHZ9)YTMPgOYqzv8>inIePaEi+|XM9 z4-dM#K|@JveBJQOh_73VcSiP?sWI^9*JXDVJ_+4uyUtl!x)XOhs(R>7{EDf;*`UWA zi|2x5PaW)Q=3%~soaO2xwkN`h+GhJtJjrbqmFi(WSz}vhkti!dA3f=P_jk@s zp=-Df9h*B~%%-_~NtLhKtX06oz`yV=G&R2V3sf@i4G#JA3Bt0_ z?|qZQ#Ag=|2DUh~pfff{Xzlb)S>i87XDEQta%R0=- zV`i>Go6z3rQJND{9&}y|o(V*tDBjP0R;D@Nm3uA-uZl9!+(j~U=0y7)PAzQGlnK;N zg;wS&G|D4R*F2%Z5YQ3N34NnL>om%eVj2lMJhGNg%<|IzTIXsMmZ@&HK@k`iekZ84 z$%<@&mzDp$w%B*c%%t~*$7>Sm{%M(RPYKb45jLc4)GdDO#pZG3@3_m@M0JEp+Y>zc)eN7JEYG0oQZp z4MG#hHH@=XeHuLzf2`SoCq?}`!6O{l&-0zi1$_t1j3dkZu8q82 zFi7)(d#N4cI7)+*zcatQob2!p-J|ZOV0?I(4AJ(iOvK2nMACD< zdYM1U@EV14xt=v8)UD1f0=?y^!*l@|Qmx?T{gN!Op%+k8ZuZeSvF z!gB(I3+pzyH@MQE%MR7KPDS1%^P?7q8*N2@Qm|O)5PJJi>kiRAkGm7+JZvLdpQ~Zo zC+R^ajbn*5*Yy+}WASEf9WCIj&O6L0+V`1X6jJyY;Jv9?t`~K23#mHbRd^4%@cxwX zka8K$x6-ODBc1U6omps9h{=Lkt=2~kq}#)MbBJhokMD38XQ>I-YgwFD)F7QMxfqFGKQ;UbtYaeg0{l-fweq-&b+6T^RMZ($dPL#o*b<# zeBLB4y&!DUtQX4c)Q>-86Uo-LxHxenczv?SQIot*%b^9?YJpJyQe^$vK&lS@C8Ea$$G^QIuiN20H67!(sJ)bh#%@!g zEu;R0)pr$Be>(B)5ZwK-nc6s&{bwS@r~6r`9cs=gB3&*9>z&UaeU6~3B$;4p4n2$T zamQUof=>%d&&vp3aoOYa#pbo~+|>JCZ5Gj|nbSNZ|F3>eF~Mi7i}aL7*nv6IxAZey zcvGBkEcu>z4(@mMRQ7dyiU&HoFk{6z^G*MW=Yg}iRJPlpsXvTzs_mx&3K1h2JnP!{ z`TwDD&^@cn-%vvIf4N#ci5|4R*16$l4sV-G^!tLTtV*eF;s5dGi8a0pfi%`T1CPRP zqS0@;DP>mtywq0pT)HrG6rF+bb;zmJn-6Vh1-uSD`{)y!0q;a7qe;n-Jyn%*_VqHl z13j`XSOeka$l}*;^#UftTUXbQfXu}sZnc7jw!4%8{I#4yAs-Wh>yDy zQf{?=>`&D6hL4&OJzCcxR)lTJMDuz>Lf1B{)|ON@S`hV#0{TMNIP*KABBHP!V+(^x z0kj~=My!%$*riSIFfU*9adB|v@7b}>ciYV@_~_11HOtZui>YnFL`ay_hB zfO}V#pQB~wo_5Z5$$Lfw@V?V_O<;;|(>|qwn8k|szaqCdLKn6uV6tyK#!j7iw07H+ z^30gf?{|-edfiFRxFt}VLwC4N zLkj=rff%>M8ml4u-y7QPm(OUlZ?nl~zv2IjG8LBca`TG@8e4J7ze~f36&cQJT(5WBrVq7so$qvIRaDnyV;}wU|>lEx)}7c;oAY*Q=kI zw?2f-RCcC_dFpsJKd7Jd!q9WHrt{Iyyeu%2B^i;C? zLL=j-P+~L{y%_A($aB{l6b9^>BW@79yA#C)((W5YNr+pLu7Wm6kj^p&co`LVjQ6iax~%S=~e zj4H(_7^r732K8--KWb74m`THT)q_J;FC_d5okG{hVkFdp zQC}$t`FK|u7rxJpcZh&5EGyF34tj_6Vbqy!)zkYbwV~hb9NtQ1eD@vT8*6+X@onJs z*|)BROlSMet(lKN?L6JJyKb)s@pkjWPDR#Ee}k6h5u^A}uc=R9+zYKMlrrNHb)O)M z4dvdo?S}ORS^bM4#(vs~^XM26Sjx-V$xaG=7&%6twj40abX(Vlvd(81G-W$JkVM zmujdS{Uev5mEqs{rn1Z{xQ};u62%rTL>Kvb;_o$hGc=609_A7{R^i(l<#<>V_;75& zchz!Df_|t=Hu*WtukR5aee%5cy5d{w&UIV9B3~RI4|?DDc&00J@ad&%o ztr5qSyGq{?NT!>CagFaXo)b;@?n+}!R+ZUljAt~FIvV3OA<6cN6++qQTcvSs_k&Qv zUs5Lcx8XTY&f3K41b{SUHNmn-9E!+gxY zRP`*FT90~Hu6or>z7anU0^PcU4{k*qefJQ@p)B^*1*5)49DUOu;mjX=Gg_YrK=0}j zZiA|7#}vfTTegI|@yf&-+7UW%z8E#LVao`oiO@1>vRg(AADd#xfod72n zCcZD>Y{n5c?LyrC(^r;CxFZEm-aB$M-nH<%5eb)Y>Q(j(;<{5)XA%y(fbm&hmgtoL z8;kSeZ3#De{jsmdZ~(tI?$}FwIOWhe{oL=9RRBlECI3vgB*ZPsJpInsh$|N#{!x-A z*#wSV8AE%ZZ(x=Pn-4IckS!WyA4Go!VfyBU_9g?2Y%jut^i>{4n7$by*+}PD1ps{$ z(htkHDF{=}U7|-39?ZYyI{r5X@yk%&IfSp``cs}>lJPa-Bzq+teF*^corR?1M1&jT?o^6AQF8M!jf$vU9$mU$#w}ofUvYTsQqz-2lxNkb^M8g_5-!I zAS~Gx!9}!q_}#_8_#EpImi7SB)jJTTcX4U_x8Yur_6^Z3xR2=lS37CuHG~!U2-Ewl z#D5TBdgtngWn9(oemkErgz5ckfUaJF@L>J}gZODpjv%~s2<}OI+mzaTab24b(g&~E z6od!&F$>|reXPAs-fP#>8-9`f8b6c zJlIb4=wAlIS=Yhs2oE0LB7`L$MQeHhVS4+?yY0mV2+PhROu6j-{uoZ3_N!l_H7r3` z@?8jX^R9#UA^dB58F&0T`nL#6evafNqc8lGA74Oj9_;fNb@A}u!irmd3%_+8+&Tik zUBg_>zfZ!bnQ%+=Hyy|xmrW}X_{});{idk52tu7ejM zOfh}`dNHzt=z}SS8<5W(X3-B~Oe?`>5gtrGt^6(hM}#S6=$9u~yoJ7cFuY5JxePq} zCH)iC0CeW}!=UC6rZZlmhY)t*#Nt0#h(0%GpnetW^mamL(MVil1^ULo0L&sh1Yvql zMVACwSg*(OJ^E8M+T$p!(>H$9_8F|Zu*^Xi|G{{yw+^&Bi1jmACSsdbEGw~2-vScf zeyme|7Pl+Bf^uWn=eNV~9)^^=L~Av5Z6;a$$+#+P{ZBZ6&s&zI}L5u~_IX zN$?R|i(Lp)P9PcKQuKF2umc;GWmuxv4?eWONL=HC$hUKV&xU;OA^lq{UAUink*@&x z0Qrt1ALS_U58$UNkcDMGmQz^9AkT3u7m@f9^58!hg7{Yk>Z7nu`4k)~TtvA~q1<}p zZ$~`kR&WVm7vfqGw-9mfBaX%asLw@&={`nn_al8h+Es)Fn1ZzbA|C(2E9jr;n-r=q zL_bR3Sy21^IF54&a|5&p!t~uiyg$_A4J=t$=-UEn`#sj_EtmS5i2fjoWhIs&Sm<4u zcv!5{do9)9!#ds7v3od${^Bz%^%yU0#c~|i@gS~Q6xRzdUOIS0Njpn7MA}7o@9n} literal 0 HcmV?d00001 diff --git a/data/scripts/mp/teams/_teams.gsc_raw b/data/scripts/mp/teams/_teams.gsc_raw new file mode 100644 index 0000000..1260a17 --- /dev/null +++ b/data/scripts/mp/teams/_teams.gsc_raw @@ -0,0 +1,670 @@ +#using scripts\codescripts\struct; + +#using scripts\shared\callbacks_shared; +#using scripts\shared\persistence_shared; +#using scripts\shared\system_shared; +#using scripts\shared\util_shared; + +#insert scripts\shared\shared.gsh; + +#using scripts\mp\gametypes\_globallogic_ui; +#using scripts\mp\gametypes\_spectating; + +#using scripts\mp\_util; + +#precache( "material", "mpflag_spectator" ); +#precache( "string", "MP_AUTOBALANCE_NOW" ); + +#namespace teams; + +REGISTER_SYSTEM( "teams", &__init__, undefined ) + +function __init__() +{ + callback::on_start_gametype( &init ); + + level.getEnemyTeam = &getEnemyTeam; + level.use_team_based_logic_for_locking_on = true; +} + +function init() +{ + game["strings"]["autobalance"] = &"MP_AUTOBALANCE_NOW"; + + if(GetDvarString( "scr_teambalance") == "") + SetDvar("scr_teambalance", "0"); + level.teambalance = GetDvarint( "scr_teambalance"); + level.teambalancetimer = 0; + + if(GetDvarString( "scr_timeplayedcap") == "") + SetDvar("scr_timeplayedcap", "1800"); + level.timeplayedcap = int(GetDvarint( "scr_timeplayedcap")); + + level.freeplayers = []; + + if( level.teamBased ) + { + level.alliesplayers = []; + level.axisplayers = []; + + callback::on_connect( &on_player_connect ); + callback::on_joined_team( &on_joined_team ); + callback::on_joined_spectate( &on_joined_spectators ); + level thread update_team_balance(); + + wait .15; + + level thread update_player_times(); + + } + else + { + callback::on_connect( &on_free_player_connect ); + + wait .15; + + level thread update_player_times(); + + } +} + +function on_player_connect() +{ + self thread track_played_time(); +} + +function on_free_player_connect() +{ + self thread track_free_played_time(); +} + +function on_joined_team() +{ + /#println( "joined team: " + self.pers["team"] );#/ + self update_time(); +} + +function on_joined_spectators() +{ + self.pers["teamTime"] = undefined; +} + +function track_played_time() +{ + self endon( "disconnect" ); + + if ( !isdefined( self.pers["totalTimePlayed"] ) ) + { + self.pers["totalTimePlayed"] = 0; + } + + foreach ( team in level.teams ) + { + self.timePlayed[team] = 0; + } + self.timePlayed["free"] = 0; + self.timePlayed["other"] = 0; + self.timePlayed["alive"] = 0; + + // dont reset time played in War when going into final fight, this is used for calculating match bonus + if ( !isdefined( self.timePlayed["total"] ) || !( (level.gameType == "twar") && (0 < game["roundsplayed"]) && (0 < self.timeplayed["total"]) ) ) + self.timePlayed["total"] = 0; + + while ( level.inPrematchPeriod ) + WAIT_SERVER_FRAME; + + for ( ;; ) + { + if ( game["state"] == "playing" ) + { + if ( isdefined( level.teams[self.sessionteam] ) ) + { + self.timePlayed[self.sessionteam]++; + self.timePlayed["total"]++; + + if ( level.mpCustomMatch ) + { + self.pers["sbtimeplayed"] = self.timeplayed["total"]; + self.sbtimeplayed = self.pers["sbtimeplayed"]; + } + + if ( IsAlive( self ) ) + self.timePlayed["alive"]++; + } + else if ( self.sessionteam == "spectator" ) + { + self.timePlayed["other"]++; + } + } + + wait ( 1.0 ); + } +} + + +function update_player_times() +{ + const minWait = 10.0; + const step = 1.0; + varWait = minWait; + + nextToUpdate = 0; + for ( ;; ) + { + varWait = varWait - step; + nextToUpdate++; + + if ( nextToUpdate >= level.players.size ) + { + nextToUpdate = 0; + + if ( varWait > 0 ) + { + wait ( varWait ); + } + + varWait = minWait; + } + + if ( isdefined( level.players[nextToUpdate] ) ) + { + level.players[nextToUpdate] update_played_time(); + level.players[nextToUpdate] persistence::check_contract_expirations(); + } + + wait ( step ); + } +} + +function update_played_time() +{ + pixbeginevent("updatePlayedTime"); + + if ( level.rankedMatch || level.leagueMatch ) + { + foreach( team in level.teams ) + { + if ( self.timePlayed[team] ) + { + if ( level.teambased ) + { + self AddPlayerStat( "time_played_"+team, int( min( self.timePlayed[team], level.timeplayedcap ) ) ); + } + + self AddPlayerStatWithGameType( "time_played_total", int( min( self.timePlayed[team], level.timeplayedcap ) ) ); + } + } + + if ( self.timePlayed["other"] ) + { + self AddPlayerStat( "time_played_other", int( min( self.timePlayed["other"], level.timeplayedcap ) ) ); + self AddPlayerStatWithGameType( "time_played_total", int( min( self.timePlayed["other"], level.timeplayedcap ) ) ); + } + + if ( self.timePlayed["alive"] ) + { + timeAlive = int( min( self.timePlayed["alive"], level.timeplayedcap ) ); + self persistence::increment_contract_times( timeAlive ); + self AddPlayerStat( "time_played_alive", timeAlive ); + } + } + + if ( level.onlineGame ) + { + timeAlive = int( min( self.timePlayed["alive"], level.timeplayedcap ) ); + self.pers["time_played_alive"] += timeAlive; + } + + pixendevent(); + + if ( game["state"] == "postgame" ) + return; + + foreach( team in level.teams ) + { + self.timePlayed[team] = 0; + } + self.timePlayed["other"] = 0; + self.timePlayed["alive"] = 0; +} + + +function update_time() +{ + if ( game["state"] != "playing" ) + return; + + self.pers["teamTime"] = getTime(); +} + +function update_balance_dvar() +{ + for(;;) + { + teambalance = GetDvarint( "scr_teambalance"); + if(level.teambalance != teambalance) + level.teambalance = GetDvarint( "scr_teambalance"); + + timeplayedcap = GetDvarint( "scr_timeplayedcap"); + if(level.timeplayedcap != timeplayedcap) + level.timeplayedcap = int(GetDvarint( "scr_timeplayedcap")); + + wait 1; + } +} + + +function update_team_balance() +{ + level thread update_balance_dvar(); + + wait .15; + + if ( level.teamBalance && util::isRoundBased() && level.numlives ) + { + if ( isDefined( game["BalanceTeamsNextRound"] ) ) + iPrintLnbold( &"MP_AUTOBALANCE_NEXT_ROUND" ); + + level waittill( "game_ended" ); + wait 1; + + if ( isDefined( game["BalanceTeamsNextRound"] ) ) + { + level balance_teams(); + game["BalanceTeamsNextRound"] = undefined; + } + else if ( !get_team_balance() ) + { + game["BalanceTeamsNextRound"] = true; + } + } + else + { + level endon ( "game_ended" ); + + for ( ;; ) + { + if ( level.teamBalance ) + { + if ( !get_team_balance() ) + { + iPrintLnBold( &"MP_AUTOBALANCE_SECONDS", 15 ); + wait 15.0; + + if ( !get_team_balance() ) + level balance_teams(); + } + + wait 59.0; + } + + wait 1.0; + } + } + +} + + +function get_team_balance() +{ + level.team["allies"] = 0; + level.team["axis"] = 0; + + players = level.players; + + for ( i = 0; i < players.size; i++ ) + { + if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "allies" ) ) + level.team["allies"]++; + else if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "axis" ) ) + level.team["axis"]++; + } + + if ( ( level.team["allies"] > ( level.team["axis"] + level.teamBalance ) ) || ( level.team["axis"] > ( level.team["allies"] + level.teamBalance ) ) ) + return false; + else + return true; +} + + +function balance_teams() +{ + iPrintLnBold( game["strings"]["autobalance"] ); + //Create/Clear the team arrays + AlliedPlayers = []; + AxisPlayers = []; + + // Populate the team arrays + players = level.players; + + for ( i = 0; i < players.size; i++ ) + { + if ( !isdefined( players[i].pers["teamTime"] ) ) + continue; + + if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "allies" ) ) + AlliedPlayers[AlliedPlayers.size] = players[i]; + else if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "axis" ) ) + AxisPlayers[AxisPlayers.size] = players[i]; + } + + MostRecent = undefined; + + while ( ( AlliedPlayers.size > ( AxisPlayers.size + 1 ) ) || ( AxisPlayers.size > ( AlliedPlayers.size + 1 ) ) ) + { + if ( AlliedPlayers.size > ( AxisPlayers.size + 1 ) ) + { + // Move the player that's been on the team the shortest ammount of time (highest teamTime value) + // Ignore players capturing or carrying objects + for ( j = 0; j < AlliedPlayers.size; j++ ) + { + + if ( !isdefined( MostRecent ) ) + MostRecent = AlliedPlayers[j]; + else if ( AlliedPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] ) + MostRecent = AlliedPlayers[j]; + } + + if ( isdefined( MostRecent ) ) + MostRecent change( "axis" ); + else + { + // Move the player that's been on the team the shortest ammount of time + for ( j = 0; j < AlliedPlayers.size; j++ ) + { + if ( !isdefined( MostRecent ) ) + MostRecent = AlliedPlayers[j]; + else if ( AlliedPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] ) + MostRecent = AlliedPlayers[j]; + } + + MostRecent change( "axis" ); + } + } + else if ( AxisPlayers.size > ( AlliedPlayers.size + 1 ) ) + { + // Move the player that's been on the team the shortest ammount of time (highest teamTime value) + // Ignore players capturing or carrying objects + for ( j = 0; j < AxisPlayers.size; j++ ) + { + + if ( !isdefined( MostRecent ) ) + MostRecent = AxisPlayers[j]; + else if ( AxisPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] ) + MostRecent = AxisPlayers[j]; + } + + if ( isdefined( MostRecent ) ) + MostRecent change( "allies" ); + else + { + // Move the player that's been on the team the shortest ammount of time + for ( j = 0; j < AxisPlayers.size; j++ ) + { + if ( !isdefined( MostRecent ) ) + MostRecent = AxisPlayers[j]; + else if ( AxisPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] ) + MostRecent = AxisPlayers[j]; + } + + MostRecent change( "allies" ); + } + } + + MostRecent = undefined; + AlliedPlayers = []; + AxisPlayers = []; + + players = level.players; + + for ( i = 0; i < players.size; i++ ) + { + if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "allies" ) ) + AlliedPlayers[AlliedPlayers.size] = players[i]; + else if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "axis" ) ) + AxisPlayers[AxisPlayers.size] = players[i]; + } + } +} + + +function change( team ) +{ + if (self.sessionstate != "dead") + { + // Set a flag on the player to they aren't robbed points for dying - the callback will remove the flag + self.switching_teams = true; + self.switchedTeamsResetGadgets = true; + self.joining_team = team; + self.leaving_team = self.pers["team"]; + + // Suicide the player so they can't hit escape and fail the team balance + self suicide(); + } + + self.pers["team"] = team; + self.team = team; + self.pers["weapon"] = undefined; + self.pers["spawnweapon"] = undefined; + self.pers["savedmodel"] = undefined; + self.pers["teamTime"] = undefined; + self.sessionteam = self.pers["team"]; + + self globallogic_ui::updateObjectiveText(); + + // update spectator permissions immediately on change of team + self spectating::set_permissions(); + + self SetClientScriptMainMenu( game[ "menu_start_menu" ] ); + self openMenu(game[ "menu_start_menu" ]); + + self notify("end_respawn"); +} + +function count_players() +{ + players = level.players; + + playerCounts = []; + foreach( team in level.teams ) + { + playerCounts[team] = 0; + } + + foreach( player in level.players ) + { + if( player == self ) + continue; + + team = player.pers["team"]; + if( isdefined(team) && isdefined( level.teams[team] ) ) + playerCounts[team]++; + } + return playerCounts; +} + + +function track_free_played_time() +{ + self endon( "disconnect" ); + + foreach( team in level.teams ) + { + self.timePlayed[team] = 0; + } + + self.timePlayed["other"] = 0; + self.timePlayed["total"] = 0; + self.timePlayed["alive"] = 0; + + for ( ;; ) + { + if ( game["state"] == "playing" ) + { + team = self.pers["team"]; + if ( isdefined( team ) && isdefined( level.teams[team] ) && self.sessionteam != "spectator" ) + { + self.timePlayed[team]++; + self.timePlayed["total"]++; + if ( IsAlive( self ) ) + self.timePlayed["alive"]++; + } + else + { + self.timePlayed["other"]++; + } + } + + wait ( 1.0 ); + } +} + +function set_player_model( team, weapon ) +{ + self DetachAll(); + self SetMoveSpeedScale( 1 ); + self SetSprintDuration( 4 ); + self SetSprintCooldown( 0 ); +} + +function get_flag_model( teamRef ) +{ + assert(isdefined(game["flagmodels"])); + assert(isdefined(game["flagmodels"][teamRef])); + return ( game["flagmodels"][teamRef] ); +} + +function get_flag_carry_model( teamRef ) +{ + assert(isdefined(game["carry_flagmodels"])); + assert(isdefined(game["carry_flagmodels"][teamRef])); + return ( game["carry_flagmodels"][teamRef] ); +} + +function getTeamIndex( team ) +{ + if( !isdefined( team ) ) + { + return TEAM_FREE; + } + + if( team == "free" ) + { + return TEAM_FREE; + } + + if( team == "allies" ) + { + return TEAM_ALLIES; + } + + if( team == "axis" ) + { + return TEAM_AXIS; + } + + return TEAM_FREE; +} + +function getEnemyTeam( player_team ) +{ + foreach( team in level.teams ) + { + if ( team == player_team ) + continue; + + if ( team == "spectator" ) + continue; + + return team; + } + + return util::getOtherTeam( player_team ); +} + +function GetEnemyPlayers() +{ + enemies = []; + + foreach( player in level.players ) + { + if( player.team == "spectator" ) + { + continue; + } + + if( ( level.teamBased && player.team != self.team ) || ( !level.teamBased && player != self ) ) + { + ARRAY_ADD( enemies, player ); + } + } + + return enemies; +} + +function GetFriendlyPlayers() +{ + friendlies = []; + + foreach( player in level.players ) + { + if( ( player.team == self.team ) && ( player != self ) ) + { + ARRAY_ADD( friendlies, player ); + } + } + + return friendlies; +} + +function WaitUntilTeamChange( player, callback, arg, end_condition1, end_condition2, end_condition3 ) +{ + if( isdefined( end_condition1 ) ) + self endon( end_condition1 ); + if( isdefined( end_condition2 ) ) + self endon( end_condition2 ); + if( isdefined( end_condition3 ) ) + self endon( end_condition3 ); + + event = player util::waittill_any( "joined_team", "disconnect", "joined_spectators" ); + + if( isdefined( callback ) ) + { + self [[ callback ]]( arg, event ); + } +} + + +function WaitUntilTeamChangeSingleTon( player, singletonString, callback, arg, end_condition1, end_condition2, end_condition3 ) +{ + self notify( singletonString ); + self endon( singletonString ); + if( isdefined( end_condition1 ) ) + self endon( end_condition1 ); + if( isdefined( end_condition2 ) ) + self endon( end_condition2 ); + if( isdefined( end_condition3 ) ) + self endon( end_condition3 ); + + event = player util::waittill_any( "joined_team", "disconnect", "joined_spectators" ); + + if( isdefined( callback ) ) + { + self thread [[ callback ]]( arg, event ); + } +} + + +function HideToSameTeam() +{ + if( level.teambased ) + { + self SetVisibleToAllExceptTeam( self.team ); + } + else + { + self SetVisibleToAll(); + self SetInvisibleToPlayer( self.owner ); + } +} + diff --git a/data/ui_scripts/doubleclick_join_server/__init__.lua b/data/ui_scripts/doubleclick_join_server/__init__.lua new file mode 100644 index 0000000..71c4808 --- /dev/null +++ b/data/ui_scripts/doubleclick_join_server/__init__.lua @@ -0,0 +1,118 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +require( "ui.uieditor.widgets.PC.ServerBrowser.ServerBrowserRowInternal" ) +require( "ui.uieditor.widgets.Lobby.Common.FE_FocusBarContainer" ) + +CoD.ServerBrowserRow = InheritFrom( LUI.UIElement ) +CoD.ServerBrowserRow.new = function ( menu, controller ) + local self = LUI.UIElement.new() + if PreLoadFunc then + PreLoadFunc( self, controller ) + end + self:setUseStencil( false ) + self:setClass( CoD.ServerBrowserRow ) + self.id = "ServerBrowserRow" + self.soundSet = "default" + self:setLeftRight( true, false, 0, 700 ) + self:setTopBottom( true, false, 0, 22 ) + self:makeFocusable() + self:setHandleMouse( true ) + + if CoD.isPC then + self:registerEventHandler( "leftmousedown", function () + if self:isInFocus() then + ServerBrowserCancelRequest( self ) + JoinServerBrowser( self, self, controller, menu ) + end + end ) + end + self.anyChildUsesUpdateState = true + + local background = LUI.UIImage.new() + background:setLeftRight( true, true, 0, 0 ) + background:setTopBottom( true, true, 0, 0 ) + background:setRGB( 0.2, 0.2, 0.2 ) + background:setAlpha( 0.8 ) + self:addElement( background ) + self.background = background + + local rowItems = CoD.ServerBrowserRowInternal.new( menu, controller ) + rowItems:setLeftRight( true, false, 0, 700 ) + rowItems:setTopBottom( true, false, 0, 22 ) + rowItems:linkToElementModel( self, nil, false, function ( model ) + rowItems:setModel( model, controller ) + end ) + self:addElement( rowItems ) + self.rowItems = rowItems + + local FocusBarB = CoD.FE_FocusBarContainer.new( menu, controller ) + FocusBarB:setLeftRight( true, true, -2, 2 ) + FocusBarB:setTopBottom( false, true, -1, 3 ) + FocusBarB:setAlpha( 0 ) + FocusBarB:setZoom( 1 ) + self:addElement( FocusBarB ) + self.FocusBarB = FocusBarB + + local FocusBarT = CoD.FE_FocusBarContainer.new( menu, controller ) + FocusBarT:setLeftRight( true, true, -2, 2 ) + FocusBarT:setTopBottom( true, false, -2, 2 ) + FocusBarT:setAlpha( 0 ) + FocusBarT:setZoom( 1 ) + self:addElement( FocusBarT ) + self.FocusBarT = FocusBarT + + self.clipsPerState = { + DefaultState = { + DefaultClip = function () + self:setupElementClipCounter( 3 ) + background:completeAnimation() + self.background:setRGB( 0.2, 0.2, 0.2 ) + self.clipFinished( background, {} ) + FocusBarB:completeAnimation() + self.FocusBarB:setAlpha( 0 ) + self.clipFinished( FocusBarB, {} ) + FocusBarT:completeAnimation() + self.FocusBarT:setAlpha( 0 ) + self.clipFinished( FocusBarT, {} ) + end, + Focus = function () + self:setupElementClipCounter( 3 ) + background:completeAnimation() + self.background:setRGB( 0.2, 0.2, 0.2 ) + self.clipFinished( background, {} ) + FocusBarB:completeAnimation() + self.FocusBarB:setAlpha( 1 ) + self.clipFinished( FocusBarB, {} ) + FocusBarT:completeAnimation() + self.FocusBarT:setAlpha( 1 ) + self.clipFinished( FocusBarT, {} ) + end, + Over = function () + self:setupElementClipCounter( 3 ) + background:completeAnimation() + self.background:setRGB( 0.39, 0.39, 0.39 ) + self.clipFinished( background, {} ) + FocusBarB:completeAnimation() + self.FocusBarB:setAlpha( 0 ) + self.clipFinished( FocusBarB, {} ) + FocusBarT:completeAnimation() + self.FocusBarT:setAlpha( 0 ) + self.clipFinished( FocusBarT, {} ) + end + } + } + LUI.OverrideFunction_CallOriginalSecond( self, "close", function ( element ) + element.rowItems:close() + element.FocusBarB:close() + element.FocusBarT:close() + element.m_leftMouseDown = nil + end ) + + if PostLoadFunc then + PostLoadFunc( self, controller, menu ) + end + + return self +end \ No newline at end of file diff --git a/data/ui_scripts/frontend_menus/__init__.lua b/data/ui_scripts/frontend_menus/__init__.lua new file mode 100644 index 0000000..e9e83a6 --- /dev/null +++ b/data/ui_scripts/frontend_menus/__init__.lua @@ -0,0 +1,156 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +local enableLobbyMapVote = true -- toggle map vote in public lobby +local enableLargeServerBrowserButton = true -- toggle large server browser button + +local utils = require("utils") +require("datasources_start_menu_tabs") +require("datasources_change_map_categories") +require("datasources_gamesettingsflyout_buttons") + +CoD.LobbyButtons.MP_PUBLIC_MATCH = { + stringRef = "MENU_PLAY_CAPS", + action = NavigateToLobby_SelectionList, + param = "MPLobbyOnline", + customId = "btnPublicMatch", +} + +CoD.LobbyButtons.MP_FIND_MATCH = { + stringRef = "MPUI_BASICTRAINING_CAPS", + action = OpenFindMatch, + customId = "btnFindMatch", +} + +CoD.LobbyButtons.STATS = { + stringRef = "STATS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "T7xStatsMenu", controller) + end, + customId = "btnMPStats" +} + +CoD.LobbyButtons.MP_START_GAME = { + stringRef = "MENU_START_GAME_CAPS", + action = function(self, element, controller, param, menu) + Engine.SetDvar("party_minplayers", 1) + Engine.Exec(nil, "launchgame") + end, + customId = "btnStartGame" +} + +CoD.LobbyButtons.SETTING_UP_BOTS = { + stringRef = "MENU_SETUP_BOTS_CAPS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "GameSettings_Bots", controller) + end, + customId = "btnSettingUpBots" +} + +CoD.LobbyButtons.GameSettingsFlyoutArenas = { + stringRef = "MPUI_SETUP_GAME_CAPS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "GameSettingsFlyoutMP", controller) + end, + customId = "btnGameSettingsFlyoutMP" +} + +CoD.LobbyButtons.GameSettingsFlyoutMP = { + stringRef = "MPUI_SETUP_GAME_CAPS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "GameSettingsFlyoutMPCustom", controller) + end, + customId = "btnGameSettingsFlyoutMPCustom" +} + +CoD.LobbyButtons.SERVER_BROWSER = { + stringRef = "MENU_SERVER_BROWSER_CAPS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "LobbyServerBrowserOnline", controller) + end, + customId = "btnDedicated" +} + +local shouldShowMapVote = enableLobbyMapVote +local lobbyMapVote = function(lobbyMapVoteIsEnabled) + if lobbyMapVoteIsEnabled == true then + Engine.Exec(nil, "LobbyStopDemo") + end +end + +local addCustomButtons = function(controller, menuId, buttonTable, isLeader) + if menuId == LobbyData.UITargets.UI_MPLOBBYMAIN.id then + utils.RemoveSpaces(buttonTable) + local theaterIndex = utils.GetButtonIndex(buttonTable, CoD.LobbyButtons.THEATER_MP) + if theaterIndex ~= nil then + utils.AddSpacer(buttonTable, theaterIndex - 1) + end + end + + if menuId == LobbyData.UITargets.UI_MPLOBBYONLINE.id or menuId == LobbyData.UITargets.UI_ZMLOBBYONLINE.id then + utils.AddSmallButton(controller, buttonTable, CoD.LobbyButtons.STATS) + end + + if menuId == LobbyData.UITargets.UI_MPLOBBYONLINE.id or menuId == LobbyData.UITargets.UI_ZMLOBBYONLINE.id or menuId == LobbyData.UITargets.UI_MPLOBBYMAIN.id or menuId == LobbyData.UITargets.UI_MPLOBBYLANGAME.id then + Engine.Mods_Lists_UpdateUsermaps() + end + + if menuId == LobbyData.UITargets.UI_MPLOBBYONLINE.id then + shouldShowMapVote = enableLobbyMapVote + if enableLargeServerBrowserButton then + utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.SERVER_BROWSER, 1) + end + elseif menuId == LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id then + utils.RemoveButton(buttonTable, CoD.LobbyButtons.MP_PUBLIC_LOBBY_LEADERBOARD) + + utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.MP_START_GAME, 1) + utils.AddSmallButton(controller, buttonTable, CoD.LobbyButtons.GameSettingsFlyoutMP, 2) + utils.AddSpacer(buttonTable, utils.GetButtonIndex(buttonTable, CoD.LobbyButtons.GameSettingsFlyoutMP)) + + lobbyMapVote(shouldShowMapVote) + shouldShowMapVote = false + elseif menuId == LobbyData.UITargets.UI_MPLOBBYONLINEARENAGAME.id then + utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.MP_START_GAME, 1) + utils.AddSmallButton(controller, buttonTable, CoD.LobbyButtons.GameSettingsFlyoutArenas, 2) + + utils.AddSpacer(buttonTable, utils.GetButtonIndex(buttonTable, CoD.LobbyButtons.GameSettingsFlyoutArenas)) + end + + if menuId == LobbyData.UITargets.UI_ZMLOBBYONLINE.id then + utils.RemoveButton(buttonTable, CoD.LobbyButtons.THEATER_ZM) + utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.THEATER_ZM) + + utils.RemoveSpaces(buttonTable) + utils.AddSpacer(buttonTable, utils.GetButtonIndex(buttonTable, CoD.LobbyButtons.SERVER_BROWSER)) + local bgbIndex = utils.GetButtonIndex(buttonTable, CoD.LobbyButtons.ZM_BUBBLEGUM_BUFFS) + if bgbIndex ~= nil then + utils.AddSpacer(buttonTable, bgbIndex - 1) + end + utils.AddSpacer(buttonTable, utils.GetButtonIndex(buttonTable, CoD.LobbyButtons.STATS)) + end +end + +local oldAddButtonsForTarget = CoD.LobbyMenus.AddButtonsForTarget +CoD.LobbyMenus.AddButtonsForTarget = function(controller, id) + local model = nil + if Engine.IsLobbyActive(Enum.LobbyType.LOBBY_TYPE_GAME) then + model = Engine.GetModel(DataSources.LobbyRoot.getModel(controller), "gameClient.isHost") + else + model = Engine.GetModel(DataSources.LobbyRoot.getModel(controller), "privateClient.isHost") + end + local isLeader = nil + if model ~= nil then + isLeader = Engine.GetModelValue(model) + else + isLeader = 1 + end + local result = oldAddButtonsForTarget(controller, id) + addCustomButtons(controller, id, result, isLeader) + return result +end diff --git a/data/ui_scripts/frontend_menus/datasources_change_map_categories.lua b/data/ui_scripts/frontend_menus/datasources_change_map_categories.lua new file mode 100644 index 0000000..468c6bf --- /dev/null +++ b/data/ui_scripts/frontend_menus/datasources_change_map_categories.lua @@ -0,0 +1,96 @@ +local f0_local0 = function(f1_arg0, f1_arg1) + if not CoD.useMouse then + return + else + LUI.OverrideFunction_CallOriginalFirst(f1_arg0, "setState", function(element, controller) + if IsSelfInState(f1_arg0, "SelectingMap") then + f1_arg0.mapList:setMouseDisabled(false) + f1_arg0.mapCategoriesList:setMouseDisabled(true) + f1_arg0.m_categorySet = false + else + f1_arg0.mapList:setMouseDisabled(true) + f1_arg0.mapCategoriesList:setMouseDisabled(false) + end + end) + f1_arg0.mapList:setMouseDisabled(true) + f1_arg0.mapList:registerEventHandler("leftclick_outside", function(element, event) + if IsSelfInState(f1_arg0, "SelectingMap") and f1_arg0.m_categorySet then + CoD.PCUtil.SimulateButtonPress(f1_arg1, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE) + end + f1_arg0.m_categorySet = true + return true + end) + end +end + +local PostLoadFunc = function(f4_arg0, f4_arg1) + f0_local0(f4_arg0, f4_arg1) +end + +local f0_local2 = 10000 +local f0_local3 = 10001 +local f0_local4 = function(f5_arg0) + local f5_local0 = CoD.mapsTable[f5_arg0] + if CoD.CONTENT_DLC6_INDEX <= f5_local0.dlc_pack or f5_arg0 == "mp_redwood_ice" or f5_arg0 == "mp_veiled_heyday" then + return f0_local3 + elseif f5_local0.dlc_pack > 0 then + return f0_local2 + else + return f5_local0.dlc_pack + end +end + +DataSources.ChangeMapCategories = DataSourceHelpers.ListSetup("ChangeMapCategories", function(f6_arg0) + local f6_local0 = {} + local f6_local1 = CoD.GetMapValue(Engine.DvarString(nil, "ui_mapname"), "dlc_pack", CoD.CONTENT_ORIGINAL_MAP_INDEX) + local f6_local2 = function(f7_arg0, f7_arg1) + return { + models = { + text = Engine.Localize("MPUI_MAP_CATEGORY_" .. f7_arg0 .. "_CAPS"), + buttonText = Engine.Localize("MPUI_MAP_CATEGORY_" .. f7_arg0 .. "_CAPS"), + image = "playlist_map", + description = Engine.Localize("MPUI_MAP_CATEGORY_" .. f7_arg0 .. "_DESC") + }, + properties = { + category = f7_arg1, + selectIndex = f6_local1 == f7_arg1 + } + } + end + + CoD.mapsTable = Engine.GetGDTMapsTable() + local f6_local3 = function(f8_arg0) + for f8_local3, f8_local4 in pairs(CoD.mapsTable) do + if f8_local4.session_mode == CoD.gameModeEnum and f0_local4(f8_local3) == f8_arg0 and (ShowPurchasableMap(f6_arg0, f8_local3) or Engine.IsMapValid(f8_local3)) then + return true + end + end + return false + end + + if CoD.isCampaign == true then + table.insert(f6_local0, f6_local2("missions", CoD.CONTENT_ORIGINAL_MAP_INDEX)) + table.insert(f6_local0, f6_local2("dev", CoD.CONTENT_DEV_MAP_INDEX)) + else + table.insert(f6_local0, f6_local2("standard", CoD.CONTENT_ORIGINAL_MAP_INDEX)) + if not Dvar.ui_execdemo:get() and f6_local3(f0_local2) then + table.insert(f6_local0, f6_local2("dlc", f0_local2)) + end + if not Dvar.ui_execdemo:get() and f6_local3(f0_local3) then + table.insert(f6_local0, f6_local2("dlc_bonus", f0_local3)) + end + if Mods_Enabled() then --and Engine.Mods_Lists_GetInfoEntries( LuaEnums.USERMAP_BASE_PATH, 0, Engine.Mods_Lists_GetInfoEntriesCount( LuaEnums.USERMAP_BASE_PATH ) ) ~= nil then + local f9_local11 = Engine.Mods_Lists_GetInfoEntries(LuaEnums.USERMAP_BASE_PATH, 0, + Engine.Mods_Lists_GetInfoEntriesCount(LuaEnums.USERMAP_BASE_PATH)) + if f9_local11 then + for f9_local12 = 0, #f9_local11, 1 do + local f9_local17 = f9_local11[f9_local12] + if LUI.startswith(f9_local17.internalName, "mp_") then + table.insert(f6_local0, f6_local2("mods", CoD.CONTENT_MODS_INDEX)) + end + end + end + end + end + return f6_local0 +end, true) diff --git a/data/ui_scripts/frontend_menus/datasources_gamesettingsflyout_buttons.lua b/data/ui_scripts/frontend_menus/datasources_gamesettingsflyout_buttons.lua new file mode 100644 index 0000000..497efef --- /dev/null +++ b/data/ui_scripts/frontend_menus/datasources_gamesettingsflyout_buttons.lua @@ -0,0 +1,260 @@ +local f0_local0 = function(f1_arg0, f1_arg1) + if not CoD.useMouse then + return + else + f1_arg0.Options:setHandleMouse(true) + f1_arg0.Options:registerEventHandler("leftclick_outside", function(element, event) + CoD.PCUtil.SimulateButtonPress(event.controller, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE) + return true + end) + end +end + +local PostLoadFunc = function(f3_arg0, f3_arg1) + f0_local0(f3_arg0, f3_arg1) + f3_arg0.disableBlur = true + f3_arg0.disablePopupOpenCloseAnim = true + Engine.SetModelValue(Engine.CreateModel(Engine.GetGlobalModel(), "GameSettingsFlyoutOpen"), true) + LUI.OverrideFunction_CallOriginalSecond(f3_arg0, "close", function(element) + Engine.SetModelValue(Engine.CreateModel(Engine.GetGlobalModel(), "GameSettingsFlyoutOpen"), false) + end) + f3_arg0:registerEventHandler("occlusion_change", function(element, event) + local f5_local0 = element:getParent() + if f5_local0 then + local f5_local1 = f5_local0:getFirstChild() + while f5_local1 ~= nil do + if f5_local1.menuName == "Lobby" then + break + end + f5_local1 = f5_local1:getNextSibling() + end + if f5_local1 then + if event.occluded == true then + f5_local1:setAlpha(0) + end + f5_local1:setAlpha(1) + end + end + element:OcclusionChange(event) + end) + f3_arg0:subscribeToModel(Engine.CreateModel(Engine.GetGlobalModel(), "lobbyRoot.lobbyNav", true), function(model) + local f6_local0 = f3_arg0.occludedBy + while f6_local0 do + if f6_local0.occludedBy ~= nil then + f6_local0 = f6_local0.occludedBy + end + while f6_local0 and f6_local0.menuName ~= "Lobby" do + f6_local0 = GoBack(f6_local0, f3_arg1) + end + Engine.SendClientScriptNotify(f3_arg1, "menu_change" .. Engine.GetLocalClientNum(f3_arg1), "Main", + "closeToMenu") + return + end + GoBack(f3_arg0, f3_arg1) + end, false) +end + +DataSources.GameSettingsFlyoutButtonsCustom = DataSourceHelpers.ListSetup("GameSettingsFlyoutButtonsCustom", +function(f7_arg0) + local f7_local0 = { + { + optionDisplay = "MPUI_CHANGE_MAP_CAPS", + customId = "btnChangeMap", + action = OpenChangeMap + }, + -- { + -- optionDisplay = "MPUI_CHANGE_GAME_MODE_CAPS", + -- customId = "btnChangeGameMode", + -- action = OpenChangeGameMode + -- }, + { + optionDisplay = "MENU_SETUP_BOTS_CAPS", + customId = "btnSetupBots", + action = OpenBotSettings + }, + { + optionDisplay = "MPUI_EDIT_GAME_RULES_CAPS", + customId = "btnEditGameRules", + action = OpenEditGameRules + } + } + -- if CoD.isPC and IsServerBrowserEnabled() then + -- table.insert( f7_local0, { + -- optionDisplay = "PLATFORM_SERVER_SETTINGS_CAPS", + -- customID = "btnServerSettings", + -- action = OpenServerSettings + -- } ) + -- end + local f7_local1 = {} + for f7_local5, f7_local6 in ipairs(f7_local0) do + table.insert(f7_local1, { + models = { + displayText = Engine.Localize(f7_local6.optionDisplay), + customId = f7_local6.customId, + disabled = f7_local6.disabled + }, + properties = { + title = f7_local6.optionDisplay, + desc = f7_local6.desc, + action = f7_local6.action, + actionParam = f7_local6.actionParam + } + }) + end + return f7_local1 +end, nil, nil, nil) + +LUI.createMenu.GameSettingsFlyoutMPCustom = function(controller) + local self = CoD.Menu.NewForUIEditor("GameSettingsFlyoutMPCustom") + if PreLoadFunc then + PreLoadFunc(self, controller) + end + self.soundSet = "default" + self:setOwner(controller) + self:setLeftRight(true, true, 0, 0) + self:setTopBottom(true, true, 0, 0) + self:playSound("menu_open", controller) + self.buttonModel = Engine.CreateModel(Engine.GetModelForController(controller), "GameSettingsFlyoutMP.buttonPrompts") + self.anyChildUsesUpdateState = true + + local Options = LUI.UIList.new(self, controller, -2, 0, nil, false, false, 0, 0, false, false) + Options:makeFocusable() + Options:setLeftRight(true, false, 243.43, 523.43) + Options:setTopBottom(true, false, 177.56, 329.56) + Options:setYRot(25) + Options:setWidgetType(CoD.FE_List1ButtonLarge_PH) + Options:setVerticalCount(3) + Options:setSpacing(-2) + Options:setDataSource("GameSettingsFlyoutButtonsCustom") + Options:registerEventHandler("gain_focus", function(element, event) + local f9_local0 = nil + if element.gainFocus then + f9_local0 = element:gainFocus(event) + elseif element.super.gainFocus then + f9_local0 = element.super:gainFocus(event) + end + CoD.Menu.UpdateButtonShownState(element, self, controller, Enum.LUIButton.LUI_KEY_XBA_PSCROSS) + return f9_local0 + end) + Options:registerEventHandler("lose_focus", function(element, event) + local f10_local0 = nil + if element.loseFocus then + f10_local0 = element:loseFocus(event) + elseif element.super.loseFocus then + f10_local0 = element.super:loseFocus(event) + end + return f10_local0 + end) + self:AddButtonCallbackFunction(Options, controller, Enum.LUIButton.LUI_KEY_XBA_PSCROSS, "ENTER", + function(element, menu, controller, model) + ProcessListAction(self, element, controller) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_XBA_PSCROSS, "MENU_SELECT") + return true + end, false) + self:addElement(Options) + self.Options = Options + + self:mergeStateConditions({ + { + stateName = "Local", + condition = function(menu, element, event) + return IsLobbyNetworkModeLAN() + end + } + }) + self:subscribeToModel(Engine.GetModel(Engine.GetGlobalModel(), "lobbyRoot.lobbyNetworkMode"), function(model) + local f14_local0 = self + local f14_local1 = { + controller = controller, + name = "model_validation", + modelValue = Engine.GetModelValue(model), + modelName = "lobbyRoot.lobbyNetworkMode" + } + CoD.Menu.UpdateButtonShownState(f14_local0, self, controller, Enum.LUIButton.LUI_KEY_XBY_PSTRIANGLE) + end) + self:subscribeToModel(Engine.GetModel(Engine.GetGlobalModel(), "lobbyRoot.lobbyNav"), function(model) + local f15_local0 = self + local f15_local1 = { + controller = controller, + name = "model_validation", + modelValue = Engine.GetModelValue(model), + modelName = "lobbyRoot.lobbyNav" + } + CoD.Menu.UpdateButtonShownState(f15_local0, self, controller, Enum.LUIButton.LUI_KEY_XBY_PSTRIANGLE) + end) + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, nil, + function(element, menu, controller, model) + GoBack(self, controller) + ClearMenuSavedState(menu) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, "") + return false + end, false) + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_START, "M", + function(element, menu, controller, model) + GoBackAndOpenOverlayOnParent(self, "StartMenu_Main", controller) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_START, "MENU_MENU") + return true + end, false) + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_XBY_PSTRIANGLE, "S", + function(element, menu, controller, model) + if not IsLAN() and not IsPlayerAGuest(controller) and IsPlayerAllowedToPlayOnline(controller) then + GoBackAndOpenOverlayOnParent(self, "Social_Main", controller) + return true + else + + end + end, function(element, menu, controller) + if not IsLAN() and not IsPlayerAGuest(controller) and IsPlayerAllowedToPlayOnline(controller) then + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_XBY_PSTRIANGLE, "") + return false + else + return false + end + end, false) + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_LB, nil, + function(element, menu, controller, model) + SendButtonPressToOccludedMenu(menu, controller, model, Enum.LUIButton.LUI_KEY_LB) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_LB, "") + return false + end, false) + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_RB, nil, + function(element, menu, controller, model) + SendButtonPressToOccludedMenu(menu, controller, model, Enum.LUIButton.LUI_KEY_RB) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_RB, "") + return false + end, false) + Options.id = "Options" + self:processEvent({ + name = "menu_loaded", + controller = controller + }) + self:processEvent({ + name = "update_state", + menu = self + }) + if not self:restoreState() then + self.Options:processEvent({ + name = "gain_focus", + controller = controller + }) + end + LUI.OverrideFunction_CallOriginalSecond(self, "close", function(element) + element.Options:close() + Engine.UnsubscribeAndFreeModel(Engine.GetModel(Engine.GetModelForController(controller), + "GameSettingsFlyoutMP.buttonPrompts")) + end) + if PostLoadFunc then + PostLoadFunc(self, controller) + end + return self +end diff --git a/data/ui_scripts/frontend_menus/datasources_start_menu_tabs.lua b/data/ui_scripts/frontend_menus/datasources_start_menu_tabs.lua new file mode 100644 index 0000000..7776726 --- /dev/null +++ b/data/ui_scripts/frontend_menus/datasources_start_menu_tabs.lua @@ -0,0 +1,217 @@ +DataSources.StartMenuTabs = ListHelper_SetupDataSource("StartMenuTabs", function(f44_arg0) + local f44_local0 = {} + table.insert(f44_local0, { + models = { + tabIcon = CoD.buttonStrings.shoulderl + }, + properties = { + m_mouseDisabled = true + } + }) + if Engine.IsDemoPlaying() then + local f44_local1 = "CoD.StartMenu_GameOptions" + if Engine.IsZombiesGame() then + f44_local1 = "CoD.StartMenu_GameOptions_ZM" + end + table.insert(f44_local0, { + models = { + tabName = Engine.Localize("MENU_THEATER_CAPS"), + tabWidget = f44_local1, + tabIcon = "" + }, + properties = { + tabId = "gameOptions" + } + }) + elseif Engine.IsInGame() then + if IsGameTypeDOA() and not InSafehouse() then + table.insert(f44_local0, { + models = { + tabName = "DOA", + tabWidget = "CoD.StartMenu_GameOptions_DOA", + tabIcon = "" + }, + properties = { + tabId = "gameOptions" + } + }) + elseif CoD.isCampaign then + table.insert(f44_local0, { + models = { + tabName = SessionModeToUnlocalizedSessionModeCaps(Engine.CurrentSessionMode()), + tabWidget = "CoD.StartMenu_GameOptions_CP", + tabIcon = "" + }, + properties = { + tabId = "gameOptions" + } + }) + if not Engine.IsCampaignModeZombies() then + if CoD.isSafehouse and CoD.isOnlineGame() and not IsInTrainingSim(f44_arg0) and Dvar.ui_safehousebarracks:get() and not IsPlayerAGuest(f44_arg0) then + table.insert(f44_local0, { + models = { + tabName = "CPUI_BARRACKS_CAPS", + tabWidget = "CoD.CombatRecordCP_Contents", + tabIcon = "" + }, + properties = { + tabId = "combatRecord" + } + }) + end + if HighestMapReachedGreaterThan(f44_arg0, 1) or LUI.DEV ~= nil then + table.insert(f44_local0, { + models = { + tabName = "CPUI_TACTICAL_MODE_CAPS", + tabWidget = "CoD.StartMenu_TacticalMode", + tabIcon = "" + }, + properties = { + tabId = "tacticalMode" + } + }) + end + if not CoD.isSafehouse and not IsPlayerAGuest(f44_arg0) then + table.insert(f44_local0, { + models = { + tabName = "CPUI_ACCOLADES", + tabWidget = "CoD.MissionRecordVault_Challenges", + tabIcon = "" + }, + properties = { + tabId = "accolades" + } + }) + end + end + elseif Engine.IsZombiesGame() then + table.insert(f44_local0, { + models = { + tabName = SessionModeToUnlocalizedSessionModeCaps(Engine.CurrentSessionMode()), + tabWidget = "CoD.StartMenu_GameOptions_ZM", + tabIcon = "" + }, + properties = { + tabId = "gameOptions" + } + }) + else + table.insert(f44_local0, { + models = { + tabName = SessionModeToUnlocalizedSessionModeCaps(Engine.CurrentSessionMode()), + tabWidget = "CoD.StartMenu_GameOptions", + tabIcon = "" + }, + properties = { + tabId = "gameOptions" + } + }) + end + else + if not IsPlayerAGuest(f44_arg0) then + table.insert(f44_local0, { + models = { + tabName = "MENU_TAB_IDENTITY_CAPS", + tabWidget = "CoD.StartMenu_Identity", + tabIcon = "" + }, + properties = { + tabId = "identity", + disabled = Dvar.ui_execdemo_gamescom:get() + } + }) + end + if not IsLobbyNetworkModeLAN() and not Dvar.ui_execdemo:get() and not Engine.IsCampaignModeZombies() and not IsPlayerAGuest(f44_arg0) then + table.insert(f44_local0, { + models = { + tabName = "MENU_TAB_CHALLENGES_CAPS", + tabWidget = "CoD.StartMenu_Challenges", + tabIcon = "" + }, + properties = { + tabId = "challenges" + } + }) + local f44_local1 = CoD.isPC + if f44_local1 then + f44_local1 = false --Mods_IsUsingMods() + end + table.insert(f44_local0, { + models = { + tabName = "MENU_TAB_BARRACKS_CAPS", + tabWidget = "CoD.StartMenu_Barracks", + tabIcon = "", + disabled = f44_local1 + }, + properties = { + tabId = "barracks" + } + }) + if CommunityOptionsEnabled() then + local f44_local2 = CoD.perController[f44_arg0].openMediaTabAfterClosingGroups + CoD.perController[f44_arg0].openMediaTabAfterClosingGroups = false + table.insert(f44_local0, { + models = { + tabName = "MENU_TAB_MEDIA_CAPS", + tabWidget = "CoD.StartMenu_Media", + tabIcon = "" + }, + properties = { + tabId = "media", + selectIndex = f44_local2 + } + }) + end + end + end + if IsGameTypeDOA() and Engine.IsInGame() and not InSafehouse() then + local f44_local1 = table.insert + local f44_local2 = f44_local0 + local f44_local3 = { + models = { + tabName = "MENU_TAB_OPTIONS_CAPS", + tabWidget = "CoD.StartMenu_Options_DOA", + tabIcon = "" + } + } + local f44_local4 = { + tabId = "options" + } + local f44_local5 = Dvar.ui_execdemo:get() + if f44_local5 then + f44_local5 = not Engine.IsInGame() + end + f44_local4.selectIndex = f44_local5 + f44_local3.properties = f44_local4 + f44_local1(f44_local2, f44_local3) + else + local f44_local1 = table.insert + local f44_local2 = f44_local0 + local f44_local3 = { + models = { + tabName = "MENU_TAB_OPTIONS_CAPS", + tabWidget = "CoD.StartMenu_Options", + tabIcon = "" + } + } + local f44_local4 = { + tabId = "options" + } + local f44_local5 = Dvar.ui_execdemo_gamescom:get() + if f44_local5 then + f44_local5 = not Engine.IsInGame() + end + f44_local4.selectIndex = f44_local5 + f44_local3.properties = f44_local4 + f44_local1(f44_local2, f44_local3) + end + table.insert(f44_local0, { + models = { + tabIcon = CoD.buttonStrings.shoulderr + }, + properties = { + m_mouseDisabled = true + } + }) + return f44_local0 +end, true) diff --git a/data/ui_scripts/frontend_menus/utils.lua b/data/ui_scripts/frontend_menus/utils.lua new file mode 100644 index 0000000..f394e0a --- /dev/null +++ b/data/ui_scripts/frontend_menus/utils.lua @@ -0,0 +1,160 @@ +local IsGamescomDemo = function() + return Dvar.ui_execdemo_gamescom:get() +end + +local IsBetaDemo = function() + return Dvar.ui_execdemo_beta:get() +end + +local SetButtonState = function(button, state) + if state == nil then + return + elseif state == CoD.LobbyButtons.DISABLED then + button.disabled = true + elseif state == CoD.LobbyButtons.HIDDEN then + button.hidden = true + end +end + +local RemoveButton = function(buttonTable, button) + if not button then + return + end + for id, v in pairs(buttonTable) do + if buttonTable[id].optionDisplay == button.stringRef then + table.remove(buttonTable, id) + end + end +end + +local RemoveSpaces = function(buttonTable) + for id, v in pairs(buttonTable) do + buttonTable[id].isLastButtonInGroup = false + end +end + +local GetButtonIndex = function(buttonTable, button) + if not button then + return nil + end + for id, v in pairs(buttonTable) do + if buttonTable[id].optionDisplay == button.stringRef then + return id + end + end +end + +local AddButton = function(controller, options, button, isLargeButton, index) + if button == nil then + return + end + + button.disabled = false + button.hidden = false + button.selected = false + button.warning = false + if button.defaultState ~= nil then + if button.defaultState == CoD.LobbyButtons.DISABLED then + button.disabled = true + elseif button.defaultState == CoD.LobbyButtons.HIDDEN then + button.hidden = true + end + end + if button.disabledFunc ~= nil then + button.disabled = button.disabledFunc(controller) + end + if button.visibleFunc ~= nil then + button.hidden = not button.visibleFunc(controller) + end + if IsBetaDemo() then + SetButtonState(button, button.demo_beta) + elseif IsGamescomDemo() then + SetButtonState(button, button.demo_gamescom) + end + if button.hidden then + return + end + local lobbyNav = LobbyData.GetLobbyNav() + if button.selectedFunc ~= nil then + button.selected = button.selectedFunc(button.selectedParam) + elseif CoD.LobbyMenus.History[lobbyNav] ~= nil then + button.selected = CoD.LobbyMenus.History[lobbyNav] == button.customId + end + if button.newBreadcrumbFunc then + local f8_local1 = button.newBreadcrumbFunc + if type(f8_local1) == "string" then + f8_local1 = LUI.getTableFromPath(f8_local1) + end + if f8_local1 then + button.isBreadcrumbNew = f8_local1(controller) + end + end + if button.warningFunc ~= nil then + button.warning = button.warningFunc(controller) + end + if button.starterPack == CoD.LobbyButtons.STARTERPACK_UPGRADE then + button.starterPackUpgrade = true + if IsStarterPack() then + button.disabled = false + end + end + if index ~= nil then + table.insert(options, index, { + optionDisplay = button.stringRef, + action = button.action, + param = button.param, + customId = button.customId, + isLargeButton = isLargeButton, + isLastButtonInGroup = false, + disabled = button.disabled, + selected = button.selected, + isBreadcrumbNew = button.isBreadcrumbNew, + warning = button.warning, + requiredChunk = button.selectedParam, + starterPackUpgrade = button.starterPackUpgrade, + unloadMod = button.unloadMod + }) + else + table.insert(options, { + optionDisplay = button.stringRef, + action = button.action, + param = button.param, + customId = button.customId, + isLargeButton = isLargeButton, + isLastButtonInGroup = false, + disabled = button.disabled, + selected = button.selected, + isBreadcrumbNew = button.isBreadcrumbNew, + warning = button.warning, + requiredChunk = button.selectedParam, + starterPackUpgrade = button.starterPackUpgrade, + unloadMod = button.unloadMod + }) + end +end + +local AddLargeButton = function(controller, options, button, index) + AddButton(controller, options, button, true, index) +end + +local AddSmallButton = function(controller, options, button, index) + AddButton(controller, options, button, false, index) +end + +local AddSpacer = function(options, index) + if index ~= nil then + options[index].isLastButtonInGroup = true + elseif 0 < #options then + options[#options].isLastButtonInGroup = true + end +end + +return { + AddButton = AddButton, + AddLargeButton = AddLargeButton, + AddSmallButton = AddSmallButton, + AddSpacer = AddSpacer, + RemoveButton = RemoveButton, + RemoveSpaces = RemoveSpaces, + GetButtonIndex = GetButtonIndex +} diff --git a/data/ui_scripts/graphics_settings/__init__.lua b/data/ui_scripts/graphics_settings/__init__.lua new file mode 100644 index 0000000..1219bea --- /dev/null +++ b/data/ui_scripts/graphics_settings/__init__.lua @@ -0,0 +1,148 @@ +DataSources.OptionGraphicsVideo = DataSourceHelpers.ListSetup( "PC.OptionGraphicsVideo", function ( controller ) + local videoSettings = {} + table.insert( videoSettings, { + models = { + label = "PLATFORM_DISPLAY_MODE", + description = "PLATFORM_DISPLAY_MODE_DESC", + profileVarName = "r_fullscreen", + datasource = "OptionPCGraphicsDisplayMode", + widgetType = "dropdown" + }, + properties = CoD.PCUtil.DependantDropdownProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_MONITOR", + description = "PLATFORM_MONITOR_DESC", + profileVarName = "r_monitor", + datasource = "OptionPCGraphicsMonitor", + widgetType = "dropdown", + disabledFunction = function () + return Engine.GetHardwareProfileValueAsString( "r_fullscreen" ) == "0" + end + }, + properties = CoD.PCUtil.DependantDropdownProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_SCREEN_RESOLUTION", + description = "PLATFORM_SCREEN_RESOLUTION_DESC", + profileVarName = "r_mode", + datasource = "OptionPCGraphicsScreenResolution", + widgetType = "dropdown", + disabledFunction = function () + return Engine.GetHardwareProfileValueAsString( "r_fullscreen" ) == "2" + end + }, + properties = CoD.PCUtil.DependantDropdownProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_REFRESH_RATE", + description = "PLATFORM_REFRESH_RATE_DESC", + profileVarName = "r_refreshRate", + datasource = "OptionPCGraphicsRefreshRate", + widgetType = "dropdown", + disabledFunction = function () + return Engine.GetHardwareProfileValueAsString( "r_fullscreen" ) ~= "1" + end + }, + properties = CoD.PCUtil.OptionsGenericDropdownProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_SCENE_RESOLUTION_RATIO", + description = "PLATFORM_SCENE_RESOLUTION_RATIO_DESC", + profileVarName = "r_sceneResolutionMultiplier", + datasource = "OptionPCGraphicsSceneResolution", + widgetType = "dropdown" + }, + properties = CoD.PCUtil.DependantDropdownProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_DISPLAY_GAMMA", + description = "PLATFORM_DISPLAY_GAMMA_DESC", + profileVarName = "r_videoMode", + datasource = "OptionPCGraphicsDisplayGamma", + widgetType = "dropdown" + }, + properties = CoD.PCUtil.OptionsGenericDropdownProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_BRIGHTNESS", + description = "PLATFORM_BRIGHTNESS_DESC", + profileVarName = "r_sceneBrightness", + profileType = "user", + lowValue = -1, + highValue = 1, + widgetType = "slider" + }, + properties = CoD.PCUtil.OptionsGenericSliderProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_FOV", + description = "PLATFORM_FOV_DESC", + profileVarName = "cg_fov_default", + lowValue = 65, + highValue = 120, + useIntegerDisplay = 1, + widgetType = "slider" + }, + properties = CoD.PCUtil.OptionsGenericSliderProperties + } ) + table.insert( videoSettings, { + models = { + widgetType = "spacer", + height = 32 + } + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_MAX_FPS", + description = "PLATFORM_MAX_FPS_DESC", + profileVarName = "com_maxfps", + lowValue = 24, + highValue = 500, + useIntegerDisplay = 1, + widgetType = "slider" + }, + properties = CoD.PCUtil.OptionsGenericSliderProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_SYNC_EVERY_FRAME", + description = "PLATFORM_VSYNC_DESC", + profileVarName = "r_vsync", + widgetType = "checkbox" + }, + properties = CoD.PCUtil.OptionsGenericCheckboxProperties + } ) + table.insert( videoSettings, { + models = { + label = "PLATFORM_DRAW_FPS", + description = "PLATFORM_DRAW_FPS_DESC", + profileVarName = "com_drawFPS_PC", + widgetType = "checkbox" + }, + properties = CoD.PCUtil.OptionsGenericCheckboxProperties + } ) + return videoSettings +end, true ) +DataSources.OptionGraphicsVideo.getWidgetTypeForItem = function ( list, dataItemModel, row ) + if dataItemModel then + local widgetType = Engine.GetModelValue( Engine.GetModel( dataItemModel, "widgetType" ) ) + if widgetType == "dropdown" then + return CoD.OptionDropdown + elseif widgetType == "checkbox" then + return CoD.StartMenu_Options_CheckBoxOption + elseif widgetType == "slider" then + return CoD.StartMenu_Options_SliderBar + elseif widgetType == "spacer" then + return CoD.VerticalListSpacer + end + end + return nil +end \ No newline at end of file diff --git a/data/ui_scripts/lua_fixes/__init__.lua b/data/ui_scripts/lua_fixes/__init__.lua new file mode 100644 index 0000000..e04639b --- /dev/null +++ b/data/ui_scripts/lua_fixes/__init__.lua @@ -0,0 +1,4 @@ + +-- Fix LUI_NULL_FUNCTION messages +function Engine.PIXBeginEvent() end +function Engine.PIXEndEvent() end \ No newline at end of file diff --git a/data/ui_scripts/party/__init__.lua b/data/ui_scripts/party/__init__.lua new file mode 100644 index 0000000..663b0e8 --- /dev/null +++ b/data/ui_scripts/party/__init__.lua @@ -0,0 +1,30 @@ +local modeInfo = LobbyData:UITargetFromId(Engine.GetLobbyUIScreen()) +local maxClients = modeInfo.maxClients + +-- Disable setting party privacy in menu. Auto set to open + max. +Engine.SetDvar("partyprivacyenabled", 0) +Engine.SetDvar("tu4_partyprivacyuseglobal", 0) +Engine.SetDvar("tu4_partyprivacyluacheck", 0) + +-- Fix for invisible bots in custom games +if maxClients >= 1 then + Engine.SetDvar("party_maxplayers", maxClients) +end + +if not Engine.IsInGame() then + return +end + +-- Removed check for public matches to allow team change in ranked matches +CoD.IsTeamChangeAllowed = function() + if Engine.GetGametypeSetting("allowInGameTeamChange") == 1 then + return true + else + return false + end +end + +-- Set com_maxclients InGame so players can join via direct connect (default from lobbydata) +Engine.SetDvar("com_maxclients", maxClients) + +require("datasources_start_menu_game_options") diff --git a/data/ui_scripts/party/datasources_start_menu_game_options.lua b/data/ui_scripts/party/datasources_start_menu_game_options.lua new file mode 100644 index 0000000..ae6eb3b --- /dev/null +++ b/data/ui_scripts/party/datasources_start_menu_game_options.lua @@ -0,0 +1,75 @@ +DataSources.StartMenuGameOptions = ListHelper_SetupDataSource("StartMenuGameOptions", function (controller) + local options = {} + if Engine.IsDemoPlaying() then + if not IsDemoRestrictedBasicMode() then + table.insert(options, {models = {displayText = Engine.ToUpper(Engine.Localize("MENU_UPLOAD_CLIP", Engine.GetDemoSegmentCount())), action = StartMenuUploadClip, disabledFunction = IsUploadClipButtonDisabled}, properties = {hideHelpItemLabel = true}}) + end + if Engine.IsDemoHighlightReelMode() then + table.insert(options, {models = {displayText = Engine.ToUpper(Engine.Localize("MENU_DEMO_CUSTOMIZE_HIGHLIGHT_REEL")), action = StartMenuOpenCustomizeHighlightReel, disabledFunction = IsCustomizeHighlightReelButtonDisabled}}) + end + table.insert(options, {models = {displayText = Engine.ToUpper(Engine.ToUpper(Engine.Localize("MENU_JUMP_TO_START"))), action = StartMenuJumpToStart, disabledFunction = IsJumpToStartButtonDisabled}, properties = {hideHelpItemLabel = true}}) + local endDemoButtonText = nil + if Engine.IsDemoClipPlaying() then + endDemoButtonText = Engine.ToUpper(Engine.Localize("MENU_END_CLIP")) + else + endDemoButtonText = Engine.ToUpper(Engine.Localize("MENU_END_FILM")) + end + table.insert(options, {models = {displayText = Engine.ToUpper(endDemoButtonText), action = StartMenuEndDemo}}) + elseif CoD.isCampaign then + table.insert(options, {models = {displayText = "MENU_RESUMEGAME_CAPS", action = StartMenuGoBack_ListElement}}) + local inTrainingSim = CoD.SafeGetModelValue(Engine.GetModelForController(controller), "safehouse.inTrainingSim") + if not inTrainingSim then + inTrainingSim = 0 + end + if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) then + if not CoD.isSafehouse and controller == Engine.GetPrimaryController() then + table.insert(options, {models = {displayText = "MENU_RESTART_MISSION_CAPS", action = RestartMission}}) + if LUI.DEV ~= nil then + table.insert(options, {models = {displayText = "MENU_RESTART_CHECKPOINT_CAPS", action = RestartFromCheckpoint}}) + end + end + if controller == Engine.GetPrimaryController() then + table.insert(options, {models = {displayText = "MENU_CHANGE_DIFFICULTY_CAPS", action = OpenDifficultySelect}}) + end + if CoD.isSafehouse and inTrainingSim == 1 then + table.insert(options, {models = {displayText = "MENU_END_TRAINING_SIM", action = EndTrainingSim}}) + elseif controller == Engine.GetPrimaryController() then + if Engine.DvarBool(0, "ui_blocksaves") then + table.insert(options, {models = {displayText = "MENU_EXIT_CAPS", action = SaveAndQuitGame}}) + else + table.insert(options, {models = {displayText = "MENU_SAVE_AND_QUIT_CAPS", action = SaveAndQuitGame}}) + end + end + elseif CoD.isSafehouse and inTrainingSim == 1 then + table.insert(options, {models = {displayText = "MENU_END_TRAINING_SIM", action = EndTrainingSim}}) + else + table.insert(options, {models = {displayText = "MENU_LEAVE_PARTY_AND_EXIT_CAPS", action = QuitGame}}) + end + elseif CoD.isMultiplayer then + if Engine.Team(controller, "name") ~= "TEAM_SPECTATOR" and Engine.GetGametypeSetting("disableClassSelection") ~= 1 then + table.insert(options, {models = {displayText = "MPUI_CHOOSE_CLASS_BUTTON_CAPS", action = ChooseClass}}) + end + if not Engine.IsVisibilityBitSet(controller, Enum.UIVisibilityBit.BIT_ROUND_END_KILLCAM) and not Engine.IsVisibilityBitSet(controller, Enum.UIVisibilityBit.BIT_FINAL_KILLCAM) and CoD.IsTeamChangeAllowed() then + table.insert(options, {models = {displayText = "MPUI_CHANGE_TEAM_BUTTON_CAPS", action = ChooseTeam}}) + end + if controller == 0 then + local endGameText = "MENU_QUIT_GAME_CAPS" + if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) and not CoD.isOnlineGame() then + endGameText = "MENU_END_GAME_CAPS" + end + table.insert(options, {models = {displayText = endGameText, action = QuitGame_MP}}) + end + elseif CoD.isZombie then + table.insert(options, {models = {displayText = "MENU_RESUMEGAME_CAPS", action = StartMenuGoBack_ListElement}}) + if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) and (not Engine.SessionModeIsMode(CoD.SESSIONMODE_SYSTEMLINK) or Engine.SessionModeIsMode(CoD.SESSIONMODE_OFFLINE)) then + table.insert(options, {models = {displayText = "MENU_RESTART_LEVEL_CAPS", action = RestartGame}}) + end + if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) == true then + table.insert(options, {models = {displayText = "MENU_END_GAME_CAPS", action = QuitGame_MP}}) + else + table.insert(options, {models = {displayText = "MENU_QUIT_GAME_CAPS", action = QuitGame_MP}}) + end + end + table.insert(options, {models = {displayText = "QUIT TO DESKTOP", action = OpenPCQuit}}) + return options +end, true) diff --git a/data/ui_scripts/playlist/__init__.lua b/data/ui_scripts/playlist/__init__.lua new file mode 100644 index 0000000..f808066 --- /dev/null +++ b/data/ui_scripts/playlist/__init__.lua @@ -0,0 +1,34 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +if CoD.LobbyMember then + local oldLobbyMember = CoD.LobbyMember.new + function CoD.LobbyMember.new(menu, controller) + local self = oldLobbyMember(menu, controller) + + -- Hide the playlist count text + if self.SearchingForPlayer then + self.SearchingForPlayer:setAlpha(0) + end + if self.FEMemberBlurPanelContainer0 then + self.FEMemberBlurPanelContainer0:setAlpha(0) + end + + return self + end +end + +function IsLobbyStatusVisible() + return false +end + +Engine.SetDvar("lobbyMigrate_Enabled", 0) +Engine.SetDvar("lobbyTimerStatusVotingInterval", 11000) +Engine.SetDvar("lobbyTimerStatusBeginInterval", 10) +Engine.SetDvar("lobbyTimerStatusStartInterval", 10) +Engine.SetDvar("lobbyTimerStatusPostGameInterval", 10) +Engine.SetDvar("lobbyTimerStatusVotingInterval_Arena", 11000) + +require("widget_playlist_match_settings_info") +require("widget_playlist_category_match_settings_info") diff --git a/data/ui_scripts/playlist/widget_playlist_category_match_settings_info.lua b/data/ui_scripts/playlist/widget_playlist_category_match_settings_info.lua new file mode 100644 index 0000000..28c34d2 --- /dev/null +++ b/data/ui_scripts/playlist/widget_playlist_category_match_settings_info.lua @@ -0,0 +1,15 @@ +if not CoD.playlistCategoryMatchSettingsInfo then + return +end + +local oldPlaylistCategoryMatchSettingsInfo = CoD.playlistCategoryMatchSettingsInfo.new +function CoD.playlistCategoryMatchSettingsInfo.new(menu, controller) + local self = oldPlaylistCategoryMatchSettingsInfo(menu, controller) + + -- Hide the playlist count text + if self.playlistCount then + self.playlistCount:setAlpha(0) + end + + return self +end diff --git a/data/ui_scripts/playlist/widget_playlist_match_settings_info.lua b/data/ui_scripts/playlist/widget_playlist_match_settings_info.lua new file mode 100644 index 0000000..9b31390 --- /dev/null +++ b/data/ui_scripts/playlist/widget_playlist_match_settings_info.lua @@ -0,0 +1,15 @@ +if not CoD.playlistMatchSettingsInfo then + return +end + +local oldPlaylistMatchSettingsInfo = CoD.playlistMatchSettingsInfo.new +function CoD.playlistMatchSettingsInfo.new(menu, controller) + local self = oldPlaylistMatchSettingsInfo(menu, controller) + + -- Hide the playlist count text + if self.playlistCount then + self.playlistCount:setAlpha(0) + end + + return self +end diff --git a/data/ui_scripts/ranked/__init__.lua b/data/ui_scripts/ranked/__init__.lua new file mode 100644 index 0000000..685aa5c --- /dev/null +++ b/data/ui_scripts/ranked/__init__.lua @@ -0,0 +1 @@ +require("online_mods_loaded") diff --git a/data/ui_scripts/ranked/online_mods_loaded.lua b/data/ui_scripts/ranked/online_mods_loaded.lua new file mode 100644 index 0000000..2c388b9 --- /dev/null +++ b/data/ui_scripts/ranked/online_mods_loaded.lua @@ -0,0 +1,23 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +function ShouldUnloadMod(arg0) + return false +end + +-- Load usermaps mod if custom map selected +local mustLoadUsermaps = function(element, controller) + if CoD.perController[controller].mapCategory == CoD.CONTENT_MODS_INDEX then + if not Engine.IsUsingMods() then + LuaUtils.Mods_LoadMod("usermaps") -- LuaUtils.Mods_LoadMod(element.loadModName) + + CoD.OverlayUtility.ShowToast("DefaultState", Engine.Localize("MENU_MODS_CAPS"), Engine.Localize("PLATFORM_MODS_LOADED") .. " " .. element.mapName) + end + end +end + +function MapSelected(element, controller) + SetMap(controller, element.mapName, false) + mustLoadUsermaps(element, controller) +end diff --git a/data/ui_scripts/server_browser/__init__.lua b/data/ui_scripts/server_browser/__init__.lua new file mode 100644 index 0000000..49cd0fc --- /dev/null +++ b/data/ui_scripts/server_browser/__init__.lua @@ -0,0 +1,378 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +function IsServerBrowserEnabled() + return true +end + +DataSources.LobbyServer = { + prepare = function(controller, list, filter) + list.numElementsInList = list.vCount + list.controller = controller + list.serverBrowserRootModel = Engine.CreateModel(Engine.GetGlobalModel(), "serverBrowser") + local serverListCountModel = Engine.GetModel(list.serverBrowserRootModel, "serverListCount") + if serverListCountModel then + list.serverCount = Engine.GetModelValue(serverListCountModel) + else + list.serverCount = 0 + end + list.servers = {} + local serversModel = Engine.CreateModel(list.serverBrowserRootModel, "servers") + for i = 1, list.numElementsInList, 1 do + list.servers[i] = {} + list.servers[i].root = Engine.CreateModel(serversModel, "server_" .. i) + list.servers[i].model = Engine.CreateModel(list.servers[i].root, "model") + end + list.updateModels = function(controller, list, offset) + local serverInfo = Engine.SteamServerBrowser_GetServerInfo(offset) + if serverInfo then + local SetModelValue = function(model, key, value) + local model = Engine.CreateModel(model, key) + if model then + Engine.SetModelValue(model, value) + end + end + + local elementIndex = offset % list.numElementsInList + 1 + local serverModel = list.servers[elementIndex].model + SetModelValue(serverModel, "serverIndex", serverInfo.serverIndex) + SetModelValue(serverModel, "connectAddr", serverInfo.connectAddr) + SetModelValue(serverModel, "ping", serverInfo.ping) + SetModelValue(serverModel, "modName", serverInfo.modName) + SetModelValue(serverModel, "mapName", serverInfo.map) + SetModelValue(serverModel, "desc", serverInfo.desc) + -- Change the client count to be the actual player count + local clientCount = serverInfo.playerCount - serverInfo.botCount + SetModelValue(serverModel, "clientCount", clientCount) + SetModelValue(serverModel, "maxClients", serverInfo.maxPlayers) + SetModelValue(serverModel, "passwordProtected", serverInfo.password) + SetModelValue(serverModel, "secure", serverInfo.secure) + SetModelValue(serverModel, "name", serverInfo.name) + SetModelValue(serverModel, "gameType", serverInfo.gametype) + SetModelValue(serverModel, "dedicated", serverInfo.dedicated) + SetModelValue(serverModel, "ranked", serverInfo.ranked) + SetModelValue(serverModel, "hardcore", serverInfo.hardcore) + SetModelValue(serverModel, "zombies", serverInfo.zombies) + -- Add the bot count + SetModelValue(serverModel, "botCount", serverInfo.botCount) + return serverModel + else + return nil + end + end + + if list.serverListUpdateSubscription then + list:removeSubscription(list.serverListUpdateSubscription) + end + local serverListUpdateModel = Engine.CreateModel(list.serverBrowserRootModel, "serverListCount") + list.serverListUpdateSubscription = list:subscribeToModel(serverListUpdateModel, function(model) + list:updateDataSource(false, false) + end, false) + if list.serverListSortTypeSubscription then + list:removeSubscription(list.serverListSortTypeSubscription) + end + local serverListSortTypeModel = Engine.CreateModel(list.serverBrowserRootModel, "serverListSortType") + list.serverListSortTypeSubscription = list:subscribeToModel(serverListSortTypeModel, function(model) + list:updateDataSource(false, false) + end, false) + end, + getCount = function(list) + return list.serverCount + end, + getItem = function(controller, list, index) + local offset = index - 1 + return list.updateModels(controller, list, offset) + end, + cleanup = function(list) + if list.serverBrowserRootModel then + Engine.UnsubscribeAndFreeModel(list.serverBrowserRootModel) + list.serverBrowserRootModel = nil + end + end +} + +CoD.ServerBrowserRowInternal.new = function(menu, controller) + local self = LUI.UIHorizontalList.new({ + left = 0, + top = 0, + right = 0, + bottom = 0, + leftAnchor = true, + topAnchor = true, + rightAnchor = true, + bottomAnchor = true, + spacing = 2 + }) + self:setAlignment(LUI.Alignment.Left) + if PreLoadFunc then + PreLoadFunc(self, controller) + end + self:setUseStencil(false) + self:setClass(CoD.ServerBrowserRowInternal) + self.id = "ServerBrowserRowInternal" + self.soundSet = "default" + self:setLeftRight(true, false, 0, 700) + self:setTopBottom(true, false, 0, 22) + self:makeFocusable() + self.onlyChildrenFocusable = true + self.anyChildUsesUpdateState = true + + local passwordFlag = CoD.ServerBrowserFlag.new(menu, controller) + passwordFlag:setLeftRight(true, false, 0, 28) + passwordFlag:setTopBottom(true, true, 0, 0) + passwordFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_protected")) + passwordFlag:linkToElementModel(self, nil, false, function(model) + passwordFlag:setModel(model, controller) + end) + passwordFlag:mergeStateConditions({ + { + stateName = "FlagOn", + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "passwordProtected") + end + } + }) + passwordFlag:linkToElementModel(passwordFlag, "passwordProtected", true, function(model) + menu:updateElementState(passwordFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue(model), + modelName = "passwordProtected" + }) + end) + self:addElement(passwordFlag) + self.passwordFlag = passwordFlag + + local dedicatedFlag = CoD.ServerBrowserFlag.new(menu, controller) + dedicatedFlag:setLeftRight(true, false, 30, 58) + dedicatedFlag:setTopBottom(true, true, 0, 0) + dedicatedFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_dedicated")) + dedicatedFlag:linkToElementModel(self, nil, false, function(model) + dedicatedFlag:setModel(model, controller) + end) + dedicatedFlag:mergeStateConditions({ + { + stateName = "FlagOn", + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "dedicated") + end + } + }) + dedicatedFlag:linkToElementModel(dedicatedFlag, "dedicated", true, function(model) + menu:updateElementState(dedicatedFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue(model), + modelName = "dedicated" + }) + end) + self:addElement(dedicatedFlag) + self.dedicatedFlag = dedicatedFlag + + local rankedFlag = CoD.ServerBrowserFlag.new(menu, controller) + rankedFlag:setLeftRight(true, false, 60, 88) + rankedFlag:setTopBottom(true, true, 0, 0) + rankedFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_ranked")) + rankedFlag:linkToElementModel(self, nil, false, function(model) + rankedFlag:setModel(model, controller) + end) + rankedFlag:mergeStateConditions({ + { + stateName = "FlagOn", + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "ranked") + end + } + }) + rankedFlag:linkToElementModel(rankedFlag, "ranked", true, function(model) + menu:updateElementState(rankedFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue(model), + modelName = "ranked" + }) + end) + self:addElement(rankedFlag) + self.rankedFlag = rankedFlag + + local name = CoD.horizontalScrollingTextBox_18pt.new(menu, controller) + name:setLeftRight(true, false, 90, 330) + name:setTopBottom(true, false, 2, 20) + name.textBox:setTTF("fonts/default.ttf") + name.textBox:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + name:linkToElementModel(self, "name", true, function(model) + local _name = Engine.GetModelValue(model) + if _name then + name.textBox:setText(Engine.Localize(_name)) + end + end) + self:addElement(name) + self.name = name + + local spacer = LUI.UIFrame.new(menu, controller, 0, 0, false) + spacer:setLeftRight(true, false, 332, 339) + spacer:setTopBottom(true, false, 0, 22) + spacer:setAlpha(0) + self:addElement(spacer) + self.spacer = spacer + + local map = CoD.horizontalScrollingTextBox_18pt.new(menu, controller) + map:setLeftRight(true, false, 341, 446) + map:setTopBottom(true, false, 2, 20) + map.textBox:setTTF("fonts/default.ttf") + map.textBox:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + map:linkToElementModel(self, "mapName", true, function(model) + local mapName = Engine.GetModelValue(model) + if mapName then + map.textBox:setText(MapNameToLocalizedMapName(mapName)) + end + end) + self:addElement(map) + self.map = map + + local hardcoreFlag = CoD.ServerBrowserFlag.new(menu, controller) + hardcoreFlag:setLeftRight(true, false, 448, 470) + hardcoreFlag:setTopBottom(true, true, 0, 0) + hardcoreFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_skull")) + hardcoreFlag:linkToElementModel(self, nil, false, function(model) + hardcoreFlag:setModel(model, controller) + end) + hardcoreFlag:mergeStateConditions({ + { + stateName = "FlagOn", + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "hardcore") + end + } + }) + hardcoreFlag:linkToElementModel(hardcoreFlag, "hardcore", true, function(model) + menu:updateElementState(hardcoreFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue(model), + modelName = "hardcore" + }) + end) + self:addElement(hardcoreFlag) + self.hardcoreFlag = hardcoreFlag + + local gametype = LUI.UIText.new() + gametype:setLeftRight(true, false, 472, 576) + gametype:setTopBottom(true, false, 2, 20) + gametype:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + gametype:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + gametype:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + gametype:linkToElementModel(self, "gameType", true, function(model) + local gameType = Engine.GetModelValue(model) + if gameType then + gametype:setText(Engine.Localize(GetGameTypeDisplayString(gameType))) + end + end) + self:addElement(gametype) + self.gametype = gametype + + local playerCount = LUI.UIText.new() + playerCount:setLeftRight(true, false, 593, 613) + playerCount:setTopBottom(true, false, 2, 20) + playerCount:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + playerCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_RIGHT) + playerCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + playerCount:linkToElementModel(self, "clientCount", true, function(model) + local clientCount = Engine.GetModelValue(model) + if clientCount then + playerCount:setText(Engine.Localize(clientCount)) + end + end) + self:addElement(playerCount) + self.playerCount = playerCount + + local slash = LUI.UIText.new() + slash:setLeftRight(true, false, 615, 624) + slash:setTopBottom(true, false, 2, 20) + slash:setText(Engine.Localize("/")) + slash:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + slash:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + slash:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + self:addElement(slash) + self.slash = slash + + local maxPlayers = LUI.UIText.new() + maxPlayers:setLeftRight(true, false, 626, 645) + maxPlayers:setTopBottom(true, false, 2, 20) + maxPlayers:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + maxPlayers:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + maxPlayers:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + maxPlayers:linkToElementModel(self, "maxClients", true, function(model) + local maxClients = Engine.GetModelValue(model) + if maxClients then + maxPlayers:setText(Engine.Localize(maxClients)) + end + end) + self:addElement(maxPlayers) + self.maxPlayers = maxPlayers + + local botCount = LUI.UIText.new() + botCount:setLeftRight(true, false, 637, 659) + botCount:setTopBottom(true, false, 2, 20) + botCount:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + botCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + botCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + botCount:linkToElementModel(self, "botCount", true, function(model) + local _botCount = Engine.GetModelValue(model) + if _botCount then + botCount:setText("[" .. Engine.Localize(_botCount) .. "]") + end + end) + botCount:linkToElementModel(self, "zombies", true, function(model) + local zombies = Engine.GetModelValue(model) + if zombies ~= nil then + botCount:setAlpha(zombies and 0 or 1) + end + end) + self:addElement(botCount) + self.botCount = botCount + + local ping = LUI.UIText.new() + ping:setLeftRight(true, false, 661, 699.37) + ping:setTopBottom(true, false, 2, 20) + ping:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + ping:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_CENTER) + ping:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + ping:linkToElementModel(self, "ping", true, function(model) + local _ping = Engine.GetModelValue(model) + if _ping then + ping:setText(Engine.Localize(_ping)) + end + end) + self:addElement(ping) + self.ping = ping + + spacer.id = "spacer" + self:registerEventHandler("gain_focus", function(self, event) + if self.m_focusable and self.spacer:processEvent(event) then + return true + else + return LUI.UIElement.gainFocus(self, event) + end + end) + LUI.OverrideFunction_CallOriginalSecond(self, "close", function(element) + element.passwordFlag:close() + element.dedicatedFlag:close() + element.rankedFlag:close() + element.name:close() + element.map:close() + element.hardcoreFlag:close() + element.gametype:close() + element.playerCount:close() + element.maxPlayers:close() + element.botCount:close() + element.ping:close() + end) + + if PostLoadFunc then + PostLoadFunc(self, controller, menu) + end + + return self +end diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua new file mode 100644 index 0000000..78f62b1 --- /dev/null +++ b/data/ui_scripts/stats/__init__.lua @@ -0,0 +1,421 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", function(controller) + local optionsTable = {} + + local updateDvar = function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + local oldValue = Engine.DvarInt(nil, dvarName) + local newValue = f1_arg1.value + UpdateInfoModels(f1_arg1) + if oldValue == newValue then + return + end + Engine.SetDvar(dvarName, f1_arg1.value) + if dvarName == "cg_unlockall_loot" then + Engine.SetDvar("ui_enableAllHeroes", f1_arg1.value) + end + if dvarName == "all_ee_completed" then + Engine.ExecNow(f1_arg0, "statsetbyname darkops_zod_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_zod_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_factory_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_factory_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_castle_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_castle_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_island_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_island_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_stalingrad_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_stalingrad_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_genesis_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname DARKOPS_GENESIS_SUPER_EE " .. f1_arg1.value) + end + end + + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Loot", + "Unlocks all Black Market loot.", "MPStatsSettings_unlock_loot", + "cg_unlockall_loot", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Purchases", + "All items that need to be purchased with unlock tokens are unlocked.", "MPStatsSettings_purchase_all", + "cg_unlockall_purchases", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Class Slots", + "Unlocks all create-a-class slots and sets.", "MPStatsSettings_unlockall_cac_slots", + "cg_unlockall_cac_slots", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + end + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Attachments", + "All attachments on weapons are unlocked.", + "MPStatsSettings_unlockall_attachments", "cg_unlockall_attachments", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Camos and Reticles", + "All camos and reticles on weapons are unlocked.", "MPStatsSettings_unlockall_camos_and_reticles", + "cg_unlockall_camos_and_reticles", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Calling Cards", "All calling cards are unlocked.", + "MPStatsSettings_unlockall_calling_cards", "cg_unlockall_calling_cards", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Specialists Outfits", + "All specialists outfits are unlocked.", "MPStatsSettings_unlockall_specialists_outfits", + "cg_unlockall_specialists_outfits", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + end + if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock Easter Eggs", + "Complete all Easter Egg Achievements.", "MPStatsSettings_complete_ee", + "all_ee_completed", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + end + + local rankLevels = {} + local rankObjs = {} + local hasDefault = true + local currentPrestige = CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()) + local currentRank = CoD.BlackMarketUtility.GetCurrentRank(controller) + 1 + + local isMasterPrestige = currentPrestige == 11 + + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + if not isMasterPrestige then + rankLevels = { 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55 } + else + rankLevels = { 56, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 } + end + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + if not isMasterPrestige then + rankLevels = { 1, 5, 10, 15, 20, 25, 30, 35 } + else + rankLevels = { 36, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 } + end + end + + local maxlevel = math.max(table.unpack(rankLevels)) + local minlevel = math.min(table.unpack(rankLevels)) + + for index, value in ipairs(rankLevels) do + table.insert(rankObjs, { + name = value <= minlevel and "Min" or value >= maxlevel and "Max" or value, + value = value - 1, + default = value == currentRank, + title = "Rank Level", + desc = value ~= currentRank and "" or "Current Rank" + }) + end + + if hasDefault and currentRank ~= minlevel and currentRank < maxlevel and not isMasterPrestige then + table.insert(rankObjs, { + name = "Current: " .. + tostring(currentRank <= minlevel and "Min" or currentRank >= maxlevel and "Max" or currentRank), + value = currentRank - 1, + default = true, + title = "Rank Level", + desc = "Do not adjust rank" + }) + end + + local prestigeTable = {} + for i = 0, 11 do + table.insert(prestigeTable, { + name = i == 0 and "None" or i == 11 and "Master" or i, + value = i, + default = i == currentPrestige, + title = "Prestige", + desc = "" + }) + end + + local createSettingsDatasource = function(controller, datasourceName, optionsTable, currentValue, loopEdges, action) + if currentValue == nil then + currentValue = 0 + end + DataSources[datasourceName] = DataSourceHelpers.ListSetup(datasourceName, function(f47_arg0) + local f47_local0 = {} + for f47_local4, f47_local5 in ipairs(optionsTable) do + table.insert(f47_local0, { + models = { + text = optionsTable[f47_local4].name + }, + properties = { + title = optionsTable[f47_local4].title, + desc = optionsTable[f47_local4].desc, + image = optionsTable[f47_local4].image, + value = optionsTable[f47_local4].value, + default = optionsTable[f47_local4].default, + action = action, + selectIndex = optionsTable[f47_local4].value == currentValue, + loopEdges = loopEdges, + showChangeIndicator = function(f48_arg0, f48_arg1, f48_arg2) + return f48_arg0.default ~= true + end + } + }) + end + f47_local0[1].properties.first = true + f47_local0[#optionsTable].properties.last = true + return f47_local0 + end, nil, nil, nil) + return datasourceName + end + + table.insert(optionsTable, { + models = { + name = "Prestige", + desc = "", + image = nil, + optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_prestige", prestigeTable, + CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()), false, + function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + UpdateInfoModels(f1_arg1) + local newPrestige = f1_arg1.value + if newPrestige == 11 then + Engine.Exec(f1_arg0, "PrestigeStatsMaster " .. tostring(Engine.CurrentSessionMode())) + end + Engine.ExecNow(f1_arg0, "statsetbyname plevel " .. newPrestige) + Engine.ExecNow(f1_arg0, "statsetbyname hasprestiged " .. (newPrestige > 0 and 1 or 0)) + Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + end) + }, + properties = { + revert = function(f50_arg0) + end + } + }) + + table.insert(optionsTable, { + models = { + name = "Rank Level", + desc = "", + image = nil, + optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_level", rankObjs, + CoD.BlackMarketUtility.GetCurrentRank(controller), false, + function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + UpdateInfoModels(f1_arg1) + local rankTable = nil + local rank = f1_arg1.value + 1 + if currentPrestige <= 10 then + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + rankTable = "gamedata/tables/mp/mp_ranktable.csv" + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + rankTable = "gamedata/tables/zm/zm_ranktable.csv" + end + local skipLines = Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER and 3 or 2 + local maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, rank - 2 + skipLines, 7)) + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 55600 + end + end + if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 54244 + end + end + if maxXp == nil then + maxXp = 0 + end + Engine.ExecNow(f1_arg0, "statsetbyname rank " .. rank - 1) + Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. 0) + else + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + rankTable = "gamedata/tables/mp/mp_paragonranktable.csv" + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + rankTable = "gamedata/tables/zm/zm_paragonranktable.csv" + end + local skipLines = 2 + local maxXp = 0 + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, rank - 57 + skipLines, 7)) + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 55600 + end + rank = rank - 55 + end + if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, rank - 37 + skipLines, 7)) + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 54244 + end + rank = rank - 35 + end + if maxXp == nil then + maxXp = 0 + end + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rank " .. rank - 1) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. maxXp) + end + Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + + currentRank = rank + end) + }, + properties = { + revert = function(f50_arg0) + end + } + }) + + return optionsTable +end) + +if Dvar.cg_unlockall_loot:get() == true then + Engine.SetDvar("ui_enableAllHeroes", 1) +end + +LUI.createMenu.T7xStatsMenu = function(controller) + local self = CoD.Menu.NewForUIEditor("T7xStatsMenu") + if PreLoadFunc then + PreLoadFunc(self, controller) + end + self.soundSet = "ChooseDecal" + self:setOwner(controller) + self:setLeftRight(true, true, 0, 0) + self:setTopBottom(true, true, 0, 0) + self:playSound("menu_open", controller) + self.buttonModel = Engine.CreateModel(Engine.GetModelForController(controller), "T7xStatsMenu.buttonPrompts") + self.anyChildUsesUpdateState = true + + local GameSettingsBackground = CoD.GameSettings_Background.new(self, controller) + GameSettingsBackground:setLeftRight(true, true, 0, 0) + GameSettingsBackground:setTopBottom(true, true, 0, 0) + GameSettingsBackground.MenuFrame.titleLabel:setText(Engine.Localize("STATS SETTINGS")) + GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText( + Engine.Localize("STATS SETTINGS")) + GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeInfo:setAlpha(0) + GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeName:setAlpha(0) + self:addElement(GameSettingsBackground) + self.GameSettingsBackground = GameSettingsBackground + + local Options = CoD.Competitive_SettingsList.new(self, controller) + Options:setLeftRight(true, false, 26, 741) + Options:setTopBottom(true, false, 135, 720) + Options.Title.DescTitle:setText(Engine.Localize("Stats")) + Options.ButtonList:setVerticalCount(15) + Options.ButtonList:setDataSource("MPStatsSettings") + self:addElement(Options) + self.Options = Options + + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, nil, + function(element, menu, controller, model) + GoBack(self, controller) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", nil) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, "MENU_BACK") + return true + end, false) + + GameSettingsBackground.MenuFrame:setModel(self.buttonModel, controller) + Options.id = "Options" + + self:processEvent({ + name = "menu_loaded", + controller = controller + }) + self:processEvent({ + name = "update_state", + menu = self + }) + if not self:restoreState() then + self.Options:processEvent({ + name = "gain_focus", + controller = controller + }) + end + + LUI.OverrideFunction_CallOriginalSecond(self, "close", function(element) + element.GameSettingsBackground:close() + element.Options:close() + Engine.UnsubscribeAndFreeModel(Engine.GetModel(Engine.GetModelForController(controller), + "T7xStatsMenu.buttonPrompts")) + end) + + if PostLoadFunc then + PostLoadFunc(self, controller) + end + + return self +end