From 7a0915a45ea2f05a834c6178a8b5cba15e04b1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=9F=D1=80=D0=BE?= =?UTF-8?q?=D0=B3=D0=B5=D1=80?= Date: Sat, 9 Jul 2022 01:22:35 +0300 Subject: [PATCH] Bug fixed, features added, code rewritten. --- Maps/lua.w3m | Bin 111614 -> 0 bytes README.md | 6 +- Scripts/blizzard.lua | 45 +- Scripts/common.lua | 2 +- Src Backup/.vscode/settings.json | 27 - Src Backup/FrameAPI.cpp | 158 ---- Src Backup/FrameAPI.h | 105 --- Src Backup/Hooks.cpp | 58 -- Src Backup/Hooks.h | 11 - Src Backup/JassMachine.cpp | 44 - Src Backup/JassMachine.h | 148 ---- Src Backup/JassNatives.cpp | 156 ---- Src Backup/JassNatives.h | 189 ---- Src Backup/LuaMachine.cpp | 438 --------- Src Backup/LuaMachine.h | 28 - Src Backup/LuaRegister.cpp | 405 --------- Src Backup/LuaRegister.h | 8 - Src Backup/Main.cpp | 55 -- Src Backup/Mem.h | 61 -- Src Backup/Variables.h | 76 -- Src Backup/Warcraft.cpp | 29 - Src Backup/Warcraft.h | 1345 ---------------------------- Src Backup/WarcraftFunctions.cpp | 92 -- Src Backup/WarcraftFunctions.h | 41 - Src Backup/fcalls.h | 16 - Src/{Main.cpp => DllMain.cpp} | 48 +- Src/EasterEgg.cpp | 54 ++ Src/EasterEgg.h | 6 + Src/EasyStormLib/EasyStormLib.cpp | 94 ++ Src/EasyStormLib/EasyStormLib.h | 23 + Src/EasyStormLib/StormLib.h | 16 + Src/GameUI.cpp | 785 ----------------- Src/GameUI.h | 507 ----------- Src/Hooks.cpp | 140 +-- Src/Hooks.h | 8 +- Src/JassMachine.cpp | 61 +- Src/JassMachine.h | 408 ++++++--- Src/JassNatives.cpp | 224 +++-- Src/JassNatives.h | 139 ++- Src/Logger.cpp | 117 +++ Src/Logger.h | 27 + Src/LuaFunctions.cpp | 1370 +++++++---------------------- Src/LuaFunctions.h | 11 +- Src/LuaHooks.cpp | 417 +++++---- Src/LuaHooks.h | 13 +- Src/LuaMachine.cpp | 258 +++--- Src/LuaMachine.h | 20 +- Src/MemHack.cpp | 489 ---------- Src/MemHack.h | 65 -- Src/Utils.cpp | 99 --- Src/Utils.h | 12 - Src/Warcraft.cpp | 33 +- Src/Warcraft.h | 70 +- Src/fp_call.h | 77 ++ Src/pch.cpp | 1 + Src/{Global.h => pch.h} | 23 +- war3_lua.sln | 10 +- war3_lua.vcxproj | 338 +++++-- war3_lua.vcxproj.filters | 59 +- 59 files changed, 1978 insertions(+), 7587 deletions(-) delete mode 100644 Maps/lua.w3m delete mode 100644 Src Backup/.vscode/settings.json delete mode 100644 Src Backup/FrameAPI.cpp delete mode 100644 Src Backup/FrameAPI.h delete mode 100644 Src Backup/Hooks.cpp delete mode 100644 Src Backup/Hooks.h delete mode 100644 Src Backup/JassMachine.cpp delete mode 100644 Src Backup/JassMachine.h delete mode 100644 Src Backup/JassNatives.cpp delete mode 100644 Src Backup/JassNatives.h delete mode 100644 Src Backup/LuaMachine.cpp delete mode 100644 Src Backup/LuaMachine.h delete mode 100644 Src Backup/LuaRegister.cpp delete mode 100644 Src Backup/LuaRegister.h delete mode 100644 Src Backup/Main.cpp delete mode 100644 Src Backup/Mem.h delete mode 100644 Src Backup/Variables.h delete mode 100644 Src Backup/Warcraft.cpp delete mode 100644 Src Backup/Warcraft.h delete mode 100644 Src Backup/WarcraftFunctions.cpp delete mode 100644 Src Backup/WarcraftFunctions.h delete mode 100644 Src Backup/fcalls.h rename Src/{Main.cpp => DllMain.cpp} (68%) create mode 100644 Src/EasterEgg.cpp create mode 100644 Src/EasterEgg.h create mode 100644 Src/EasyStormLib/EasyStormLib.cpp create mode 100644 Src/EasyStormLib/EasyStormLib.h create mode 100644 Src/EasyStormLib/StormLib.h delete mode 100644 Src/GameUI.cpp delete mode 100644 Src/GameUI.h create mode 100644 Src/Logger.cpp create mode 100644 Src/Logger.h delete mode 100644 Src/MemHack.cpp delete mode 100644 Src/MemHack.h delete mode 100644 Src/Utils.cpp delete mode 100644 Src/Utils.h create mode 100644 Src/fp_call.h create mode 100644 Src/pch.cpp rename Src/{Global.h => pch.h} (56%) diff --git a/Maps/lua.w3m b/Maps/lua.w3m deleted file mode 100644 index 6e7ef8321f61132fc03e7f772667a1fe303611ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111614 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�<1cM+C;C2%<5vj)er|O)IGKuT@dP~-=z`0g>y5@7|T3^ zscPvq#S(kYQfohZk5XX=ApA-)%Hf#q0npb4gZo7@rVR<}4qNw5TorUe7e*Mx9lRI`)q8<%|b4kqmQWAFQ)4aS{OItWrB zvJLuqhvOk2B`_04h08BH8n7l}@q+Ql7W$U$q{V8oG4SKm=MYcl6S_V;hFJsT^fs2? zehZ2pM8ahY9m=DQ+zB&bMRT65 z7_LjFR|p=q?*vnOM0LL ze@BL|o689VeMBb3{0$b*d+*JSxibghkmoooWJ5=*o%4qT(*Q{NoIBH~VaMQTh}f9& zBH;ZD0xvuo*Kn8`_=$QXoh18}m69K*GWdjxSA5xd&I3(3n1zp{vb$c9ZgRx-AvK-? z^Pa68>%iF^WjoAgwZECN(lL<}{VJNu;|l^oy8w2<>Zw#caoc`Ed)q_)jL3a)33Fm3 zi=cLBdwtj){%Y$|Ml{4_{w1Z#H>9-rtLO7bH^a_!XvS#pHA9lwE!UM(_Q^tYpo_1za1> z4h4P3frUcwb`lyS7a-^vvnEeYhiX}7E!1u>c!}+2sI$+vln4XXT(1XekN5_|ut9n; zCvvW^7whNlcY8~n_IA;k@n93X0&#dO;iWv=zYc>SqM=i5NR_VIHSf{YO4YG3=TR47 z1A7zGo?nX;B%CFC#by)@@*aCccZmR{6`k+n{(PZA{5dWVGMsRktG{!BI)%~f)X_!_ zE@v~UamDDQ!sTx-b>1Y6PhP|-`6D$ALCO}1TZdpltV^DA z2|v8ErP)0g!A(D>$33Vx2K%fTG)55!mT@C=vap$W*A* zJ2WXMyy-Se+xguc0t;t{lI2*Q+vob#={n0Y{n0n8``WvCiz7uPH{G}$Q2$zl?-P&U zdNYGhd3-TP7kL}Xnkel`m*zFx=yz6M11_6(g3~k)ZKSD5M4OehdFhYK&@l8}G?{ke zzEzH?dulxMux;)?Eu#g{z`a=cIS!iXbDVS1na;Rg zIw5jt;q#5P@K2(Nwc#{P>nIU)7i^tA1T~u{r}vf$3ZH^0pWsNk3U{Fld%3~M7{Dlf z_JKXI_9{mg-KTF6gpIL@Dm|>@ta)1R)m~oMWQkvq(uZqgVHxpghh)D1J0Xu^4Tzrc zFs;TU(Kud-z9ueC6v3)ATik!}UcW1A`z5ki z#j^C@`UOrWZ1$vq$Z!pZ-t^@%A{wzs@!{h#0asPe%jYM#Pc#yF$#&YmFybV7*cP{M z4Tu)bpDoCwT?X7fQD(_0`OC~=hboS(MIRTs=}$m4>(6nN5L;RXl9u|J%YmaPs3Z}{I6!Fb38IMs$v9tX<4N~$qYE}?2g%T!AS2h$@F^+ygLd5}1V zMedWNTFqh3LZ_<$(DaL6t?Hsbf7)h3Ym>ngWSfZvpq5&wloSuqMpy<6|5?AHYiR*h zy};Z?*LUyJ(|5;!|HH)n0oANev>5!8JHa!iTNo3Hv4n73$E-^n;1d(?`w z)QH6q{R6s}q0$cZOh$yw@siWG^KbX%z&W3Uku>{f;L(1$8HDa0Cyn%L^yY1(IQ_IC zf5e5A>3d`%rR*zLZyWWk`q&weFAR{aN#~`ij_(rL8CXrRR$jjP`S6_Ui@1Kvx&7T& zx%C51uh&T7pXUe`wgXsav1NWm^O0h6HXW8=1LR~#ZU!janH-lS57&2b41*4XXp^Sw zbV=Zj6`*3`RF#CKUwlwltrGD0deRlK2ILgO6ysJ7)o5XA8eQ(}_5jkj_JVDejjN5+ zh8(qp6YdS!Y5Z!+U^g)<^v|E$jX}lVf>~0X`LAGjTNHo5D#%h5!&J-v?Z?i|)&Y+B zHeW!r?FF?mv4&?ojTrcRSd-DL0;tL`&pSF;`*?qMpP2Q$&|kdcVO;2grg8dAWy%EkuB_ZCPhBY5TM54@YK0EMaMy$>(6bSW&<K-;8z0uiTYRPkcjYL@u+h#Ao<~`*Hqd@c%p%B+cN_4s4hg8 zx*H3qNSecaUrdO`Qd7v~XjTd)-;=^26SEx2dn)uVNm)3)>{Fnsih$k7vNI;7SisCN za^OTJy?|-?QCp+8Z8MJom68vGahFy`5li`g<8hlkQVOt5lUVKOaC#5YmFfs zC5T^Fnik69UZwzTDC}2|ZAV}~JY9KEjX+udieQrFl(vbN&1L{uN|#5l2*8FB(mma{ zKiNuq_24Cr?nIrTZIf1)NqU}E70W~~Q-i8oTS)jl9O!0a^KY3?{jwGRP3$AT6FcXA zbV8le83ot~c{3*{x3ANaygJ#ruf0IwSIb`nqF(tmQ!6BwUeW~6CHn-JR=yCCilI4E)bbnPLVHf6r zW0YM>XjnV!#ez6cW9jQ63C<4e&b>2d#?;QmhHDkABE+XOyuDBt;E_~qly;&dfFApS z-(q$KnY&x`RBd0wY0lfH+JUQYopsU-m5oUxD zNJz^41Y$k>>Ng1m!tnG#NuUFdYv^!`9-k55_R%){8{Z;5&~*_=#3Uh9p+N1-(a(dg zhyz9X-vH$VeSh>QuuwiAr0WW3*Eoj9uaWhCpB!~&Rx=uF$Lrc{NIC4yp?>UOB#E2t zqF>rqi+;2Ib5rKb$!+xjDd+t_Q37Ye6ixHZdiXFPr4&uTMUl28YW5ny94YIN3S;B) ztKk`8&Nm`&*u;f#a%WfH{uO>1CKh!l4X)UWWEL3tR}RVCIb4B80r?l zkX4z)5W>v6wF&2<<4f?ooDoSuX4MUv)oQGFG$#mJtIr|#sKtZB$wvD+iKw%PEsgFz zB2}9-^d-^Gd={n}ZJPRSQl09|P8HfVmLyXw@u=v_<3tOhsq+hf7QdlI4r({ddJ*P+ zpZwaJ;N&+*V;}u7a5GK<|?oa zT3M1|&dqhl$LA4eRtvXB$APw}D)|_wKA4iP`Mpk&8z`CPkWeGj%e8kjVs>AzqYXiE0wUW#)!{P}j6r`b zav(uV-^dU`peydi*{uMV{wrYQ!^6`~E==f{_W@gW%A0V^C#}_F~n#tx=TRf>EM!pTS`9{u> zpMa={0S8EJIz)0iD;pc5_r+IY4cslE&Rl|+1K%a^Vu}W35pEMEgbfHIoOUj+&|2>p zKF#*2=L!%4i#$$xfH-OEt6rOjUK@wp(@?1cNeqFrr7+!Wc2ElerNrU+Dy{tCI9=nhH^&wW{If#x42p0cEXy#@|R)o1i*NUdb%GjQm zGzEs4Qi~zUiY;$Ua>^H(x-Ce~n}GmmitX&7x7b*meGy`mc~WNoi!95U_g{KbQ;N35 zzn$t$2a+IXjGpbK%3&NSJZk4`Q+cAA0`vyW#!j=&-4vmDl*ZO=XG6t}hve~>0(ekk zA7Tif;nQXh+gr=x#~^pLs4EuL%G9#pRV1+DmK`^* z?7}vp(Skz2pOC{LJilec4iaNSgLaM#ABU}2y69_3YHx|O@z~d87+~=7+KfHC-dU?N z{)Y6X4*8^mc8enlVF@Sy0z2iZ!2cgo-iThHhxf8A`X1~ZWmofZKD#p2KArS9FSw;6pc_WfytCLLP8 zWX*gWY{8^fc8If{Vu*uDrwf^ATPMXz?pE=uJ<;xsc<+Xu@dKP>LkCCgb8YJH^|ccw zoag!Z)NH5p7UvL9gFoH82Vo0w;uj(cC97JSV z9EHBu_VdQzFS)%C2sYkgNmrI47g{^Ha;ej%?-D(bG6(i~eMKhsUMHMYfMa7ZCKDGwc$DnM7d%mTrb2CRi}%LO_H>fs`>Brc!7m z(cS}+J8i=mmW0{r zi$E$`64)L|575saOQ|-8**`3qhRyFu_Qb_6>KlMHK26qNM1nP0;O;tF|1Z9OvsIj- z6`0i5ZJHYH{l0Tq#V=5DsMhF34sB>qUt5YnJ@-e%ULF`MfyoNF$@$KdEdX5bWk$BD z;3{Ft3`0{yU(LL@Bp`nOV^2Zz1*FS^aFx;|egK~(xc}2b7gBa4Guue5bUGQM3*yFa z9{cH_qJA*udP;Iqad5sfnVs*)qd%)_R(jM?K=J$x;>Q_deftD?gXfm1bLGK$`*LJadI@dx%5We7ssP-jizPs?Aiuux{*+ImSBf>({14HtLbMt!}+Qr zTo)ut)IfaK=Egm(*#e~iIHt??CRl~HMTPg>lCsaMyM!Sg;PN^*pXlgZ9`n*bCfS5%1F~NU4G`zPYzCAW0#*9Y zQ+ADEdT79F&=Yf{?kvVT#53qjn%=Lxnu84(^`|$NvT=1#$x#>=f^lU-LrB>PyE)KT z>lBduO$U(eL5x^{Z0urt7upQ*t+mTfz`$b~zKE023%u?qz#75y^6jpWaWNozmMyTS z&_!#5Vo}?42=p624YfH~{pnsC*6R(!yDT5NJaS~_)XEO6DzV0OnfUe){eEx4<=9ii zu?IPbP+KoFW;;?(C`btl8cXTaCUjg2)rdp0XVbm@BdvW5zG@1!>@8K|`2rr&b{0JEbaGVI_74Vfnn z9DfH~6)KB)>GiVSSVx=EmL5Gykl5AcBjuJ(6jXFKcN+P(o;C!3Jvr$EOonry^?wL| zB0ilTStmy2dqBs~AGIL{DoRvhD3U~WX>$C$7lgC#8iKi)R4>OC*#`M8?!Hg7@P@~0 znkPi8L&tg1>go3qSxtU=*C|psm&X1(ssl8sr`b$!a7(o7`S#$1nlMa#*|i*eU2~+} z(^v2x63DAz>2`n7%4K|ighC-hfX=ErOqyB^ONRW|XQPl(*($ON^R?d$@QG(#N=&mm z0WT&ISkSupBvScz1^p*P8CH431-CWI8H$+b?!A!+BGY509&>oR-cy+^4Q7gA0UV3W z_93oNAQSHd z3sV2mIl2*AnmR~+WkWq2ukTVlZcVP0ePp$vAZ(e1_;XCMGmsoQ5>;E-OqPMq{h>71LK;&RGk@TyaUSWvHW_PWK%+!`5?3?* z8=xEDN4~zRn+303R-}+Vm5fKoY>h}-IP|Xw+`xJO#3n5y)zswRnrWtl8vB$Z*$YYL z2{d9!1q%htOW!+ml7k%zQbK^7kzV@P9Dk@yb4kq#X5+5gGMMFOU?(p)vZG-N80qE+ z2twU^ZWw`<){=?7@WuPy2$ z<8Oe#hdHkQYVVg1{!a@x0R3ZN7erw^3MXzFAJ2T9I7=}rA&X&9BM?Ph6fd0{^8H+G z3`Dw1Yz$}v>s$2YdQ+vk9hgA1SPl_`ge&`=yhbXWCSIpdp(>AFSR+{hLZ65!#FG5U zCK_8BI>K$7Oa%e49u}Sp;z^w(T8ji6)uYJ#JPH!0P<75nJ~{UBwN&0@nK?ddbjr!^ zG*aj@6ZBf#+E{$eVe-hm@3taDLx0Gy7@-9WFUoh*-X&}Aw$X*I{lw{FmL)q77cUDL z#kv%~xXU`B5pO3muwr}$H{&uhzs@r?v>Rny+M6?%EV=2L0t6&28aohz= zZf0{vGqgEdro%}!(<{Aq#8{`!JNwMO%V+ZN)F%Zh9#NkjdcQ(sO}mlG_AofG_3bP0 z55<}YLsg#|F+C^Vi>GT*-g|I=_($f+IN@y6yMJ!>$llS;_3~?J!fXpJ>{Cy(*L1Y z5)R@RK2OO5XB^m|dkJ^@3BcwIPFMoClmvl>Xm%kt9jCepe}uaSy#APB2ySUE^B`Eb znc-m}1v(>sR*AWt9h{mplY9QN~K&z zZGceNG z;4h;@pwJO!;>YA6H{u_KvrZGNH7WlMLfO5!@gG)6-f;Zwk>HvE=$l+AbBPi+Uv1z^ z;%oU^dvRK(@TOtQz{9vB`1i*oYk*^YB+gxX6R8RxzORmWf~n!B-(cIFnl*FQ{zR~F z$mro*ZV)H2aMw|sUdr=tOBzB-_J7PpADPvN|P1a&?TYoFxN5q8dI7Gls z^A^8^T*Wa2wDI68gXKS~5rN|RfgA`<35r6Du3)NvHeoct7N?HAD^IP{$R^M!`L|-0 zIV%HbCB0(Zc3qUl!H<}xbo$%EES4_K@;b1@$&V~`_5hA9Jw`t~Q1hzGtWk%Bj*#VU(D z;H8NgbYzI?T&;kcMBTri1f4r*0rw$E@&gLAlv*Eiwa;Cchiby*Rx+wpWyr3DH#dWA zHNr5hP`M};D*~#SW^k6MYX6e$Cf~Y~#tF(B!N#Kg(8!QQ-kRoU6l_fEm9XhXD5o!J zxZuEKi>{V5)y!*;zg|3m8b^)W&of-s5Wn!kaKiEKRV@7bKF8^5*(zrGl= zH)Vh?Hb&%BK`p98` zg~^pXh0I)=pQnI-7y>Xx$t_}ce0hUhp`(A`&3Bv#1eM32eb$yku!tFqJ6A+tl=wV} z=r3p!Q6U;)wLN&ZN!`iQf%*GhnK>!)I5wtv2#tJc)9}=no6_o7xGOx1bMVyDo`&^{ zQI`9uv23C8>Iw8@-I&$L6IqUy3Mz?Us7U>_o5(~KoX&j7jCzB!B&d%0KTQ6=qk&(2 zMhFsJp<*~-!ZR>j(WiV%IDuy26-3&hIgfUSWG2CL?@qVVC8=yibl4m!!FuLQ_sq`A zR#NkN)rj`+FK%{;zYuWzq>-V=AvV+V?*#w5Ue$%{oGn@F_YaEX>+Ij&_|(9)!CJ8opjDX^bevY#@hV&szW{Z1-B+9rTB;Pml3Nd11|KzR4pR~3bZo8+2H zQgSjgTD9#;j^QV;ra&;bFvZo^Igo*4jvE?+c_KE*7~Kj*on!A{kW~G|Z zePA=`Od>T5{9B{FMO9zvr8-efaw}8(m_1!&@mw4cQ!27aYpR)d3trBPxa+W{5*uyD zu#Hi_y7c+!&7Gx52ut50L=r&mFPTv=8zEX&#yDEbJkKU4$xZPgPxk} zaI@@}k*29EPdNh=Nu-D=&Z79vL|$~1zm|%XYMD%kT-r9SKMajLi9RXIJ^f(W3U6-u z1IOV>$kS*8>TICNn#bH0aen%h^ni9yh}(-Yqoybqk}~aN z?1-7rOXbiry;u2dO&)h`v3vWDCCLV5k>W|QqTXE9)Bl{ree-+Ff8+15OEx46LB)KS z{&^*IsaOdsNYW3{LZ(dM0;|G;x&+goCiu}Yc)o)rym|gPwoWBdiCRXaQ#SZYa&iiQ z5LU!s!7JuZgNGYrQlFS9QJ0DXO^~ zZqM!k3bw@`ot(uxr9PJ77;+mIK5bx+ZYOw}Q-S2Fzx8NVV)8dhqpH8@_M7?HOcHb1 zZ^^Dz^LuzYMk#p&&$c)fkjKKd+C^vZp^&LZKVt7PxQ~Vvv9#ke#bq2=5@sh z9InnE4C@*1F@KaLgS(o&)ulMlc&h}I+l>;V?N6;H9rV85xHMA`Q&>w=QA{Wq zZ)NfAaGlV~x~5JNvjI$AgDt!nuV+2~>Nvex8gCC#GoCQVOLaTCf~Gfko;15q%@~=r zB~o*HXVnWKQl$K%Wa@cH9}YlKkGy zFY7(*bWzWdRgK&T?OY_e5{4OFX$t2BT?$IokItps6RjetnueWb4N2!ISHn#TA$h@@ zMXnS+JAw`wRtwma36QuVNErmSp{4!ft?j_kOey^14Watm`AZ1{gO%~;7R5p#OGu> zAn_gs_E?KXT&aE-HIaA%y>-W$jk~RLmJ`W)}>l+$n*rtK9tq z(K~?9FPpSbN$HY#v)LMb_PDWAUcAzCK&e&@(d~KVJsDy*l4dfeJh^zV(ZVEh;q_D3ovlun@$kYDNdi zbqJ~eSxXJXn8(4?XY`-_X1XHO=uxjdq8nCjQ24E_-yvQOivgYoDeQ-yEuIp;=>;1S z7*QC?KQ|f4ak-(xmhIPoDD3`*tJ#HZ+cTFiu9T{qF}rSuyC+TK9iNzZ5+59@pWh-D zXaZg1Y~olvLWIF&?55#hS|RTgi8{40#k^8gsx%uw+NVqS*{W)s1H`&+8GwQcI$r7) z@mK=#0*5y44vg8vU~J-ioWVRT_R1#qObv^bYWl^0O5tZ$gW-FbzYyUrEIwJ-B-EZ9B9r3*VI+$!0Wz}Z zK#^tIo|ObIgGuU)6gBlQ7J2kx4U)XqQJ%SWfgy4G=y-MY zL&C8v5`VOgM(pRPD+aZQb8~B=3N_VbZ}|fNg|;0VW!b8i^hb(cP3SOzSk)|l`4V(7 zxv^;d6il3hi%yuLrO#>L?YLWzB>gMO_Z z%Jp!}pYBu8ld3*t{ys>EY6B;6!`AUa<;?Uw&`g>&9!LQ*B@n0}=EEWu=cuN~siDfV zkIoyM;<5x7joAR&=EkT(Ru1O1VFL* z>M0H$&CF)(liqA_*wr{4-e^aT>=7QQZnCM<^o1_n#C{?zZi<{bPZ<|n{5!X?(^3kz zpmV{ao61-ZqSn!+`u9z{40iNSGxI~e=2X>DW?0DO;~SFkd>ytW$!BXB=_&aE_Uvsl%|paK zbQ?00-eT|;j}=XiF;I>!w0pKQSz)Les!{1ZG8b#gzpdJ(wiC0?{(p8Eoj8rwb`|AG zlt~Hou|>)qQ2v)HFM;*O;B8F*&e@ATUvM_w_Wn$44cN?D5-{cP>_nOkCwR96aG(FH zuGWA3@oLYqHA{GCk^~MRDHqEw)%y49FVU&OrswftQ@?Gw_lNzu%JmPU^6Je$T^zbr zXuB})SgCGlgaT48m2jMWlt&JIsl*e-!W~51Fs}qB%`p}W(q)2x*b!)h(^K&z>s&LG zoDlmhuqF}NeKnF-93K3M+TkyTz!$t3{2iay!n*YvNz)#^frXulIz9+fC_CwO&PW!o zlunH$L1?lR!_os%1-vtgX#tIs(HebG+~#4o$P9Y3pR{*~P5@g9H9K?+$aox9rKd7v zt|JwJ9H3_5H7%bRq%f%QQKIF%0*BBJDB51V^lnzkNKpbk#=%AjFCB3fn*omS$p@xX z*4AvIbK^QF3l^uQG`l^%SJ(c^~vG z>Wi_B>Qe4ssDS^3$3O=l&odZ`D=dlQf}_Ha-7MKN^hlPho9nFH@BU=cn5#>qita#K zq{M$qBQqOErp52e_iEa2oe(rh-$O0bx6X!!dz*03qO@&Mb!P0i`MgCe1^l2>cXlMP zrBQz#IlhPd-BW6drG?tF?tBqMKUChGX|##MT=*l@ zYlgl83uVgowc*V;q0`o+d48IsNX&a%5vhcK5D$1HN-_Ncw1png4J~6F#Evy55_hht~mnU*Fl%6}!IbzIm(5 zO5w9y`etH=xl(|nJX9bUk;|%Y6`I~|Z;scZ^5Uxv;O;~70Dg%A(p{COA;aRtB@M)8 zmK$#c3f!pz%I>?BZwPi?E0O57BIDzP(Z9sz!9>5>RpTS}P&Pi~$?ihb2?`CFtlCoe zA(s+CfO5{_nfE`SIY1D`EK^w9a$Wk}qnH6@+BN4cNVm)vXEcNzN*S2f)cxvaA!{=l8Y zzBM8CP}A4Gx}niS$>dAjtoSJ`;_fLk;2&<^d9In}QKlMR8CGR0E2{D)`ACG^OO%0n z-5CVcQJ)ELld)_f>bw{iLc!vWb5rtSOU-9v8yd#T3Q{SzYT1ggwH(6RlH7Mgt8yg` zq}DeI=O*zXMRAMvLhbm(I&p7I~JDAI>;7_)QU-P?})x(#R37;|#=$ReD>*zV{jgMFy@zmtAMa zdm@|1G!G#DB6{yANQ9=k-Cp0I4Wkp!|9v8=dUlu`@IIu9-2prCnc!DwqY{NA5M<_r z>au6Qh!5z(vW{azE8e4Z#+&K6+68SMFl?P1?$Y)9^O%k4SzD*;<>t{?p>$EAYL%vS z(B5Qay)`ZV`n~2MVj&?KKrMAki4%xKR*sf#twZ4xd`8>}U|)s)X^u{4zL&8P*`kyX zB-AWnjG4$GGoQh-*F5bJ51S!qI zbf4uFwNpBV`UyA4u!djWnrJ(;57la*-Ag^_^JBjv(56Hav{_$@+AP#Dqds6IGrm9X zaX>opa@(z?S@IF*(V$EUjcfRc4k+!Fn;gwKDS$i&X%y%{Yc}276KzQ}7ka=%BfjjI zm+YN*h)$h3`i$hqYuDbhEF=J>WFg}1<~JsxlFSX#H~`4295OVTH4yc|P8@L;H8s-a z9W9b(R$I8KoUjDb@kSifKU@c029gITMFRA!61#^?Ej35^BSp&u!8OjNK^I97um`{1 zjyS0@ct!>h0i*g;+DDz&%2@cI1!<39N(>ds7JG${A7Pz8Q-P|v+R%b&LzD`(WFpoSSz?cAcQX*uyH z8i7r9Lnpj3pOFQ;xyEj8`DDw17I-s$ddREghvg|q2F9Zf@7BOkePiomSiboNj=0r; zcBpX-NVv|sy2Q=~hvjOUqjvfoQRze3bS`Qs0Fr3&hO}R$Lp!+?zxmJ z402vSAzboZszvsBhFU0fT?XLvY`Id@@~s2tHiQCr2F}7~6||zi^gK$@mg-EyL9Wre zBl-1x^88vw_j-vPh>fdRCrkHHB3etPs~mWsv*rUwU${4;j2k>=202MT*xH=y~s zza-09OaWWDY5?;Pjp&8D`Dj*PyiTitI65_90}S{zY1-bac#9phPom8Oh}t=-^Pzjy z1pvXwf;}^AgU=+Dvhh&;!nWk}BXXBqf0>niF7OCJ0aT_-`DRC)l$lrq(_!pb*64Sv zwYcFuH$0DSebqE)MK9~Wm5o%a@|LNBG!IqWs(EzjhsMf1jNrDa^yz2bRX92VTuCbp z`ISVgJaGK)q|`#)&gQ$Sd{zO1O1c%tC?5kIra5A&Q26>Gc^JxpO8fNu4dxG$wp&Xv z{@Xi!>JAL)%U-hWY14$_#S%>L*p@-=NQkOpQRz0*z9s55-0z4<`6G_k`i^L-w2N)d zx8jf_g3>d+JCm1w++KI#mSyjtWZN|6qs3)eA_R)0es;qTsYNUPSK;C*=vI;;ji%@x zp^*9;3<&eH^!L%&QvHn~ricHQF8U7n0LQ9o#Ooz)PfltAQ9fP&RVwoK4%Jnx`aSQg zqy+8-`aTOPSs)OG-CVbwaEzF(SPD9L`k@xS%-kNmma0~SS+L$Vfh3gN$$S`WUVU|* zM!mPh=%1A8BNAx+p_KhTqxo{_NkH<|f__325UYh(RE+dMWy(tpREO|@oNdB~M#srV zA;4s_UPbP+42|D~wxDHqfuI;=&ia7m$Dc-3o$PfAl*%(A(regN0y~S7%@N&b6r>6)L|)MdP&18g{p7pvZT_QPi7V~I~=zTP3$LYdSSnE zH^;2%hoaf%(zpV`YQ}dS1rvkVels{`#3C#e2D%RJ-m@$a0wOqt-L#|)?8L|_aGndX zFvuU+5&$`!tps_p;j`zN$oe8rC}-JazTuOyqRJFzX08@$nHyAJe0`vn+cD*~V#q!( zR1pxAK)I=v!q#VmF{ltYPKs+wvTzmL6R{*dowV3i7o zl+4OV=|MKXH*GhHy=6AvG4_IBD1UI)CrW>Wg09tP>d`MTD|`(B++5 z>;lYByv_`=4we9-V8)M*?_wn|)E*?Y(xqOkt51t>Zi?jHJtP^rYfb}v#Wh~9``a5j z5A;+kYJ19nrCHLf5V^RywcVK^hICE09^h@q?T)P-c|-T1*7f~WJ0Bmd&McI%^T(R; zImJX8;H3|zm^la5g~XMDyq5!0jK22KVIT`daaHZqIEX3x!tbGHMcKz`#2})ZQj_2P zK5%;4DFkEX5J(h9e~d8Bb17=7jbUi7?Y>cRmgjUwi{ZoZWX7KadE2L~5`|H>G*62u zq}q^o#7ALl->-+*X{_u=$kd&Eg^I5rW4Fw>I-7e99BR2e1C>#&LFpr{!xBR(NMYDv zprCoAPOx34A*PCLtpn%c6DB-y>c5|HN=?e?*UFt&i|HMXt1VH|V#T()&g`*So9teE zTH0y6mzbCU1ONq?rlhC4;}3-bG)V=Mi6*YK|EiAX$7il=$B@dVZC1{}Q_oAI*3~kh zQrvIlq;3GnRgDo&WE1zSDAa0%nX7!STC_|DlUWWEZ6q<$6VQ_}3mP~+_)U-Y{ow=cppzzcyRjuMJR-&KMMNSb5ap1D z(Ox-1;&ThS7oA$km9hC`qk1J5GC$N&m%FfsE=ms@ck#aeR~`MczV8%L1QERx z9?_IYo9<4iP=%U&+3i#gk~gX=2n%O~@lQ2Ev+Y>57+-Mpha;4z`bLMz<(H_i;IX!}@o3AOzIwOmD!sFe2WU*DzNR0j8h<3BS^ zqburmo)G@t@8RhrLJ0L*q-g-A>>aPX(qiBY^wFwC2Z-Sx~R6b)-Uc| z*`u|dbNv7aGp6K*keXaf_NNX?0g5dB>8pe;pYj?`y3!fg{ zp1Y*|=7D!yv&@5V zoTw3YMwe27O@lrQ&f9hbtrdVtU)wH*oRudIFAnTp=+o^n31=g8Ums_ltyW=~9B^A+ z|NPB7X#8&0JF~~(Zwo#w_A2fxF^8%VCA`_7_h7aJ57?@MO~&OOz;<}E52vTH*?J%- zUP5_zF-#^gq693Jf^NSFw)^bA*)zPq;qdMJ;@M$NawlC{4fc1phfL?fMNrsgCE5l#q%*$*5xRwJJe}w$khY335&%|Du&nWlo=qjw;h4n zW<|y%nL*SXl@Yc?u?cocOnYZ3Gcgo3+=4bX0rtpCe!L{io&ICT*x^OZO3`wcbCK%A zM7zLpZIRl$ZX`?>fAs<4ncnIA?d+!iUuO&3lE~TQINKwysggx$jhr1M0*s-A1p=yb z6LnBEzJ(EDj6_WH{APAz>*(yvp02LG*(F1-1j6n+b1+hzHtKVgMr5rKM>dW- zFk;u5XvS#;eM>;UL~u5+E&RH~vf%Twgk(gXk>pZ`d?abWyZB&$ zgVhX@v5G-E_#6tqv*sPfdR9FgGplX>`3$$_uwV5b9By~NU5Oq#EywelOe&@weJSko z;lVJ75E$r7|4KrTs69<89LCOMTU>5?I#0@fu8;Vfb<=>&7q9fM*p|Ur z=?E>r`9qm{xcDYEG%n!yxdig=Zg%v1Z@1#RGBFxqC{k9 zl$`Q=6Ah)tPIQP0EGAqE7Z4IS9$O{%kJ4CkL4>b1tpY-U5?E`Y<-%o32!-8fjXx-r z&V^u-rJZmUoqWU^P$p*dD(fc!!ITYijf(i+%#ZjH_NbTn{65IuhX4|dZbbcM%*a-Xvs0zGLAknrp z{hKN83I1xHsw78tE*5W#&U+o2Nw>N_3I$k&&LNtN^yRv@rZ|O=aY80=HzMsNMi{k> zW&`lytQ<(Oh;H#HPlbgdbaGC#VylmL@IBgxh12ZMi3K11UxPM*ID9=4FPs3t!ZyCMmbEjaS^JI{u z_6er8DKpJN{)Oa>COGba+*2infbo_0h1docI#|H&9w*KN0YQN&awW1$65Dw8} z05RyDL>M%TI~So063E3cAhtP%KoLm&rNE6NuN1{iLX6T(K~clN=fE%mnBgrHYa0Eq zVRj`=i+ilxnp>J%_KP5|SVx@lOwkkH$&BX}`Yx+HN4-Kt#5dk@(Mm^8c$QO?J63k; zl;>Qt4Ov$tfFH4YXFQ%NHAR`QbJNo}_!&O_x!mA%2A-u<9O%=hW@bn7HSQr{sF?fr zv;j?1o`&H3jV6RSVdc;8bf$XSke!k@kc_EIvT=|C;7-Biy`l@*ct4DjJS@ok6~FJtx*Uh5kyR@mKY z`px?`-V0Q=Op)AEre(F#=1#_5qQvrQKC8FSNJUf5KF6H2c!DBoRV-~E41&K7$HURp z(O`J|F&JGP4^IMeTr1Pw`0$#AW0E0n_&XYxXPhtaG^%9u;a_XmM&?Ewn|Df;3XzOs zOi@vJl$??{OB1VND!E@|kS(;KdYUPnV#ULV6#rh*`dt8Te5+er8H7S{+37G`E^-Uc z#C22I6^|}9yA}%{G7Yy_Ewn|C?Y2@ncTU=O**U!w%`#;!+XZ`NaBP*fto~L|sl!DS zA&zQqgO>*~#>U6LQABFi-bZS1?Z}omo-O2X?CzmJB=QFDC*jwFmIfC%qIZgqi}#^J z_DQT-e4K8i(UIJ%^qz71A@Ap)r(dXyC<_erVs0dB`Ee`qT7HqgTo0AEM^iTy;;E zPL_W59B}>}@TCimsDF)hb(HXlxxd$$JVQB~Pc_GR@7*s=&#*E%9o#lLIUEeG#+QEv zSM<{7Ys~j>!QuJ1Nhc=eUUo(&@-(l!6WBKEapJT!QQq{OT)g8_QZGHKDxHpw*UkOJ z4gC{acs3l3Kit>Eq7vFx-qS>PX>H~HkFoK5c=0eBcOGx!&i`cNBzQokcI|sWrmord z?M$tj)XS%P%Bwz;(wT-!!`I!TrA+Kec41^9O%CtNHkLW?C)V&>jdvpQ8Qqf(>5H6? zM}K&teC5__=h)31m{(5uP@$jeKgo5erl&u6YV5?~a1BS>UIXgQ`QrFinJk!Z^l2(da zp%wgKb;c|{qP;_7g<`Jti{>9cMVqE;Hl19QXsc2Iwfp{PaMaIkL_9q0uMR+SqDrQd z%S(8P>5)$_u!R!#JKBXob0h7XYegZYl4UV$a=~-g??OAoMO}XkZa_fx!|5JBUo$Dd zVh#%{q_8zSv;mj^aN^QiLH=c1T-!-cNz%?xY{0^Etb;1s`5;kShAobF3 z8}qXf9~X3@!H|vh=Bh1=VD()Igmi+1M=NK)+D(%9V?z{ciQ#e4Clq3PB83OgD1^UZ zp`Y;8oOkeXX&LW1HmR;nlW)XR>h)jfb_8-=CcT zz|u$rp*1u{`TF?i#R~x85TrG=D$rpu2ftGFz!Wx$Y;KTb2oCE;du1wc!W8zFu}&B( z0)8eXxe~#ZEg2vv3#il`8rBAThmOGpe#rCb%TIIItcVMIqU#75R84bxLskUIb~>Ll$>Hn_PV+$8km=BC3?nckw}ctk1(wVZO>un0 z|0t@nzjwsM2d6dFE-5vXj?So@fnl4>$J3c@R!Xi|5GV)WMad;T$2l9QwwYVMq7TJYi2>BTl6QN*nh|fnF$Ghi$?8 zOz6rweTVYCEzK3&gzr)$TdpD2$>X4>6dU!z9pv54d&%{d^6-zn|e z^K-V!yM%qm zIter!PgR5oZp$)uRP2^)m*sL}h}d=o&~;Rb?=QUg+Gj|pNveG447X8)942FucGKRm z-(FMEkZJ<@D}6Z5?w|FbFcmJ#4_5ZQCJNQm+hmb|->?602s`v{N%erOpZ|6|JMuiF zV_6v=++R-VAxC;yetuZvqM%qt=Q$`vjh{|)R6ATL66#s_R8d9Wh4Hg>q!o8&drGWK zf%oxUn@{`s53edzEsfw^Loc2-{ebI}K$?+J5HtEk_=e%< z#Rv=$k7mw!b7H@ZWVveSi!g+HRC)L}N{P|yI*;lTAA_`e_yZwAXWr;i)4T~;#wd=2q1eu(U zW25LX8Nr7do%G-zOa5NuGCVnZ*I*F)v=Vo(H)PS;k?*sQmTW|y5a;Feavgo-Yaf~EumotF%#surh{K^C8|KrZ%+v~u11DUdCY zwL>e!VVA3s-BApooMCZm*Y5GA$Kg}G(;GZTZT8bw-oDz)SaD?gn1SF0`N2uhDU^|9 ztG~mtmHdyuRCk59_o#zFys!as#HH!vqi(25>GslCRvV?Ufol$^FBk#QcG#(--*VI4 zu+bunx#?Rd3mio+M50IL(RvBg#g|cY^Ix&m0(tb3Xy7E#KqQ4kFp_&sMve=Tno$D@ zDHvoLvcjmQKvIHKd>byzwpftl`D2xPW7%iZj$aH^K(a2on7*YVFDIg4ZqDq8uOGo! zNFI29chdYXjw3=s6%-1jdND9?LPmjaaW#qCziZr7tXJY2k2@(@-%ev$HQ2Ujxgmr+ zE*oufcZJ(@_U3EE5BTbn?M4Xi?}OXCm9!Lfa7CJ8|ESfhTr}r~DJ1kLZ=8O|%7V{u zS(nuTHk+^J!IRQN#GrDBD$7$wM0DAQs~A4DC5B5P6IRP?rM{Jil$MH9rHc}B{dhSo_F%TPchT;emVbXUvo6?RqPr+mYAuA> z`TpMF9N;|y>aaiu1~CU*p<9E)N@=4_0kzQ~1?zxFgtc62A1tqsM~+uCI)Aojns8JSeT z&NGCOLlq)j!i0T}$`{cVeMkuxAw};)VHz<3XT(oT)VE_Jee@jmb1E8M4&joEO{v!CB;tR~r|Tt7^06)hx@21sa{(|71%m7zZ_Y`};E89*b*WeQ>d$1$GXQdv z+4vAObg)Bdj&j$UNO}C`kcvAPi-c#*Bv0Y%LT8Ie&}x;T(O(3dGnKULw;-u(Ump17-=o0H|o7>xU1yj97ADmscAlqzr9sZuA-=FRgc~L09 zwb7)I({&$oslyt^P5yj~?unHjtKx3a$7a}gl}P@i9Vo(g2eBzU^MShQ+2Htn(O5Cn z72Z*W;|}4t(eyKX#9wTK+xg+lR)v9cjJL zPe%>}$%E-ad!S{?b2xH6pVLp6J6p*nmD#GY=HfGGLnC9Z=&I9(Fe(UImCJ>Kl`3nD z(nyx$)r>bUZ$Wto7G_9-{gNk5E+D!G{ZctJ**cZsuS&W^=<=hb&8Z4WRcu=zA|mHm zD4b1jRDq;N$u>x~7?`aC`irL1_tX0~x`5wCwzQ6Jo>pQU(&R22qDf&!PNW^%S}AQw zX!AEEGqulOyhupcU$vh1t@alY%Kg!OK*HlJCU?qLfHV~h^zU1JaiX| z?VM}0>WGA*i<*!S=E zJ70bF+1ZAt-8w!72vFs~ph&s;l*5>XJe`2bV4Cq%LBu77O3Z;NU}>gelt%T$7`I#P z*0@MR#j{j9x+lqn@i55fje0!b2}Yf#n1`_*c0n;YL3&4pWZLj^yLBM4kO|}1%R)GV zuca>!=>%4wG!A)y+)D>W~D}$gtUzt2aKi#M~BGm{d3^PfYOh z>nd9F`6AO$Ut4U{-!%csdLMHoi%_wVz$%Ss75sJjE4BBM{Wrm1Z}A}nY&Ks)22;ey zM;T(OG@xnu8PGonH)Y@0H4WehPESt1RA?M+@3DJ?b_&qvOk@+dS6py4hYL$DuPALf z@~#%7WYXvPRIoV}(O9sFt&37*2R?~W>LsaJbSlDznfA1YiYmiVoqWSQXA@j(M++E9 zIlV-_R9&aIAIMG=ofk?iH_!!;k(nLfvuPBgUqiui)sx5+S_^6_4Ik?~bm3Gxk*Erp z!YW^Tr~8Ae_%c(EIA2e^3$fAIMgo?e{(&s?1TtCYy{t?lY>0LO>je}YO}u6*2;Ijd ztBR^8c=)&)QB&I4N0w~Fa#_~lDW#n~^dCnE&e9P7hYm#haoIl>q$s_4R#027wUvdG z)D@kVyD(#-z%H0${IWagTYxWdMrQ(;npwIB$Sk2Vzrtjy?1g{{x&}PaP6TA036LkD(TvSl1$Gb*ldZyZH2Fmf9ZY>pU7PDsDDX+EqE*`;n$@dUFm%juDLJniKH! zc)}8dLjpBFgfPbNag;r;z8cke28y-@ZT4#6YLxAH;B9$wJnzc6>A6GS34*H!_q}c| zUC$rhxwrRjFxZl>!2f;|yc<|>>D;;f;ZJ`{jsoBHykNJdus^J*AZC)LA9zmX^B1L6 z8lGSO26aHP^8!eT?U&zg+At8upF!e(IQ6NOM*o97WRPi@P(TEDMJ8N=H)D79r5*e0 zcMd;Vw2eevifC0{h|S&CzRw-8@7kHdrZ`e!gZ2X$TA|$!G9~hxPP>&LZKndIq|hl| zpKuBWgD8l5;XL^gjKltX7A4UzK8T@ScG}%8d~EJh>H%*Ogi_@?4hn}$SZsiI22yu( zu|~K`R>Jc1R7-MKkghQOzA!&;OaD&0)6NQ=k~A9r2sj}@*fW}}QJ=n^3cnF%y_-;wQ4`#iMh-G-)*y&*eMeH~K*sxR4ryCERQKpOA1#@|(Q+K@(*b-A{KehPK26}tJas|l+Hiy8 zTOo@-3UqY4zaqbA+vXQM-VERRjRm2(*&@kX;t~Hu=0Vt{a^V-kOzgjsdor4*h$+b#$bWfb?l5JlkLm?_PzSBk&M$O zExR+j3}7Tn=YE}YEw)Xyk*uyDq4Gn`H1cWG3m=?_*InIIC}kATz$R>q5xf zmBIPhsH`_x31&lF<@C>P&g^UF@a-&uOL&Jfj|D3!NZwG$YaFXpBen(C0l2(`_1D#h z`EnAi$aK0|Ov#sMnLy1U7K<|bMtNN6rDHQ1JBES~9IPM!S&<9{wJ;m{#TX1~5c{Y&_@Y&Aewc4RYIpP+e(NIkR_TCm$Y&esDw)pH zM0*ZvPP0FtHDRyzqCS4b-I2A1w!AgZw57lG*Tn^HI@wF(K}v-LS%aVyR5BiGc+lw< zkZ}r|`a&g|<}kL`Mezt9uX6hvfr<0oKU1NhuLJNMS3Z~32 zJX@7uIpt^s9a>XxEuyV^LCZZAXiyW?LaIErpdH0Hl?|^nx!Vkmti_3q$k<$C5HK8> zwR7F4>QO8qpf+MMLy;^!IAF(T(tn?djP#qMh++1TidJ@^dF>%=>=o#7n{OF z5&(&<^O`$_O68sjRs5{VAWhINmWk0+YhjK@1QoQ3j$t z<=Kms@NtLsOYV*i9ok#d>(Kvta~@LO^Yzv#4dqoZ z@fLg9izW8I7T9TpabjH@!+8iE_D{i`L}mYFbxqKcRObMAHKUE>Na8z&YPf&ZKHEfD z%QtvNLiOn1fY*mi2)0KW*N+*`^+U_R=|e;NNDE=zNFzRXTAw+x-HuZqq+s`N&5=Xv zvQs5?{Vm%yoLUEsf8)Sc-4hx#bCtXEpfXIoJ$BBb+jL2$$mmHL-vmay8VUT@OGL~% z`Kr$``8=DcExy3A3S&yacMf_|JmOh7c7iy=-q2i*bn=*$A z$%K_HWdFc9l+0eC$o2IyGRH*RajM+@YHC}Y;cVnJ3QYyQQ%P9YO(o59=wMg>k?T9( z{xwQT8m+F;P_nw3-_Fu6A-oHo)f@f>*PH*V0!WGFR!eUpIS@W4QvO4U%QhNjclNTk z96HbtRzPQZ~@*lc4WKBu)luGb_3mcO)^qOGrI_)*sjOts;{bie*U)4+3B*7 z3oDd_A-lz?6xLiZW5gD_N?+w{hdPnPCTgCYo=ng>f%IOYj(TX_f!m0hEeN8~{O{S- zAihb)vr#h5#_?cw-EU|8AxSJ*Zjj8NnYFlsrP6>~ z)H^5$C8#At_iM3O2dvFs3|M3vunHs=R3XMXvPcg18mY|>8xV61r?PRNRc}|!WI0~Bwx&}Q|q9y zTJ0XG{+IHVk@8E~>PwDa4tv6_f*|eDw<1I-{X{!tD@U-pK;VkjClwtMsin;8HNDWX zJTbAxwu>GaAz-hv-ATGhoIPtgfc_@SWhZ`QI(iy*6PV=3!q>V9$J2;#cD+bdOYKF z7VHFx$`Q4{4YL!ggVXPXpM;Et`oLik{~!;WQKMwkAn9hFRt--An&ofP54F=zr<2B!MQ-wh`(5h)8@WZfC9LWt9wVdQK#tL=?9;h z8`QKgK!Thyvj(OSn0r9re&#w2;_$}N$z>tkYxm8N-F0*3t`H65t66$6NyY?pGD}AU zHqI`a$CQ0@(+O7lqu%Q~PerAcw*Pe#;+0nLy?W4|FYnTT{spgd{#XJ?iOp9_bK*D< zK9j2a2Nfr~DwE1y_Lc*|4(naOj2~3Z$>rb%yb%^9%VgQZ{Pt~0Hns^6&rXt>6iErG zTm7l~>qpG%s~%;Gn35b<`1$gM5G&2MG~ScG{0p2=SPCN6KvwYv`eXxn9Oz9Xe>vXZ!>l<>XKELDd2*g;LOaFz$7d*{YMt?RQe6zi1Y(ECkXfUz+ zrm3-{OJbmclL=S>AE9wy!~zT{6#2m*up`UyhwgN04+GmW$@hD5XG)|QYWH$-f6|^* zcjsuasoa+~f#%RjQz4Kmt(GMku$9J?t$Yv@?II(&A$j>2fp-o$ApU@-D}0Y356ZO% zt27tD^#u=w5G=EIkO@QF5WP7_lCMQ7^qIU^@B&Ud^Z?WSt8cbN{$S!6_D3R>zqO$< zsO<=r_M{-jfD4}$S@OuZK7aVLE&cR&l)w_-S~^4uqpI=~672r{ey*>sua-r&5Gl)u z2OG8n4PwS22fl+aOGSQ+Px9D6%;ew`uO& z{bnUBxm<6f3rIy^XlTpil zvVizcg_>B${;ci`|voho6};zMY0AjPoA1>2M^be|Dd8EGVGn){eAw2a}w z1GBiuL4q}wF}_YgmUZ!=*lblDOw#2tU7$<%wvt(Ita^R zW@&-Orr9bXGGvHsv5vD9j9~|K5^tw?jf`HF(mGCdmMDyEX@AXL`~^eyHw)UZ7C3#o z%GvYRd~%pnq5H)H)xrHAUGG{xJC%0kp}U{%KKd-dGp(&9j8;2nce9J_rYv94#2+1c z_&c<{y5(K8j;%a!rlI|2%c}*=1{O3lP;QmBUlol{f6dp>38IPP`;I$(^F?jpZm-fg z)}FMKg|eZUvfwni)F?dh6NM1l>yTxFGip?$!R2gir0YRJr&Hs~(5Z9zXs&u|Fqt!2 zY+%G$u|?AAZ)Zmo-wmf$GQBP>ley{;jio?E*NnCEBM z3)+o{WlUV+&%6GEsLeZW==WcdM-nx32+Qc6WB^Gnsre*1s{lYEzhm{``EA8Dw4}|K zRgAVlsg#)vW~yCy?l=m4+iP&}9A&UW)WK1bXsixheL=5N`)=^K*CF>0PU%S6{{WAQ z_0IxGiN#k-bK*DXvav5EGNqz_P1}# zvd4B}U@|qyx_DV`b$|W()QmaA#= z!IbWyzoTgedZ`pB7M0BP8u0k~>ca=}V?bVqF3uyc*>1<8JXOaMW-20@k{FlCh)kgX zR|^#)-Ok_(ag#r}h`tc@0EG^-i^SrI4+-0mgUB+rP2nR-<89yA8Igsx+Ss$nWHt`x z!TrXu{QH4c!cneJ>kBE5L$b{kVG8v@#(z;H0YxZ35}+9ai5n=#50+{5fVj?>Si0WA zn%74B7p`_;x~%uJ<=L;$TEZyxR^EnOLL?H-{(-m=M=ho6qxXN;&Ro#=bXnUhJEZie zg=|Jsk@Vjc+&X7f&taane{ERiGoGZdLQqAOnA~(A{}x@HgirbY@Vt<>6pK5@WnrGc zj^es5x0jj5=CRH5X8&k24v*hFZzqCd5`y7*dSKCmiO7)bAYs5rr_VH_4lTR(0ozLbt`lfClBgM?)YWQjjlN^s{9xazB6iN=a!v#t$e z@aGz>?jT=DG}ynHS_{X$bG(h`_<`jGH-om^XQ95pu}f~ygo1XgBCy(YC*K#+`mK4Q zgG0%`7Z~qUFy1H{b~tt#V7?4=Q5bPmVMDzBlLX*U}&*L zB;D@3g*WSP7Hk$X-=De5i(a*b2MtUooinsrcXGcnVEP!V8V|z;tJKx(aEeEMn1LJ% zuB1pS;_IDfga$)@+fY_YtumZ-(6@--XF47AcV!>yGZ`XPi@vTr(ngdL$em&h+`d)dzoJ9%nGT$5NEVU|AKvF0~@&A|ec8nnmITQ;b1fbMT(8 zn8`4|Ak61*{CU{y{aqM7mM^hh0V3@~Kdi$;eM0q92u3owNRdd4H=3;GG{a)#X<+fR zLm5)Z&~tERAhpZJE-{NzdXZFcHzWQ7uz5iw_?pO*n?y^m&Di4em8y8T8ENUQX{%z~ zA+7S;tc5sV7|JeELReNrAVqmiIXFO*G4gmazPnS4^Utoycrs3|Jko?K`4yqN9& zi}!k>(Ww|{VYajGy0xsg5c-@P8OBN(nx`4mB{qPT${CcD0p%9?UJIim(M?gfAVbNt zO06NbqsHvo?1m2|zpAT-_~^~R?Q4YQ0q=_7hFgR>cg`30+i)<_fZ zf^5x5j%mPGB8||~!50x>#_CPgMmU{^M>9Ao;4hE@$cvz{PNkej*(d!z{nsjtsNVw%@|^-miM5tnkD5RffS)z- zKTP&X8*Tard_Wjo8pI2*cApG|v+guF;|@bp`|CRlTCuwg(HscZxqQR<&SU_>;{nKc zOuqlvt|A(Qa~cHJjBXt_uoq8sO`QQzufTiVPN(Cr{E)@RknJH2;g<@%1 ziL=w=U`W20T~kB)E!;ZPv!1H~hU9@f3=na9$n$sy6*5qyQXvMhse5W zQmc)Ph91n$DePUjUCFQNZnZ%ye9ULIY{bd@wb3l*&?_(#UoU7=gv#(EBL1zebT z8tTl}WCYY+Q$!IJ4^P6G*CZf-M8bUvBHs-y+blJRD@2`&r{kL1+N?0cJn2=)ns^l1 z$r+0*<$`U^iW|~7{zR!$@tj;!o0PZ;_Ez#%FnQ^S=k=@~~2tv?crjRcqD}0!WG7SKn{i zFc5w&692=gPhog$|XQX?V+@ffB z71^n?AJyUkf7Q%n zxJ%xy=5aUBhC{x+eJYCh5jIat3Ie8fw(Bg#3MYU#)KZ%gr$P7gWDr#!W->#caHi~v z8B}S$CxGA}n2*t@pFQ_oyBbcG=)=wHdoxm;`pA*DjB|9CL-doO6jE9y(>RkS0Bc zv7uJaKnEWl+)UI;<{-TZq?#inN`pf3shZD4+Jm*Ag;35;SXV+i{RyOjJ!`>%qs>)n zFTB5&rX0v~VBdFczRFuf*Ph7{fjs(HuZO_f=F^A6UBO@B6yP2iM>EsRaCjgg1?6yC z!ncv;ftNoh-4WqYIPN?re)-8JXP)Y!+`Y&hP9imzqC3LnP-lut)pA=kmG0RL}TDav5+k3~75T(;)Yx4IBe@fb2#Jl>^RwG$AW zy_tYNu5{80s18Xx1igM@`VDxBzN7+3iRD&HZyGTWJ}(mg!N)~~id4!m2Ou=1qAdav zl~ZJPC$O!tk=G>M{`!s|+kLT6p@OP3iW2X5#`DcL;~BS_4Q~uI1i2JchBHtj1)DKl z0viY>q|cUZl2f{L@xMVvh z%dWcJw_Va9N>UzgsRSM*tyZ%EJZv^P9dh&cewvMD<7vkO6$ws?Y`9>NlLv|*4JZAN zelF%V(IjA`ZDL|;6CF*vhPoeZqp{G=7uZ$j(e8&va z>zewgRhU8?{RDHu#lg>1!oY!#*W$$>wad?R1F>D21iJMo5InAiXbw8zmsN-jD(`QE!1alvSh$+_{r7kDXknP-q3bS2E5hRsAk8Hw~n zDSla)D8pYPAUC9oYm9*b-t8TbP~f+h(?%7$@Qtu#wx7r-<$)Wwe$FDpLev_#Ht_6D z5qQzY)`({a^nRnW|KE@+=hn$@$nx9cr{34c$+))|PG`muSxTVai9NymJ$E(+=ukm1 z7cTZ(|3RpX#>y&(Icqc2P|_%lat>@@fNdk&=6}ScSCA5&!2-^ zh?Nvc`9f%L)vb#+8Al~T(w#W1@;zLq?fkOvdSU3gU*(<4>|A-)gG6J-%jf@bBg}4o zVfb#uGaPK6?)p~|`ejHJ%i1aLA(hwxS$Q05l_WoY$`A9xXu51(%2ZVoR0;VwxBtXD zNJztLoIZr`d!B4DoixVRW*G5RT5Rc->-MuR)A@Wc8Jb0Z@z5LJ5BHW?<{~k#AmgWS zIPxLYF^@rnQF0vf9udqTOxwApf(Tap`PfBl@~ zK62b(eP}7Fj+}AqpMSO!7Zm==QJenZK?l>t;emS`AH(S7K8FW~2g^K-4VNiQkS$O} zlBva1DsyEp(WmPh!PclwzjQ@(1Wd<-f~OBX0<}xOrTsSGCoDqoeC$sBEumkc@%&w- z3w$Ert4AI`deISx$U;|Wa?+heW4S0U-$f+vVT6FXSVLe$21O-{v=y@%M|{ zsk01`LiQ8975}WOt%$|z&%a*W&2Gn&`OSDby}G~HLyvg>#8|*zvpss7V4KPts;`2# zLTgd-rmmqB*Qlfa_cs?tHXES7DArILeKs_hkK*k9D6Qn}Kj zCPr$I2ZcyuK_qgt-NI5$a|ovKdV7yL8_vQFDw-Y5On&(Iu}kK98zN_XQ)pdn%7%kM ze?T{X1HfKM8Vey;b+s)8d)Qzg&oYHtmlc;v1BKRJQ)%b-saXpwvPkEtJCA++-!qp; zyS$2JTF-iMuIOBcVw|gFl*^_p%@fkoB&)q%26sXd%#Wl?`&+utUZKaer*OCJ8HJZ>VmT=@fqo~ zgAX){MG<~UfEAronQ0T?DR>qM9&E)!f!$F->zWErh82}$6l)JBAfwaqHLzJRe*r@T zyoUlviS1WWi`y^^er}=vL5~efw{&oiJ-8igWNc&HjqTYbu>+s9-hqBX!|ApuxVBc0uwE5JcLlYo@Hctxx3xsD#vxRiiH?=qRi2E|W^UE(jtzS-^M0a~<{V_MCwVDOj2)>3fKpEe+*^vS`J z{+rd&8sD3lH} zWtz}wPaR>eW3@s`B?Smy-<2%Kc8E(4#BF_utpAX~FPE1i>XTEtX&wNls%d*hfRap9^NufK`wqpXC;Y`@`|;{Sr(g%7I3~EWZno zg`WYY5pt$e)Gm6anVAEVsl%7m$=NT-^fDXct-*^!f!C zctu33>TgjoGe=A}s^tepj-IP-;rrm6 zk9g=+7vBG1MTEljzFriPN^J zo@k`AN~xDhh^J}xsiF)2$(Bxgi(tkUkZHiAR^6B*>OE=CH0Q?9#ul*NPFo_{J8XG8 zX$gEjz3QN~5u)Q-g)N|X(|6jaQG*+u+n9sKZ$E#^Bj9YI{xwvt=p_>0!WGNS50r)KoC6> zDgR*s?>-ZQt+dB>q(uIf( zmjcev445`Oh0I`5!trczg=V1yOnzNuYYsK4_uD&Mz9K0=j|-eL!(+HGju<#CA?t?U zmW%I(;)pFYp0PQ87mnD6YtN_!`n#TRT|P}$>ZdHzI|I;wKtjLJsCrTuC9_khV#~$d zjK?!~VNvlEyii9O%Ta~GnLR5`8MCagdVT!xt0ElIR;0Xx= z4H(7Jl*c~YaWmtB;<$zhIbMU2z-}c^Ai;WF_63_{*g#wjYKIGQ16wq@H$+#Zs~6&n zo|d67s8SZ=y0`*JS%O~{idpYH<8BGNli51l*CKIAb8m=6r@mLBG2&u6 z)1zpA$#hwo8W~?!Po*9l;^O=%MXf4`074_|zlNUB&|?g5P|;%{d#)p=_Wu1po=o%( zV)Bg43X=e)3Xx2ctk?w=GNC)4PEG)z0})aRVaAdS9@%Rr7iryAoSeOOvzcA86}PJ5 zemy6voRPv?f(jqo?RS_$;|el{9k z4*FN4a2O5xjbshMkWf~|QIrZE#v4=AW}lF)gK@pGz&5q6}wy^lG>i{-QgF zZ}<7M`)RkRbmpbeaJ6=PX0lUb=}(5~L+^eevqgAFK$$Foyt0C?B;fo?(W%8efw@Jb zqnWCZF?Y;8W9u_|auh6m?~&oXjiZ}*^crXH9hy{&nZj?zs{GW%=NY$skJ$`i$`~r2X0GK!gqt%K-D->iVN9bt-8a;R`ib7_4 za4-ErYPu&KaW>g4cmv|j$Q*KXE1kJeT-$L*lpj_|HHynDQ?2cOi{dD3nSr2HA0 zJG9LaliDgE6z+~smYm0^dT$Jai=xrAj_VKDW@y-U2TucPGw5C}al9(yzrG5!?#*T+ zTeoNPa;(kq@H`#gT&2^&$;rAkn`;zmLJ+7ot{;VfYCbyU8dMHn@-a%sTYdb3g~`!x zq1=Duqg_?B#mvmL{7JggI^733*T!OVssC%-5-|?#CRpuKt08t#l7s7Z!bGbtlj7U6J3Yt$wp4UtJn;O<6~aCLYhhHUjqqB7q;3 z^UZ_}8w(%zJ7PLgh-H-14vtQpbwEFvPZ7m>Im!)9Qy!)GKocctT?^V+3sET#3iaGC zUc^D9FD}Plh8Lfwqss|Rl#|Id&6CTEN622)0Ue0GyPwj2kyYOFCSZyVg(N_0=6-$F z*rCOMR*E=Ga_Qdp+=sB&X)XP{5LU+a^TWl5R-vSe zk`BZ=)20J29awk3>Ov(qWzZ}!6ia$qqP1d94@qGJtL1nn=q{zgB`w607!{JzH|HA` z-cbiXz~gVT>9{+b45G;-x*N_$cjM{oraQczMuYygVS39H$^hW^b3zB)0u^U|B-MN% zm0XIv6+(KWI2vBhSZTXNDi&D=91Qtp#K%I$Pa|!mhnH2fzbjN+Dm`iQOsqkG!xvYj z2b`vr5pAG>Yom)CR?;m%C=hY1m$^`DiZ)=@37T?koDtFyk~w0$0I3og3&;5pS5?D7R?5rEPy>Evs~?)(aAoxJp3Z-wv~p!q0Xu!AO-!Y^TF7|8o6W-A zD(_7dSIr%shz;m8#l&?pHS35@Z~Ei{7vfoJLzc=)?m8#p#e@}4HQU?np^Y1*I0xES zwlElQ3dJ?pezO60~a-Th1Z7;(gh`K_mc5X0=6c zGDl+?K*glH$gb;+}U1@Bgh zdbPx`77eoe`1!R0etOti{MLv(q)I!8ENi@xNrI~BOpWdVFLaY6stBmnAc)r^CK~oa z;&*La+}`(h?_7`j{o(Gd?(OKN8+`UtsQL<@p;4G~Jju7-Yu=xm(~@h}kG~x^n|;aq zMCSe`33#u+|J8?!t0zUK=LIs=PjVDbX!5^*8}Ji+Ean#aFFvs{49K-1;L_bbi4a;p_JBD${PeW$6-}EYL)SxR2v7`tLv?=;;p01Ut z|7Yu8n5}#7{ad}Xhxs>Pdr5Db|1eFQAsLpg8n|p;X82!l-88uW?3AviI}W{v!`?q6 zd+6~$Ow8TPk_^FL%}5rDgS@-`+DzQljH43g@9f1;aME zGqY#TT(wY<;({sais?p~nn?$;&hA>CtEg{y@9mo%IsIK3dg$|>F2?Hi;A7Sb4e8wg zD)^cHab;A96R&KjbO_qnquRr$v(P%_2T!u#YFmC#wlq9UuqNwe`yZ?iwsy~rT639; zcpptqzk#7=l#N1?_9J`Ze8Cwm|Kti~nzz{i_FXy|41^8~wVj;fp|)HBR*@HM89v?t z7nZE9**ExLu`zb&jPu#dyQ+B}q_cFJ{tI}c*LE%djbE7dW!j9RbEj9-h(J>6Ktf*Rd_}r}^DPbER}7_)6JRe*W4=wYy6M z5)Dnfp3m9mhIzSPq=b9U-!HiCUuNnCwdYuSOVQUz%Jde9-oM@_*`vtqK= zYoS#Cs;moMHpnOE4JMRGg{Cc0ZONvpV&CN8Ha=MJ#=(whn)`8Fyeq{u&O1WhE z7)wH+O4&79LsfzO%Mk^R5j#Sl0<&d~bF^4zQ@h9TsL@eYC>EOXTw4o4sj$Wzn3v~b zLr~y9YldpTNIG+|?bpGfSEKiE5n+6}M0=8kgQ8oeRuP7cIhkOj0?p9?(iAKA+8K(U z+NKVrriPm#hR-e?8dg3Hgiv?}N;jj39jt2~VJrGUBY4_I_A^zmIG!1J&VK4{sX}B2 z-^nHzogK=6cMTLJhOmlJ71u-JSnTz*j&u-sLYW7@HhO37pSq$jbx5Vv9bvQWIZatw z0Jik>uJ|O~`emZseNzLhhigW?` zJY*{8WDd>=`G7U){${i(e5w0mSs5hLO_@1L5m->E6Zq>u1nEcs9=9W zB}C;TK(09s340-|RK1*>!2*)Ks<_lx8O^%g2CR$Hqs3C*SlAA*d)H&7c=z30+~B@D z_i}Z^38FNChzk*treasZk|oap#Gq;-865k)?(0Sis5857JgX9GT<>c~|J&MrU22!f zvYqDU&O@r(g{WD|?~0v!Y=n7A`A!Ve?NkVnm)SkLN#VrJ^QO6p!YJVR*h=C)rZ7g8 zbQ-OKyn0&cNUbm~QC`&C(mg+_CA^pU)|bYaiNpU6Zl(SQ zKZaFW^{#Xu`v4(9>=ud&y?5V`n@qr4V^_A*mVdu9P6C01N_SOO+NhrzQV2%i z?n$p)4SFHNyq8$1gz!gU*IFTn6LHwSUHSDEbL1|P=`d7!D3?Z`` zE5{v6F+CgZL~7Y9;sR@}tgsH0liQmrrboYVPO*Cw0-i!5Ohj5`w=WIwY&%x$j(IPt ztx;{hUt~geIQV}+@F7yElD`1dUEy0e-AfwSd;|+Fs5fMbb(y{iZb_@<2$5*GSDbIO zrWjTUPn|aZ2G^$myD!x-`0JX_jL^ofb^!ZWk3?w5p|3}9Kh{J^Q}IL(?2>oX0>{>B zL9dPFhU%QZK{l@<@!9hqn7q5Md#*08F7raA4vWurjX}p_-D*!7kVaPywBnCWy^u8t zX*^xTk4Zm@lm0O7?c@0E>mF~fG|KjIutZ2~3HIcK6mH9sDpK1}|6(7`Rhyx(#Dx@E z85HI{#~z`Iv}Cp9KLZRAPNX**tc=y~cS`yIr?tgJhq^`;k&jo3bi& z-zW@{HGH&W1Bqs+hl0U$rFLsVDkd%D1JAlt#Co7_9LJrdt{tdFV@(3TARROk>4cM0xt zk7h^LdO1nH`LCmAA9-E5KgMau+B49VURLDaokr%LJKEi?<5ODdc;nq#l-|k`oqeL% zev)}5S52}{3W8c?aQ^`7gyo|GNQu2y-*4hL5Poi@{txp=_b7ss`q+~w4Hc&?MQvDZ zpHN5!@LjMu$Js9TaDV&Fj2#FRs#a<@s?=c5d^7XS4?9Mmot{kpnxsl&KgqCXv{Smo z7=MC1SK#m`$5-#AA@v5ssNcPb;-^tG;g|byyd{8(mhFKl z9hWOtsl|Uv;srA*-rQI&)03mQJlR?7ndQ=G+Is2ZUJ#vjyXH4ip}xiU!SI0VO2f>W z<*)Ny+?Ego#TUyCR(Iym5>%!5o){@V2g5v`p(Z3c69t(oFiq0GH>@ZpB(UYm8~6j- zTLZ7~^KOFR3$$C82UAR7hvv{eQx(FIA{S^6_eR>oTwwMqI>*{#YUWz~OAKz(aRF+s zjm0{{tzX~#DyJB3QKMC9Efiv5X)@f7fOep#?fI#wZp&sTYCi;Y0{&faxSblj0Q4e{xa?p?C#=gGWi#L@S=?r75g+P$3&?}yO~VL8sm-x}mN z{gJ1g7b20)UKbFI9=Aecgf>O(V)OguB^PS@ya_vNp0xc{p>ThZ3b@s#y70uFAM)$4 z(au4mFIFWruNv*VGBlK{>#Tbg6Ba29M;Ub4TsQ zdN9RB@*Op{vg;2Jl7_Q4~Mft?ftw^>4M*z!5KO;yrvXzxH=397P-MBtE-#? znQ7djyMNZ?_DC41Z__yzK(~jAMVcPEek+q6ePjywqU9CjXQ*(-y65=c;wzy|u(+x}h)X|wpWvq*kFM3233G#L$sx085q z7k&CAI<{&)N86QO?1#^57G`#C(j;frrTwnh@1Vg8B2v$7Ob1;fNH<|T9K;j3cRa=q z<6b;|h_)Hrsh^F?ei_hjFGwFKo*~a`Z=0{{Je!}_PT&s%maKg00nN?Vbq<#+xq2z) z*m-&j84yQi0L=?3v}#-=Iz^8~pL2zgOAJqwVqwahI$KjuPwAu48=@--rK_4ez;Y_cV=UeKCRP_<-?f848;KTlN1#RA>j-%s*&o9V~-1LI(1I`s)dP4)VmFNc@n}^+_ zQ`Hxe*rE!GzD2`$GWyzmiXJ9X`M#HLni7T>@_t?U_~AF`{0}DG=*9v_iN#mjZsITy zeWp_XVbqs~UAmVK=tD?Dq2f|Okh)LEBrbUC*pcJ(^7lKo6H2;i3)+@N2!b;297fg5Qn%py~I#9*gAaiSKgOcu58(}P%{Wv>A3Lo~ecyK{ARVfoR zhle#qDGH6W;A z`_tvg>LC7XIFHC3-P9{tavI5=R59`mMUi@jXr!J7wFp=1IZ86OQFRT#9Fg=Ts`=4@ zOR5d(H78G0dF>7~h4wgEwLeMrPQty1HH+7dG0QjiJ7CvskkM_*!f-Xs!=5l8xhoD6 z{k;&IYq-U_Gf^bVl*|+(nnGqx$iKNtXfzBfVMFDWFiYTknvqd&{= zjoq~hs`_SGL0saoa}64Q;k)eB@B^<=13IWxK_QW*B^%!dw?H&-N^%WSRAxfX@o=*o zPBu?EIg6#xN^(vU+)ZODZbSv+&L5s@M+cwcD%)&|nHe4ytSi=_LQ!5>y_RFUZ6?ad zzg`5BaWtI_7t?SS%>C{#Y}=t?fZjVmt(Ky?P-1KBR0g>3ukf=Z)I7u*=2vaveEGOn z+4Kx301Bc+#cLoUfqAx4B%v_Zj5GZNy>jRCt&|Vu@u8Jk@8fQhBO0$Oku;e-kj&G# z#ITe&y{9}cdxDEDn_*L`w-wfbI>rHdU5(XM>U;*|>9LCD+n zb;z>vm$r@h_k?jfvaUR0t~)@?oxkP0npsy;Wm~ZJ=lAGBuL z>|a-Lxil`)rL)dV+WKla;sSqk?GG-;i^2FJyjeugGqnNQoBBbxm_&Gj?f+anr@I38 zcL46sNB($U;Q0=~bBy#a_C=oT;>9%B7k0b@?09h5kHTSZU+kN=!NW&yJ7?1C&BDke z?faPeZvFwT;lwZkNQu2y+j8145Pc3a{KF0}F`bYmACL!1OrTTjOu;j}F^au_I!2*N^Ym-h>y93~!v}BX_xoda zGMf(C&Bg`B66qYAaD(xZ)e{Q1yMtZG(7Si1vuV%hOUVg0RR~<=$APoxBE^=sDcp+}vDBi0FbUpb|pPB#lt$NvBgR z+)x(b>s970eSUi>b8n}BhFFG!7pj(&=>eh&ml**K)JMb_=I$iVjZzm%(8WTp@|+8O zpN1d|5{X+GBEi?4h`(sh9AYXJkT?cD&wW|^H+nb4R# z#rW;JL(KJ+!4A`@q-hfKki@W`ifp+DuUE+! zwm&E+ziwHZaS29)dW;5V7!8sYVRh)Z_ZA&DdOtdDRGE%nPaXdZ9bbes zwDId{Q-VwlWr96rN|FiAkO_1|64ekVs3%T2J~j05>gnU1;p5T8Qn~TGhC*IFg~~Fj zq0zKzbrqZXKBx3;GE84BZF0~WG9~!51(m5)6|2~-&sAHJ5&Hkfj4?m@HFN!;pEEl< z;gC`FKvsGu4wt(db)V)_)6>o)Q01N_1iOrVLZh|lrhObA$J8-FqK7tq1CF-_|WzOt! zsc;6}N=Zs_@$E-T!Bz!ovQ@kyr~mo+KkaE{fH*`;l)?gq3HTn+$oHnxVD@((-}@|R z$ZZ#YbX6z6%l{v@75@gs|{jd&zWrb@O+i?O5FYsw)8W}RH= zhY^0BWdsnl4zKjX2*2SB)7U1v+TU8&FbKBgDN*MCNpP5mXIloLZ6#>jTu`8W-`vV0 zL~bCZ9m&cqzxpyr|I`|}>!BS&^!}MOqSqrkgy_8!+a#}dd(||E@Gk@%fUOXX%q zlqE|pt-YH{3SBWV9LHx=RneA9x9B0Oq;A<38I7hu;8pSU8q@_=ZkWglnB9#&Hay+@v>3L=$vb?FlP%xx zt6%r#yJo8b&g1AzfiBgraU-0wmtt1;AXONMERH6VgiiXid2s-tZ8DaIQClf~DGmk_ zUP+aLO~VqA)>`g2;b0)swUXt|HercqYAyGha4?YRL8h#G;nh{5%ntG6>e)cP7f78e z%v6Z3X0hL7<^p+UQWn6(;&Z2L7B;FXk=Dua3+wbi%B3ttX8W*2#I=_DSvVNTw8-<$ zxp=G*RqcQiH+q~5L%KaI`Ov993a#V4Oj+hC7E)bh^+>7pXNrL*s3+-fvk^Z zp?MFrsS~AckRRGi2X}UFQcZ8bovJU8YW|0N);D4o@NEJ}iM`g*Zh|lr2H@+N_zsO% zF40HuVrJQNb2s81pyCl4YrDX4n{U5Lg_VM(ELpw6!#O{EKnb&1>u)$14)!MzBa?ze z^b_rt+m26)O^W5%dw&9Ne< z9dXK)O?L)z%}gBtnYTBUx5GZS@ehuIvrx zdy_l1XOK0B}jO+N>D2uWAlp zdzo7#AnqVlDK zp1)h@v0RB{+f`4LD#Xx7CIXcn3HJu*E4S$y4Ezh|3WB;;&?ZCwk*2xM8nAa6<{EmF z6^w7l@DB2;%1dxG^&!Kn{u(N0Yq`-t^RQ3yI=OeSqB+{Y z6W@V&^*^f>b>RsRX6;s$C0Tt4orV4@gSl!ek23O$J_|<^d9~5mNQUX;`ph*!~GyBMO6u{p4~k`D)BCk zdIqUBDw%8GTP0|zf2jUpNSm_LSOyi3qv0?a{ofTwag^1Hk$ux4%OhcV%JNr(HWk+3 zrN)Z<;x~{R$nF;Niu@-mtiuE|1bWbl3-`>= z1mwAa+Ej3Zh2|m?XuKubU|5eCR0a8ei#u32hn4-8(FV6l&|I@AFxwyRResro0V{0E zOqNIUy22v*Ly<%%OId`-7kMOx-FMWTLP?1}g@3G0Knd=ww znBxnVDa~{ONQu=~(Qeu>6n!2N|KLZEVA4Kd4}qnGjnazHZhNZSvp=GRiZqi!WIzgFaiQYdRK0C|Ve*FYTAq8j=aK3ST?AX|@1$=tp2Tqah>)RNxkTBPOy~u(o1a-zU2`p?eI9z{LwhmeCIU(i09E($c+Ob{UW#G za+Z0PQ&XBPucyPGA?@ltmkFd>{Fxq?`z=)Lb|NoUte58?HQGuO>)IY$W5<3N-Q3J< zYu;x%0EOAvemg>q!cYRQFi?INfsCOZWjbHl6MIpEGF2MZ5S@jxu&r4Q!~(cHtNz`5 zx~!?+aAY^vcbALld{Tqp>Ie_`1`L{s9%Oea0xw)E@eBOaBuo?PkcqXzY6Qa~_?h6D z`@R6T;%O0M=2jeypT974z8k9+(Xm`-X^mzLh9;!U&o4G`W2cTFwSFd$%+BY4oVGI| z7&o6&zRqm~a4_3B5RNtfG_y}bI9&NvN9q6TXEz9U;{-1;n=#*PIWik1TI1_C#=wB> z=;D=*kUST3Rr0-v1-)Vl*{JfvfKibaUNh79Br8#-Rk)x{UZv$yD#$2!vGpJbr4JFy zHQ}w7@kEC#M&q#+a3l?vwE_Z}J7NIdQ}+8{!?!d($MFI4LlfIl%)yVbL~)jhG|suS z9q7(Yl#sr}$1C(e#>Mq;OjVaTC!S*$mhHB?{^=zTP-!prE+Py zjC>ig2waTF0zIjIVFMR|H#fUrTm+EzB zz1`U1vS6#jTr%+YwD)u`jkv?&wMNia+ijt0!AtlyGYh$GbG2C zl<6Q#v_n_}GcodPJ`NaF6;{ixkRZYF|AF1vO318pGmBiIH~v$c5u4um9xnaLy-NG+UFirv`S2#J#9FuClrPfL~^ z+d$1vEi6R=>OXy7tGg{w-w2k@&|ZG(Z!;ce4}!g;7e-JM47!~&jW*X3CTI)U%rc90 zuZD*UF@WI^F1j6*Nw;%;POJay)$MdUt6avGD+!|{c|@af9ph-Na_QJ4C@c$zo+P)9 z!H!+OQb*t&2FC|W`5P1ZUl?b0E1MC1lC+4 zY`M)y@FE;kOlq2y(qJ=$l)s^bjX&K#eWV80OYb=$H)4P{N*8rNtkWRdnJPlXO!!R} zjn%TTav>{$#H|ZOYkE5}ckC6xIB} z3UZnNMCXjJ+zGgOFeeRlT?u;t{|=!iY1wmmkYrn)q2z*A{-8=cGxml)UDf720~@V2 z)EnI8oRDZ-E3zu~_4I*W!*c({$JRl=Z0MIedcW7OsG!D-s~bN0U0r~NIN%;@q>)ZZ zyJh4^1@MtPt3p;=#2or?9<+H8;4;*YGjhn9&j`=8_*zEr^3U_r*XjKEW;C9Doj5GB z9ReYKR8>N)gQ{9Mb{iik?Zbsl%mgzwq_T9RB>hH{1hV@>9*KK>fPLBBwf}$Nsv(=2 z2gT`WAL`BDVNhcYS<9mDxX=u7-iu%yK~1;}!efoz3i_;kw2zfgboSRWU-v`#yY}>A z2iGZlzYct}n9^^~bc%)92_9l?xXqT1oshmVCR4or#*L-f`!U?pV!||I?1?ZaCU7%M zHEs`(r-t&*&LoBXuW~R=w8}R=%V+*)nOk$eD!aMSdXXFM-kiF$a3+I&N9T>M&{(bB zgW;fjDxB!7NVT*aDWoYA#pROp+BRmMHP z@EnD~Uv~ZLxY?<4Lw)@^VQZXi(9eg^VRvlf{-5;kMi0+l?#G{>XAjrcR}om9i4Ny4ML-ZC?C8QcgrE@_M>y(`RGQHhq8Wc@j2$`g=fB348f? zNjd)8gc|NY;e52~`h2S(@dGioRHZyk>GsMzQ3ElPJ-XIrOc$3kL!|{(9werejXD4;nbJWiS{4#feMP4N~vhNYEQ@{M{t+K z$iB48zu(yjkc6Oh8bm4&$g%Iv-*>+IY?3MgBjZh!K`dkG8=y7964&BQDh+A{A_4p@ z4ap<~UqsP$w{vv`-A=c&N)w-KfQd0FdP0XtLo}pQpTsi4nGR6*-q+G!KPQsF!j5giUwtr&m!!#~1!){- zdyD^;!BXWOk-@VzKr@n>5Pqr_-1Fg#W}NwQT6<-{NM2qIb&Io=;+$(BgNN~n_ln^+6K8OyPaDg%INK&4&IJ-=#N~Sb>xLl zo6svIQKMkj{*^-EbGFKQCK*X83Db%dC^alc8L;w_(pMoSs9Ayoklfx7Xte>yZ!3!C zx)4kjyL})Yiy&YxVXU6z!U?2+*+EcBQxUO<)z4!&?Gyw8-d)${MzP3PCs~zOE7X{f zbg))h#cY^z0-f1bE%yf`-q5vlt{|?Nm#>RR7%EM}O{ul_mMv7zZ6w1r&Cw_BL{3`% zU0l+Sk;tqDy1TJr+^eqlVdvT^Y!S%Ru-Mve=`k7AynRhG|r!4afbA!M~mU`G~mF%MmB zbo4NBOFSEU#A_KzCb7FS%TdhVkNS_4V>Ak4m3ZtX%0k(1$?rrh%v*?FJ6}%?-6)uZ zx31=?w^tg@eUs`Th!5YX;VKBToNUVq!#kX)qPY7GO~HUEfHb zFZM2tXFvhQ$PppNl4O?%LliZPin5S9UY0{&+q+IrPETg5DwVW>A;fHzqLD7fG#|5< zKIio_W?d@OG~b9SY0S%dz|}Ih4TcJWW{_ZQg&qcRw)>|KPmI$>sAq6~1w{j^1~ZVg z(z{3%w^eOIQsLB)=9n&ERtwUdNni~;Bj*?E2DHxQ8(ac;tlz$`Gj2CQ^zlS@R=ZbL zR<&rA&_xxkcZVt|T~Y5e^F#ea5nIyIbHcy|mef|3o2I{AJ}rHy9X15CZExs?K{E2j zUfkR7M$TrJst7x6PYFluPKqLxMm}bk)3H?=AYYfb(MuuxqwMxV_TX&D%K2Fj_S1_W z?_HClb1YoBunM+aD2mZ8? zHsKhzSu8&N(%Xca6(8EWpYn`75Uf&%3w_r1B$mx5Icx8q?_$A<3bRR7NUu?Ax%qil za7i*Mc?8OpsK9H~cuYqo^~cYQD@&JDp7>sDL{;)Stqy+xJmbmW0!WFySKn_UHxPa% zQvQc|3$&YS@3krqT(W^}2|?^~O;nwbvlwu1v5{?#(7(Pjws%=lAgP)QO3?oBjK7)r zz8M4UxBHx*U0woY3l1}(jfDX$xK`YN)l5h}1*KsjG+xZ`inDwHtAcI024k7Fpk_1J z2)h90J>gS1WqJyR(@PMRFU<$qK^VZle62N?w%GpS*8^O_$0ta0t%`ySGPRK~RNAt_ ztvEkBKbx&(ZiSL?%L~rCnn|0G-%RxoY;&^^`C=@EZJnPr3Y9Z-w2=t04P9=B4sJ4S z;`QA|3OV;rYG!1Ie}pH&a5ya3H!d$M*o}~1G4?7elmttmgd}Xajr=NL8@By`Uc?NV zkAF>;1U2*aJ!kx<1N8-d1$=!Q_v3hS+qs`)exZW@HFGo4bP zpSB3Uf*Zkwv76Nep>CYqsSPJz{|Fz^1((zFGxvq@zbUhhmo4+;a@C_S4%Zb678X+2 zO)Aqnf`{A znzOIqGVA$T1~uYyVJr%fgvlgu)UAaL+TayF@!^T8okd_2x@4AAo}4&+#BD z^DrJH*(4ivlELIA86;^h!d_jVE60VJLJ~t2`Se?TTkIem$DFXyDJi!0>-XA1{qGt{ zzQ*ztRju5-saGmED(m%PrH&TkztkdRe-Mu`_x;JRlcve%_+W9;xZi(GQC?e*cfe{)7WBoNDM@U8V>7*En{G``BlquRzN!)VkR-FKPz2bnU!|Hmz%FwLh3 zwh^En=X}Qsxm(~XUVBh=#I9EBm7|ioDg!f#9FezX%_f4{HW5fsklBsW-pAg`LxiT) z*Boo6w*RttpR>|4K*vu@_LgHGjZ5|hdpTdj4-H~z`D3a;hT`aZ zJjaJH(mAPj-S2hWYoD%#%WEHZ+L`x z=ed@alQ{_Z$UyrC%+bg_0!WFyS6gq|NECifr2dDazQj(QD7W3GvJy*3Kq?mj$p)zs zn&5%BYi7{ckfaa$+xMI^zKk)cR;xBBF`k)k&i%&m@&EsPI6OIl#?SkFI9zPhJdL!1 zo{XhztIg^rQej^TBa^fjDe3ti4i92I7codYy;D&N4Y-wQJ6kz`FiO&5vB9%1dX8)S zix%MF9l}pu*RmUWIWZsgfg`ol@sSVdlT?U4$nIK3cXm8-?-ARFYD_=x_|*w9^|R8a!>r#A)`kwL~Q zq!NHOBrwclogig=-y{oR0@x%H&`Oa?QYpeyqD1=dk%VN2&v51wEibgIH*lqO4)!3x z8Y8#STQFwW$Q^YcRfu2whm255Sq729^T$^@PHgPFr7h~AqIf@m z^+dqQ`Tlbb0X#nj0HtyP2})OQ zw6Sz5z_(J5Zd~KL(XX{zz7^ZZbYs-Mka;JMqVl0$b)+GKdg}n9@SGkO^thzQRRFQg zDeK=S#1;#q>0Z%9ymtrMhD@}q> z%Dk=X$$PtxHH95XNx7x+bKf3~yMz90)b8H)XM>wrtJ55e%Y-8-Z7s6uc2(-3mX}0C z#)^;8aQL?pf2jDi#qDE zj=HR)uIi{OM^Vz@P8m7ZOBH>WAs(Xwp?rZ8_8_Ze%Ov>;&v+-sj6AKY;abKf8l&kZ zp_xLSf|PH~G>bDL!;!@${;uDh%x;>kZvQs(Y@QOgXzrBavzy9QQmED|&Uk;K3E~mE z(qUP0*?|2e*+g28m`j5GkF!1m&ri|(iNc#(0yQ@u#ItyXh0!aZs_Exu4I@+Lg_jDm z^iP>?JykI@hem%xxD3gNT%YJh0680clW{7VY8g8f8G#RZ3L%laT|TfNE^4|5HLapb zc^l9~o)=yP%L-s15wW1k%sG1S;gch2>8hfWv&f$cz2F#HI`InTeqhC|AjXk$5dJ$A zP}DK2+V>*f$iE_-Hk7v&aX?eXJ%5WA{4OdMTJdvs=9DOF0J~l0G^78>Db&!s?G`b+ zzqOn1HWpYvTh&Ks|7}%hIx-9v4C@ zZD2|BOdoQ!rqLp^eU zX^#fZEo47li#ZvNYT55sr)OuC>9m-zoITpGzjn$g$6c=_MrCC+EmkSoo=ji?Kw`b#abJXgf zb*{U2FT3#zt2%)x`+s=}Fh&E4i9oJlg-U{s*j7L!xiDZP z%n{^bVOwT}pm|`waM{be_q$%`o?;Qp~lon=hQ^fqr<`wnE85CpGn7Ipd_JPOw)$AIOgzZHk;d8p8=6E6&+0!5sSR!c_$Hq(8oZ zN*aa#HbL;PYK;l2-9=*%wB|hI=J~JBm2zv%eF7wzQB9bLsV-fP#BUoYJ&vh z3$qFi1hPZxK%H5(5Ow2Kmqsy6R-^vJpq;fQ(b7U8I>{1w_=GXA z(|fmN4!R_3o)I15`C~&&EGit{x2E1`HlDO5-fZNJ2M?pRH|uz#!E7@4+v|@V(R$v! z=UJiAgt(R;jx9O7_fT)MH7Zs_y-hnuI9f=3Hw*-~{o=IEoP}v(buf|Nv67+G-0sY+ zRI%U1HRMTIElm8f;r`PrXS-#%2YK8)-OuTRvE>xS30PulSV#o}VVP_n=xYORNRjBi3$_gHirvL)?SrPmtHMy>v*LC=vZ zH!Djm?r{9LI|Ad;T)X$wSxu7h}_Pg^+J^ z7VMgXu}oW#DqvQq=x~4U-Mg;l%<`K^*p9tcLH%(pg7sLkC$5`tpjMh6H2pqYZNlCC z;%3;NEiO9U{_wKlG`Rm(3t$?v#|Xw;MFv8ld0^!e7?s#Hs3n=V3I*1Phb+e^c?)g0 zVAr;*01xb^%l9xxydbP7KQ2o)?6zv#MM}d2n$2O9f$kG*eY8$ z6pP!7)I&;Ue5@1L4A&;i4hN4y{Kh}AgnFp1Pz^T?XC=xI_Px>C#G`Z~HBhm$0m6Xc zHZ4OEiz#IAC=f0ydv=)V8=;tf6oxlpCBAXD>j6b;OU*e+*3j{<-1~*F62rY|XE{gq zZonlkExhayqdUnC+;zz`U2U+Yt67J5O(RCh;L>nXirMh{rxuA&RXD!x%zKl?bk>>m z7L(p|bTjGp7FWH=XfYf8*&9wN&x77|ujhm&GfZ`P*;}G`KZ|;oJ#fvcQSb7|VjNva z16l?Qw|f$pK*6MMXA~m@?KO;*5iTtkN_)^%2g-zKR5t#Vh~VpvyU7RoLb&a>`;b1E zIzk~w!4;!{rP6p8au$NeW4su+x`!bTw2GA!rs?<>@X#GA)ha2=U$F#(8^WcMAq+&s z^KBU8h%?Qx;#O|)0T+v%AD|N``DA%v=Z@P)&ZB3>0BQMuir&NJS|#!awS1IfwZ`HL zh$>sqV{OLT#f@Q%jB$k~nO<=~IaVWO`+NI)%OncOCY4ndeG0yhdzB2uv77Y_cjw9E z?#7x+#X`pu=Z$<;#BJ!C0gEprTOkMQgU)y{=?p)O22?MlT}87(kK1sT9;$vd^>si& zDZO(q5L@Nl3=jD7yR`cAXJU8dX`Vl=TmY*;RKKontB>as}Nap$id(!{T+lGU@m(Gw2Vo)$}@(?iI%GQ~!o~jKfsc_iq~_ zA*v&I(smq_Jsb?jTHWKQ$wL>lB0#v}g6UqCa5b86e16`9 zBf{hvx6MRqr!t+EkQEx{uh%etp#c*~O8&mg&cuGD2{ise4O<7M1ot8@Qb#sVMJdMJ zM<&Wt){2W{IU40@N}IrrY1*2cB7Yx_kFqrRad6i(rN~OZBX&(wS;O`Wu;BHB_~{Q# z$1hBsoo+VOdRtSiw=k6tTx1eEP|R>pbfdO!MR-uE1P@}zu)JGkbC>TqFWO=$Nlp0U z4C~tJgzq@_tL4(&QCk)vf7S5+-K0K0X~M}Vok{5|{IidV{{Ru1=tKfYiM>}#Zz4Gm zJ}1)rhY}ZHhai#(nOrz9q?54AYk??18VNbw2Apx)E!#ba%l`H)yC1lDNSRG`P(ruu za=rY0b0@fP?|utwhWrV3PWpZ$ODy zuRtt7uP6+tFGVCcQ+1;uq9S~P7Ti(Y6F$)lhZUuXG{b5pF)K>Uwi0j#7Z;cHM#G49 zBqf?YgiKe~E9S38oNTD9K{+PADAyn{b_VD5W&{3!7zNRLpM}e0Z3dsAfx33ro?qs> z(ZAJH<9C_*{QsI-u3S?ekiZN+iAf+35$#))Jae{OX&_R>h$Vv=d)mO$)3>;pQ2ouy zAqa}TX3(g?*Q@IqXc^NYUa1C&C>5`;qEdje_>BY$HE03P6kcMbi=aK=fZ2;y5SSS% zD>ge>A`q8*i7w6u_vTFDXy{(~lQpf2?&bej>w z17w8fB`(8XqGTi#GbeK^Wa4)*1{V|6!p6U2=KuJ`-8KySg&wy)?ql`A#9#_x3Z?)k zSO^INOGS?_AaO}0l33M~Z>;FX2ANI23w*Z}63 zgiB6?t)3=4G8L(<0;<=Ph6U~RR@qZ)b$mMgbh?N`-?GC(Gz-H-8SHH`9Ap)?_J{J+FUl9+OS;)VCRO=F9}foX=rJh}?0?&wOmb zR~XImkw(W|LS+fd8I?{Tpi9b^EYj-x_v|d}Db*t$lnMpW@f#zwLbogo2HWY%_S|yf z_qzjRzto$E*NEH1-=k6U?DO6&_ZH4Hft^$l6x%#6_O~^V`QG}(hPnQ9^+oTj!ao+VF4@Y zopfjP^)pYL1J06%4O8kH4NS4dv7v-{by8Dx*>Kft)Syv4t`J9$)}t}1tvE6@)1R5i zTa35Eq|fQMKaZPq;;CA522hZGTCnXy+WQxLnQCF~lY;dF9Y$BFm`;gYQazLgiN;0^ zO4(7e5Cac&spc}~Kx=Eu6A*o@6G(aVjBteEn2{nyi-m5*xPR6p5N7aH$W zyVG~WZs+Za9BmirT1AD0xiPFpM%=FJj|1@ukr_J1bX^<@n%oA$~{yU!!Hz;UX-sV)^RsiV1ZN=v{b2EsSR z-yB+?z>08Q-x79*u9+o=uRCnbCCu-Ui?scCGZx%mF#iJlQU_B4NQu2x-*4hZ5PnXi z{0}2u0#}1*s@_{35a*Dn1X3GxiF6X$*hAQh@w&U_X!_T8X4g(^0w}qXqQq-^XXcw< z->fqc$@Ia43{`puzd*Os?ZPKmr7{n*V(2TlJ;L{u$-$^qz5q3ce1Twcp>s%7Byy?J4x3`#p^D%fhQ;fqb++`Yy~Stt z1JjtU^e5-gjMXKXLDOQCwDj=Gfi?o?C5tpbWsCvRfWh1=JYuoTrVQ4S+!fWxI;Fia ziRra8=)r^hfvmM8(Z*aOTFC|l{)jFva%*MKK{N8RXGhnVU}b~C-l&-$E#`IQ=lEMyMOS8TRh{U=~h#6Mq)?;dmPK{n@1-jAxVaAO0w` zb-wn8zRyCzgi2lAc1Skg8(Hs*C2CR6dLPrA^2jNT>^4xk`AJd%rAXkbG?}qEBBz~& z8)YPy&h*`fhO8;&*silo^-`~9;AbZOO8?%u9a+39-l+vje}HdpDq zTWLHObS~bXbD=n3xTioKVJk7VjibT7nc)G=Ngk7#%%4hfd?=$2L1n}Jx}C~YfE|2% zuFq~JzfJk$h`fhR&DVUWJUKV(@4~|6`dj9s%YVTlinL)OEwkKw`xY*Q#@M2FvLtS_ z-oUGh10+%;&%SIG9o!r|_f(>C*H;y-7B_dRg zL19N%gUg9Oyx0#sk`IgAPv$=fy*r+lbMGfC+v!*?Z#ouu;`VN5jzHm#BjSSw*4~k| zF-kcj9@M64QvC|x1iYVM+yT$#chPGXxpq6_!CWN##cdZm^^10U4OXMoc2XS%Xp>Gm z$#fXF*EHHgqW40UXZTAywLbvw+6GR%r6h=CS*!{`(j7fBk?0 zNQu=~TW{hx6n>^s|HIKdK?l0q&T}8Kkai+bKwLUojVfdkL%eltlsN5V9`?8Iv7H2m zLZ@AIA2#9^bMBY#oSdEg`|I?i*8}r$25?I`r7)+-mJ>x`rbw!o*nk(nEKJ!}We)kr zT}Iy3$6couw{iSny(&92C9JWY=H~2zJfRe0$ zh^^Nw%(*H+&?lNgp3w}5C?L!;B@-Q#tO|-@Q!!CMQVJ2x*hbI@l!O%p0xPBK0$FBsISw1piE1qxpdg6r#`zZlN%mm~k%AAyews6e)s$;+Nk+Lu;J zRi0`RDkAF+s>m+2K*4y;uf2sUxX^?=qnhT+5gN2_N<<`+K&Unb?y^%dy+UK+>RMpw zP~k5wQW7yi5341={QlUwTwjC~0Sd*c5?@yPr;ds8B z&Aqw5)F;8{rc=kdRa<3~Yq|A(Lz*RZwf3b@sl)YKG@p)#_AjO z(e%$W7uYK)>gi=$8Zzt&NDLy?t#)pywN}T-E0}tHfBAKB>y2EYEw}d_i@NYB&J!Ze z3H#L5Rc}75LsbbLkUyUG-zZ(C;X7q7Mg!j)yit6PcO*Kfp*5vp5psHylQf#hjOh|> zul`zYVwv;rM$W@8tr-P3U+4bt`i=HbzCP-1$*l9c5Gf7iMzEgJcCtA$s<@P zJE(A)dnm)lW-PJMH`<07RSUsXKc#eQD9k@y)3Kc$=6v*+JTj{9Sg2%Lz;7_1Yl?FS zdoeNw{|`sD@y%vC$i~~P6ci`R)*k3|c0rb>L4|)7Pcf+_Lc$Is9mWP_C3#2rLTWkL z=P?B<1!9(DSnt3x5E93|s7*Py!_HNw%dRQ2ZYVpdVNGn0)Z@}N3ho+Fr7=S+&&*z- z6;|T1O5Fj>cYN!>-*3YF*UYivGkA`rF@tdIng}-}Q)y`EQQNTP41f}1#dVEyb;3R#GB26JAY^1F)=${ zN9J)cd-y^%YU*_1ItDNx&$3cdRcbcMeya4&E*XvcG3&9pc)^~yT7-e}WsKV6||a_#z7?M}5@ zSj@eGs$Sh@q3l^#b!9gcmn)--Jn*hHat|WSK-D&5sAQ68jKoKokRU9TT@Uz3Bmj%B zkU7NUiB=A1uh2^D$tt3lnN_YdA$G4JT~Xu}><5iXJ-V1nl<{;5Y|Fb@=t5(o#K#TO z>@NVuapa-VzweUo^u~UioA;l=>A^+?H8!MjCur;|jWOZYmb1I;jgn&<%s;CJwV(n> ziM?0dZyGree@>+Q5Az5*IQ3p5@jziqxg#G6o9e1lh0N{%K8%fQFO)vq-+p6z7Yrq| zs38%G*53L2&2PruIiSpMuCKy>`f0RjqEfALbW5%{mQZ-$bW&iz4V@#;7D!$|~QIp_{@j#s5DC9@~f za$(-J{~kRK+MkoBp?3>ojcon`Yxin+SU!eY^oy@zlXMfjb6Ju+Sc^<#h1Mvo*g&zIYUUe(lna7G6Qg7hC7xHzclv+rg>efh1p*(*Sp#|m zl`WrBjp&#<;1g`XJ!V=hmEh)d50UX`?g=iyZ9MC3AdEpZD@DJoQZwsKT$ka9cW6w@Bq^-R_g;^r=0F=J{J(oGwO;6pi)8 z3Q_q1m7_(y;1YqNWngKv(9kllrq2QZ8aCA?$*#FZJc5Itkb|DnYtAY*HjLr&pCIRSJ?CDc{0rUy7GO0TY121!QPgEvQFonrbjA|aQE^H4Aw z2RkY(W=H-IUZdo)sJ^=51HRwKG9h8~7ThR2H-Oz@UKfAN*UZL%Tq1ufA^qMKAUWmj z*0}*0(rXEx_c1a3LTQ^E6C+DLUvZFGuaD_1T)weL6(+rVjZ+7m$&saiQ|oXGunr9K za)>n~++|v-Z6*$6oFR_UX4++Dls)*ftx}AgYGz9jHyWDER;MTF#Ea6%eQ>|)AyuER z#P@|iwVhq&|GxKS{&?5>bvT(?>tX?eUqx;s|68QtXQB<53Q#Bt{St(6r4I8%WD013 z5qn3{O75tDfSI)j^8OGB;?s^a8)h$x9A~XF1>O<^WO7MxkkI? zCd(NDKb1YNv*UjI-kB0tBH2b0irrWxYJtvMCcz4O@>0J&dYL=yKzzQ>#C&;SEx}6n zpL;p&nh_++Ceh~&%^wwwCM)&7AjBW}PJLO`?o(8;7_(qAi+!MpHC0qfq1~A!<1Vq}L36AuY&jzxxjejSB7yEm zly|xEmM;#jkZ&FXnemR9TvIfoZ)T>vFQEI5tJOcYJK}?V|A?QaTWns9ewbFAzG_-h z+!wa-0Mkp7!xW(-vzq#9i%C<8zRic=$w4f(GKo;u*-g{wCWrn;5b;wb;rRr5W-b)@ zdSxb*hk`p(o(c7#P!on1213a@ug+2*onl=^GWYD(xhvW6Fgwelhz4?M6{$|rh#rb89_T5dMj`#I2jr@nUwT2R|C_R3I9UDjC~amy2UP~YZx z(_GS%UVk|M^mN}F*Qcq-g;D-V5flk#Th0Dt^!Ru;oPX|3#-s7AJ84ynFxac850n18 zFmdh~#PR6%(`;3f3LzO zBz{4Oy~KpByoAAYwA%Vw9r75}T!nuF%P{_p0!WF)S8Z?NMiBl?r2K~wUkYk+O8IAeBhIu@wf_wo|pK_(cfC#fAl^Y4My>)KfI^E2~7=I!tIGI$W0ol;i9j&d<)z=4%;cLP;26j7Us$tsxKb zD>C{XVw$pj0iHlz82lD=2K~{^bQ}iP{l|I}ek|oWV#_M1T|5Qt?tWt6-ig{>QiA7| zO3_B?M|=TjR?2!@nd^PY@wvDr^e^jBT+5WjoG2>bZh|bsYn4#>x|(%4IJ9NydI575 z+ui9s`*Z4cPptv}R8ZaL6{0`WrZ#f&^FoGKUv0P|7sAp)O4bNmX~la-Boi042i!D9 zREbh$ZaM8F*j1f47Rajy^uU^BrPd5T9nKxPPlNBFZH*{unv}}v+J1USY(KfEDmHB( zB8Q#F>3GojBM9$J05GEzeF2MWKTl6msgWM0S)#T!)1}FK$@q|niEzh%@{QH4%{@*9&gu3%o0@)UxeByr^b+>*=9~875015lruLu0N!9M98=NaQGf^ ztYAsJ#JC$aY;>PI_s=>d{$V`flCME}Q8n+T03G>@j=NK1;aQ>gXq$3dtaP+xy~8NYW~I*CGU7Gk!dN=9%$OAP#fPKL4upP>ao`Kt3th z0k!FL-<_TmDq{s~{LEN#e5mJydkUuYT-HW_J`6Q7iv*rwgeT06+E?4P5vMFenxXgk zIY62toGpbECI_RGJOg~#D6`cFY6+~UTr;3{sI}l|fXM@#Rh~2p2vIEI{?A2#n-SWe zC=&N8agj^O zA|i>LOPbl|qCl{Ei@=rhAmSB(jKZ)Jt?YWUm_jnU#sV?ej!iY+iNO3Szj6s3sjQ=7 z^T_^>XqQh!ByUHmThru$JT;}K_n5IY)+hf7jAhz7d!egYuwsq+!Y_Sw^SW z%;9xtS+#|qZLR6KBV8v~NwOGD$CJrbvPj3*$?ZJt!IBjQdx534&K-{0+HP|!N6>q; zS5A~A`(5bwW5q{Icoyb{R3M83lzE^yI+8&maiH09DY7o?h0TSem4b9ahM%2^*iH!! zq}zkcOyK6E!JXx5@3som5rX7uUs`zrMuHV;H4?@V@r0f`Z*Ly4ED279KZ zkSkcDF>Hn9ZsqR|mZ$h&Q&mzEvC@M}|9%pN>)HFoXg(dJQ)gi_RNQ*w&yA$;%S{f2!~|s;f^_2urGN z9wi*$t*Z27y&%g>$)(V1W`&ZKHeLO7eg&lO3|M4q3OR*N(A~fav8(j!=&XcCb^kD< zEXb(V<4|p-ZHW$kfy;P~l#__4emTQ+@9&EWUN$>Igip|MVYpuKt&M zc{~`QMZFfX7JH$Lr8*@nk)^f;2aRT1P^FW;_2Iarmdm)_V<$4Jv_O~91oiIp-RY7F zoX?N^$Ckb+-Q9~X2nV4o-BZKlPsHd%_ghhLg1!iinyYjl* zgJ&bOwMV+UC+xa*?sz8`3HPGJ=nO*ban%(rJ%DkAh$G`Ye;L_)Yg`dCR7{=3qsGvA z)bjaAC;sj9wPN(ZUsqVK(N`}(srsTkr}odf^X5#hUeVuxbL3uttQs{6tf!unU~5eo zjCN_+M{(>0;rX+z=~~IzF23_27waGL5Y^|pj9Qmt-f4T+{q&3kkNvUwdPSp6ajL~? zg?iwph9p0qO+zL#EIMuB)rG+IX5OIi#Xe+Tr~9>3_=3aEoe_yG_pZ8-jE$R14;yrD zjt-;*?{l{Y^P6$HNIy=J#Vno9hv|HpbdNr-!Ksbq z>aFql8!>DQNCHTS-B#Of+eQ$5c7XiDz)v#j7-=61sDLWVi38adM7nMf1j33Oid#{; z!tTW?m8<|gynumwCs`O( z)qX5%VInE`3Em&sR|yh6c=rzAyZ~mPLZ%H!fxt)$xCU)_Rnb3wOJ^d7HP6;utd2pK zOd-^Q8x1>d%Ek~G-8jjuk{M#|E+MBd%M&Y;SiQ+Ds=X=6&<)+D$Ts~DTmV8ESpL4) z*f^R*eWrlC*m)kQeCdKYaB-hXuW`>TikyD1(ip`pBv5$diw&Bi28A2O1%!we^v5%WPSVxz=TDvdG0di;-zM|Lhtb7kF`p#Y z({yn;xlZS!=`j?HVCQO}(9}w_W%x=?+ZfZ5C`k|9fwoaHO~A5c2E5B~YuwG&r)z}* z6+y;}Z%}KtLI{=)gHT1ucK0@Eht{6lZV3uGVY?ODwXeba@Z^8eVggI177G2V|3rUy z#{GXMxd|kkiHv+=Vug;mFZ$S*7%RTrR+#%xUpa_W5@(4c!klrzb(u&hoQt-)m(t*m za6>F(d*YpClx3;cgiT!;PL6}&#KN|*d2*eL9PipQZvXlCx&}yEa|bz#LEi))aVCw$ z2HheMhDgy0QXwXHf#ZRmPu&kGhT3tV!SS4WpK+kiLN!7h9{*&JE9bG&$L^%$Il2bp zgK4##4CI_ua%GK2*?{;ng!lG(S8|&`@&R7ZM!PfcWQIhj5q>!jEiW{ z2ZuFHJ3+lPWLQ$dX?38MLpW5dD0p_{dJGpHmrD{{+y2gOCC{nz=)K7FNiZ2%{@B#c z7i&je$Xz4nA~|*SJLTF&^dQa~r=WY`#)Gg~N5V^+KQR=BF-_n*_`a!XPiSb1d@=fU z;RkTyQUptdYz@I`_-SzL5$=E-@Y^<3e?=^a`b;;ft#V?w44aoj&l=D~o5LQY9riW) z*-CzR8i&zA1SLz4C$Q)dI@}*S7Gk-7s&(FPo;OSrJezHeNSu}3 zpz?Utl{AT=)uP)g+7)*!g;BDq?&-o`L%0~t7UQeSbbd8mTql!xM+?7RwNz{?*S^U2 zP;V<~4(~fhPcSry6o<`|cPa`)Fe+G&F zVRSDfy?`KnJt{>IC{m9glDlhFRmkj45|@olZ7;dJ^l$IXct4Y+MLpUTY}WSpH{TyU zZBqQ&KiJ>f({uQU8R8e^KY4VwncAT1$$9+lLs+6=(!D3ym?qZYuR`$~oWT`_na!P1 zD>OmQTDRpQG3mJb;S5e{@NV=|IYX23FJ>NJ7UV=oBBgB7Ui^I@VMvN%{|p{}zyCP; z`Tq8&(J$k>sYn424%H(>g!rbvqa%QGyL!q4LO`_w&s;qylg9Pjx&%E@^6K2?CKR$n zUi`%MdZ{zQa5+M13wb&e`Lkt}hAE+X&Y2obCjrm~D2Ub3+5!*kL)pd9oX zPy#)K_EQ*C2zJ!zR%p1bQA?-cmM+77K~s{>i(@}>cy32orZH{C*8rMm{U)22tkJps zzDx2FNQ^T|(?ZfNLvG1Y-t00*>5nQ{8y|%oqwNc856k$iBY60l5Uyb>_m|;We;3dN z<=dyuY>BX-(g50nv1_o;=;(+rR$O(i=x9P)EE7di>z+gKOPgmYsBEn^9v%=>fDDxn zU`CI=nHRBzU?dY`J z5m#0_+bQ0W6omk-6#oHgs5)Sq4C^#&aotAR^>U~8TJEdOu^TasFp#>p#N-jyOC(Ci zCGEK|fJyxnx*} zIcCJvsWsbuu8I~@+VN$tMhXh4%5SwR>9}^=2k13a`)NyspG<45TCKhSN)v=xTD{z z72KH@YOQci-L69~(W#71irRLxzfReI2#VJjL&R&CqpLA|yIuC$MtRmru#}q}R@pH^ zhYqExwHluzV5LW+FC6U45Ai;GyXRnko|`0Sl2{~|IlWk*tH)BR@!BtM>{=$A%qCP! zT%O_f_*&83(V@^5?dWoSH3?sC!Wm zs(5uFDEbl=BVj4Y7B%Y@b<{g$Vas^u>$eUwy&?>9>?<+8?{9bSsWu6=G-r)rU3F%M zE83B;u@AAbG9%%0Cufs#o6Y&Zc>mhyP()zNr-su5MMkwKn`~nh=eNe>FT*h?X={$# zMM^^qjr?MicXKfycx%l&A+a=!JfYJzrGYTOQt{LiFBgapn5di@9-WdoQ%4CXt%(?A zLI^zq@j8{BSef1jmV-0&+3J+)nBSPh_v0uP#h8*5Gv;)mRc05}Xy4fD8J#tvdWwNn zi`l~9)JT#0yA$?zT(T!^;Fy=y7-{@zQcv~G#+q%j2WlLC<7RO z9^cIFuSOro_p`~TyBqqT_2u==_4LR4>11-#z@TY-Bt9?h{$1X)VZK3Y8e6-RerpA9 zCSU%gew4sl>g7*>ipHQ=%4t?xSr=5M0}Vqq#pAyKmk-C50!WF)S8Z?GHW2=t0QnF1 z(cYY--FJTwWGxlom&}s06+C}MAV=4D?G>+kI?z=S+gklPaH=1juI zPLRA%;2xP+-x-A~=si$nHAN^8DWYhvW~UEBv^4fU2J<8u&*CJCy*Nnpn{fKjM+;PF zO;^i*k{8M;9nlp<9ogST$tQ5v5LSds+7NwWsVYj=maU7LAC1W`wN@aY*b9OoB6D|p zoLlUH2}p_5h-n2Fv8E;4Y&gyCD!X3oQ60OX{+M^@j)^#)1 z>z|zRr@K;GM-_AnfMctQjXeTRh0E?w1j9a2eekD3z2)8(>0Td zme!YrU@F*Ap?Z4e0BUXyAb1LSF%9FypG~89zVPwRoBF|c0D|#`dN0eoRIx%h zg(fJ~m>KX3A#nw!$~REX4aOEdhKy19zXV_uc=3lWsI{FD`jmIVyF{M_l3#@m6}I93 zxAbGpn#Wz^;MZVac`Vg=F{zi}%+yACTWnRQ0K5(SDEJ+DKNG3dR2A>;5IH3~Dt{un zao{}#oxqLh>Ib+>b0XHbj`7ufu5+Dprb~kCwvs(J-8X7aq4vh(P?xRb(Tk$6g}JHB z?AqT9U$uLijazFCM#)p?$FuoIjO`x_4-4b_Gb7q`-%O_M?fs||7@A(@`z^r9&Hn># z_t*)U+ybg`+Im_nB`uLCn{T?A38h6nb0f{2?9i?JKw5u~>I)@y_spguGhEoeuRSBW zYyW?R_pa}A?}va?OuWCG7m*1OED_r?SS|J!KRRSFmCA&EXNY@+dsox|KT=o6?Pkzu z#~S}^2VO{Z=agbHVF#zR5|DXOD%09&LN-K7&5Be5kOk^PD_ZFb z+34N^hXj*3DkGU|X-ykr%5<;McMagTyLSVdTyIKf0~@{j<#LzNXO)8M-a$9r;Oz+G zWXU*FuQj0yTOMBSy18C$h27ZwoTkqq?vsZ@L>-P<7`#Xcw;5+sNiS7_z%lpqu>`kR zRTg}%^W(5c>qnvEv(Qy@?n0ifAx)`fyFc+Bb(0X!XX9iM1#??PjMYo_N66O`W0=+F^)0t=Nr)5N)l7Uk zgrr4ZL&$RCeEs zZExa65dNG<`46M}1Xps(<@&A1NiH}vDlaKEN~5Ymi#@XJ?~y?Pk&#+Kh+=lFq`67N64M~jCaV~tHS|K6 z>e=Z@q9c)jR5AXuJ##w>8gHTr{Q@+MTEd}UV~WxJ_F>+Gkck+{M4DxV*(@~F;ex(- zKjhzErZPb==>j3vG(VAJsEj@jGXiO7Wm26CGK~MS`~R+jnWAF0lMPu3%6(KUv1->z zT1RA=D;wN3tCC}~lGH5$euDQ7m;|tdPj10!x;}Wd>B7!X#XRPNRUp^YjX5fT=JYy{ zb{+4};Z57S^ZS7XhEa;*9vq5&+t*9SM-d$zOc2ZA!6w-iHrw)6Ut6}TEAM|QSx;e4 z(QB7@bSSjtOd9qlOvH?WTEivGEnoI-Gk-3tZssuZ`7Zq~UtJ|Wv4sj#8I?71=|2gV zbEIf)p=ps)JPRmzB7<=yPk&CBoQ?Rrjz0|VZv0`#Z~Oi_Z}x^9CK>L5pio!??1_s5 z+Xn$j;oS@aKMb$CtzeDC-fC)4+DxUI{9=7J6Z7+Ij*%S82(l=Za|2VM;si5Vm)3;` z4(oOK&%^qdLjiLDD!lCtL*MJzz+R*6i;#m*zx93pSg;RIxuZAeAB*+#3TtKVfl4vb z6D1!p1`Z|Q1Ip#@P``ZUWAPj)z^{pXd=zQ??z0VfDQGS@12(u`_~_S3SSlOMZX=+c z6lYEGMY-lW=BBd9kSWbYcJI~;2L(o?#?rWC#>8YN)$h}6wnQf3{)@;fh94oaSZ>tA zP&ZvQ4CM@a3hPX#=Y{2zoJ@`9cr397V?k+Ivv}2A(XrfQ{{aT? zvdGUe`Nu7b>l8|UC@g-wwXKn!Z|;)yo-+1V-uX`E<{DVoySTqJ=n`r$SBL7-3R*)7LsP)EJojrZCC&@cx3He5mH&tE4{& zeyfx5vygLTDdJ!;C&$Rigf3yMZi?Al({c2uw=W=m6Xu)qVGIB3WVXa^!D= z{sZ~9QiiCx)*6IfNDcOyK6_Ub!FM(A{}_1f+GbF1pnGxbSugGYEO&=o-z`Q`=v##+ zh@*w)++AcGL~amA6K5X#LG0cvoN1rj{~JgCFdjO0^V5^#qe$@83Pb=a zE)|GzvW8G43fwJZs)t~f(J(JECWpy$pNyTE8;6k-xpCy-tv^Dh?|m|L!_X-01Qy}f znt;QYLlw`nx11rU;e1dH=tcOe!{&VTpvWZ|2td5PQWh{ticI-}p;Oc}r&oUy zb6t{=!StFzcJj2Ma#Sh#WwTof%e&EkOJmf!ZTocg(oKRj84+%;d+Bxy59* zyXrMB?2~fZJf50`rA4J>e~=3twCc7vS{i3MEvdo=b#tdJ}uQk>JH*MjFF+yJo3xfoieI_g2AzYibfD=b|K4_U)KiO+7P^Q;*@ zOXTAVzJ%+c`jWcUW#uF{1r+d3JiHePe^rrivv3#gFpdImJl0-r42GXtlDWTtmPW{3 zNMt;HgIY+y3dw4yC010}oqMaLp zci_idkZQ;!&9@+cy$H4O-)Q(8p1LY5HVoNVZ65~}EWE48AYX4%sLLD_so-68MhPZd zeJ_V~EWE48glFpYvA2n6WLNeOr~vhmEm-78k9HOD6s#Tkv*1-=wTWnC08jW*+g0N( z5gBIU2Lh`^b`aQds{8GbCuv?&`1GJ+utdInna>QWdM%^5*hnB$bL$sbj<5MR(r(D>nRz8~Cn%sX8zl-|9XHW#|4MG*#pHF9!DTHh9ZhJa}NaDo^%$! z&;PKi!5ZR-WgtsU`edkpYN#ZwV09lt$_fq2h^kXEiptJ*N>Cy8%; zJYwU8*H==&;45l_NKQ}A&q@EsefH2A(>#P&Z*j_KZk8G4Q%*N@!NEtA5G*6*-GCla z42%wBDUvZ0-@Pt5C)?#QRVfqR&>sh(KOg(y&FF4^8(c@-9y!o`c!Ta>5=E2op*CHc zoj<;!9gc3kv}{e+4{uP8Ce!W#C=D|Of?_O`N?~aKR4E z)07={9>mLVYr%7io{a+Yc@{2}KI_>Sx?SUsFjhLVraGqC=UhIwsH3(~|74)**aUSt zTQ89`K&?QL`zok&5-G{~?#(}QSuR%p!eyzgdaKJBU6W!39JCY#$6$aIMzt)`I`VT=kvjLI?QpbuoZ|(29G=qWQ zK2MO!ZDnHo=P{>6K?*J772zzyioURNrzefxaXK?24I^lHy-v!yc}uB8l4nv zav-kZ%^UOBDt8M{z;|-?@ueVs8xB*K4x-WEPuwcUGFvb~jf=)>TWD^7M0pei<9YNj z4d&Az9Q${{U9>AEOo0u#%JCFbMg?-yug?2*PtJZ-QM)*H@cz~P+WZN*54tOXD|m8C)|R|jVK;@u1H8XJI6 zQUK?Mft@qbab(Ky(BM3yC}q>zv$wW8Xo4~5x-j?3GNAF&mgb;j+;D6l%B;!l2!pMW ziqzd|&f*m$rqo7>tF;5NZ;F^R&{E0*LUc-IW-(ZMb#A6xNt02_4SVZ0S>1{WMujsv ztDx|jJ9Q5UVM|}5NAiqd;mlZ;c9sx~iV76dc<>^&mm9qy4ZNkO5wEQn;ENuS3bXM9 zYJ(!Yj8_{>jbcz3C1s-|2;>4uyl3-++g;cI8hGyRcRc6q7JoKK%%aKgn`JyK^U#k* zhAelqu0WSc?6}(f;vvw&DQ#xWY06~v9w)Ac9NfgKM=tUEUdM;mtIc(BuOhTv*`=7eFA7j4SNCcu7SJrr8!?4u;MJJH~cC93=a)ji^l1 zy*AMr9oHUA+iKO+b^~m|iu>^29kyJHeAmpf%f?Qf{GjSv#`3=CLHTcwan+?I-o07- z|BJRdEc}RA_m2Q?3-(V=i1Ty;NQu2y?M~ZB6#WfS-(h}+Zi?CmU?r2d)Vm?2i9uUc zRWz}$lPUI0G#*3Y>G#|jJ70uqwF?^o#&_;LbMEI%C?A+=uC#Q@=vw?HKD;?TIyzE? z=v|PTNS&K1(XRKQFJxJod)m=I5oc%O!-;T9(%$Z9rLtSf6Gv70up%MOM3Tmrv-Im# zJc}l2@-Z5u`t3T102 z8cz~QMi6||q_t8nu-rI~P*|@|z5ScxqR|<9FQ!gf=lu$9);;h(YVn`QQ&o}mCOssp z-YoltK4);6ejfZeo5bOnjMI2>6OH=9*#`6u0KZn8)-Fz{GIw;<*la25kRb0&kn`(D zYXT+inJJYe(tE9y>z(ukBwdP=+^?Im#W;C&>Iq1Usc}}8UD<_1lqQqqrs3L#7%Y() zVT!KRh0l<0hT3;P*Mslza=%n1`Lu}KaOHOyje;>!RY^_SeG6vaVOPkqrUSaX@q+TT zruc9LZC+SAL8xE2v5!Y1pR_&({$}4O z&m-S%&+T+zfV_I=UrKv>AuIA}q1?v_^cEWtLdnew`H*U7%|j@OT_rDjb+SWpl(}Ei z{b%L7Z{W-KBD#!G!?=FL!&&+Xb^Ph`Xt=K2y-@uxL;1W^kB`y@N4Hvp+qfOr;zmKg z5-VS)eysGlaWG{3iOi~U&KER|WHtb;TPzIloC*$8-dfkE*g@$G*Bw()*M_yApDP3& zQ0Tj@eXvIhML*F}{h+`);rInE9(+oOO0N8{8yH=v1$edW1NmM%1h!qiD9s#!_e(7Q z(olnJwUpN43DsF6=OvxfQr;a?47Rr~$5{9e@%q&zfS`@%-XDagF^o-FJ+*G@pff%K>sI zjn`-Iy>iPnXO&|%t3vtVpZfzqJL1D3uxGqE;l|BI5768fz^|I0i}D6jbjGVZ5bd)=v68TK*MjKYBUhO zV>|+S{=k|FP1jWY4y88Ovh*v$QYqPtzm+t=0#m~Gh>i?Ht7?UTAoX_2UbtjmXAJI@ zV>j|S`aZL0a2KwcuQHAgGHI*3r*wkzLFs{y^B%Kg_-&u(_wH^9yFE8N!U2P`HT)sJ z58hm#X!$$re~ZrFE&0@_0!WFqS8Z?GHW2>o0QnDxev(?*NH(A!h8jf|Z-a-m3lbN# zQWOO(QWhJT6euc=Gwi?b_@Xzpg`(n0Bd}3mu$ChJ3iE1d5JpO)^NNQmibb zpe4c~Dlfe@jWk{xpJLZBNwS@ka*x&x6YJT(vN3H!M{SLCQ0B7^LQMu;%>2gW zR6LrK;HydLOm2}6!=~T{-RO}-`jYhPI6bign26_3*DRg`1(+#W*gey;z9qM;v_-S# zcSyAoTmv<(t!)tWPHOfGENo54DyLAOL1>N}Xa@=NS2^xaKtT+W#YO*8qoiD{ zYbe(gUuPPmt6oOe%x*`+rXV^ahy(;RL=%OK6a^EuDr=s7Fhdv9YO9tFAhsD(41`=s zYPbqmGbE-blSyZZPnm+wLHQmH`7`{u-JM<3mzC+w`z~>&? z);WQ$7|8=S!Pu`Ya_hmZ==ug=_l@XyFFNi;oAaoZ0Rb+s05tRJJ1HW#k6`D$ubDPh zo1$6JiH+*jEp`Q)(|U;}?0rEI^IFT~_RSsPIa%?X>s>cG>}~j7X6j9U=!X5y)~mP= z95++9=A7Y2s%~o$mV5p9d#lXDx%4`A%Z6vzIK*9txaZKRvi%yV!P_dSEr+V?aCAI~ z9#olM*|GAn>-}HP_YcY(j1=nJm%Y(Ht5U-jUGTzD2YsHBmPKre5LNvxOg4Jtf(MUzJydGXv0PyoF z^*eCvZX^8dp@-MxCGjwJ>NvFYVnryMs!^DLPU^RxlMb30BTSN8CG(U0o}b@q2sFh` zlkcwcBVTTd>nka;W`ZVmn>Q_dhcs1Fcv2t)%vDOBUBSCf&l?TL*H;OJISR!vlLDwp zv`A*y`Lh4YrQN~NI*1~H|1YgpdWV%hr(7t3!6nD?*Q-CpW|u7U_hRF(m+Q^Vx330y zPcI0YmF$|NKL^&1^h`3zL_*!OVIg}aIY&zQV;iz>l3W0bTJ3URlKNhtb1<#s@F_y@)7*8U4FV{{Rr?;#o6?N!ZA&e zFN&Lk#f5*VWLnBV+qJurIK5z}UC-|R>vhfD@(ux| z1eng(zOy=i2N#yhmwdG-@zy=O7gM0drsx!JdvGm;XwI<=bvi|KPF1wVV4PMSlD3Bj!V(*d`eqq?b6?q_iC zJhPlI$0y^dLjA;_83*lV*%xOhDnuZOnBt-GW8jzNeO7F?FY8rRLVGS0{27^&vEa<@ zhQY=3{Ht+%;@vJ^{Q9i%nm9#@4MyIYXzno~sB_Uq^b9d2=sZZ; z#h!U;h=}`0U=#a>=zL{PiUUK`EtorlR0Q6b$L(JHOxesUuG00!@pPwC~E;hW6 zHL-7q$l~hVX)X>7F(jf%XRL{1L)61=lm9$x;;kW8^F1Rhs($eo_27&R0!WFa);(|A zFc1ddJwX10#&!r0DRw@F43tD$2T`OT(pEef8jQ3<9is>e^xs!egVsKsNm}$|81RF; z<1Z2&JoEn$h}3Hyhr3hHJSG)Y4QOd4`-$bBOmec zfDCQ?39q_f(gcwSPEXDkTxwYR&66ZY>EV?UV8AbwB#G0bg=+nSPLeo1x`qbKR)8$0 zlB4t#Ebr^orh(EuPm;vxS;_ur8qI`9jc3S@^t7DSO8zC=LX}dr+DrUTw!7}|wjan_ zBv#xo(NA(&m~B?5`f@QQ#fs;!s@x5 z8u9j=)R;1DzceZF!BV3WB*jPT91Tk^7N2Z$bb<7SAOBOiDNU6 zzWYOyI5$U)yN{bDad3_spSD6VPR>!|Q>z?ZyhkVQ+##C8**Q7!X?uyolL^)a?j=so zKnCq)g3~jQL3^3t^spE1{lqy#;`B5sE5nv(cx|cscTk_vsvJ0&dA;?qXFan~`pq;@JTfVOL^7dd(F>gD z6%+vup#j+hXL<=emT{91TT-^?yRr6|FN4rk@o`SVj*Iqiti9Le?`k(FPW^?agfb2t zuYm?>|l0_;X!Zhr-YZ_d6hSe+wxcx(iBxeWtI9Jw=-Q$*i0N$Ny<+k&ud1|2X z5*0x&Z&Fn+d;%927k0uR#AbZeuu$gwP-`FO5AQx))h=!XbI`siGp<|MY#M^fpPrcO z26$uHhY>1-#Hc#hY#+|&-b{IHmornx)M;_y+&O9HJf45_x}M+@;^_NGQ@@^Hc%Ss%4m-8%P#O^2G?KUvs!witQ}TwhVN)rX48@A&2GN>cqu-s%uA7~Z>@twt0qR^hW`M!L5KqaNQtG_ z-ENyO6ae7+NqYxhZc;0iByBfoo#cQ?tO7zC2j&!0?a2O6>{cAtVdg8q{%C=|zg5$ifu zJ%ghNQdzSRXW^P@(erb(C}XbPv{j2ZCNwTmm9{#Ej&@%PN$EQ%t%*V906e2SUEt^d)ZrQP6@%jzcwr7F9JCGigq$jYZa`h= zq5zq;E3@Dm(2m1bmeDvZXb~2yE=`-Qo?vS>oK=LZfpn=Hbh1^MuCKwv`JehdK+`f= zR(M{7Ns$l7DDf;U@QLA>Xyy>l4m=CHCh?JptdnzW=H{nyxn{F0EjM))#AN-HN~Y^0 zsR&7xm{TZG10gvQl6-|5Mo)yDtHSmv-*lou@f z@%v}}b+lzk(Y!J!q8T*Nu5D=8#}?uzn~NNuXB-ntDml3Bo=uxO5UENm3#l%WIf6x^ zawxi(|4Q^ggHrd8M%3TM(TAQ{n>Fts%Fp#P#9hy9rd`!+QDzyh2*_BTmf3=Vm~C0S zE9$|Rd^qAcDj%E}y{Qq7sT@zEA^AF=B4+^E%1lGfkwXHPJn}o`dE~g0)Cti7720P< zIXO*w^yFF-lDEg?KDa{Q{GSr&&d(;5n=W&Bm`ZE^c$Q8KerJYLqyKOao4b1x zD8heX5v2*p_+#+QJ2?v%FHKtz^n06sqtV8zi+B+`#U z=}9idw_o4S&wPilz+;HvV1%9moAfc%dn$mPBG5rKVMl)Q{XVgL zn>_~(o_0yioIikw^uom=oNd?g-ITGwbm<7$UtxAiOyYRR`BI#^m=_lSuWSA;5=dup zB4EeYTalihjcxRdY2aBd#epul7ch#5gL}1|jSbh+SW}Y<_ z+ww}}T@gtb9(lo_*0!uh-WQQ0)fq1s5?X^;jr?6i4qRK+QpXrDmz_8Vs<(PcKA)KW z_z~lAb7o0DhH1MVtARYiED31OWaz0?IXfi<8RmdYuyYD{lv$FHVNz^ig>APvJ0%U- z{-~>7PWSvcvm~ONS+7gg%#w;eGf#G@npu)j&aBs^YGz4CIkR4us?YbzYp7<2jxkF* z(g)oanI#=j?76AWr5g)i}vA zQ_iz=RYFlJd0sDow@|J$G>p=15=Kk4if1nVAWz?wBOG8QN;P~<5xoKtZ8w=^nC9+G zz#Ez2Jri&eTN+Bp;DoAT@O7N=OtJ;PGmcgdWw387*b26ly%y- zUm7Syv0poXI!;K4U+gD--XsW|pZkEm?B2?1A3Z*o@K)~jle>%W-yjE}i-^QfEHcK! zLS>5>MCQg2aC%jXmzTkP|4;M3VEIx7zhBGX&vySS(A9RcDJxlSwy*oLN}nG8mQ{11 z;TJhzGWZ7cG-;&WNB;&=nC8gagc3+YDg|q{9*&=5^c5 z8P$n=7-P=cCI^y3$7LesP1~$v?7DNz{LwZ+gau^+Vxk!xX5RkygP!fS`>#CgnP9pg zS`)hVoJw=kr?pI`Kigq8t^`FhKkIPstZrDJ`&IuN|LM-I5SNlJXCHTs;vZcNRFBAa zW|Y5iS1b%cj9ITS02)^TAGuy*2pn_hCgZL#2pX3rLTQ;%{XV-TJ{WM<7zQnuz7KES z-@Wy?OD32?k23Ds`v@ww|AJh*H0_}ujl9^AF}SY>gXjCn7a+j|_!BrTYR zc(7~lamwgA>mcJU^4wI=Wx2R}WA8Cf>ZhjvwYqWt0fvqZIRZ$DrPo1k+AtIc@cX2F z2dk&`P>Ga6!=VQ^als-a%yC-v6lKMLB}h<`(RH7GhIDH&FT*4pDu|jN?-~DXC*6v? zoUW2Lkw>X4$yTK0x1M$R^$U3^z&R_9*YLU zS1)$08;vBGk4#I1i|p#6gP+@pM>TTdaO07L#NMGeqOME)RyFny#gKSyYrNIFKFfqe zTdR>{PGXNvC~qnbs`R1##{#`B<;xPSlQ*|i?Xs$w5E(N;C)L)f11zhZI zJSYb{-y_P18*|KtAr`88Z)B+bxhYY)9HwBr&|rs@;Q=IA3j#Zh!P!)lTn4kldc z;1UoG2NM);^)T*5!@-0_>nJ(|GiPMjI3ym2u@cQ1hs17;Xx2C+YGI^dsMd=(U@l<| z$FT>B(}1cgr(H!Qj3$$y)oIMuPmC;>#*~vub5YC8lsey_FvO#`(&ACzeS4pGS5@I9_QHWff5?-?PCTZ~iT6fUh$`{QUR5zK5%o?Dg}<<0An6sRZxm z9DEklZ$Qi9aLCIfKNROGFW39G9DU@+>he`7Ci)5ViZEqs7$FuC=phfNzE;3J9Y6B2 z`bzPzcwWwWBqdpb>o@ghKfpn{VJRW_I?|dVG1*?3((aQfd_~H~7LZP#bhDI_h-Cru zllrp;X&UpHep{z*PW)&8H!tsUcj6H4P{Lr6kSz<5Pnk!y;vV9YjYuIX|d&0>X|LevtX(>aBxJwzjtrAR5J z2sP(iO8H~S5$ z*d`%re*0d|jzx9P-JIcovJ{1(#;L!u)WgIz{sOxjh}VeKtwM<&Y|TgECNT>rinJ43 z+^uTixRIOO7|CiPfw`O2g<(py6LU|N4vc&sxl&pJb5EBJ-2Ri>=|lO^m&XYDi#i zBVOPb)=#e6ZUwg$+r$*QFAA~{HVx++SHs9vfs z2c+Wc%SdOGoSb?I>CDH->3Nrt#uzz0=`wOLnsRc+Wu)0BRi|4XVZb zbohSqP5aOOUO?h_D#w_iwx1j1<=Lw)svupa6<-~k9)9AcTujL?g@exAnc-Rq-*W@Q z`GR0cM27+!-1!dIv$~<-%rduoWM6X^JvyRpJ5_h1d|T-nHeG4@5k2JvdMP#fomO*1 z%lef1jDsGRQjE%}oJ3?gCW3dm<4qZL_ieoq!J~fO8Sr8$lqZ!SoxK6@Zi5MBexLfz zf#(aZSc^MudPCr0DY17KJJ;FtF07twolWl&cp(YMS|y^3cLh9wnNLRUVAH#X>p?M- z|1Rqr?+5HZ6^5J<=M}c}^XX1QE7roZfiNLafPK{ugb|4u7A-s*2s2_DuhmqrfWw_8 z^vvX^p6kT6fG{Ny;jLaI77)fH#!=)Fk8ePj6Upz{7zgd&>RS*71v8J57E!T)Fewt7 zDc#~JS|&A2O2ld0FM5NWr0`%8auJOkO$)e_6f+B>7OxWv2$Ld6Ok?Rj!7Lz53X$do zPdaP{w;)VPh<)l!X&5Tz^h&mXm;ZZ@nR~Z%-ln> zx%aw=&0cBinIR_pE|YuXodGZ6_e7|uhc^Ho7Lwj#&v`~Py>nQf66Tg;{4;Rd%{9Ft ze115LF!h~hPSd*pUPxn)1c6y%uHsJKCGZrxV`gl-mS^#<;Cir$vt{?LKXQOZdR6F0 z^PhKigvxpTvY5T6r_oBEuP%A$x(WZ{>Vuxa$62~es^no|lAkPfk)YdDFJ|Ru^)K2# zq9X!GiKW)fZ`v>v0Py>y{SQ92he{>TeH=JE5<6IR;>V# zEYsEO=KfYA35e&9ol9g#Cn5A1R-7o165PiIq;nSK_Fj@>iYJYt?CPZ8jJ135-Z?2j zQXV!ZA9V7W6B1+DBFZm18R9EaZY00zB;zhH6;bI98q{46L(ufP#&phs2C>JE!ju+ z`gB44q3!%W>gdxYk8B@aPIvU_11=>GY^QhIWeLyc=}UniqK6bU7cn8&l}b({tm?7- zci7cm9guu~tvA18u|6-i5j&dbLM*XpBRZNGN7$ucdlWT^T}>=E1F-*?Cb6f90gYp7 zy)>A_2Tf#E!-O>S8;jMsHs+&plWtHv2Qkjyve~|P&cO1}$RnFo)&O>H{{hc-9c%~y z000yK002#SO=WI%E@otA4GIVV007+q0006wjg3^xZlf?1-ABqlSYAghjg;;KIE_`3 zRA8oEWaGh3YL%MEn2MR9|32nb3M7+Z0oJ|eoclDlw*bp1&KO^bm;)H%{Yuey?()O_ zAj;W8U>rjrT<;DZ+;f?kLn60+Mu05`wv zOzT8KfVXSpV-kR8OxDgCd#;bR05*~}suhOd&vXLJ6Q+C_Y4O3GL~5SvS#567xdt$Z zlsIWu&^S4EcGw`Byvm&5MQoSbFr8eFQZi2+xDD|+oqT?4LEvE*`BmvbEEreUO0Q9) zIM0IVS76=D@2#rCrLBf;g#1Cx41qQ4nQ2~|@2tK9OQB84EeCw}1)84%@!ODQ{W6e? ziM@NN>Of3rJISvV(!fTQ^o7e6an{IrY}K7t9=-jCe2crH-;BD`9gO&_wnu;R`0Tj* z;wyi-L8ZFkRHiSS%cDdYVtH@2#*q&CX)m2e*WW!g>Qw5-7gy)pq)fXu2wNUrsigQMd%l{SJ-|*3iB!a^Z05z%pO{I^ToyREoi>Dzlgyy zHOy&;l?}b5c43NMxB_y;Cc-?L0=4bYEl*ZRU8HHo{WYJ4CIUl_4 z7yKg>@SgBNd@HE>fPa)q^eyGYO;;LrX8!t{e~{MDaNgaGJj`kT)VDjLCf zGcdz>DA_WYymN1#vWQOU7or4Z8wW50Wt4CfhsEvvIh|0$rW1Z@HsQE7JGkogxQ z*=9Xlnj}Z;4AG*X4f5i|>WW|kmKjxNA`#Mi*OFvWvAsJK+MnE*M)1=~jQl$%z+lr<}+{n};j{W4xbF$(7pjLEpt^K>WN-Y5|MyipWTbH1TWyt42b*~*qrH<+vIZDM$cDj{5 zkjs9X>ebLa7FfkaDT?d~d+79X0Q>IA&9?N-jP_pwRRe`2mQaGdh5p8iF{& zc`F@%;??Ll!*pO?RVLrB zuBz><@8Y?=0a|UKMxAx0)1gm0QbHIT+s8&!+@*Zwj(Ui|oJnrW*T*Yh8GwT#0!Yoa zfpb9;j%1!JY6ou}{g^2QJgs-j1(1^vMss2-IQ1vPU7v#>%H|#SDJHK_lP0=6blY3p zCSy*M3(I%)IEa^OSM^*ofZHK;AuhTha|?HbNm&p2fKCDWw0Z4D4s~`;dDQhmgJ=$Z zXEuWbiKoM)+BB*Qu;6u7$m?+Qze^WaxRKk}fsdkLr`Q-dQL+uPGUS*Pq=PKeN&6Ww zHo$)x6)jBQ{tEcNUrkoWaT1r^wqw?aLpI52!eqo4OE`B2RNT|Zr&PFIQ*UEs0{*H? z5vR$tdc-6oTQ(Z8?HbtsvU@o5zfEo+zH1Dm#~#4@NZKHLdOWi$-_CcMj0TvmGBfHB zU7hhZA$?;gItW||$@G82w&|q#m4+6iev}RU-v%A0@%uEkHhnR5!+(e2)sT0Odv(p= zqnk?;^7cnj3QgETUo+(drYrzM!|logRRXhApa9=fF%8`Sx3=KG`>{ z%UoIcN?ci*(;%z6)E#U&hVf>SYbB!Bm@W;Hw`Ye*;F+3Gfw)R+(%~2(Ss#)-MrQn! zC6!&O4s|xn`VTM$+&AHeaK{-dhj2VW(th$1c+yNqc`ASd{4?Penstg2)V zbUPriw~U0{$vlm@4%w08n^yB18jvy&qt2@Aq=jLMR#OQAt7k|(qQeNv8o4$2`1dvF z%#QW4nW;?p6Rzs!87}P2i$=@E(cw(+uCtMPO`Vo`eB~ zyiHde<+e$TS5hn=V-pZRQwqGA%JfFZ?gd9D=h!gy!Bh4mp+6h`!|x8e_?PwZysgS7 zMvp26c5EosyvB7I-MZG+*2Oy%cVtVho(klE9flG?? zPg;MEQ$NJHR~qqamq;DIBc16P%z7p~{;Hcwo~>%wU>I!Q9eMbn?VTmqlqBN8qEpfb zWEyrnXT9e{0$k^|&ZhDT=0{LY|D64yR0s4MJm=t(OZW%nXZ-nmttvkOZ`I;5OU0JS zVN^19kjjM-BspTa6T!2}EWE6$8z!DQWjGFqCEMR#QAg1+YX}2T>CFs#JlJO!F;(Jy LAp12Bq+T0s>E`j} diff --git a/README.md b/README.md index eb23eb6..6778b25 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# War3 Lua - 1.1.5 (Ashenvale - Experimental) +# War3 Lua - 1.1.6 (Outland) [![build](https://github.com/Ev3nt/war3_lua/actions/workflows/build.yml/badge.svg)](https://github.com/Ev3nt/war3_lua/actions/workflows/build.yml) @@ -6,6 +6,8 @@ War3 Lua is a modification that allows you to run lua scripts at the JASS level. Some natives doesn't work (thx jass for beautiful VM). +Lua version: **5.4.4** + ![](https://github.com/Ev3nt/war3_lua/blob/master/war3_lua.png) --- @@ -23,5 +25,5 @@ Some natives doesn't work (thx jass for beautiful VM). ### Recommended build parameters * Configuration **Release** * Windows platform **x86** -* Platform **10.0.19041.0** +* Platform **10.0.19041.**0**** * Build tools **Visual Studio 2015 (v140)** diff --git a/Scripts/blizzard.lua b/Scripts/blizzard.lua index 212578b..797b5b6 100644 --- a/Scripts/blizzard.lua +++ b/Scripts/blizzard.lua @@ -9823,7 +9823,7 @@ function InitBlizzardGlobals() end bj_FORCE_ALL_PLAYERS = CreateForce() - ForceEnumPlayers(bj_FORCE_ALL_PLAYERS, 0) + ForceEnumPlayers(bj_FORCE_ALL_PLAYERS, nil) -- Init Cinematic Mode history bj_cineModePriorSpeed = GetGameSpeed() @@ -9897,17 +9897,17 @@ function InitSummonableCaps() -- upgraded units -- Note: Only do this if the corresponding upgrade is not yet researched -- Barrage - Siege Engines - if (not GetPlayerTechResearched(Player(index), 'Rhrt', true)) then - SetPlayerTechMaxAllowed(Player(index), 'hrtt', 0) + if (not GetPlayerTechResearched(Player(index), StringToId('Rhrt'), true)) then + SetPlayerTechMaxAllowed(Player(index), StringToId('hrtt'), 0) end -- Berserker Upgrade - Troll Berserkers - if (not GetPlayerTechResearched(Player(index), 'Robk', true)) then - SetPlayerTechMaxAllowed(Player(index), 'otbk', 0) + if (not GetPlayerTechResearched(Player(index), StringToId('Robk'), true)) then + SetPlayerTechMaxAllowed(Player(index), StringToId('otbk'), 0) end -- max skeletons per player - SetPlayerTechMaxAllowed(Player(index), 'uske', bj_MAX_SKELETONS) + SetPlayerTechMaxAllowed(Player(index), StringToId('uske'), bj_MAX_SKELETONS) index = index + 1 if index == bj_MAX_PLAYERS then break end @@ -10046,7 +10046,7 @@ function InitNeutralBuildings() -- Set up a trigger to fire whenever an item is sold. bj_stockItemPurchased = CreateTrigger() - TriggerRegisterPlayerUnitEvent(bj_stockItemPurchased, Player(PLAYER_NEUTRAL_PASSIVE), EVENT_PLAYER_UNIT_SELL_ITEM, 0) + TriggerRegisterPlayerUnitEvent(bj_stockItemPurchased, Player(PLAYER_NEUTRAL_PASSIVE), EVENT_PLAYER_UNIT_SELL_ITEM, nil) TriggerAddAction(bj_stockItemPurchased, RemovePurchasedItem) end -- =========================================================================== @@ -10218,37 +10218,6 @@ end -- -- *************************************************************************** --- function GetEffectPos(effect) --- return GetObjectPos(effect) --- end - --- function GetEffectX(effect) --- return GetObjectX(effect) --- end - --- function GetEffectY(effect) --- return GetObjectY(effect) --- end - --- function GetEffectZ(effect) --- return GetObjectZ(effect) --- end - --- function SetEffectPos(effect, x, y, z) --- SetObjectPos(effect, x, y, z) --- end - --- function SetEffectX(effect, x) --- SetObjectX(effect, x) --- end - --- function SetEffectY(effect, y) --- SetObjectY(effect, y) --- end --- function SetEffectZ(effect, z) --- SetObjectZ(effect, z) --- end - function _print(...) local string = "" diff --git a/Scripts/common.lua b/Scripts/common.lua index f0b6ec6..76666c0 100644 --- a/Scripts/common.lua +++ b/Scripts/common.lua @@ -1,6 +1,6 @@ FALSE = false TRUE = true -JASS_MAX_ARRAY_SIZE = 32768 +JASS_MAX_ARRAY_SIZE = 8192 PLAYER_NEUTRAL_PASSIVE = 15 PLAYER_NEUTRAL_AGGRESSIVE = 12 PLAYER_COLOR_RED = ConvertPlayerColor(0) diff --git a/Src Backup/.vscode/settings.json b/Src Backup/.vscode/settings.json deleted file mode 100644 index 6f26099..0000000 --- a/Src Backup/.vscode/settings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "files.associations": { - "map": "cpp", - "bit": "cpp", - "compare": "cpp", - "concepts": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "cwchar": "cpp", - "exception": "cpp", - "initializer_list": "cpp", - "limits": "cpp", - "new": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "vector": "cpp", - "xmemory": "cpp", - "xstddef": "cpp", - "xtr1common": "cpp", - "xtree": "cpp", - "xutility": "cpp" - } -} \ No newline at end of file diff --git a/Src Backup/FrameAPI.cpp b/Src Backup/FrameAPI.cpp deleted file mode 100644 index b99317b..0000000 --- a/Src Backup/FrameAPI.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "FrameAPI.h" -#include "Variables.h" -#include "fcalls.h" - -std::unordered_map> frameEventHashTable; - -UINT GetOriginFrame(EOriginFrame originframe, UINT index) { - CGameUI* gameui = GetGameUI(); - - switch (originframe) { - case ORIGIN_FRAME_GAME_UI: - return (UINT)gameui; - case ORIGIN_FRAME_WORLD_FRAME: - return (UINT)gameui->WorldFrameWar3; - case ORIGIN_FRAME_HERO_BAR: - return (UINT)gameui->HeroBar; - case ORIGIN_FRAME_HERO_BUTTON: - return (UINT)GetPanelButton((UINT)gameui->HeroBar, index, 0); - case ORIGIN_FRAME_HERO_HP_BAR: - return *(UINT*)((UINT)GetPanelButton((UINT)gameui->HeroBar, index, 0) + 0x1cc); - case ORIGIN_FRAME_HERO_MANA_BAR: - return *(UINT*)((UINT)GetPanelButton((UINT)gameui->HeroBar, index, 0) + 0x1d0); - case ORIGIN_FRAME_HERO_BUTTON_INDICATOR: - // Undefined - break; - case ORIGIN_FRAME_ITEM_BUTTON: - return *(UINT*)(*(UINT*)(*(UINT*)(gameui->InfoBar + 0x148) + 0x130) + 8 * index + 4); - case ORIGIN_FRAME_COMMAND_BUTTON: - return (UINT)GetPanelButton((UINT)gameui->CommandBar, index / 4, index % 4); - case ORIGIN_FRAME_SYSTEM_BUTTON: - // Undefined - break; - case ORIGIN_FRAME_PORTRAIT: - return (UINT)gameui->Portrait; - case ORIGIN_FRAME_MINIMAP: - return (UINT)gameui->Minimap; - case ORIGIN_FRAME_MINIMAP_BUTTON: - return (UINT)gameui->MinimapButtons[index]; - case ORIGIN_FRAME_TOOLTIP: - return GetTooltipFrame(); - case ORIGIN_FRAME_UBERTOOLTIP: - // Undefined - break; - case ORIGIN_FRAME_CHAT_MSG: - return (UINT)gameui->ChatMessage; - case ORIGIN_FRAME_UNIT_MSG: - return (UINT)gameui->UnitMessage; - case ORIGIN_FRAME_TOP_MSG: - return (UINT)gameui->TopMessage; - default: - break; - } - - return NULL; -} - -UINT GetPanelButton(UINT frame, BYTE row, BYTE column) { - return *(UINT*)(*(DWORD*)(16 * row + *((DWORD*)frame + 85) + 8) + 4 * column) - sizeof(CFrame); -} - -UINT GetTooltipFrame(UINT unknown0) { - return fastcall(MakePtr(gameBase, _getTooltipFrame), unknown0); -} - -BOOL LoadTOCFile(LPCSTR filename) { - DWORD stringHastTable = MakePtr(gameBase, _stringHastTable); - DWORD FDFHashTable = MakePtr(gameBase, _FDFHashTable); - - if (*(int*)(stringHastTable + 0x14) < 0xFFFF) { - thiscall(MakePtr(gameBase, _stringHashNodeGrowListArray), stringHastTable, 0xFFFF); - } - - if (*(int*)(FDFHashTable + 0x14) < 0xFFFF) { - thiscall(MakePtr(gameBase, _baseFrameHashNodeGrowListArray), FDFHashTable, 0xFFFF); - } - - return fastcall(MakePtr(gameBase, _readFDFFile), filename, stringHastTable, FDFHashTable, MakePtr(gameBase, _CFrameDefStatus)); -} - -UINT GetFrameByName(LPCSTR framename, UINT id) { - return fastcall(MakePtr(gameBase, _getCFrameByName), framename, id); -} - -UINT CreateFrame(LPCSTR baseframe, UINT parentframe, EFramePoint point, EFramePoint relativepoint, UINT id) { - return fastcall(MakePtr(gameBase, _createCFrame), baseframe, parentframe, point, relativepoint, id); -} - -void SetFrameText(UINT frame, LPCSTR text) { - thiscall(MakePtr(gameBase, _setCFrameText), *(UINT*)(FRAMELAYOUT(frame) + 0x130), text); -} - -void SetFrameTextColor(UINT frame, BYTE red, BYTE green, BYTE blue, BYTE alpha) { - DWORD color = ((alpha << 24) + (red << 16) + (green << 8) + blue); - thiscall(MakePtr(gameBase, _setCFrameTextColor), FRAMELAYOUT(frame), &color); -} - -float GetFrameTextHeight(UINT frame) { - return thiscall(MakePtr(gameBase, _getCFrameTextHeight), FRAMELAYOUT(frame)); -} - -void SetFrameWidth(UINT frame, float width) { - thiscall(MakePtr(gameBase, _setCLayoutFrameWidth), FRAMELAYOUT(frame), width); -} - -void SetFrameHeight(UINT frame, float height) { - thiscall(MakePtr(gameBase, _setCLayoutFrameHeight), FRAMELAYOUT(frame), height); -} - -void SetFrameSize(UINT frame, float width, float height) { - SetFrameWidth(frame, width); - SetFrameHeight(frame, height); -} - -void SetFrameScale(UINT frame, float scale) { - thiscall(MakePtr(gameBase, _setCLayoutFrameScale), FRAMELAYOUT(frame), scale); -} - -void SetFrameAbsolutePoint(UINT frame, EFramePoint point, float offsetX, float offsetY) { - thiscall(MakePtr(gameBase, _setCLayoutFrameAbsolutePoint), FRAMELAYOUT(frame), point, offsetX, offsetY, 1); -} - -void SetFramePoint(UINT frame, EFramePoint point, UINT parentframe, EFramePoint relativepoint, float offsetX, float offsetY) { - thiscall(MakePtr(gameBase, _setCLayoutFramePoint), FRAMELAYOUT(frame), point, FRAMELAYOUT(parentframe), relativepoint, offsetX, offsetY, 1); -} - -float GetFrameWidth(UINT frame) { - return *(float*)(FRAMELAYOUT(frame) + 0x58); -} - -float GetFrameHeight(UINT frame) { - return *(float*)(FRAMELAYOUT(frame) + 0x5c); -} - -UINT GetFramePoint(UINT frame, EFramePoint point) { - return *(UINT*)(FRAMELAYOUT(frame) + 4 * (UINT)point + 8); -} - -UINT GetFramePointParent(UINT frame, EFramePoint point) { - return *(UINT*)(GetFramePoint(frame, point) + 4); -} - -UINT GetFramePointRelativePoint(UINT frame, EFramePoint point) { - return *(UINT*)(GetFramePoint(frame, point) + 8); -} - -float GetFramePointX(UINT frame, EFramePoint point) { - return *(float*)(GetFramePoint(frame, point) + 12); -} - -float GetFramePointY(UINT frame, EFramePoint point) { - return *(float*)(GetFramePoint(frame, point) + 16); -} - -//--------------------------------------------------------------------------------------- - -void TriggerRegisterFrameEvent(UINT trigger, UINT frame, EFrameEvent event) { - frameEventHashTable[event][frame] = trigger; -} \ No newline at end of file diff --git a/Src Backup/FrameAPI.h b/Src Backup/FrameAPI.h deleted file mode 100644 index 49effa2..0000000 --- a/Src Backup/FrameAPI.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include "Warcraft.h" -#include "Mem.h" - -enum EFramePoint : UINT -{ - TopLeft = 0, - Top = 1, - TopRight = 2, - Left = 3, - Center = 4, - Right = 5, - BottomLeft = 6, - Bottom = 7, - BottomRight = 8 -}; - -enum EOriginFrame : UINT { - ORIGIN_FRAME_GAME_UI, - ORIGIN_FRAME_WORLD_FRAME, - ORIGIN_FRAME_HERO_BAR, - ORIGIN_FRAME_HERO_BUTTON, - ORIGIN_FRAME_HERO_HP_BAR, - ORIGIN_FRAME_HERO_MANA_BAR, - ORIGIN_FRAME_HERO_BUTTON_INDICATOR, - ORIGIN_FRAME_ITEM_BUTTON, - ORIGIN_FRAME_COMMAND_BUTTON, - ORIGIN_FRAME_SYSTEM_BUTTON, - ORIGIN_FRAME_PORTRAIT, - ORIGIN_FRAME_MINIMAP, - ORIGIN_FRAME_MINIMAP_BUTTON, - ORIGIN_FRAME_TOOLTIP, - ORIGIN_FRAME_UBERTOOLTIP, - ORIGIN_FRAME_CHAT_MSG, - ORIGIN_FRAME_UNIT_MSG, - ORIGIN_FRAME_TOP_MSG -}; - -enum EFrameEvent : UINT { - FRAMEEVENT_CONTROL_CLICK = 1, - FRAMEEVENT_MOUSE_ENTER, - FRAMEEVENT_MOUSE_LEAVE, - FRAMEEVENT_MOUSE_UP, - FRAMEEVENT_MOUSE_DOWN, - FRAMEEVENT_MOUSE_WHEEL, - FRAMEEVENT_CHECKBOX_CHECKED, - FRAMEEVENT_CHECKBOX_UNCHECKED, - FRAMEEVENT_EDITBOX_TEXT_CHANGED, - FRAMEEVENT_POPUPMENU_ITEM_CHANGED, - FRAMEEVENT_MOUSE_DOUBLECLICK, - FRAMEEVENT_SPRITE_ANIM_UPDATE, - FRAMEEVENT_SLIDER_VALUE_CHANGED, - FRAMEEVENT_DIALOG_CANCEL, - FRAMEEVENT_DIALOG_ACCEPT, - FRAMEEVENT_EDITBOX_ENTER -}; - -//DWORD eventType[16] = {MakePtr(gameBase, _frameevent_control_click), MakePtr(gameBase, _frameevent_control_mouseenter) }; - -UINT GetOriginFrame(EOriginFrame originframe, UINT index); - -UINT GetPanelButton(UINT frame, BYTE row, BYTE column); - -UINT GetTooltipFrame(UINT unknown0 = NULL); - -BOOL LoadTOCFile(LPCSTR filename); - -UINT GetFrameByName(LPCSTR framename, UINT id); - -UINT CreateFrame(LPCSTR baseframe, UINT parentframe, EFramePoint point, EFramePoint relativepoint, UINT id); - -void SetFrameText(UINT frame, LPCSTR text); - -void SetFrameTextColor(UINT frame, BYTE red, BYTE green, BYTE blue, BYTE alpha); - -float GetFrameTextHeight(UINT frame); - -void SetFrameWidth(UINT frame, float width); - -void SetFrameHeight(UINT frame, float height); - -void SetFrameSize(UINT frame, float width, float height); - -void SetFrameScale(UINT frame, float scale); - -void SetFrameAbsolutePoint(UINT frame, EFramePoint point, float offsetX, float offsetY); - -void SetFramePoint(UINT frame, EFramePoint point, UINT parentframe, EFramePoint relativepoint, float offsetX, float offsetY); - -float GetFrameWidth(UINT frame); - -float GetFrameHeight(UINT frame); - -UINT GetFramePointParent(UINT frame, EFramePoint point); - -UINT GetFramePointRelativePoint(UINT frame, EFramePoint point); - -float GetFramePointX(UINT frame, EFramePoint point); - -float GetFramePointY(UINT frame, EFramePoint point); - -//--------------------------------------------------------------------------------------- - -void TriggerRegisterFrameEvent(UINT trigger, UINT frame, EFrameEvent event); \ No newline at end of file diff --git a/Src Backup/Hooks.cpp b/Src Backup/Hooks.cpp deleted file mode 100644 index da1cfa1..0000000 --- a/Src Backup/Hooks.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "Hooks.h" - -#include "Variables.h" -#include "Mem.h" -#include "LuaMachine.h" -#include - -DWORD __fastcall jassEntryPoint(DWORD a) { - return (fastcall(MakePtr(gameBase, _jassEntryPointProc), a), startLua()); -} - -DWORD __stdcall getWarcraftID() -{ - return *(DWORD*)GAME_ID; -} - -BOOL __fastcall isFrameValid(UINT frame, UINT, UINT eventcode) { - for (const auto& event : frameEventHashTable) { - for (const auto& eventframe : event.second) { - if (eventframe.first == frame) { - // our code - - return TRUE; - } - } - } - - if (!*(DWORD*)(frame + 8)) { - return FALSE; - } - - return thiscall(MakePtr(gameBase, 0x62a1c0), *(DWORD*)(frame + 8), eventcode, 0); -} - -BOOL __fastcall frameEventObserver(UINT frame, UINT, DWORD eventaddress) { - if (frameEventHashTable[(EFrameEvent)(*(DWORD*)(eventaddress + 8) - 0x40090063)].find(frame) != frameEventHashTable[(EFrameEvent)(*(DWORD*)(eventaddress + 8) - 0x40090063)].end()) { - if (!running) { - return FALSE; - } - - lua_State* l = getMainLuaState(); - getFunctionByRef(l, frameEventHashTable[(EFrameEvent)(*(DWORD*)(eventaddress + 8) - 0x40090063)][frame]); - lua_State* thread = createThread(l, -1); - lua_xmove(l, thread, 1); - - int res; - switch (lua_resume(thread, l, 0, &res)) { - case LUA_ERRRUN: - lua_throwerr(thread); - - break; - } - - return TRUE; - } - - return thiscall(*(DWORD*)(*(DWORD*)frame + 0x14), frame, *(DWORD*)(eventaddress + 8), eventaddress); -} \ No newline at end of file diff --git a/Src Backup/Hooks.h b/Src Backup/Hooks.h deleted file mode 100644 index 19103cf..0000000 --- a/Src Backup/Hooks.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -DWORD __fastcall jassEntryPoint(DWORD a); - -DWORD __stdcall getWarcraftID(); - -BOOL __fastcall isFrameValid(UINT frame, UINT, UINT eventcode); - -BOOL __fastcall frameEventObserver(UINT frame, UINT, DWORD eventaddress); \ No newline at end of file diff --git a/Src Backup/JassMachine.cpp b/Src Backup/JassMachine.cpp deleted file mode 100644 index 0b11610..0000000 --- a/Src Backup/JassMachine.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "JassMachine.h" - -#include "Variables.h" -#include "Mem.h" -#include "LuaMachine.h" - -DWORD OPCODES_FUNCTIONS[44]; - -DWORD _declspec(naked) jassOpcodeStartLuaThread() { - _asm { - push edi - push esi - call startLuaThread - - sub esp, 8 - mov[esp], eax - add esp, 8 - mov eax, gameBase - add eax, 0x45f79a - push eax - sub esp, 4 - pop eax - - ret - } -} -// game.dll + 45969d -void jassOpcodeInitialize() { - DWORD overflow = MakePtr(gameBase, _overflowOpcodeProc); - memcpy(OPCODES_FUNCTIONS, (LPVOID)MakePtr(gameBase, _opcodeList), sizeof(OPCODES_FUNCTIONS)); - OPCODES_FUNCTIONS[42] = overflow; - OPCODES_FUNCTIONS[43] = (DWORD)jassOpcodeStartLuaThread; // My own opcode function - - DWORD dwOldProtect; - DWORD address = MakePtr(gameBase, _opcodeListSize); - VirtualProtect((LPVOID)address, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect); - *(BYTE*)address = sizeof(OPCODES_FUNCTIONS) / 4 - 1; - VirtualProtect((LPVOID)address, 1, dwOldProtect, &dwOldProtect); - - address = MakePtr(gameBase, _opcodeSwitch); - VirtualProtect((LPVOID)address, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); - *(DWORD*)address = (DWORD)OPCODES_FUNCTIONS; - VirtualProtect((LPVOID)address, 4, dwOldProtect, &dwOldProtect); -} \ No newline at end of file diff --git a/Src Backup/JassMachine.h b/Src Backup/JassMachine.h deleted file mode 100644 index 0d2a12b..0000000 --- a/Src Backup/JassMachine.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once - -#include -#include - -#include "Warcraft.h" - -enum OPCODES { - OPTYPE_MINLIMIT = 0x00, - OPTYPE_ENDPROGRAM = 0x01, - OPTYPE_OLDJUMP = 0x02, - OPTYPE_FUNCTION = 0x03, - OPTYPE_ENDFUNCTION = 0x04, - OPTYPE_LOCAL = 0x05, - OPTYPE_GLOBAL = 0x06, - OPTYPE_CONSTANT = 0x07, - OPTYPE_FUNCARG = 0x08, - OPTYPE_EXTENDS = 0x09, - OPTYPE_TYPE = 0x0A, - OPTYPE_POPN = 0x0B, - OPTYPE_MOVRLITERAL = 0x0C, - OPTYPE_MOVRR = 0x0D, - OPTYPE_MOVRV = 0x0E, - OPTYPE_MOVRCODE = 0x0F, - OPTYPE_MOVRA = 0x10, - OPTYPE_MOVVR = 0x11, - OPTYPE_MOVAR = 0x12, - OPTYPE_PUSH = 0x13, - OPTYPE_POP = 0x14, - OPTYPE_CALLNATIVE = 0x15, - OPTYPE_CALLJASS = 0x16, - OPTYPE_I2R = 0x17, - OPTYPE_AND = 0x18, - OPTYPE_OR = 0x19, - OPTYPE_EQUAL = 0x1A, - OPTYPE_NOTEQUAL = 0x1B, - OPTYPE_LESSEREQUAL = 0x1C, - OPTYPE_GREATEREQUAL = 0x1D, - OPTYPE_LESSER = 0x1E, - OPTYPE_GREATER = 0x1F, - OPTYPE_ADD = 0x20, - OPTYPE_SUB = 0x21, - OPTYPE_MUL = 0x22, - OPTYPE_DIV = 0x23, - OPTYPE_MOD = 0x24, - OPTYPE_NEGATE = 0x25, - OPTYPE_NOT = 0x26, - OPTYPE_RETURN = 0x27, - OPTYPE_LABEL = 0x28, - OPTYPE_JUMPIFTRUE = 0x29, - OPTYPE_JUMPIFFALSE = 0x2A, - OPTYPE_JUMP = 0x2B, - OPTYPE_MAXLIMIT = 0x2C, - OPTYPE_STARTLUATHREAD = 0x2D -}; - -enum OPCODE_VARIABLE_TYPE { - OPCODE_VARIABLE_NOTHING = 0, - OPCODE_VARIABLE_UNKNOWN, - OPCODE_VARIABLE_NULL, - OPCODE_VARIABLE_CODE, - OPCODE_VARIABLE_INTEGER, - OPCODE_VARIABLE_REAL, - OPCODE_VARIABLE_STRING, - OPCODE_VARIABLE_HANDLE, - OPCODE_VARIABLE_BOOLEAN, - OPCODE_VARIABLE_INTEGER_ARRAY, - OPCODE_VARIABLE_REAL_ARRAY, - OPCODE_VARIABLE_STRING_ARRAY, - OPCODE_VARIABLE_HANDLE_ARRAY, - OPCODE_VARIABLE_BOOLEAN_ARRAY -}; - -#ifndef _JassMachine_h -#define _JassMachine_h -typedef struct { - DWORD unk; - DWORD zero1; - DWORD zero2; - DWORD zero3; - DWORD zero4; - DWORD zero5; - DWORD type1; - DWORD type2; - DWORD value; - DWORD zero6; - - void set(DWORD value, OPCODE_VARIABLE_TYPE type) { - this->value = value; - type1 = type; - type2 = type; - } - -} JASS_DATA_SLOT, * PJASS_DATA_SLOT; - -typedef struct { -private: - DWORD unk1; - DWORD unk2; - size_t stack_top; // Idk why it's here - PJASS_DATA_SLOT stack[32]; - size_t size; -public: - PJASS_DATA_SLOT pop() { - return stack[--size]; - } - - PJASS_DATA_SLOT& operator[](size_t index) { - return stack[index]; - } - - void clear(size_t number) { - size = number < size ? size - number : 0; - } - - size_t Size() { - return size; - } -} JASS_STACK, * PJASS_STACK; - -typedef struct { -private: - std::vector oplist; -public: - void addop(BYTE opcode, BYTE reg = 0, DWORD value = NULL, BYTE type = OPCODE_VARIABLE_NOTHING, BYTE rettype = OPCODE_VARIABLE_NOTHING) { - JASS_OPCODE* _opcode = new JASS_OPCODE; - _opcode->rettype = rettype; - _opcode->type = type; - _opcode->reg = reg; - _opcode->opcode = opcode; - _opcode->value = value; - - oplist.push_back(*_opcode); - } - - DWORD getcode() { - //return (DWORD)oplist.data(); - //printf("%08X\n", getJassMachine()); - - return ((DWORD)&oplist - (DWORD)getJassMachine()->code_table->codes) / 4; - } - -} JASS_OPLIST, * PJASS_OPLIST; -#endif - -//--------------------------------------------------------- - -void jassOpcodeInitialize(); \ No newline at end of file diff --git a/Src Backup/JassNatives.cpp b/Src Backup/JassNatives.cpp deleted file mode 100644 index 95aee39..0000000 --- a/Src Backup/JassNatives.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "JassNatives.h" - -#include "Variables.h" -#include "Mem.h" -#include "JassMachine.h" - -std::map jassnatives; -std::map triggers; - -DWORD to_Code(lua_State* l, int index) { - DWORD key = (DWORD)lua_topointer(l, index); - - auto it = triggers.find(key); - - if (it != triggers.end()) { - return (DWORD)&it->second; - } - - JASS_OPLIST& oplist = triggers[key]; - - BYTE reg = 0xD8; - oplist.addop(OPTYPE_MOVRLITERAL, reg, pushFunctionRef(l, index), OPCODE_VARIABLE_INTEGER); - oplist.addop(OPTYPE_PUSH, reg); - oplist.addop(OPTYPE_MOVRLITERAL, reg, (DWORD)l, OPCODE_VARIABLE_INTEGER); - oplist.addop(OPTYPE_PUSH, reg); - oplist.addop(OPTYPE_STARTLUATHREAD); - oplist.addop(OPTYPE_MOVRR); - oplist.addop(OPTYPE_RETURN); - - return oplist.getcode(); -} - -//--------------------------------------------------------- - - -#pragma pack(push) -#pragma pack(1) -struct asm_opcode_5 { - BYTE opcode; - DWORD value; -}; -#pragma pack(pop) - -struct asm_register_native_function { -private: - asm_opcode_5 push; - asm_opcode_5 mov_edx; - asm_opcode_5 mov_ecx; - asm_opcode_5 call; -public: - bool verify() { - return ((push.opcode == 0x68) && (mov_edx.opcode == 0xBA) && (mov_ecx.opcode == 0xB9) && (call.opcode == 0xE8)); - } - - const char* get_params() { - return (const char*)(push.value); - } - - const char* get_name() { - return (const char*)(mov_edx.value); - } - - uintptr_t get_address() { - return (uintptr_t)(mov_ecx.value); - } -}; - -//--------------------------------------------------------- - -JASSNATIVE::JASSNATIVE(DWORD address, LPCSTR params) : _address(address) { - LPCSTR it = params++; - bool is_end = false; - - for (; *it; it++) { - if (*it == ')') { - is_end = true; - } - else if (isupper(*it)) { - if (is_end) { - _rettype = (JASS_TYPE)*it; - - break; - } - else { - _params.push_back((JASS_TYPE)*it); - } - } - } -} - -JASSNATIVE::JASSNATIVE() : _address(NULL), _rettype(TYPE_NONE) {} - -bool JASSNATIVE::is_valid() { - return _rettype != TYPE_NONE ? true : false; -} - -bool JASSNATIVE::is_sleep() { - return has_sleep; -} - -void JASSNATIVE::set_sleep(bool sleep) { - has_sleep = sleep; -} - -const std::vector& JASSNATIVE::get_params() { - return _params; -} - -const JASS_TYPE& JASSNATIVE::get_rettype() { - return _rettype; -} - -DWORD JASSNATIVE::get_address() { - return _address; -} - -DWORD JASSNATIVE::call(DWORD* params, int size) { - uintptr_t func_address = _address; - DWORD retval; - uintptr_t esp_ptr; - size_t params_size = size * sizeof DWORD; - - _asm { - sub esp, params_size - mov esp_ptr, esp - } - - memcpy((LPVOID)esp_ptr, params, params_size); - - _asm { - call[func_address] - mov esp, esp_ptr - add esp, params_size - mov retval, eax - } - - return retval; -} - -//--------------------------------------------------------- - -JASSNATIVE& get_native(LPCSTR lpName) { - for (auto& e : jassnatives) { - if (!strcmp(e.first, lpName)) { - return e.second; - } - } - - return *(JASSNATIVE*)NULL; -} - -void jassNativesInitialize() { - for (asm_register_native_function* ptr = (asm_register_native_function*)MakePtr(gameBase, _jassNativesList); ptr->verify(); ptr++) { - jassnatives[ptr->get_name()] = JASSNATIVE(ptr->get_address(), ptr->get_params()); - } -} \ No newline at end of file diff --git a/Src Backup/JassNatives.h b/Src Backup/JassNatives.h deleted file mode 100644 index 7d70df0..0000000 --- a/Src Backup/JassNatives.h +++ /dev/null @@ -1,189 +0,0 @@ -#pragma once - -#include -#include - -#include "LuaMachine.h" - -typedef void jNothing; -typedef UINT32 jBoolean; -typedef UINT32 jCode; -typedef UINT32 jHandle; -typedef INT32 jInteger; -typedef UINT32 jReal; -typedef UINT32 jString; -typedef UINT32 jTrigger; - -const jBoolean jTrue = 1; -const jBoolean jFalse = 0; -const jHandle jNull = 0; - -typedef DWORD HUNIT; -typedef DWORD HWIDGET; -typedef DWORD HLIGHTNING; -typedef DWORD HPLAYER; -typedef DWORD HEFFECT; -typedef DWORD HLOCATION; -typedef DWORD HEFFECTTYPE; -typedef DWORD HRECT; -typedef DWORD HWEATHEREFFECT; -typedef DWORD HCAMERAFIELD; -typedef DWORD HBOOLEXPR; -typedef DWORD HSOUND; -typedef DWORD HCAMERASETUP; -typedef DWORD HITEMTYPE; -typedef DWORD HCONDITIONFUNC; -typedef DWORD HAIDIFFICULTY; -typedef DWORD HALLIANCETYPE; -typedef DWORD HATTACKTYPE; -typedef DWORD HBLENDMODE; -typedef DWORD HDAMAGETYPE; -typedef DWORD HDIALOGEVENT; -typedef DWORD HFGAMESTATE; -typedef DWORD HFOGSTATE; -typedef DWORD HGAMEDIFFICULTY; -typedef DWORD HGAMEEVENT; -typedef DWORD HGAMESPEED; -typedef DWORD HGAMETYPE; -typedef DWORD HIGAMESTATE; -typedef DWORD HLIMITOP; -typedef DWORD HMAPCONTROL; -typedef DWORD HMAPDENSITY; -typedef DWORD HMAPFLAG; -typedef DWORD HMAPSETTING; -typedef DWORD HMAPVISIBILITY; -typedef DWORD HPATHINGTYPE; -typedef DWORD HPLACEMENT; -typedef DWORD HPLAYERCOLOR; -typedef DWORD HPLAYEREVENT; -typedef DWORD HPLAYERGAMERESULT; -typedef DWORD HPLAYERSCORE; -typedef DWORD HPLAYERSLOTSTATE; -typedef DWORD HPLAYERSTATE; -typedef DWORD HPLAYERUNITEVENT; -typedef DWORD HRACE; -typedef DWORD HRACEPREFERENCE; -typedef DWORD HRARITYCONTROL; -typedef DWORD HSOUNDTYPE; -typedef DWORD HSTARTLOCPRIO; -typedef DWORD HTEXMAPFLAGS; -typedef DWORD HUNITEVENT; -typedef DWORD HUNITSTATE; -typedef DWORD HUNITTYPE; -typedef DWORD HVERSION; -typedef DWORD HVOLUMEGROUP; -typedef DWORD HWEAPONTYPE; -typedef DWORD HWIDGETEVENT; -typedef DWORD HDESTRUCTABLE; -typedef DWORD HDEFEATCONDITION; -typedef DWORD HFOGMODIFIER; -typedef DWORD HFORCE; -typedef DWORD HGROUP; -typedef DWORD HIMAGE; -typedef DWORD HITEM; -typedef DWORD HITEMPOOL; -typedef DWORD HLEADERBOARD; -typedef DWORD HMULTIBOARD; -typedef DWORD HQUEST; -typedef DWORD HREGION; -typedef DWORD HTEXTTAG; -typedef DWORD HTIMER; -typedef DWORD HTIMERDIALOG; -typedef DWORD HTRACKABLE; -typedef DWORD HUBERSPLAT; -typedef DWORD HUNITPOOL; -typedef DWORD HFILTERFUNC; -typedef DWORD HDIALOG; -typedef DWORD HBUTTON; -typedef DWORD HHASHTABLE; -typedef DWORD HGAMECACHE; -typedef DWORD HGAMESTATE; -typedef DWORD HHANDLE; -typedef DWORD HABILITY; -typedef DWORD HEVENTID; -typedef DWORD HQUESTITEM; -typedef DWORD HMULTIBOARDITEM; -typedef DWORD HTRIGGERACTION; -typedef DWORD HTRIGGERCONDITION; -typedef DWORD HEVENT; -typedef DWORD HAGENT; -typedef DWORD HTERRAINDEFORMATION; - -enum JASS_TYPE { - TYPE_NONE = 0, - TYPE_BOOLEAN = 'B', - TYPE_CODE = 'C', - TYPE_HANDLE = 'H', - TYPE_INTEGER = 'I', - TYPE_REAL = 'R', - TYPE_STRING = 'S', - TYPE_NOTHING = 'V', -}; - -inline jReal to_jReal(float fX) { - return *(jReal*)&fX; -} - -inline float from_jReal(jReal val) { - return *(float*)&val; -} - -inline jString to_jString(LPCSTR lpString) { - UINT32* string = new UINT32[8]; - - string[2] = (UINT32)&string[0]; - string[7] = (UINT32)&lpString[0]; - - return (jString)string; -} - -inline LPCSTR from_jString(jString string) { - if (!string) { - return NULL; - } - - string = ((jString*)string)[2]; - - if (!string) { - return NULL; - } - - return (LPCSTR)((jString*)string)[7]; -} - -DWORD to_Code(lua_State* l, int index); - -inline jInteger to_ID(LPCSTR lpID) { - return (lpID[0] << 24) + (lpID[1] << 16) + (lpID[2] << 8) + lpID[3]; -} - -//--------------------------------------------------------- - -#ifndef _JassNatives_h -#define _JassNatives_h -class JASSNATIVE { -public: - JASSNATIVE(DWORD address, LPCSTR params); - JASSNATIVE(); - - bool is_valid(); - bool is_sleep(); - void set_sleep(bool sleep); - const std::vector& get_params(); - const JASS_TYPE& get_rettype(); - DWORD get_address(); - - DWORD call(DWORD* params, int size); -private: - DWORD _address; - std::vector _params; - JASS_TYPE _rettype; - bool has_sleep = false; -}; -#endif - -//--------------------------------------------------------- - -JASSNATIVE& get_native(LPCSTR lpName); - -void jassNativesInitialize(); \ No newline at end of file diff --git a/Src Backup/LuaMachine.cpp b/Src Backup/LuaMachine.cpp deleted file mode 100644 index bccce79..0000000 --- a/Src Backup/LuaMachine.cpp +++ /dev/null @@ -1,438 +0,0 @@ -#include "LuaMachine.h" - -#include -#include -#pragma comment(lib, "storm.lib") - -#include "Variables.h" -#include "LuaRegister.h" -#include "Warcraft.h" -#include "Mem.h" - -lua_State* mainLuaState = NULL; -bool running = false; - - -//--------------------------------------------------------------------------------- -// Utils - -BOOL isInGameCatalog(LPCSTR fileName) { - char filepath[MAX_PATH] = { 0 }; - GetFullPathName(fileName, sizeof(filepath), filepath, NULL); - - char path[MAX_PATH] = { 0 }; - GetModuleFileName(GetModuleHandle(NULL), path, sizeof(path)); - for (int i = strlen(path); path[i] != '\\'; path[i] = NULL, i--); - - return !_strnicmp(filepath, path, strlen(path)) ? TRUE : FALSE; -} - -BOOL isAllowedExtension(LPCSTR fileName) { - char* fileextension = (char*)fileName + strlen(fileName); - - for (; fileextension[0] != '.'; fileextension--); - fileextension++; - - std::vector extensions = { "exe", "dll", "asi", "mix", "m3d", "mpq", "w3x", "w3m", "w3n" }; - for (const auto& extension : extensions) { - if (!_strnicmp(fileextension, extension, strlen(extension))) { - return FALSE; - } - } - - return TRUE; -} - -//--------------------------------------------------------------------------------- -// File stream only in catalog - -// Open -luaL_Stream* newprefile(lua_State* L) { - luaL_Stream* p = (luaL_Stream*)lua_newuserdatauv(L, sizeof(luaL_Stream), 0); - p->closef = NULL; - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; -} - -int io_fclose(lua_State* L) { - luaL_Stream* p = (luaL_Stream*)luaL_checkudata(L, 1, LUA_FILEHANDLE); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); -} - -luaL_Stream* newfile(lua_State* L) { - luaL_Stream* p = newprefile(L); - p->f = NULL; - p->closef = &io_fclose; - return p; -} - -int l_checkmode(const char* mode) { - return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && (*mode != '+' || ((void)(++mode), 1)) && (strspn(mode, "b") == strlen(mode))); -} - -int io_open(lua_State* L) { - const char* filename = luaL_checkstring(L, 1); - const char* mode = luaL_optstring(L, 2, "r"); - - if (!isInGameCatalog(filename) || !isAllowedExtension(filename)) { - return luaL_fileresult(L, FALSE, filename); - } - - luaL_Stream* p = newfile(L); - const char* md = mode; - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - fopen_s(&(p->f), filename, mode); - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - -// Remove -int os_remove(lua_State* L) { - const char* filename = luaL_checkstring(L, 1); - - if (!isInGameCatalog(filename) || !isAllowedExtension(filename)) { - return luaL_fileresult(L, FALSE, filename); - } - - return luaL_fileresult(L, remove(filename) == 0, filename); -} - -// Rename -int os_rename(lua_State* L) { - const char* fromname = luaL_checkstring(L, 1); - const char* toname = luaL_checkstring(L, 2); - - if (!isInGameCatalog(fromname) || !isAllowedExtension(fromname) || !isInGameCatalog(toname) || !isAllowedExtension(toname)) { - return luaL_fileresult(L, FALSE, NULL); - } - - return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); -} - -void lua_replaceFileStreamFunctions(lua_State* l) { - lua_getglobal(l, "io"); - lua_pushcfunction(l, io_open); - lua_setfield(l, -2, "open"); - - lua_pop(l, 1); - - lua_getglobal(l, "os"); - lua_pushcfunction(l, os_remove); - lua_setfield(l, -2, "remove"); - - lua_pushcfunction(l, os_rename); - lua_setfield(l, -2, "rename"); - - lua_pop(l, 1); -} - -//--------------------------------------------------------------------------------- -// Disabled functions - -void disable_functions(lua_State* l) { - lua_getglobal(l, "os"); - - std::vector functions = { "execute", "getenv", "setlocale", "tmpname" }; - - for (const auto& function : functions) { - lua_pushnil(l); - lua_setfield(l, -2, function); - } - - lua_pop(l, 1); - - lua_getglobal(l, "io"); - - functions = { "stdin", "stdout", "stderr", "flush", "input", "lines", "output", "popen", "tmpfile", "type" }; - - for (const auto& function : functions) { - lua_pushnil(l); - lua_setfield(l, -2, function); - } - - lua_pop(l, 1); - - lua_pushnil(l); - lua_setglobal(l, "dofile"); - -} - -//--------------------------------------------------------------------------------- -// Loader lua from mpq - - -// Lua -int checkload(lua_State* L, int stat, const char* filename) { - if (stat) { - lua_pushstring(L, filename); - return 2; - } - else { - return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); - } -} - -int searcher_Lua(lua_State* l) { - HANDLE map = *(HANDLE*)MakePtr(gameBase, _mapMPQ); - - std::string scriptName = luaL_checkstring(l, 1) + std::string(".lua"); - lua_pop(l, 1); - - char mapName[MAX_PATH] = { 0 }; - SFileGetArchiveName(map, mapName, sizeof(mapName)); - std::string scriptPath = mapName; - - for (size_t i = scriptPath.size(); i > 0; i--) { - if (scriptPath[i] == '\\') { - scriptPath = scriptPath.substr(i + 1); - - break; - } - } - - scriptPath = "(" + scriptPath + "):\\" + scriptName; - - HANDLE script; - if (SFileOpenFileEx(map, scriptName.c_str(), NULL, &script)) { - int lenght = SFileGetFileSize(script, NULL); - char* buffer = new char[lenght + 1]; - - ZeroMemory(buffer, lenght + 1); - - SFileReadFile(script, buffer, lenght, NULL, NULL); - SFileCloseFile(script); - - int result = checkload(l, (luaL_loadbuffer(l, buffer, strlen(buffer), ("@" + scriptPath).c_str()) == LUA_OK), scriptName.c_str()); - delete[] buffer; - - return result; - } - - lua_pushstring(l, std::string("no file '" + scriptPath + "'").c_str()); - - return 1; -} - -void lua_replaceSearchers(lua_State* l) { - std::vector searchers; - - lua_getglobal(l, "package"); - lua_getfield(l, -1, "searchers"); - - lua_rawgeti(l, -1, 1); - searchers.push_back(lua_tocfunction(l, -1)); - lua_pop(l, 2); - - searchers.push_back(searcher_Lua); - - lua_newtable(l); - - for (size_t i = 0; i < searchers.size(); i++) { - lua_pushvalue(l, -2); - lua_pushcclosure(l, searchers[i], 1); - lua_rawseti(l, -2, i + 1); - } - - lua_setfield(l, -2, "searchers"); - - lua_pop(l, 1); - searchers.clear(); -} - -//--------------------------------------------------------------------------------- - -lua_State* getMainLuaState() { - if (!mainLuaState) { - lua_State* l = mainLuaState = luaL_newstate(); - - luaL_openlibs(l); - disable_functions(l); - lua_open_jassnatives(l); - lua_open_warcraftfunctions(l); - lua_replaceSearchers(l); - lua_replaceFileStreamFunctions(l); - } - - return mainLuaState; -} - -lua_State* createThread(lua_State* l, int index) { - lua_pushvalue(l, index); - getGlobalTable(l, "_LUA_THREADS", false); - lua_pushvalue(l, -2); - - if (lua_rawget(l, -2) != LUA_TTHREAD) { - lua_pop(l, 1); - lua_newthread(l); - lua_pushvalue(l, -3); - lua_pushvalue(l, -2); - lua_rawset(l, -4); - } - - lua_State* thread = lua_tothread(l, -1); - lua_pop(l, 3); - - return thread; -} - -void clearScreen() { - HANDLE hStdOut; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD count; - DWORD cellCount; - COORD homeCoords = { 0, 0 }; - - hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - - if (hStdOut == INVALID_HANDLE_VALUE) { - return; - } - - if (!GetConsoleScreenBufferInfo(hStdOut, &csbi)) { - return; - } - - cellCount = csbi.dwSize.X * csbi.dwSize.Y; - - if (!FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count)) { - return; - } - - if (!FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count)) { - return; - } - - SetConsoleCursorPosition(hStdOut, homeCoords); -} - -void destroyMainLuaState() -{ - if (mainLuaState) { - lua_close(mainLuaState); - mainLuaState = NULL; - running = false; - triggers.clear(); - frameEventHashTable.clear(); - } - - clearScreen(); -} - -lua_State* getMainThread(lua_State* thread) { - lua_rawgeti(thread, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); - lua_State* l = lua_tothread(thread, -1); - lua_pop(thread, 1); - - return l; -} - -BOOL getGlobalTable(lua_State* l, LPCSTR name, bool weak) { - lua_getfield(l, LUA_REGISTRYINDEX, name); - - if (!lua_istable(l, -1)) { - lua_pop(l, 1); - lua_newtable(l); - - if (weak) { - lua_newtable(l); - lua_pushstring(l, "__mode"); - lua_pushstring(l, "kv"); - lua_rawset(l, -3); - - lua_setmetatable(l, -2); - } - - lua_pushvalue(l, -1); - lua_setfield(l, LUA_REGISTRYINDEX, name); - - return FALSE; - } - - return TRUE; -} - -int pushFunctionRef(lua_State* l, int index) { - lua_pushvalue(l, index); - getGlobalTable(l, "_LUA_FUNCTIONS_REF", false); - - int ref = (int)lua_rawlen(l, -1); - lua_pushvalue(l, -2); - lua_rawseti(l, -2, ++ref); - - lua_pop(l, 2); - - return ref; -} - -void getFunctionByRef(lua_State* l, int ref) { - getGlobalTable(l, "_LUA_FUNCTIONS_REF", false); - lua_rawgeti(l, -1, ref); - lua_remove(l, -2); -} - -void lua_throwerr(lua_State* l) { - running = false; - - LPCSTR error = lua_tostring(l, -1); - printf("--------------------Lua Error--------------------\n%s\n-------------------------------------------------\n\n", error); - MessageBox(FindWindow("Warcraft III", NULL), error, "Lua Error", MB_ICONHAND | MB_TOPMOST ); -} - -LUA stacktrace(lua_State* L) -{ - luaL_traceback(L, L, lua_tostring(L, -1), 0); - - return 1; -} - -DWORD startLua() { - destroyMainLuaState(); - - lua_State* l = getMainLuaState(); - - HANDLE war3luaScript; - - if (SFileOpenFileEx(*(HANDLE*)MakePtr(gameBase, _mapMPQ), "war3map.lua", NULL, &war3luaScript)) { - SFileCloseFile(war3luaScript); - - running = true; - - lua_pushcfunction(l, stacktrace); - lua_getglobal(l, "require"); - lua_pushstring(l, "war3map"); - if (lua_pcall(l, 1, LUA_MULTRET, -3) != LUA_OK) { - lua_throwerr(l); - } - - lua_pop(l, 1); - } - - return 0; -} - -BOOL __stdcall startLuaThread(DWORD esi, DWORD edi) { - if (!running) { - return FALSE; - } - - PJASS_STACK stack = (PJASS_STACK) * (DWORD*)(esi + 0x2868); - - lua_State* l = (lua_State*)stack->pop()->value; - getFunctionByRef(l, stack->pop()->value); - lua_State* thread = createThread(l, -1); - lua_xmove(l, thread, 1); - - int res; - switch (lua_resume(thread, l, 0, &res)) { - case LUA_OK: - ((PJASS_DATA_SLOT)(esi + 80))->set(lua_toboolean(thread, 1), OPCODE_VARIABLE_BOOLEAN); - - break; - case LUA_ERRRUN: - lua_throwerr(thread); - - break; - } - - return TRUE; -} \ No newline at end of file diff --git a/Src Backup/LuaMachine.h b/Src Backup/LuaMachine.h deleted file mode 100644 index 30eea9d..0000000 --- a/Src Backup/LuaMachine.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include -#pragma comment(lib, "lua.lib") - -typedef int LUA; - -lua_State* getMainLuaState(); - -void destroyMainLuaState(); - -lua_State* getMainThread(lua_State* thread); - -lua_State* createThread(lua_State* l, int index); - -void lua_throwerr(lua_State* l); - -BOOL getGlobalTable(lua_State* l, LPCSTR name, bool weak); - -int pushFunctionRef(lua_State* l, int index); - -void getFunctionByRef(lua_State* l, int ref); - -DWORD startLua(); - -BOOL CALLBACK startLuaThread(DWORD esi, DWORD edi); \ No newline at end of file diff --git a/Src Backup/LuaRegister.cpp b/Src Backup/LuaRegister.cpp deleted file mode 100644 index 328f332..0000000 --- a/Src Backup/LuaRegister.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include "LuaRegister.h" - -#include "WarcraftFunctions.h" -#include "Variables.h" -#include "Warcraft.h" -#include "JassNatives.h" -#include "FrameAPI.h" - -#define lua_registerJassNative(L, n, f) (lua_pushstring(L, (n)), lua_pushcclosure(L, (f), 1), lua_setglobal(L, (n))) -#define lua_setint(L, n, v) (lua_pushinteger(L, v), lua_setglobal(L, n)) - -LUA lua_jCall(lua_State* l) { - LPCSTR name = lua_tostring(l, lua_upvalueindex(1)); - JASSNATIVE native = get_native(name); - - if (!native.is_valid()) { - return 0; - } - - { - std::vector params = native.get_params(); - int size = params.size(); - if (size > lua_gettop(l)) { - return luaL_error(l, "function '%s' must have %d %s", name, size, size > 1 ? "arguments" : "argument"); - } - } - - int size = lua_gettop(l); - float* temp_params = new float[size]; - DWORD* params = new DWORD[size]; - ZeroMemory(temp_params, size); - ZeroMemory(params, size); - UINT i = 1; - - for (const auto& type : native.get_params()) { - switch (type) { - case TYPE_CODE: - if (lua_isinteger(l, i)) { - params[i - 1] = (DWORD)lua_tointeger(l, i); - } - else if (lua_isfunction(l, i)) { - params[i - 1] = to_Code(l, i); - } - - break; - case TYPE_BOOLEAN: - params[i - 1] = (DWORD)lua_toboolean(l, i); - - break; - case TYPE_HANDLE: - params[i - 1] = (DWORD)lua_tointeger(l, i); - - break; - case TYPE_INTEGER: - if (lua_isinteger(l, i)) { - params[i - 1] = (DWORD)lua_tointeger(l, i); - } - else { - params[i - 1] = to_ID(lua_tostring(l, i)); - } - - break; - case TYPE_REAL: { - temp_params[i - 1] = (float)lua_tonumber(l, i); - params[i - 1] = (DWORD)&(temp_params[i - 1]); - - break; - } - case TYPE_STRING: - params[i - 1] = to_jString(lua_tostring(l, i)); - - break; - default: - params[i - 1] = NULL; - - break; - } - - i++; - } - - DWORD result = native.call(params, size); - delete[] temp_params; - delete[] params; - - switch (native.get_rettype()) { - case TYPE_BOOLEAN: - lua_pushboolean(l, result); - - break; - - case TYPE_CODE: - case TYPE_HANDLE: - case TYPE_INTEGER: - lua_pushinteger(l, result); - - break; - case TYPE_REAL: - lua_pushnumber(l, from_jReal(result)); - - break; - case TYPE_STRING: - lua_pushstring(l, from_jString(getJassMachine()->string_table->get(result))); - - break; - } - - return native.get_rettype() != TYPE_NOTHING ? 1 : 0; -} - -//------------------------------------------------------------- - -LUA lua_GetMouseWorldPos(lua_State* l) { - PVECTOR3 mousePos = GetMouseWorldPos(); - - lua_pushnumber(l, mousePos->_x); - lua_pushnumber(l, mousePos->_y); - lua_pushnumber(l, mousePos->_z); - - return 3; -} - -LUA lua_GetMouseWorldX(lua_State* l) { - lua_pushnumber(l, GetMouseWorldX()); - - return 1; -} - -LUA lua_GetMouseWorldY(lua_State* l) { - lua_pushnumber(l, GetMouseWorldY()); - - return 1; -} - -LUA lua_GetMouseWorldZ(lua_State* l) { - lua_pushnumber(l, GetMouseWorldZ()); - - return 1; -} - -LUA lua_GetObjectPos(lua_State* l) { - PVECTOR3 objectPos = GetObjectPos(ConvertHandleToObject((UINT)lua_tointeger(l, 1))); - - lua_pushnumber(l, objectPos->_x); - lua_pushnumber(l, objectPos->_y); - lua_pushnumber(l, objectPos->_z); - - return 3; -} - -LUA lua_GetObjectX(lua_State* l) { - lua_pushnumber(l, GetObjectPos(ConvertHandleToObject((UINT)lua_tointeger(l, 1)))->_x); - - return 1; -} - -LUA lua_GetObjectY(lua_State* l) { - lua_pushnumber(l, GetObjectPos(ConvertHandleToObject((UINT)lua_tointeger(l, 1)))->_y); - - return 1; -} - -LUA lua_GetObjectZ(lua_State* l) { - lua_pushnumber(l, GetObjectPos(ConvertHandleToObject((UINT)lua_tointeger(l, 1)))->_z); - - return 1; -} - -LUA lua_SetObjectPos(lua_State* l) { - UINT_PTR object = ConvertHandleToObject((UINT)lua_tointeger(l, 1)); - - switch (lua_gettop(l)) - { - case 2: - SetObjectX(object, (float)lua_tonumber(l, 2)); - - break; - case 3: - SetObjectX(object, (float)lua_tonumber(l, 2)); - SetObjectY(object, (float)lua_tonumber(l, 3)); - - break; - case 4: - SetObjectPos(object, VECTOR3((float)lua_tonumber(l, 2), (float)lua_tonumber(l, 3), (float)lua_tonumber(l, 4))); - - break; - } - - return 0; -} - -LUA lua_SetObjectX(lua_State* l) { - SetObjectX(ConvertHandleToObject((UINT)lua_tointeger(l, 1)), (float)lua_tonumber(l, 2)); - - return 0; -} - -LUA lua_SetObjectY(lua_State* l) { - SetObjectY(ConvertHandleToObject((UINT)lua_tointeger(l, 1)), (float)lua_tonumber(l, 2)); - - return 0; -} - -LUA lua_SetObjectZ(lua_State* l) { - SetObjectZ(ConvertHandleToObject((UINT)lua_tointeger(l, 1)), (float)lua_tonumber(l, 2)); - - return 0; -} - -LUA lua_ConvertHandleToObject(lua_State* l) { - lua_pushinteger(l, ConvertHandleToObject((UINT)lua_tointeger(l, 1))); - - return 1; -} - -//------------------------------------------------------------- - -LUA lua_GetOriginFrame(lua_State* l) { - lua_pushinteger(l, GetOriginFrame((EOriginFrame)lua_tointeger(l, 1), (UINT)lua_tointeger(l, 2))); - - return 1; -} - -LUA lua_LoadTOCFile(lua_State* l) { - lua_pushinteger(l, LoadTOCFile(lua_tostring(l, 1))); - - return 1; -} - -LUA lua_GetFrameByName(lua_State* l) { - lua_pushinteger(l, GetFrameByName(lua_tostring(l, 1), (UINT)lua_tointeger(l, 2))); - - return 1; -} - -LUA lua_TriggerRegisterFrameEvent(lua_State* l) { - TriggerRegisterFrameEvent(pushFunctionRef(l, 1), (UINT)lua_tointeger(l, 2), (EFrameEvent)lua_tointeger(l, 3)); - - return 0; -} - -LUA lua_CreateFrame(lua_State* l) { - getGlobalTable(l, "_LUA_FRAMES", false); - lua_pushinteger(l, CreateFrame(lua_tostring(l, 1), (UINT)lua_tointeger(l, 2), (EFramePoint)lua_tointeger(l, 3), (EFramePoint)lua_tointeger(l, 4), (UINT)lua_tointeger(l, 5))); - - return 1; -} - -LUA lua_SetFrameText(lua_State* l) { - SetFrameText((UINT)lua_tointeger(l, 1), lua_tostring(l, 2)); - - return 0; -} - -LUA lua_SetFrameTextColor(lua_State* l) { - SetFrameTextColor((UINT)lua_tointeger(l, 1), (BYTE)lua_tointeger(l, 2), (BYTE)lua_tointeger(l, 3), (BYTE)lua_tointeger(l, 4), (BYTE)lua_tointeger(l, 5)); - - return 0; -} - -LUA lua_GetFrameTextHeight(lua_State* l) { - lua_pushnumber(l, GetFrameTextHeight((UINT)lua_tointeger(l, 1))); - - return 1; -} - -LUA lua_SetFrameWidth(lua_State* l) { - SetFrameWidth((UINT)lua_tointeger(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -LUA lua_SetFrameHeight(lua_State* l) { - SetFrameHeight((UINT)lua_tointeger(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -LUA lua_SetFrameSize(lua_State* l) { - SetFrameSize((UINT)lua_tointeger(l, 1), (float)lua_tonumber(l, 2), (float)lua_tonumber(l, 3)); - - return 0; -} - -LUA lua_SetFrameScale(lua_State* l) { - SetFrameScale((UINT)lua_tointeger(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -LUA lua_SetFrameAbsolutePoint(lua_State* l) { - SetFrameAbsolutePoint((UINT)lua_tointeger(l, 1), (EFramePoint)lua_tointeger(l, 2), (float)lua_tonumber(l, 3), (float)lua_tonumber(l, 4)); - - return 0; -} - -LUA lua_SetFramePoint(lua_State* l) { - SetFramePoint((UINT)lua_tointeger(l, 1), (EFramePoint)lua_tointeger(l, 2), (UINT)lua_tointeger(l, 3), (EFramePoint)lua_tointeger(l, 4), (float)lua_tonumber(l, 5), (float)lua_tonumber(l, 6)); - - return 0; -} - -LUA lua_GetFrameWidth(lua_State* l) { - lua_pushnumber(l, GetFrameWidth((UINT)lua_tointeger(l, 1))); - - return 1; -} - -LUA lua_GetFrameHeight(lua_State* l) { - lua_pushnumber(l, GetFrameHeight((UINT)lua_tointeger(l, 1))); - - return 1; -} - -LUA lua_GetFramePointParent(lua_State* l) { - lua_pushinteger(l, GetFramePointParent((UINT)lua_tointeger(l, 1), (EFramePoint)lua_tointeger(l, 2))); - - return 1; -} - -LUA lua_GetFramePointRelativePoint(lua_State* l) { - lua_pushinteger(l, GetFramePointRelativePoint((UINT)lua_tointeger(l, 1), (EFramePoint)lua_tointeger(l, 2))); - - return 1; -} - -LUA lua_GetFramePointX(lua_State* l) { - lua_pushnumber(l, GetFramePointX((UINT)lua_tointeger(l, 1), (EFramePoint)lua_tointeger(l, 2))); - - return 1; -} - -LUA lua_GetFramePointY(lua_State* l) { - lua_pushnumber(l, GetFramePointY((UINT)lua_tointeger(l, 1), (EFramePoint)lua_tointeger(l, 2))); - - return 1; -} - -//------------------------------------------------------------- - -void lua_open_jassnatives(lua_State* l) { - for (const auto& native : jassnatives) { - lua_registerJassNative(l, native.first, lua_jCall); - } -} - -void lua_open_warcraftfunctions(lua_State* l) { - lua_register(l, "TriggerRegisterFrameEvent", lua_TriggerRegisterFrameEvent); - - lua_register(l, "GetMouseWorldPos", lua_GetMouseWorldPos); - lua_register(l, "GetMouseWorldX", lua_GetMouseWorldX); - lua_register(l, "GetMouseWorldY", lua_GetMouseWorldY); - lua_register(l, "GetMouseWorldZ", lua_GetMouseWorldZ); - - lua_register(l, "GetObjectPos", lua_GetObjectPos); - lua_register(l, "GetObjectX", lua_GetObjectX); - lua_register(l, "GetObjectY", lua_GetObjectY); - lua_register(l, "GetObjectZ", lua_GetObjectZ); - - lua_register(l, "SetObjectPos", lua_SetObjectPos); - lua_register(l, "SetObjectX", lua_SetObjectX); - lua_register(l, "SetObjectY", lua_SetObjectY); - lua_register(l, "SetObjectZ", lua_SetObjectZ); - - lua_register(l, "ConvertHandleToObject", lua_ConvertHandleToObject); - - lua_setint(l, "ORIGIN_FRAME_GAME_UI", ORIGIN_FRAME_GAME_UI); - lua_setint(l, "ORIGIN_FRAME_WORLD_FRAME", ORIGIN_FRAME_WORLD_FRAME); - lua_setint(l, "ORIGIN_FRAME_HERO_BAR", ORIGIN_FRAME_HERO_BAR); - lua_setint(l, "ORIGIN_FRAME_HERO_BUTTON", ORIGIN_FRAME_HERO_BUTTON); - lua_setint(l, "ORIGIN_FRAME_HERO_HP_BAR", ORIGIN_FRAME_HERO_HP_BAR); - lua_setint(l, "ORIGIN_FRAME_HERO_MANA_BAR", ORIGIN_FRAME_HERO_MANA_BAR); - lua_setint(l, "ORIGIN_FRAME_HERO_BUTTON_INDICATOR", ORIGIN_FRAME_HERO_BUTTON_INDICATOR); - lua_setint(l, "ORIGIN_FRAME_ITEM_BUTTON", ORIGIN_FRAME_ITEM_BUTTON); - lua_setint(l, "ORIGIN_FRAME_COMMAND_BUTTON", ORIGIN_FRAME_COMMAND_BUTTON); - lua_setint(l, "ORIGIN_FRAME_SYSTEM_BUTTON", ORIGIN_FRAME_SYSTEM_BUTTON); - lua_setint(l, "ORIGIN_FRAME_PORTRAIT", ORIGIN_FRAME_PORTRAIT); - lua_setint(l, "ORIGIN_FRAME_MINIMAP", ORIGIN_FRAME_MINIMAP); - lua_setint(l, "ORIGIN_FRAME_MINIMAP_BUTTON", ORIGIN_FRAME_MINIMAP_BUTTON); - lua_setint(l, "ORIGIN_FRAME_TOOLTIP", ORIGIN_FRAME_TOOLTIP); - lua_setint(l, "ORIGIN_FRAME_UBERTOOLTIP", ORIGIN_FRAME_UBERTOOLTIP); - lua_setint(l, "ORIGIN_FRAME_CHAT_MSG", ORIGIN_FRAME_CHAT_MSG); - lua_setint(l, "ORIGIN_FRAME_UNIT_MSG", ORIGIN_FRAME_UNIT_MSG); - lua_setint(l, "ORIGIN_FRAME_TOP_MSG", ORIGIN_FRAME_TOP_MSG); - - lua_register(l, "GetOriginFrame", lua_GetOriginFrame); - lua_register(l, "LoadTOCFile", lua_LoadTOCFile); - lua_register(l, "GetFrameByName", lua_GetFrameByName); - lua_register(l, "CreateFrame", lua_CreateFrame); - lua_register(l, "SetFrameText", lua_SetFrameText); - lua_register(l, "SetFrameTextColor", lua_SetFrameTextColor); - lua_register(l, "GetFrameTextHeight", lua_GetFrameTextHeight); - lua_register(l, "SetFrameWidth", lua_SetFrameWidth); - lua_register(l, "SetFrameHeight", lua_SetFrameHeight); - lua_register(l, "SetFrameSize", lua_SetFrameSize); - lua_register(l, "SetFrameScale", lua_SetFrameScale); - lua_register(l, "SetFrameAbsolutePoint", lua_SetFrameAbsolutePoint); - lua_register(l, "SetFramePoint", lua_SetFramePoint); - lua_register(l, "GetFrameWidth", lua_GetFrameWidth); - lua_register(l, "GetFrameHeight", lua_GetFrameHeight); - lua_register(l, "GetFramePointParent", lua_GetFramePointParent); - lua_register(l, "GetFramePointRelativePoint", lua_GetFramePointRelativePoint); - lua_register(l, "GetFramePointX", lua_GetFramePointX); - lua_register(l, "GetFramePointY", lua_GetFramePointY); -} \ No newline at end of file diff --git a/Src Backup/LuaRegister.h b/Src Backup/LuaRegister.h deleted file mode 100644 index 9d3905b..0000000 --- a/Src Backup/LuaRegister.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -#include "LuaMachine.h" - -void lua_open_jassnatives(lua_State* l); -void lua_open_warcraftfunctions(lua_State* l); \ No newline at end of file diff --git a/Src Backup/Main.cpp b/Src Backup/Main.cpp deleted file mode 100644 index 6ca76a4..0000000 --- a/Src Backup/Main.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -#include "Variables.h" -#include "Mem.h" -#include "Hooks.h" -#include "JassMachine.h" - -BOOL APIENTRY DllMain(HMODULE hModule, UINT ul_reason_for_call, LPVOID lpReserve) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - if (gameBase) { - DisableThreadLibraryCalls(hModule); - - LPSTR cmdline = GetCommandLine(); - size_t i; - for (i = strlen(cmdline); i > 0 && cmdline[i] != '\"'; i--); - - if (strstr(&cmdline[i + 1], "-console") || strstr(&cmdline[i + 1], "-debug")) { - FILE* console; - AllocConsole(); - freopen_s(&console, "CONOUT$", "w", stdout); - SetConsoleTitle("Lua Console"); - } - - printf("%s\n%s\n", LUA_COPYRIGHT, WAR3_LUA); - - jassNativesInitialize(); - jassOpcodeInitialize(); - - call(MakePtr(gameBase, _jassEntryPoint), jassEntryPoint); - call(MakePtr(gameBase, _getWarcraftID1), getWarcraftID); - call(MakePtr(gameBase, _getWarcraftID2), getWarcraftID); - jmp(MakePtr(gameBase, 0x62a580), (DWORD)isFrameValid); - jmp(MakePtr(gameBase, 0x629a90), (DWORD)frameEventObserver); - - break; - } - else { - return FALSE; - } - case DLL_PROCESS_DETACH: - BYTE originalFrameValid[] = { 0x8b, 0x49, 8, 0x33, 0xc0}; - patch(MakePtr(gameBase, 0x62a580), originalFrameValid,sizeof(originalFrameValid)); - - BYTE originalFrameEventObserver[] = { 0x8b, 0x44, 0x24, 4, 0x8b }; - patch(MakePtr(gameBase, 0x629a90), originalFrameEventObserver, sizeof(originalFrameEventObserver)); - - break; - } - - return TRUE; -} \ No newline at end of file diff --git a/Src Backup/Mem.h b/Src Backup/Mem.h deleted file mode 100644 index e1a5e6a..0000000 --- a/Src Backup/Mem.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include - -#define MakePtr(a, b) ((DWORD)a + (DWORD)b) - -inline bool patch(LPVOID lpAddress, LPVOID lpData, SIZE_T dwSize) { - DWORD dwOldProtect; - - if (VirtualProtect(lpAddress, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { - memcpy(lpAddress, lpData, dwSize); - - VirtualProtect(lpAddress, dwSize, dwOldProtect, NULL); - - return true; - } - - return false; -} - -inline bool patch(DWORD dwAddress, LPVOID lpData, SIZE_T dwSize) { - return patch((LPVOID)dwAddress, lpData, dwSize); -} - -inline bool call(LPVOID lpAddress, LPVOID lpProc) { - DWORD dwOldProtect; - - if (VirtualProtect(lpAddress, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { - *(CHAR*)lpAddress = (BYTE)0xE8; - *(DWORD*)((DWORD)lpAddress + 1) = (DWORD)lpProc - ((DWORD)lpAddress + 5); - - VirtualProtect(lpAddress, 5, dwOldProtect, NULL); - - return true; - } - - return false; -} - -inline bool call(DWORD dwAddress, LPVOID lpProc) { - return call((LPVOID)dwAddress, lpProc); -} - -inline bool jmp(LPVOID lpAddress, LPVOID lpDestination) { - DWORD dwOldProtect; - - if (VirtualProtect(lpAddress, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { - *(CHAR*)lpAddress = (BYTE)0xE9; - *(DWORD*)((DWORD)lpAddress + 1) = (DWORD)lpDestination - ((DWORD)lpAddress + 5); - - VirtualProtect(lpAddress, 5, dwOldProtect, NULL); - - return true; - } - - return false; -} - -inline bool jmp(DWORD dwAddress, DWORD lpDestination) { - return jmp((LPVOID)dwAddress, (LPVOID)lpDestination); -} \ No newline at end of file diff --git a/Src Backup/Variables.h b/Src Backup/Variables.h deleted file mode 100644 index b61c47a..0000000 --- a/Src Backup/Variables.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "fcalls.h" -#include "JassNatives.h" -#include "JassMachine.h" -#include "FrameAPI.h" - -#define WAR3_LUA_MAJOR "1" -#define WAR3_LUA_MINOR "1" -#define WAR3_LUA_RELEASE "4 (Beta)" - -#define WAR3_LUA_VERSION WAR3_LUA_MAJOR "." WAR3_LUA_MINOR "." WAR3_LUA_RELEASE -#define WAR3_LUA "War3 Lua " WAR3_LUA_VERSION - -#define GAME_ID "W3L" - -#define MakePtr(a, b) ((DWORD)a + (DWORD)b) - -static HMODULE gameBase = GetModuleHandle("game.dll"); - -enum OFFSETS { - _mapMPQ = 0xaae788, - - _jassEntryPoint = 0x3b0a90, - _jassEntryPointProc = 0x3b54b0, - _getInstanceProc = 0x4c34d0, - _overflowOpcodeProc = 0x45f79a, - _opcodeList = 0x45f808, - _opcodeListSize = 0x45ea4d, - _opcodeSwitch = 0x45ea5a, - - _jassNativesList = 0x3d4025, - - _getWarcraftID1 = 0x54f248, - _getWarcraftID2 = 0x54f24f, - - _netProvider = 0xacec10, - - _getGameUI = 0x300710, - _getGameWar3 = 0x75f0, - _getTooltipFrame = 0x337240, - - _stringHastTable = 0xacd214, - _FDFHashTable = 0xacd264, - _stringHashNodeGrowListArray = 0x5ca9b0, - _baseFrameHashNodeGrowListArray = 0x5d5650, - _readFDFFile = 0x5d8de0, - _CFrameDefStatus = 0xa8c804, - _getCFrameByName = 0x5fa970, - _createCFrame = 0x5c9560, - _setCFrameText = 0x611d40, - _setCFrameTextColor = 0x611590, - _getCFrameTextHeight = 0x6118a0, - // _getCLayoutFrameWidth = 0x604fb0, - // _getCLayoutFrameHeight = 0x604fa0, - _setCLayoutFrameScale = 0x605d40, - _setCLayoutFramePoint = 0x606770, - _clearCLayoutFrameAllPoints = 0x606270, - _setCLayoutFrameWidth = 0x605d90, - _setCLayoutFrameHeight = 0x605db0, - _setCLayoutFrameAbsolutePoint = 0x6061b0, - _setCLayoutFrameCageMouse = 0x604fc0, - _setCLayoutFrameAllPoints = 0x6067f0, - - _frameevent_control_click = 0xa9a86c, - _frameevent_control_mouseenter = 0xa9a84c -}; - -extern std::map jassnatives; -extern std::map triggers; -extern std::unordered_map> frameEventHashTable; -extern bool running; \ No newline at end of file diff --git a/Src Backup/Warcraft.cpp b/Src Backup/Warcraft.cpp deleted file mode 100644 index 6a4856b..0000000 --- a/Src Backup/Warcraft.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "Warcraft.h" - -#include "Variables.h" -#include "fcalls.h" -#include "Mem.h" - -PJASS_INSTANCE getJassMachine(DWORD index) { - DWORD jass_thread = *(DWORD*)(*(DWORD*)(getInstance(5) + 0x90) + index * 4); - - return jass_thread ? (PJASS_INSTANCE)jass_thread : NULL; -} - -PJASS_INSTANCE getJassInstance() { - DWORD instance = getInstance(5); - - return *(DWORD*)(instance + 0x14) ? *(PJASS_INSTANCE*)(*(DWORD*)(instance + 0xc) + *(DWORD*)(instance + 0x14) * 4 - 4) : NULL; -} - -DWORD getInstance(DWORD index) { - return fastcall(MakePtr(gameBase, _getInstanceProc), index); -} - -CGameUI* GetGameUI(UINT unknown0, UINT unknown1) { - return fastcall(MakePtr(gameBase, _getGameUI), unknown0, unknown1); -} - -CGameWar3* GetGameWar3(UINT unknown0) { - return fastcall(MakePtr(gameBase, _getGameWar3), unknown0); -} \ No newline at end of file diff --git a/Src Backup/Warcraft.h b/Src Backup/Warcraft.h deleted file mode 100644 index be7ebab..0000000 --- a/Src Backup/Warcraft.h +++ /dev/null @@ -1,1345 +0,0 @@ -#pragma once - -#include - -#ifndef _Warcraft_h -#define _Warcraft_h -typedef struct { - DWORD unk; - DWORD max_size; - DWORD array; - - UINT32 get(DWORD index) { - DWORD result = 0; - - if (index < max_size) { - result = array + 0x10 * index; - ++* (UINT32*)(result + 0xC); - } - - return result; - } - -} STRING_TABLE, * PSTRING_TABLE; - -typedef struct { - BYTE unk[4]; - DWORD counter; - DWORD* codes; // max_size = 1024 - - DWORD push_code(DWORD address) { - codes[counter] = address; - - return counter++; - } - - DWORD Size() { - return counter; - } -} CODE_TABLE, * PCODE_TABLE; - -typedef struct { - BYTE rettype; - BYTE type; - BYTE reg; - BYTE opcode; - DWORD value; -} JASS_OPCODE, * PJASS_OPCODE; - -typedef struct { - BYTE unk0[0x20]; - PJASS_OPCODE opcode; - BYTE unk1[0x10]; - UINT has_sleep; - BYTE unk2[0x2818]; - DWORD index; - BYTE unk3[0x20]; - PSTRING_TABLE string_table; - BYTE unk4[0x10]; - PCODE_TABLE code_table; - BYTE unk5[0x1C]; -} JASS_INSTANCE, * PJASS_INSTANCE; - -typedef struct { - BYTE unk0[18]; - char access_key[12]; - DWORD wacraft_key; - char language_ltype[8]; - BYTE unk1[8]; - DWORD language_key[8]; - char language[8]; - -} NetProviderLTCP, *PNetProviderLTCP; - -typedef struct { - int VirtualTable; - int field0004; - int field0008; - int field000C; - int field0010; - int field0014; - int field0018; - int field001C; - int field0020; - int field0024; - int field0028; - int field002C; - int field0030; - int field0034; - int field0038; - int field003C; - int field0040; - int field0044; - int field0048; - int field004C; - int field0050; - int field0054; - int field0058; - int field005C; - int field0060; - int field0064; - int field0068; - int field006C; - int field0070; - int field0074; - int field0078; - int field007C; - int field0080; - int field0084; - int field0088; - int field008C; - int field0090; - int field0094; - int field0098; - int field009C; - int field00A0; - int field00A4; - int field00A8; - int field00AC; - int field00B0; -} CFrame, * PCFrame; -#define FRAMELAYOUT(f) ((UINT)f + sizeof(CFrame)) - -struct CGameUI : CFrame { - int VirtualTable; - int field00B8; - int field00BC; - int field00C0; - int field00C4; - int field00C8; - int field00CC; - int field00D0; - int field00D4; - int field00D8; - int field00DC; - int field00E0; - int field00E4; - int field00E8; - int field00EC; - int field00F0; - int field00F4; - int field00F8; - int field00FC; - int field0100; - int field0104; - int field0108; - int field010C; - int field0110; - int field0114; - int field0118; - int field011C; - int field0120; - int field0124; - int field0128; - int field012C; - int field0130; - int field0134; - int field0138; - int field013C; - int field0140; - int field0144; - int field0148; - int field014C; - int field0150; - int field0154; - int field0158; - int field015C; - int field0160; - int field0164; - int field0168; - int field016C; - int field0170; - int field0174; - int field0178; - int field017C; - int field0180; - int field0184; - int field0188; - int field018C; - int field0190; - int field0194; - int field0198; - int field019C; - int field01A0; - int field01A4; - int field01A8; - int isUserInputEnabled; - int isUserInterfaceEnabled; - int field01B4; - int field01B8; - int field01BC; - int field01C0; - int field01C4; - int field01C8; - int field01CC; - int field01D0; - int field01D4; - int field01D8; - int field01DC; - int field01E0; - int field01E4; - int field01E8; - int field01EC; - int field01F0; - int field01F4; - int field01F8; - int field01FC; - int field0200; - int field0204; - int field0208; - int field020C; - int field0210; - int field0214; - int field0218; - int field021C; - int field0220; - int field0224; - int field0228; - int field022C; - int field0230; - int field0234; - int field0238; - int field023C; - int field0240; - int field0244; - int field0248; - int field024C; - int field0250; - int Camera; - int isInGameMenu; - int field025C; - int isGamePaused; - int field0264; - int field0268; - int field026C; - int field0270; - int field0274; - int field0278; - int field027C; - int field0280; - int field0284; - int field0288; - int field028C; - int isDragSelectionEnabled; - int isDragSelectionVisible; - int isPreSelectionEnabled; - int isPreSelectionVisible; - int isSelectionEnabled; - int isSelectionVisible; - int field02A8; - int field02AC; - int field02B0; - int field02B4; - int field02B8; - int field02BC; - int field02C0; - int field02C4; - int field02C8; - int field02CC; - int field02D0; - int field02D4; - int field02D8; - int field02DC; - int field02E0; - int field02E4; - int field02E8; - int field02EC; - int field02F0; - int field02F4; - int field02F8; - int field02FC; - int field0300; - int field0304; - int field0308; - int field030C; - float MouseWorldX; // Use from WorldFrame - float MouseWorldY; - float MouseWorldZ; - int field031C; - int field0320; - int field0324; - int field0328; - int field032C; - int field0330; - int field0334; - int field0338; - int field033C; - int field0340; - int field0344; - int field0348; - int field034C; - int field0350; - int field0354; - int field0358; - int field035C; - int field0360; - int field0364; - int field0368; - int field036C; - int field0370; - int field0374; - int field0378; - int field037C; - int field0380; - int field0384; - int field0388; - int field038C; - int field0390; - int field0394; - int field0398; - int field039C; - int field03A0; - int field03A4; - int field03A8; - int field03AC; - int field03B0; - int field03B4; - int field03B8; - CGameUI* WorldFrameWar3; // CWorldFrameWar3* - CGameUI* Minimap; // CFrame* - CGameUI* InfoBar; - CGameUI* CommandBar; - CGameUI* ResourceBarFrame; - CGameUI* UpperButtonBarFrame; - int field03D4; - CGameUI* ClickableBlock; - CGameUI* HeroBar; - CGameUI* PeonBar; - CGameUI* Message; // CSimpleMessageFrame* - CGameUI* UnitMessage; // CSimpleMessageFrame* - CGameUI* ChatMessage; // CSimpleMessageFrame* - CGameUI* TopMessage; // CSimpleMessageFrame* - CGameUI* Portrait; // CFrame* - CGameUI* TimeOfDayIndicator; // CFrame* - CGameUI* ChatEditBar; - CGameUI* CinematicPanel; - int field0404; - CGameUI* MinimapButtons[5]; - CGameUI* FrameB; // CFrame* - CGameUI* MouseBorders; - CGameUI* FrameA; // CFrame* - CGameUI* SimpleConsole; - int QuickSaveHotKey; - int QuickLoadHotKey; - int QuickHelpHotKey; - int QuickOptionsHotKey; - int QuickQuitHotKey; - int MinimapSignalHotKey; - int MinimapTerrainHotKey; - int MinimapColorsHotKey; - int MinimapCreepsHotKey; - int FormationToggleHotKey; -}; - -struct CGameWar3 { - int field0000; // Pointer - int field0004; - int field0008; - int field000C; - int field0010; - int field0014; // Pointer - int field0018; - int field001C; // CGameState - int field0020; // CGameIdMaps - int field0024; - int field0028; - int field002C; - int field0030; // CMapSetupWar3 - int field0034; // CFogOfWarMap - int field0038; // Pointer - int field003C; - int field0040; // CStringRep - int field0044; - int field0048; - int field004C; - int field0050; - int field0054; - int field0058; // CPlayerWar3 - int field005C; // CPlayerWar3 - int field0060; // CPlayerWar3 - int field0064; // CPlayerWar3 - int field0068; // CPlayerWar3 - int field006C; // CPlayerWar3 - int field0070; // CPlayerWar3 - int field0074; // CPlayerWar3 - int field0078; // CPlayerWar3 - int field007C; // CPlayerWar3 - int field0080; // CPlayerWar3 - int field0084; // CPlayerWar3 - int field0088; // CPlayerWar3 - int field008C; // CPlayerWar3 - int field0090; // CPlayerWar3 - int field0094; // CPlayerWar3 - int field0098; // 16 - int field009C; // 12 - int field00A0; // Pointer - int field00A4; - int field00A8; // 12 - float field00AC; // 320 - float field00B0; // -3264 - int field00B4; - int field00B8; - int field00BC; // Pointer - int field00C0; - int field00C4; - int field00C8; - int field00CC; - int field00D0; - int field00D4; - float field00D8; // -192 - float field00DC; // 2304 - int field00E0; - int field00E4; - int field00E8; // Pointer - int field00EC; - int field00F0; - int field00F4; - int field00F8; - int field00FC; - int field0100; - int field0104; - int field0108; - int field010C; - int field0110; - int field0114; - int field0118; - int field011C; - int field0120; - int field0124; - int field0128; - int field012C; - int field0130; - int field0134; - int field0138; - int field013C; - int field0140; - int field0144; - int field0148; - int field014C; - int field0150; - int field0154; - int field0158; - int field015C; - int field0160; - int field0164; - int field0168; - int field016C; - int field0170; - int field0174; - int field0178; - int field017C; - int field0180; - int field0184; - int field0188; - int field018C; - int field0190; - int field0194; - int field0198; - int field019C; - int field01A0; - int field01A4; - int field01A8; - int field01AC; - int field01B0; - int field01B4; - int field01B8; - int field01BC; - int field01C0; - int field01C4; - int field01C8; - int field01CC; - int field01D0; - int field01D4; - int field01D8; - int field01DC; - int field01E0; - int field01E4; - int field01E8; - int field01EC; - int field01F0; - int field01F4; - int field01F8; - int field01FC; - int field0200; - int field0204; - int field0208; - int field020C; - int field0210; - int field0214; - int field0218; - int field021C; - int field0220; - int field0224; - int field0228; - int field022C; - int field0230; - int field0234; - int field0238; - int field023C; - int field0240; - int field0244; - int field0248; - int field024C; - int field0250; - int field0254; - int field0258; - int field025C; - int field0260; - int field0264; - int field0268; - int field026C; - int field0270; - int field0274; - int field0278; - int field027C; - int field0280; - int field0284; - int field0288; - int field028C; - int field0290; - int field0294; - int field0298; - int field029C; - int field02A0; - int field02A4; - int field02A8; - int field02AC; - int field02B0; - int field02B4; - int field02B8; - int field02BC; - int field02C0; - int field02C4; - int field02C8; - int field02CC; - int field02D0; - int field02D4; - float field02D8; // -0.0000232331422 - int field02DC; - int field02E0; - BYTE field02E4; // 157 - BYTE field02E5; // 92 - BYTE field02E6; // 101 - BYTE field02E7; // 111 - float field02E8; // -0.003639792325 - int field02EC; // Pointer - int field02F0; // Pointer - int field02F4; - int field02F8; // CStringRep - int field02FC; // Pointer - int field0300; - int field0304; // CStringRep - int field0308; // Pointer - int field030C; - int field0310; // CStringRep - int field0314; // Pointer - int field0318; - int field031C; // CStringRep - int field0320; - int field0324; - int field0328; - int field032C; - int field0330; - int field0334; - int field0338; - int field033C; - int field0340; - int field0344; - int field0348; - int field034C; - int field0350; - int field0354; - int field0358; - int field035C; - int field0360; - int field0364; - int field0368; - int field036C; - int field0370; - int field0374; - int field0378; - int field037C; - int field0380; - int field0384; - int field0388; - int field038C; - int field0390; - int field0394; - int field0398; - int field039C; - int field03A0; - int field03A4; - int field03A8; - int field03AC; - int field03B0; - int field03B4; - int field03B8; - int field03BC; - int field03C0; - int field03C4; - int field03C8; - int field03CC; // Pointer - int field03D0; - int field03D4; // CStringRep - int field03D8; - int field03DC; - int field03E0; - int field03E4; - int field03E8; - int field03EC; // Pointer - int field03F0; - int field03F4; - int field03F8; - int field03FC; - int field0400; // CGameCacheManager - int field0404; // CGameHashTableManager - int field0408; - int field040C; - int field0410; - int field0414; - int field0418; - int field041C; - int field0420; - int field0424; - int field0428; - int field042C; - int field0430; - int field0434; - int field0438; - int field043C; - int field0440; - int field0444; - int field0448; - int field044C; - int field0450; - int field0454; - int field0458; - int field045C; - int field0460; - int field0464; - int field0468; - int field046C; - int field0470; - int field0474; - int field0478; - int field047C; - int field0480; - int field0484; - int field0488; - int field048C; - int field0490; - int field0494; - int field0498; - int field049C; - int field04A0; - int field04A4; - int field04A8; - int field04AC; - int field04B0; - int field04B4; - int field04B8; - int field04BC; - int field04C0; - int field04C4; - int field04C8; - int field04CC; - int field04D0; - int field04D4; - int field04D8; - int field04DC; - int field04E0; - int field04E4; - int field04E8; - int field04EC; - int field04F0; - int field04F4; - int field04F8; - int field04FC; - int field0500; - int field0504; - int field0508; - int field050C; - int field0510; - int field0514; - int field0518; - int field051C; - int field0520; - int field0524; - int field0528; - int field052C; - int field0530; - int field0534; - int field0538; - int field053C; - int field0540; - int field0544; - int field0548; - int field054C; - int field0550; - int field0554; - int field0558; - int field055C; - int field0560; - int field0564; - int field0568; - int field056C; - int field0570; - int field0574; - int field0578; - int field057C; - int field0580; - int field0584; - int field0588; - int field058C; - int field0590; - int field0594; - int field0598; - int field059C; - int field05A0; - int field05A4; - int field05A8; - int field05AC; - int field05B0; - int field05B4; - int field05B8; - int field05BC; - int field05C0; - int field05C4; - int field05C8; - int field05CC; - int field05D0; - int field05D4; - int field05D8; - int field05DC; - int field05E0; - int field05E4; - int field05E8; - int field05EC; - int field05F0; - int field05F4; - int field05F8; - int field05FC; - int field0600; - int field0604; - int field0608; - int field060C; - int field0610; - int field0614; - int field0618; - int field061C; - int field0620; - int field0624; - int field0628; - int field062C; - int field0630; - int field0634; - int field0638; - int field063C; - int field0640; - int field0644; - int field0648; - int field064C; - int field0650; - int field0654; - int field0658; - int field065C; - int field0660; - int field0664; - int field0668; - int field066C; - int field0670; - int field0674; - int field0678; - int field067C; - int field0680; - int field0684; - int field0688; - int field068C; - int field0690; - int field0694; - int field0698; - int field069C; - int field06A0; - int field06A4; - int field06A8; - int field06AC; - int field06B0; - int field06B4; - int field06B8; - int field06BC; - int field06C0; - int field06C4; - int field06C8; - int field06CC; - int field06D0; - int field06D4; - int field06D8; - int field06DC; - int field06E0; - int field06E4; - int field06E8; - int field06EC; - int field06F0; - int field06F4; - int field06F8; - int field06FC; - int field0700; - int field0704; - int field0708; - int field070C; - int field0710; - int field0714; - int field0718; - int field071C; - int field0720; - int field0724; - int field0728; - int field072C; - int field0730; - int field0734; - int field0738; - int field073C; - int field0740; - int field0744; - int field0748; - int field074C; - int field0750; - int field0754; - int field0758; - int field075C; - int field0760; - int field0764; - int field0768; - int field076C; - int field0770; - int field0774; - int field0778; - int field077C; - int field0780; - int field0784; - int field0788; - int field078C; - int field0790; - int field0794; - int field0798; - int field079C; - int field07A0; - int field07A4; - int field07A8; - int field07AC; - int field07B0; - int field07B4; - int field07B8; - int field07BC; - int field07C0; - int field07C4; - int field07C8; - int field07CC; - int field07D0; - int field07D4; - int field07D8; - int field07DC; - int field07E0; - int field07E4; - int field07E8; - int field07EC; - int field07F0; - int field07F4; - int field07F8; - int field07FC; - int field0800; - int field0804; - int field0808; - int field080C; - int field0810; - int field0814; - int field0818; - int field081C; - int field0820; - int field0824; - int field0828; - int field082C; - int field0830; - int field0834; - int field0838; - int field083C; - int field0840; - int field0844; - int field0848; - int field084C; - int field0850; - int field0854; - int field0858; - int field085C; - int field0860; - int field0864; - int field0868; - int field086C; - int field0870; - int field0874; - int field0878; - int field087C; - int field0880; - int field0884; - int field0888; - int field088C; - int field0890; - int field0894; - int field0898; - int field089C; - int field08A0; - int field08A4; - int field08A8; - int field08AC; - int field08B0; - int field08B4; - int field08B8; - int field08BC; - int field08C0; - int field08C4; - int field08C8; - int field08CC; - int field08D0; - int field08D4; - int field08D8; - int field08DC; - int field08E0; - int field08E4; - int field08E8; - int field08EC; - int field08F0; - int field08F4; - int field08F8; - int field08FC; - int field0900; - int field0904; - int field0908; - int field090C; - int field0910; - int field0914; - int field0918; - int field091C; - int field0920; - int field0924; - int field0928; - int field092C; - int field0930; - int field0934; - int field0938; - int field093C; - int field0940; - int field0944; - int field0948; - int field094C; - int field0950; - int field0954; - int field0958; - int field095C; - int field0960; - int field0964; - int field0968; - int field096C; - int field0970; - int field0974; - int field0978; - int field097C; - int field0980; - int field0984; - int field0988; - int field098C; - int field0990; - int field0994; - int field0998; - int field099C; - int field09A0; - int field09A4; - int field09A8; - int field09AC; - int field09B0; - int field09B4; - int field09B8; - int field09BC; - int field09C0; - int field09C4; - int field09C8; - int field09CC; - int field09D0; - int field09D4; - int field09D8; - int field09DC; - int field09E0; - int field09E4; - int field09E8; - int field09EC; - int field09F0; - int field09F4; - int field09F8; - int field09FC; - int field0A00; - int field0A04; - int field0A08; - int field0A0C; - int field0A10; - int field0A14; - int field0A18; - int field0A1C; - int field0A20; - int field0A24; - int field0A28; - int field0A2C; - int field0A30; - int field0A34; - int field0A38; - int field0A3C; - int field0A40; - int field0A44; - int field0A48; - int field0A4C; - int field0A50; - int field0A54; - int field0A58; - int field0A5C; - int field0A60; - int field0A64; - int field0A68; - int field0A6C; - int field0A70; - int field0A74; - int field0A78; - int field0A7C; - int field0A80; - int field0A84; - int field0A88; - int field0A8C; - int field0A90; - int field0A94; - int field0A98; - int field0A9C; - int field0AA0; - int field0AA4; - int field0AA8; - int field0AAC; - int field0AB0; - int field0AB4; - int field0AB8; - int field0ABC; - int field0AC0; - int field0AC4; - int field0AC8; - int field0ACC; - int field0AD0; - int field0AD4; - int field0AD8; - int field0ADC; - int field0AE0; - int field0AE4; - int field0AE8; - int field0AEC; - int field0AF0; - int field0AF4; - int field0AF8; - int field0AFC; - int field0B00; - int field0B04; - int field0B08; - int field0B0C; - int field0B10; - int field0B14; - int field0B18; - int field0B1C; - int field0B20; - int field0B24; - int field0B28; - int field0B2C; - int field0B30; - int field0B34; - int field0B38; - int field0B3C; - int field0B40; - int field0B44; - int field0B48; - int field0B4C; - int field0B50; - int field0B54; - int field0B58; - int field0B5C; - int field0B60; - int field0B64; - int field0B68; - int field0B6C; - int field0B70; - int field0B74; - int field0B78; - int field0B7C; - int field0B80; - int field0B84; - int field0B88; - int field0B8C; - int field0B90; - int field0B94; - int field0B98; - int field0B9C; - int field0BA0; - int field0BA4; - int field0BA8; - int field0BAC; - int field0BB0; - int field0BB4; - int field0BB8; - int field0BBC; - int field0BC0; - int field0BC4; - int field0BC8; - int field0BCC; - int field0BD0; - int field0BD4; - int field0BD8; - int field0BDC; - int field0BE0; - int field0BE4; - int field0BE8; - int field0BEC; - int field0BF0; - int field0BF4; - int field0BF8; - int field0BFC; - int field0C00; - int field0C04; - int field0C08; - int field0C0C; - int field0C10; - int field0C14; - int field0C18; - int field0C1C; - int field0C20; - int field0C24; - int field0C28; - int field0C2C; - int field0C30; - int field0C34; - int field0C38; - int field0C3C; - int field0C40; - int field0C44; - int field0C48; - int field0C4C; - int field0C50; - int field0C54; - int field0C58; - int field0C5C; - int field0C60; - int field0C64; - int field0C68; - int field0C6C; - int field0C70; - int field0C74; - int field0C78; - int field0C7C; - int field0C80; - int field0C84; - int field0C88; - int field0C8C; - int field0C90; - int field0C94; - int field0C98; - int field0C9C; - int field0CA0; - int field0CA4; - int field0CA8; - int field0CAC; - int field0CB0; - int field0CB4; - int field0CB8; - int field0CBC; - int field0CC0; - int field0CC4; - int field0CC8; - int field0CCC; - int field0CD0; - int field0CD4; - int field0CD8; - int field0CDC; - int field0CE0; - int field0CE4; - int field0CE8; - int field0CEC; - int field0CF0; - int field0CF4; - int field0CF8; - int field0CFC; - int field0D00; - int field0D04; - int field0D08; - int field0D0C; - int field0D10; - int field0D14; - int field0D18; - int field0D1C; - int field0D20; - int field0D24; - int field0D28; - int field0D2C; - int field0D30; - int field0D34; - int field0D38; - int field0D3C; - int field0D40; - int field0D44; - int field0D48; - int field0D4C; - int field0D50; - int field0D54; - int field0D58; - int field0D5C; - int field0D60; - int field0D64; - int field0D68; - int field0D6C; - int field0D70; - int field0D74; - int field0D78; - int field0D7C; - int field0D80; - int field0D84; - int field0D88; - int field0D8C; - int field0D90; - int field0D94; - int field0D98; - int field0D9C; - int field0DA0; - int field0DA4; - int field0DA8; - int field0DAC; - int field0DB0; - int field0DB4; - int field0DB8; - int field0DBC; - int field0DC0; - int field0DC4; - int field0DC8; - int field0DCC; - int field0DD0; - int field0DD4; - int field0DD8; - int field0DDC; - int field0DE0; - int field0DE4; - int field0DE8; - int field0DEC; - int field0DF0; - int field0DF4; - int field0DF8; - int field0DFC; - int field0E00; - int field0E04; - int field0E08; - int field0E0C; - int field0E10; - int field0E14; - int field0E18; - int field0E1C; - int field0E20; - int field0E24; - int field0E28; - int field0E2C; - int field0E30; - int field0E34; - int field0E38; - int field0E3C; - int field0E40; - int field0E44; - int field0E48; - int field0E4C; - int field0E50; - int field0E54; - int field0E58; - int field0E5C; - int field0E60; - int field0E64; - int field0E68; - int field0E6C; - int field0E70; - int field0E74; - int field0E78; - int field0E7C; - int field0E80; - int field0E84; - int field0E88; - int field0E8C; - int field0E90; - int field0E94; - int field0E98; - int field0E9C; - int field0EA0; - int field0EA4; - int field0EA8; - int field0EAC; - int field0EB0; - int field0EB4; - int field0EB8; - int field0EBC; - int field0EC0; - int field0EC4; - int field0EC8; - int field0ECC; - int field0ED0; - int field0ED4; - int field0ED8; - int field0EDC; - int field0EE0; - int field0EE4; - int field0EE8; - int field0EEC; - int field0EF0; - int field0EF4; - int field0EF8; - int field0EFC; - int field0F00; - int field0F04; - int field0F08; - int field0F0C; - int field0F10; - int field0F14; - int field0F18; - int field0F1C; - int field0F20; - int field0F24; - int field0F28; - int field0F2C; - int field0F30; - int field0F34; - int field0F38; - int field0F3C; -}; -#endif - -PJASS_INSTANCE getJassMachine(DWORD index = 1); - -PJASS_INSTANCE getJassInstance(); - -DWORD getInstance(DWORD index); - -CGameUI* GetGameUI(UINT unknown0 = NULL, UINT unknown1 = NULL); - -CGameWar3* GetGameWar3(UINT unknown0 = NULL); \ No newline at end of file diff --git a/Src Backup/WarcraftFunctions.cpp b/Src Backup/WarcraftFunctions.cpp deleted file mode 100644 index afaed07..0000000 --- a/Src Backup/WarcraftFunctions.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "WarcraftFunctions.h" -#include "Warcraft.h" - -PVECTOR3 GetMouseWorldPos() { - CGameUI* gameUI = GetGameUI(); - - return gameUI ? (PVECTOR3)&gameUI->WorldFrameWar3->MouseWorldX : NULL; -} - -float GetMouseWorldX() { - PVECTOR3 mousePos = GetMouseWorldPos(); - - return mousePos ? mousePos->_x : 0.f; -} - -float GetMouseWorldY() { - PVECTOR3 mousePos = GetMouseWorldPos(); - - return mousePos ? mousePos->_y : 0.f; -} - -float GetMouseWorldZ() { - PVECTOR3 mousePos = GetMouseWorldPos(); - - return mousePos ? mousePos->_z : 0.f; -} - -UINT_PTR ConvertHandleToObject(UINT handle) { - return handle ? *(UINT_PTR*)(*(UINT_PTR*)((GetGameWar3()->field001C) + 0x19C) + handle * 0xC - 0x2FFFFF * 4) : NULL; -} - -PVECTOR3 GetObjectPos(UINT_PTR object) { - return object ? (PVECTOR3)(*(UINT_PTR*)(object + 0x28) + 0xC0) : NULL; -} - -float GetObjectX(UINT_PTR object) { - PVECTOR3 objectPos = GetObjectPos(object); - - return objectPos ? objectPos->_x : 0.f; -} - -float GetObjectY(UINT_PTR object) { - PVECTOR3 objectPos = GetObjectPos(object); - - return objectPos ? objectPos->_y : 0.f; -} - -float GetObjectZ(UINT_PTR object) { - PVECTOR3 objectPos = GetObjectPos(object); - - return objectPos ? objectPos->_z : 0.f; -} - -void SetObjectPos(UINT_PTR object, const VECTOR3& pos) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->operator=(pos); -} - -void SetObjectX(UINT_PTR object, float x) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->_x = x; -} - -void SetObjectY(UINT_PTR object, float y) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->_y = y; -} - -void SetObjectZ(UINT_PTR object, float z) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->_z = z; -} \ No newline at end of file diff --git a/Src Backup/WarcraftFunctions.h b/Src Backup/WarcraftFunctions.h deleted file mode 100644 index 6079cdc..0000000 --- a/Src Backup/WarcraftFunctions.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -#ifndef _WarcraftFunctions_h -#define _WarcraftFunctions_h -typedef struct VECTOR3 { - VECTOR3(float x, float y, float z) : _x(x), _y(y), _z(z) {} - VECTOR3& operator=(const VECTOR3& from) { - if (this == &from) { - return *this; - } - - this->_x = from._x; - this->_y = from._y; - this->_z = from._z; - - return *this; - } - float _x; - float _y; - float _z; -} * PVECTOR3, * LPVECTOR3; -#endif - -PVECTOR3 GetMouseWorldPos(); -float GetMouseWorldX(); -float GetMouseWorldY(); -float GetMouseWorldZ(); - -UINT_PTR ConvertHandleToObject(UINT handle); - -PVECTOR3 GetObjectPos(UINT_PTR object); -float GetObjectX(UINT_PTR object); -float GetObjectY(UINT_PTR object); -float GetObjectZ(UINT_PTR object); - -void SetObjectPos(UINT_PTR object, const VECTOR3& pos); -void SetObjectX(UINT_PTR object, float x); -void SetObjectY(UINT_PTR object, float y); -void SetObjectZ(UINT_PTR object, float z); \ No newline at end of file diff --git a/Src Backup/fcalls.h b/Src Backup/fcalls.h deleted file mode 100644 index fc194a2..0000000 --- a/Src Backup/fcalls.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -template -inline R stdcall(F function, A...args) { - return reinterpret_cast(function)(args...); -} - -template -inline R fastcall(F function, A...args) { - return reinterpret_cast(function)(args...); -} - -template -inline R thiscall(F function, T _this, A...args) { - return reinterpret_cast(function)(_this, NULL, args...); -} \ No newline at end of file diff --git a/Src/Main.cpp b/Src/DllMain.cpp similarity index 68% rename from Src/Main.cpp rename to Src/DllMain.cpp index 1e996c8..b7ef24b 100644 --- a/Src/Main.cpp +++ b/Src/DllMain.cpp @@ -1,19 +1,17 @@ -#include -#include -#include -#include "Global.h" -#include "lua.h" -#include "JassNatives.h" +#include "pch.h" #include "JassMachine.h" +#include "JassNatives.h" #include "Hooks.h" -#include "Utils.h" +#include "Logger.h" +#include "EasterEgg.h" -bool consoleMode = false; bool developerMode = false; +SYSTEMTIME date; +std::string celebratingText; -bool startUp(); +bool StartUp(); -//----------------------------------------------------------------------------- +//--------------------------------------------------------------------- BOOL APIENTRY DllMain(HMODULE module, UINT reason, LPVOID reserved) { switch (reason) { @@ -21,26 +19,25 @@ BOOL APIENTRY DllMain(HMODULE module, UINT reason, LPVOID reserved) { if (!gameBase) { return FALSE; } - - DisableThreadLibraryCalls(module); - if (!startUp()) { + if (!StartUp()) { return FALSE; } - if (consoleMode) { - system("cls"); - } - printf("%s\n%s (%s)\n", LUA_COPYRIGHT, WAR3_LUA, WAR3_LUA_VERSION_NAME); + GetLocalTime(&date); + celebratingText = GetEasterText(date); + !celebratingText.empty() ? MessageBox(NULL, celebratingText.c_str(), "Celebration Message!", MB_ICONINFORMATION) : NULL; - jassNativesParse(); - jassOpcodeInitialize(); + JassMachine::JassOpcodeInitialize(); - attachHooks(); + Hooks::AttachHooks(); break; case DLL_PROCESS_DETACH: - detachHooks(); + + Hooks::DetachHooks(); + + Logger::CloseConsole(); break; } @@ -48,9 +45,9 @@ BOOL APIENTRY DllMain(HMODULE module, UINT reason, LPVOID reserved) { return TRUE; } -//----------------------------------------------------------------------------- +//--------------------------------------------------------------------- -bool startUp() { +bool StartUp() { DWORD handle; DWORD size = GetFileVersionInfoSize("game.dll", &handle); @@ -78,7 +75,10 @@ bool startUp() { } if (strstr(&cmdline[i + 1], "-console") || strstr(&cmdline[i + 1], "-debug")) { - consoleMode = openConsole(developerMode ? "Lua Console [Developer]" : "Lua Console") ? true : false; + Logger::OpenConsole(developerMode ? "Lua Console [Developer]" : "Lua Console"); + + system("cls"); + printf("%s\n%s (%s)\n\n", LUA_COPYRIGHT, WAR3_LUA, WAR3_LUA_VERSION_NAME); } return true; diff --git a/Src/EasterEgg.cpp b/Src/EasterEgg.cpp new file mode 100644 index 0000000..4e02344 --- /dev/null +++ b/Src/EasterEgg.cpp @@ -0,0 +1,54 @@ +#include "pch.h" +#include "EasterEgg.h" + +std::string GetEasterText(SYSTEMTIME& date) { + WORD day = date.wDay; + WORD month = date.wMonth; + std::string text = ""; + + if (day == 2 && month == 6 ) { + text = "~~~ Happy Birthday to Ev3nt! ~~~"; + } + + if (day == 1 && month == 1 ) { + text = "~~~ Happy New Year! ~~~"; + } + + if (day == 2 && month == 3 ) { + text = "~~~ Glory to Billy! ~~~"; + } + + if (day == 7 && month == 10 ) { + text = "~~~ Happy Birthday, the best president! ~~~"; + } + + if (day == 9 && month == 5 ) { + text = "~~~ Glory to the Red Army! ~~~"; + } + + if (day == 5 && month == 10 ) { + text = "~~~ Birthday of the best programming language! ~~~"; + } + + if (day == 16 && month == 12 ) { + text = "~~~ Happy Birthday, Warcraft III - Lua! ~~~"; + } + + if (day == 13 && month == 5 ) { + text = "~~~ Welcome to XGM! ~~~"; + } + + if (day == 24 && month == 10 ) { + text = "~~~ Three Hundred Bucks ~~~"; + } + + if (day == 6 && month == 5 ) { + text = "~~~ Quro started his work... ~~~"; + } + + if (day == 6 && month == 4) { + text = "~~~ Kokomi's day ~~~"; + } + + return text; +} \ No newline at end of file diff --git a/Src/EasterEgg.h b/Src/EasterEgg.h new file mode 100644 index 0000000..c9d7ec2 --- /dev/null +++ b/Src/EasterEgg.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +std::string GetEasterText(SYSTEMTIME& date); \ No newline at end of file diff --git a/Src/EasyStormLib/EasyStormLib.cpp b/Src/EasyStormLib/EasyStormLib.cpp new file mode 100644 index 0000000..84db052 --- /dev/null +++ b/Src/EasyStormLib/EasyStormLib.cpp @@ -0,0 +1,94 @@ +#include "../pch.h" +#include "EasyStormLib.h" +#include "StormLib.h" + +namespace Storm { + Archive::Archive() { + m_handle = NULL; + m_owner = false; + } + + Archive::~Archive() { + if (m_owner) { + Close(); + } + } + + void Archive::Open(std::string name, DWORD priority, DWORD flags) { + if (StormOpenArchive(name.c_str(), priority, flags, &m_handle)) { + m_owner = true; + } + } + + void Archive::Connect(HANDLE handle) { + m_handle = handle; + m_owner = false; + } + + void Archive::Close(bool force) { + if (m_owner || (!m_owner && force)) { + if (m_handle) { + StormCloseArchive(m_handle); + } + } + + m_handle = NULL; + } + + std::string Archive::GetArchiveName() { + char name[MAX_PATH]; + FillMemory(name, sizeof(name), 0); + + if (m_handle) { + StormGetArchiveName(m_handle, name, sizeof(name)); + } + + return name; + } + + std::string Archive::GetArchiveName(std::string fileName) { + char name[MAX_PATH]; + FillMemory(name, sizeof(name), 0); + + HANDLE _handle; + if (StormOpenFile(fileName.c_str(), &_handle)) { + HANDLE _archive; + if (StormGetFileArchive(_handle, &_archive)) { + StormGetArchiveName(_archive, name, sizeof(name)); + } + + StormCloseFile(_handle); + } + + return name; + } + + std::string Archive::operator[](std::string name) { + std::string filedata; + + HANDLE _handle = NULL; + + if (m_handle) { + StormOpenFileEx(m_handle, name.c_str(), 0, &_handle); + } + else { + StormOpenFile(name.c_str(), &_handle); + } + + if (_handle) { + SIZE_T high; // Idk how i can use it on x32, so maximum size limit is 4gb + SIZE_T size = StormGetFileSize(_handle, &high); + + SIZE_T readed; // Useless shit, cause we have checked file size + char* buffer = new char[size]; + FillMemory(buffer, size, 0); + StormReadFile(_handle, buffer, size, &readed, 0); + StormCloseFile(_handle); + + filedata.append(buffer, size); + delete[] buffer; + } + + return filedata; + } +} \ No newline at end of file diff --git a/Src/EasyStormLib/EasyStormLib.h b/Src/EasyStormLib/EasyStormLib.h new file mode 100644 index 0000000..84505c9 --- /dev/null +++ b/Src/EasyStormLib/EasyStormLib.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../pch.h" + +namespace Storm { + class Archive { + public: + Archive(); + ~Archive(); // It's calling close if we're owner of archive + + void Open(std::string name, DWORD priority = 13, DWORD flags = 0); + void Connect(HANDLE handle); + + void Close(bool force = false); + std::string GetArchiveName(); + std::string GetArchiveName(std::string fileName); + + std::string operator[](std::string name); // Open file such as string + private: + HANDLE m_handle = NULL; + bool m_owner = false; // We're owner, if we have opened archive + }; +} \ No newline at end of file diff --git a/Src/EasyStormLib/StormLib.h b/Src/EasyStormLib/StormLib.h new file mode 100644 index 0000000..1c42ee3 --- /dev/null +++ b/Src/EasyStormLib/StormLib.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../pch.h" + +HMODULE stormBase = LoadLibrary("storm.dll"); + +auto StormCloseArchive = (BOOL(WINAPI*)(HANDLE archive))(GetProcAddress(stormBase, (LPCSTR)252)); +auto StormCloseFile = (BOOL(WINAPI*)(HANDLE file))(GetProcAddress(stormBase, (LPCSTR)253)); +auto StormGetFileArchive = (SIZE_T(WINAPI*)(HANDLE file, HANDLE* archive))(GetProcAddress(stormBase, (LPCSTR)264)); +auto StormGetFileSize = (SIZE_T(WINAPI*)(HANDLE file, LPDWORD filesizehigh))(GetProcAddress(stormBase, (LPCSTR)265)); +auto StormOpenArchive = (BOOL(WINAPI*)(LPCSTR archivename, DWORD priority, DWORD flags, HANDLE* handle))(GetProcAddress(stormBase, (LPCSTR)266)); +auto StormOpenFileEx = (BOOL(WINAPI*)(HANDLE archive, LPCSTR filename, DWORD mode, HANDLE* handle))(GetProcAddress(stormBase, (LPCSTR)268)); +auto StormReadFile = (BOOL(WINAPI*)(HANDLE file, PVOID buffer, SIZE_T bumberofbytestoread, SIZE_T* read, LONG distancetomovehigh))(GetProcAddress(stormBase, (LPCSTR)269)); +auto StormGetArchiveName = (BOOL(WINAPI*)(HANDLE archive, LPSTR name, SIZE_T length))(GetProcAddress(stormBase, (LPCSTR)275)); +auto StormGetFileName = (BOOL(WINAPI*)(HANDLE file, LPSTR buffer, SIZE_T length))(GetProcAddress(stormBase, (LPCSTR)276)); +auto StormOpenFile = (BOOL(WINAPI*)(LPCSTR filename, HANDLE* file))(GetProcAddress(stormBase, (LPCSTR)267)); \ No newline at end of file diff --git a/Src/GameUI.cpp b/Src/GameUI.cpp deleted file mode 100644 index 4c0f6ca..0000000 --- a/Src/GameUI.cpp +++ /dev/null @@ -1,785 +0,0 @@ -#include "GameUI.h" -#include "Global.h" - -auto getGameUITrue = (CGameUI*(__fastcall*)(UINT, UINT))((UINT_PTR)gameBase + 0x300710); -auto getTooltipFrameTrue = (UINT(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x337240); - -auto GrowStringHashNodeListArray = (void(__fastcall*)(LPVOID, UINT, DWORD))((UINT_PTR)gameBase + 0x5ca9b0); -auto GrowBaseFrameHashNodeListArray = (void(__fastcall*)(LPVOID, UINT, DWORD))((UINT_PTR)gameBase + 0x5d5650); -auto ReadFDFFile = (BOOL(__fastcall*)(LPCSTR, LPVOID, LPVOID, LPVOID))((UINT_PTR)gameBase + 0x5d8de0); - -auto GetCFrameByName = (UINT(__fastcall*)(LPCSTR, UINT))((UINT_PTR)gameBase + 0x5fa970); -auto CreateCFrame = (UINT(__fastcall*)(LPCSTR, UINT, EFramePoint, EFramePoint, UINT))((UINT_PTR)gameBase + 0x5c9560); -auto SetCTextFrameText = (void(__fastcall*)(UINT, UINT, LPCSTR))((UINT_PTR)gameBase + 0x611d40); -auto SetCFrameTextColor = (void(__fastcall*)(UINT, UINT, DWORD*))((UINT_PTR)gameBase + 0x611590); -auto GetCFrameTextHeight = (float(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x6118a0); -auto SetCEditBoxText = (void(__fastcall*)(UINT, UINT, LPCSTR, UINT))((UINT_PTR)gameBase + 0x615B50); -auto SetCTextAreaText = (void(__fastcall*)(UINT, UINT, LPCSTR))((UINT_PTR)gameBase + 0x61E090); -auto SetCEditBoxFont = (void(__fastcall*)(UINT, UINT, LPCSTR, float, UINT))((UINT_PTR)gameBase + 0x613CA0); -auto SetCLayerFont = (void(__fastcall*)(UINT, UINT, LPCSTR, float, UINT))((UINT_PTR)gameBase + 0x5FB960); -auto SetCLayoutFrameWidth = (void(__fastcall*)(UINT, UINT, float))((UINT_PTR)gameBase + 0x605d90); -auto SetCLayoutFrameHeight = (void(__fastcall*)(UINT, UINT, float))((UINT_PTR)gameBase + 0x605db0); -auto SetCLayoutFrameScale = (void(__fastcall*)(UINT, UINT, float))((UINT_PTR)gameBase + 0x605d40); -auto SetCLayoutFramePoint = (void(__fastcall*)(UINT, UINT, EFramePoint, UINT, EFramePoint, float, float, UINT))((UINT_PTR)gameBase + 0x606770); -auto SetCSliderCurrentValue = (void(__fastcall*)(UINT, UINT, float, UINT))((UINT_PTR)gameBase + 0x61ee70); -auto SetCSimpleStatusBarTexture = (void(__fastcall*)(UINT, UINT, LPCSTR, BOOL))((UINT_PTR)gameBase + 0x60e610); -auto SetCSimpleStatusBarValue = (void(__fastcall*)(UINT, UINT, float))((UINT_PTR)gameBase + 0x60e430); -auto SetCSimpleStatusBarMinMaxValue = (void(__fastcall*)(UINT, UINT, float, float))((UINT_PTR)gameBase + 0x60e3b0); -//auto clearCLayoutFrameAllPoints = (void(__fastcall*)(UINT, UINT))((UINT_PTR)gameBase + 0x606270); -auto SetCLayoutFrameAbsolutePoint = (void(__fastcall*)(UINT, UINT, EFramePoint, float, float, UINT))((UINT_PTR)gameBase + 0x6061b0); -//auto setCLayoutFrameCageMouse = (void(__fastcall*)(UINT, UINT))((UINT_PTR)gameBase + 0x604fc0); -//auto setCLayoutFrameAllPoints = (void(__fastcall*)(UINT, UINT))((UINT_PTR)gameBase + 0x6067f0); -auto SetCBackDropFrameTexture = (void(__fastcall*)(UINT, UINT, LPCSTR, UINT, BOOL, UINT, UINT))((UINT_PTR)gameBase + 0x6212d0); -auto SetCSimpleTextureTexture = (void(__fastcall*)(UINT, UINT, LPCSTR, BOOL))((UINT_PTR)gameBase + 0x60e090); -auto SetCControlState = (void(__fastcall*)(UINT, UINT, BOOL))((UINT_PTR)gameBase + 0x336c20); -//auto SetCControlState = (void(__fastcall*)(UINT, UINT, BOOL))((UINT_PTR)gameBase + 0x601de0); -auto ClickCFrame = (void(__fastcall*)(UINT, UINT, UINT))((UINT_PTR)gameBase + 0x601f20); -auto AddCModelFrameModel = (void(__fastcall*)(UINT, UINT, LPCSTR, UINT))((UINT_PTR)gameBase + 0x6215d0); -auto SetCSpriteFrameArt = (void(__fastcall*)(UINT, UINT, LPCSTR, UINT, BOOL))((UINT_PTR)gameBase + 0x60f360); -auto SetCStatusBarArt = (void(__fastcall*)(UINT, UINT, LPCSTR, UINT))((UINT_PTR)gameBase + 0x6279a0); -auto SetCStatusBarMinMaxValue = (void(__fastcall*)(UINT, UINT, float, float))((UINT_PTR)gameBase + 0x6277c0); -auto DestroyCFrame = (void(__fastcall*)(UINT, UINT, UINT))((UINT_PTR)gameBase + 0x606910); -auto ShowCFrame = (void(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x5fe690); -auto HideCFrame = (void(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x5fe6f0); - -auto TriggerEvaluate = (BOOL(__cdecl*)(UINT))((UINT_PTR)gameBase + 0x3c3f80); -auto TriggerExecute = (BOOL(__cdecl*)(UINT))((UINT_PTR)gameBase + 0x3c3f40); - -int* pWheelState = (int*)((UINT_PTR)gameBase + 0xa9a844); - -const std::map> frameTypes = { - {BackdropFrame, {0x96f3f4, 0x96f3cc}}, - {ButtonFrame, {0x96f6fc, 0x96f6d4}}, - {ChatMode, {0x93a8bc, NULL}}, - {CommandButton, {0x93ebc4, NULL}}, - {CursorFrame, {0x97063c, 0x970610}}, - {EditBox, {0x96ecec, 0x96ecc0}}, - {Frame, {0x96deb4, 0x96de8c}}, - {FloatingFrame, {0x96fab4, 0x96fa88}}, - {GameUI, {0x93631c, 0x9362f4}}, - {HeroBarButton, {0x93f8dc, NULL}}, // 0x93F8BC ?? - {HighlightFrame, {0x96f974, 0x96f94c}}, - {LayoutFrame, {0x96de48, NULL}}, - {MessageFrame, {0x96f864, 0x96f83c}}, - {Minimap, {0x94002c, 0x940004}}, - {ModelFrame, {0x96f5ac, 0x96f584}}, - {PortraitButton, {0x9401e4, 0x9401bc}}, - {ScreenFrame, {0x96e07c, 0x96e054}}, - {SimpleButton, {0x96dc8c, NULL}}, - {SimpleFontString, {0x96e404, NULL}}, - {SimpleFrame, {0x96dfb4, NULL}}, - {SimpleGlueFrame, {0x96ee04, NULL}}, - {Uknown_1, {NULL, NULL}}, - {SimpleMessageFrame, {0x96dd84, NULL}}, - {Slider, {0x96f274, 0x96f24c}}, - {SpriteFrame, {0x96e584, 0x96e558}}, - {StatBar, {0x93e604, NULL}}, - {TextArea, {0x96efd4, 0x96efac}}, - {TextButtonFrame, {0x96f114, 0x96f0e8}}, - {TextFrame, {0x96e9b4, 0x96e988}}, - {UberToolTipWar3, {0x93f68c, NULL}}, - {WorldFrameWar3, {0x94157c, 0x941550}}, - {GlueButtonWar3, {0x95c92c, 0x95c900}}, - {GlueTextButtonWar3, {0x95a00c, 0x959fe0}}, - {GlueCheckBoxWar3, {0x95c7ec, 0x95c7c0}}, - {GluePopupMenuWar3, {0x959e84, 0x959e5c}}, - {GlueEditBoxWar3, {0x95cA6c, 0x95ca40}}, - {SlashChatBox, {0x95daec, 0x95dac4}}, - {TimerTextFrame, {0x95a564, 0x95a538}}, - {SimpleStatusBar, {0x96e48c, NULL}}, - {StatusBar, {0x970264, 0x97023c}}, - {UpperButtonBar, {0x93c3e4, 0x93c3c4}}, - {ResourceBar, {0x93d22c, NULL}}, - {SimpleConsole, {0x93bd2c, NULL}}, - {PeonBar, {0x93fc0c, 0x93fbf0}}, - {HeroBar, {0x93f974, NULL}}, // 0x93F958 - {TimeOfDayIndicator, {0x93fe64, 0x93fe38}}, - {InfoBar, {0x94066c, NULL}}, - {TimeCover, {0x93c054, 0x93c028}}, - {ProgressIndicator, {0x93834c, NULL}}, - {HeroLevelBar, {0x93fa24, NULL}}, - {BuildTimeIndicator, {0x93d684, NULL}}, - {InfoPanelDestructableDetail, {0x93ce54, NULL}}, - {InfoPanelItemDetail, {0x93b4c4, NULL}}, - {InfoPanelIconAlly, {0x93b374, NULL}}, - {InfoPanelIconHero, {0x93b284, NULL}}, - {InfoPanelIconGold, {0x93b20c, NULL}}, - {InfoPanelIconFood, {0x93b194, NULL}}, - {InfoPanelIconRank, {0x93b11c, NULL}}, - {InfoPanelIconArmor, {0x93b0a4, NULL}}, - {InfoPanelIconDamage, {0x93b02c, NULL}}, - {InfoPanelCargoDetail, {0x93cf8c, NULL}}, - {InfoPanelBuildingDetail, {0x93de9c, NULL}}, - {InfoPanelUnitDetail, {0x93cf0c, NULL}}, - {SimpleTexture, {0x96e440, NULL}} -}; // Type = {TypeAddress, LayoutAddress} - -const std::map frameEvents = { - {FRAMEEVENT_CONTROL_CLICK, 0x40090064}, - {FRAMEEVENT_MOUSE_MOVE, 0x40090066}, - {FRAMEEVENT_MOUSE_UP, 0x4009006a}, - {FRAMEEVENT_MOUSE_DOWN, NULL}, - {FRAMEEVENT_MOUSE_WHEEL, 0x4009006b}, - {FRAMEEVENT_CHECKBOX_CHECK, 0x400c0064}, - {FRAMEEVENT_EDITBOX_BUTTON_DOWN, 0x40060066}, - {FRAMEEVENT_POPUPMENU_ITEM_CHANGED, NULL}, - {FRAMEEVENT_MOUSE_DOUBLECLICK, NULL}, - {FRAMEEVENT_SPRITE_ANIM_UPDATE, NULL}, - {FRAMEEVENT_SLIDER_VALUE_CHANGED, 0x40100064}, - {FRAMEEVENT_DIALOG_CANCEL, NULL}, - {FRAMEEVENT_DIALOG_ACCEPT, NULL} -}; - -std::map> frameEventHashTable; - -std::vector frames; - -UINT triggerFrame = NULL; -EFrameEvent triggerEvent = FRAMEEVENT_NONE; - -PVOID pStringHastTable = (PVOID)((UINT_PTR)gameBase + 0xacd214); -PVOID pFDFHashTable = (PVOID)((UINT_PTR)gameBase + 0xacd264); -PVOID pCFrameDefaultStatus = (PVOID)((UINT_PTR)gameBase + 0xa8c804); - -EFrameEvent GetFrameEventType(UINT eventtype) { - for (const auto& frameEvent : frameEvents) { - if (frameEvent.second == eventtype) { - EFrameEvent event = (EFrameEvent)frameEvent.first; - - return event; - } - } - - return FRAMEEVENT_NONE; -} - -EFrameType GetFrameType(UINT frame) { - if (frame) { - UINT_PTR typeOffset = *(UINT*)frame - (UINT_PTR)gameBase; - - for (const auto& frameType : frameTypes) { - if (frameType.second.first == typeOffset || frameType.second.second == typeOffset) { - return frameType.first; - } - } - } - - return MissingFrame; -} - -UINT GetFrameLayout(UINT frame) { - if (!frame) { - return NULL; - } - - UINT_PTR typeOffset = *(UINT_PTR*)frame - (UINT_PTR)gameBase; - - for (const auto& frameType : frameTypes) { - if (frameType.second.first == typeOffset || frameType.second.second == typeOffset) { - return frameType.second.second ? (frame + 0xB4) : frame; - } - } - - return NULL; -} - -bool IsFrameLayout(UINT frame) { - if (!frame) { - return false; - } - - UINT_PTR typeOffset = *(UINT_PTR*)frame - (UINT_PTR)gameBase; - - for (const auto& frameType : frameTypes) { - if (frameType.second.first == typeOffset || frameType.second.second == typeOffset) { - return frameType.second.second == typeOffset; - } - } - - return false; -} - -CGameUI* GetGameUI(UINT unknown1, UINT unknown2) { - return getGameUITrue(unknown1, unknown2); -} - -UINT GetOriginFrame(EOriginFrame originframe, UINT index) { - CGameUI* gameui = GetGameUI(); - - switch (originframe) { - case ORIGIN_FRAME_GAME_UI: - return (UINT)gameui; - case ORIGIN_FRAME_WORLD_FRAME: - return (UINT)gameui->WorldFrameWar3; - case ORIGIN_FRAME_HERO_BAR: - return (UINT)gameui->HeroBar; - case ORIGIN_FRAME_HERO_BUTTON: - return (UINT)GetPanelButton((UINT)gameui->HeroBar, index, 0); - case ORIGIN_FRAME_HERO_HP_BAR: - return *(UINT*)((UINT)GetPanelButton((UINT)gameui->HeroBar, index, 0) + 0x1cc); - case ORIGIN_FRAME_HERO_MANA_BAR: - return *(UINT*)((UINT)GetPanelButton((UINT)gameui->HeroBar, index, 0) + 0x1d0); - case ORIGIN_FRAME_HERO_BUTTON_INDICATOR: - // Undefined - break; - case ORIGIN_FRAME_ITEM_BUTTON: - return *(UINT*)(*(UINT*)(*(UINT*)(gameui->InfoBar + 0x148) + 0x130) + 8 * index + 4); - case ORIGIN_FRAME_COMMAND_BUTTON: - return (UINT)GetPanelButton((UINT)gameui->CommandBar, index / 4, index % 4); - case ORIGIN_FRAME_SYSTEM_BUTTON: - // Undefined - break; - case ORIGIN_FRAME_PORTRAIT: - return (UINT)gameui->Portrait; - case ORIGIN_FRAME_MINIMAP: - return (UINT)gameui->Minimap; - case ORIGIN_FRAME_MINIMAP_BUTTON: - return (UINT)gameui->MinimapButtons[index]; - case ORIGIN_FRAME_TOOLTIP: - return GetTooltipFrame(); - case ORIGIN_FRAME_UBERTOOLTIP: - // Undefined - break; - case ORIGIN_FRAME_CHAT_MSG: - return (UINT)gameui->ChatMessage; - case ORIGIN_FRAME_UNIT_MSG: - return (UINT)gameui->UnitMessage; - case ORIGIN_FRAME_TOP_MSG: - return (UINT)gameui->TopMessage; - default: - break; - } - - return NULL; -} - -UINT GetPanelButton(UINT frame, BYTE row, BYTE column) { - return *(UINT*)(*(DWORD*)(16 * row + *((DWORD*)frame + 85) + 8) + 4 * column); -} - -UINT GetTooltipFrame(UINT unknown1) { - return getTooltipFrameTrue(unknown1); -} - -BOOL LoadTOCFile(LPCSTR filename) { - if (*(int*)((UINT_PTR)pStringHastTable + 0x14) < 0xFFFF) { - GrowStringHashNodeListArray(pStringHastTable, NULL, 0xFFFF); - } - - if (*(int*)((UINT_PTR)pFDFHashTable + 0x14) < 0xFFFF) { - GrowBaseFrameHashNodeListArray(pFDFHashTable, NULL, 0xFFFF); - } - - return ReadFDFFile(filename, pStringHastTable, pFDFHashTable, pCFrameDefaultStatus); -} - -UINT GetFrameByName(LPCSTR framename, UINT id) { - return GetCFrameByName(framename, id); -} - -UINT GetFrameParent(UINT frame) { - return GetFrameType(frame) ? (IsFrameLayout(frame) ? *(UINT*)(frame + 0x68) : *(UINT*)(frame + 0x20)) : NULL; -} - -UINT GetFrameChildrenCount(UINT frame) { - if (frame) { - UINT childtable = *(UINT*)(frame + 0x1c); - UINT i = 0; - - for (; (int)childtable > NULL; i++, childtable = *(UINT*)(childtable + 8)); - // for (; ReadProcessMemory(GetCurrentProcess(), (LPVOID)(childtable + 8), &childtable, sizeof(childtable), NULL); i++); - - return i; - } - - return NULL; - // return frame ? *(UINT*)(frame + 4) - 1 : NULL; ?? -} - -UINT GetFrameChild(UINT frame, UINT index) { - if (frame) { - UINT count = GetFrameChildrenCount(frame); - - if (count && index < count) { - UINT childtable = *(UINT*)(frame + 0x1c); - for (UINT i = 0; i < index; i++, childtable = *(UINT*)(childtable + 8)); - - return *(UINT*)(childtable + 0xc); - } - } - - return NULL; -} - -void TriggerRegisterFrameEvent(UINT trigger, UINT frame, EFrameEvent event) { - frameEventHashTable[frame][event] = trigger; -} - -UINT CreateFrame(LPCSTR baseframe, UINT parentframe, EFramePoint point, EFramePoint relativepoint) { - UINT prevframe = NULL; - - if (frames.size()) { - prevframe = frames[frames.size() - 1]; - } - - UINT frame = CreateCFrame(baseframe, parentframe, point, relativepoint, prevframe ? (IsFrameLayout(prevframe) ? *(UINT*)(prevframe + 0xB0) + 1 : *(UINT*)(prevframe + 0x164) + 1) : 0); - frames.push_back(frame); - - return frame; -} - -void SetFrameText(UINT frame, LPCSTR text) { - if (!frame) { - return; - } - - switch (GetFrameType(frame)) - { - case EditBox: - case GlueEditBoxWar3: - case SlashChatBox: - SetCEditBoxText(frame, NULL, text, 1); - - break; - case TextArea: - SetCTextAreaText(frame, NULL, text); - - break; - case TextButtonFrame: - case GlueTextButtonWar3: - frame = *(UINT*)(frame + 0x1e4); - case TextFrame: - case TimerTextFrame: - SetCTextFrameText(frame, NULL, text); - - break; - } -} - -LPCSTR GetFrameText(UINT frame) { - if (frame) { - switch (GetFrameType(frame)) - { - case EditBox: - case TextButtonFrame: - return *(LPCSTR*)(frame + 0x1e4); - case TextArea: - return *(LPCSTR*)(frame + 0x230); - case GlueTextButtonWar3: - frame = *(UINT*)(frame + 0x1e4); - case TextFrame: - return *(LPCSTR*)(frame + 0x1e8); - } - } - - return ""; -} - -void SetFrameTextColor(UINT frame, BYTE red, BYTE green, BYTE blue, BYTE alpha) { - if (!frame) { - return; - } - - DWORD color = ((alpha << 24) + (red << 16) + (green << 8) + blue); - - switch (GetFrameType(frame)) - { - case TextArea: - frame = *(UINT*)(frame + 0x230); - - break; - case TextButtonFrame: - case GlueTextButtonWar3: - frame = *(UINT*)(frame + 0x1e4); - case TextFrame: - break; - case EditBox: - SetCFrameTextColor(*(UINT*)(frame + 0x254), NULL, &color); - SetCFrameTextColor(*(UINT*)(frame + 0x258), NULL, &color); - default: - return; - } - - SetCFrameTextColor(frame, NULL, &color); -} - -float GetFrameTextHeight(UINT frame) { - if (frame) { - switch (GetFrameType(frame)) - { - case EditBox: - frame = *(UINT*)(frame + 0x254); - - break; - case TextArea: - frame = *(UINT*)(frame + 0x230); - case TextFrame: - break; - case TextButtonFrame: - case GlueTextButtonWar3: - frame = *(UINT*)(frame + 0x1e4); - - break; - default: - return 0.f; - } - - return GetCFrameTextHeight(frame); - } - - return 0.f; -} - -void SetFrameFont(UINT frame, LPCSTR filename, float height, UINT flag) { - if (frame) { - switch (GetFrameType(frame)) - { - case MissingFrame: - break; - case EditBox: - SetCEditBoxFont(frame, NULL, filename, height, flag); - - break; - default: - SetCLayerFont(frame, NULL, filename, height, flag); - - break; - } - } -} - -void SetFrameWidth(UINT frame, float width) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return; - } - - SetCLayoutFrameWidth(layout, NULL, width); -} - -void SetFrameHeight(UINT frame, float height) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return; - } - - SetCLayoutFrameHeight(layout, NULL, height); -} - -void SetFrameSize(UINT frame, float width, float height) { - SetFrameWidth(frame, width); - SetFrameHeight(frame, height); -} - -void SetFrameScale(UINT frame, float scale) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return; - } - - SetCLayoutFrameScale(layout, NULL, scale); -} - -void SetFrameAbsolutePoint(UINT frame, EFramePoint point, float offsetX, float offsetY) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return; - } - - SetCLayoutFrameAbsolutePoint(layout, NULL, point, offsetX, offsetY, 1); -} - -void SetFramePoint(UINT frame, EFramePoint point, UINT relativeframe, EFramePoint relativepoint, float offsetX, float offsetY) { - UINT layout = GetFrameLayout(frame); - UINT relativelayout = GetFrameLayout(relativeframe); - - if (!layout || !relativelayout) { - return; - } - - SetCLayoutFramePoint(layout, NULL, point, relativelayout, relativepoint, offsetX, offsetY, 1); -} - -float GetFrameWidth(UINT frame) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return NULL; - } - - return *(float*)(layout + 0x58); -} - -float GetFrameHeight(UINT frame) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return NULL; - } - - return *(float*)(layout + 0x5c); -} - -UINT GetFramePoint(UINT frame, EFramePoint point) { - UINT layout = GetFrameLayout(frame); - - if (!layout) { - return NULL; - } - - return *(UINT*)(layout + 4 * (UINT)point + 8); -} - -UINT GetFramePointParent(UINT frame, EFramePoint point) { - return *(UINT*)(GetFramePoint(frame, point) + 4); -} - -UINT GetFramePointRelativePoint(UINT frame, EFramePoint point) { - return *(UINT*)(GetFramePoint(frame, point) + 8); -} - -float GetFramePointX(UINT frame, EFramePoint point) { - return *(float*)(GetFramePoint(frame, point) + 12); -} - -float GetFramePointY(UINT frame, EFramePoint point) { - return *(float*)(GetFramePoint(frame, point) + 16); -} - -UINT GetTriggerFrame() { - return triggerFrame; -} - -float GetFrameValue(UINT frame) { - switch (GetFrameType(frame)) - { - case Slider: - return *(float*)(frame + 0x1f4); - case SimpleStatusBar: - return *(float*)(frame + 0x130); - case StatusBar: - return *(float*)(frame + 0x1bc); - } - - return 0.f; -} - -float GetTriggerFrameValue() { - if (triggerEvent == FRAMEEVENT_MOUSE_WHEEL) { - return (float)*pWheelState; - } - - return GetFrameValue(triggerFrame); -} - -void SetFrameValue(UINT frame, float value) { - switch (GetFrameType(frame)) - { - case Slider: - SetCSliderCurrentValue(frame, NULL, value, 1); - - break; - case SimpleStatusBar: - SetCSimpleStatusBarValue(frame, NULL, value); - - break; - case StatusBar: - float min = *(float*)(frame + 0x1b4); - // float max = *(float*)(frame + 0x1b8); - - value = value < min ? min : value; - - *(float*)(frame + 0x1bc) = value; - - break; - } -} - -void SetFrameMinMaxValue(UINT frame, float minValue, float maxValue) { - float value = 0.f; - - switch (GetFrameType(frame)) { - case Slider: - value = *(float*)(frame + 0x1f4); - - *(float*)(frame + 0x1ec) = minValue; - *(float*)(frame + 0x1f0) = maxValue; - - value = value >= minValue ? (value <= maxValue ? value : maxValue) : minValue; - - SetCSliderCurrentValue(frame, NULL, value, 1); - - break; - case SimpleStatusBar: - SetCSimpleStatusBarMinMaxValue(frame, NULL, minValue, maxValue); - - break; - case StatusBar: - SetCStatusBarMinMaxValue(frame, NULL, minValue, maxValue); - - break; - } -} - -void SetFrameStepSize(UINT frame, float stepSize) { - if (GetFrameType(frame) == Slider) { - *(float*)(frame + 0x1f8) = stepSize; - } -} - -void SetFrameTexture(UINT frame, LPCSTR texFile, BOOL flag) { - switch (GetFrameType(frame)) - { - case BackdropFrame: - SetCBackDropFrameTexture(frame, NULL, texFile, NULL, flag, NULL, 1); - - break; - case SimpleStatusBar: - SetCSimpleStatusBarTexture(frame, NULL, texFile, flag); - - break; - case SimpleTexture: - SetCSimpleTextureTexture(frame, NULL, texFile, flag); - - break; - } -} - -void SetFrameEnable(UINT frame, BOOL enabled) { - if (frame) { - SetCControlState(frame, NULL, enabled); - } -} - -void ClickFrame(UINT frame) { - if (frame) { - ClickCFrame(frame, NULL, 1); - } -} - -void SetFrameModel(UINT frame, LPCSTR modelFile, UINT modeltype, BOOL flag) { - switch (GetFrameType(frame)) - { - case ModelFrame: - AddCModelFrameModel(frame, NULL, modelFile, modeltype); - - break; - case SpriteFrame: - SetCSpriteFrameArt(frame, NULL, modelFile, modeltype, flag); - - break; - case StatusBar: - SetCStatusBarArt(frame, NULL, modelFile, modeltype); - - break; - } -} - -void DestroyFrame(UINT frame) { - if (frame) { - for (size_t i = 0; i < frames.size(); i++) { - if (frames[i] == frame) { - frames.erase(frames.begin() + i); - } - } - - auto frameevent = frameEventHashTable.find(frame); - if (frameevent != frameEventHashTable.end()) { - //frameevent->second.clear(); - frameEventHashTable.erase(frameevent); - } - - DestroyCFrame(frame, NULL, 1); - } -} - -void SetFrameVisible(UINT frame, BOOL visible) { - if (frame) { - if (visible) { - ShowCFrame(frame); - } - else { - HideCFrame(frame); - } - } -} - -void SetGameUIVisible(BOOL visible) { - CGameUI* gameui = GetGameUI(0, 0); - - if (visible) { - HideCFrame((UINT)gameui->SimpleConsole); - ShowCFrame((UINT)gameui->TimeOfDayIndicator); - ShowCFrame((UINT)gameui->Portrait); - ShowCFrame((UINT)gameui->Minimap); - - SetFramePoint((UINT)gameui->WorldFrameWar3, FRAMEPOINT_TOPRIGHT, (UINT)gameui, FRAMEPOINT_TOPRIGHT, 0.f, -0.02f); - SetFramePoint((UINT)gameui->WorldFrameWar3, FRAMEPOINT_BOTTOMLEFT, (UINT)gameui, FRAMEPOINT_BOTTOMLEFT, 0.f, 0.13f); - } - else { - ShowCFrame((UINT)gameui->SimpleConsole); - HideCFrame((UINT)gameui->TimeOfDayIndicator); - HideCFrame((UINT)gameui->Portrait); - HideCFrame((UINT)gameui->Minimap); - - SetFramePoint((UINT)gameui->WorldFrameWar3, FRAMEPOINT_TOPRIGHT, (UINT)gameui, FRAMEPOINT_TOPRIGHT, 0.f, 0.f); - SetFramePoint((UINT)gameui->WorldFrameWar3, FRAMEPOINT_BOTTOMLEFT, (UINT)gameui, FRAMEPOINT_BOTTOMLEFT, 0.f, 0.f); - } -} - -void SetFrameCheck(UINT frame, BOOL check) { - if (GetFrameType(frame) == GlueCheckBoxWar3) { - *(BOOL*)(frame + 0x1d4) = *(BOOL*)(frame + 0x1d4) ^ (check << 5); - } -} - -//--------------------------------------------------------- - -BOOL __stdcall eventCallback(UINT frame, UINT eventtype, DWORD eventaddress) { - EFrameEvent event = GetFrameEventType(eventtype); - UINT eventData = *(UINT*)(eventaddress + 0x10); - - switch (event) - { - case FRAMEEVENT_MOUSE_MOVE: - event = eventData ? FRAMEEVENT_MOUSE_ENTER : FRAMEEVENT_MOUSE_LEAVE; - - break; - case FRAMEEVENT_CHECKBOX_CHECK: - event = eventData ? FRAMEEVENT_CHECKBOX_CHECKED : FRAMEEVENT_CHECKBOX_UNCHECKED; - - break; - case FRAMEEVENT_EDITBOX_BUTTON_DOWN: - event = (eventData == 0x201) ? FRAMEEVENT_EDITBOX_ENTER : FRAMEEVENT_EDITBOX_TEXT_CHANGED; - - break; - } - - auto frameevent = frameEventHashTable[frame].find(event); - if (frameevent != frameEventHashTable[frame].end()) { - triggerFrame = frame; - triggerEvent = event; - - UINT trigger = frameevent->second; - if (TriggerEvaluate(trigger)) { - TriggerExecute(trigger); - - return TRUE; - } - - return FALSE; - } - - return -1; -} - -void GameUI_reset() { - frameEventHashTable.clear(); - frames.clear(); - triggerFrame = NULL; - triggerEvent = FRAMEEVENT_NONE; -} \ No newline at end of file diff --git a/Src/GameUI.h b/Src/GameUI.h deleted file mode 100644 index f029b90..0000000 --- a/Src/GameUI.h +++ /dev/null @@ -1,507 +0,0 @@ -#pragma once - -#include -#include -#include - -enum EOriginFrame : UINT { - ORIGIN_FRAME_GAME_UI, - ORIGIN_FRAME_WORLD_FRAME, - ORIGIN_FRAME_HERO_BAR, - ORIGIN_FRAME_HERO_BUTTON, - ORIGIN_FRAME_HERO_HP_BAR, - ORIGIN_FRAME_HERO_MANA_BAR, - ORIGIN_FRAME_HERO_BUTTON_INDICATOR, - ORIGIN_FRAME_ITEM_BUTTON, - ORIGIN_FRAME_COMMAND_BUTTON, - ORIGIN_FRAME_SYSTEM_BUTTON, - ORIGIN_FRAME_PORTRAIT, - ORIGIN_FRAME_MINIMAP, - ORIGIN_FRAME_MINIMAP_BUTTON, - ORIGIN_FRAME_TOOLTIP, - ORIGIN_FRAME_UBERTOOLTIP, - ORIGIN_FRAME_CHAT_MSG, - ORIGIN_FRAME_UNIT_MSG, - ORIGIN_FRAME_TOP_MSG -}; - -enum EFramePoint : UINT { - FRAMEPOINT_TOPLEFT, - FRAMEPOINT_TOP, - FRAMEPOINT_TOPRIGHT, - FRAMEPOINT_LEFT, - FRAMEPOINT_CENTER, - FRAMEPOINT_RIGHT, - FRAMEPOINT_BOTTOMLEFT, - FRAMEPOINT_BOTTOM, - FRAMEPOINT_BOTTOMRIGHT -}; - -enum EFrameType : UINT { - MissingFrame, // Frame doesn't exist - BackdropFrame, - ButtonFrame, - ChatMode, - CommandButton, - CursorFrame, - EditBox, - Frame, - FloatingFrame, - GameUI, - HeroBarButton, - HighlightFrame, - LayoutFrame, - MessageFrame, - Minimap, - ModelFrame, - PortraitButton, - ScreenFrame, - SimpleButton, - SimpleFontString, - SimpleFrame, - SimpleGlueFrame, - Uknown_1, - SimpleMessageFrame, - Slider, - SpriteFrame, - StatBar, - TextArea, - TextButtonFrame, - TextFrame, - UberToolTipWar3, - WorldFrameWar3, - GlueButtonWar3, - GlueTextButtonWar3, - GlueCheckBoxWar3, - GluePopupMenuWar3, - GlueEditBoxWar3, - SlashChatBox, - TimerTextFrame, - SimpleStatusBar, - StatusBar, - UpperButtonBar, - ResourceBar, - SimpleConsole, - PeonBar, - HeroBar, - TimeOfDayIndicator, - InfoBar, - TimeCover, - ProgressIndicator, - HeroLevelBar, - BuildTimeIndicator, - InfoPanelDestructableDetail, - InfoPanelItemDetail, - InfoPanelIconAlly, - InfoPanelIconHero, - InfoPanelIconGold, - InfoPanelIconFood, - InfoPanelIconRank, - InfoPanelIconArmor, - InfoPanelIconDamage, - InfoPanelCargoDetail, - InfoPanelBuildingDetail, - InfoPanelUnitDetail, - SimpleTexture -}; - -EFrameType GetFrameType(UINT frame); - -enum EFrameEvent : UINT { - FRAMEEVENT_NONE, - FRAMEEVENT_CONTROL_CLICK, - FRAMEEVENT_MOUSE_MOVE, - FRAMEEVENT_MOUSE_ENTER = 2, - FRAMEEVENT_MOUSE_LEAVE, - FRAMEEVENT_MOUSE_UP, - FRAMEEVENT_MOUSE_DOWN, - FRAMEEVENT_MOUSE_WHEEL, - FRAMEEVENT_CHECKBOX_CHECK, - FRAMEEVENT_CHECKBOX_CHECKED = 7, - FRAMEEVENT_CHECKBOX_UNCHECKED, - FRAMEEVENT_EDITBOX_BUTTON_DOWN, - FRAMEEVENT_EDITBOX_TEXT_CHANGED = 9, - FRAMEEVENT_POPUPMENU_ITEM_CHANGED, - FRAMEEVENT_MOUSE_DOUBLECLICK, - FRAMEEVENT_SPRITE_ANIM_UPDATE, - FRAMEEVENT_SLIDER_VALUE_CHANGED, - FRAMEEVENT_DIALOG_CANCEL, - FRAMEEVENT_DIALOG_ACCEPT, - FRAMEEVENT_EDITBOX_ENTER -}; - -struct CGameUI { - int FrameType; - int field0004; - int field0008; - int field000C; - int field0010; - int field0014; - int field0018; - int field001C; - int field0020; - int field0024; - int field0028; - int field002C; - int field0030; - int field0034; - int field0038; - int field003C; - int field0040; - int field0044; - int field0048; - int field004C; - int field0050; - int field0054; - int field0058; - int field005C; - int field0060; - int field0064; - int field0068; - int field006C; - int field0070; - int field0074; - int field0078; - int field007C; - int field0080; - int field0084; - int field0088; - int field008C; - int field0090; - int field0094; - int field0098; - int field009C; - int field00A0; - int field00A4; - int field00A8; - int field00AC; - int field00B0; - int LayoutType; - int field00B8; - int field00BC; - int field00C0; - int field00C4; - int field00C8; - int field00CC; - int field00D0; - int field00D4; - int field00D8; - int field00DC; - int field00E0; - int field00E4; - int field00E8; - int field00EC; - int field00F0; - int field00F4; - int field00F8; - int field00FC; - int field0100; - int field0104; - int field0108; - int field010C; - int field0110; - int field0114; - int field0118; - int field011C; - int field0120; - int field0124; - int field0128; - int field012C; - int field0130; - int field0134; - int field0138; - int field013C; - int field0140; - int field0144; - int field0148; - int field014C; - int field0150; - int field0154; - int field0158; - int field015C; - int field0160; - int field0164; - int field0168; - int field016C; - int field0170; - int field0174; - int field0178; - int field017C; - int field0180; - int field0184; - int field0188; - int field018C; - int field0190; - int field0194; - int field0198; - int field019C; - int field01A0; - int field01A4; - int field01A8; - int isUserInputEnabled; - int isUserInterfaceEnabled; - int field01B4; - int field01B8; - int field01BC; - int field01C0; - int field01C4; - int field01C8; - int field01CC; - int field01D0; - int field01D4; - int field01D8; - int field01DC; - int field01E0; - int field01E4; - int field01E8; - int field01EC; - int field01F0; - int field01F4; - int field01F8; - int field01FC; - int field0200; - int field0204; - int field0208; - int field020C; - int field0210; - int field0214; - int field0218; - int field021C; - int field0220; - int field0224; - int field0228; - int field022C; - int field0230; - int field0234; - int field0238; - int field023C; - int field0240; - int field0244; - int field0248; - int field024C; - int field0250; - int Camera; - int isInGameMenu; - int field025C; - int isGamePaused; - int field0264; - int field0268; - int field026C; - int field0270; - int field0274; - int field0278; - int field027C; - int field0280; - int field0284; - int field0288; - int field028C; - int isDragSelectionEnabled; - int isDragSelectionVisible; - int isPreSelectionEnabled; - int isPreSelectionVisible; - int isSelectionEnabled; - int isSelectionVisible; - int field02A8; - int field02AC; - int field02B0; - int field02B4; - int field02B8; - int field02BC; - int field02C0; - int field02C4; - int field02C8; - int field02CC; - int field02D0; - int field02D4; - int field02D8; - int field02DC; - int field02E0; - int field02E4; - int field02E8; - int field02EC; - int field02F0; - int field02F4; - int field02F8; - int field02FC; - int field0300; - int field0304; - int field0308; - int field030C; - float MouseWorldX; // Use from WorldFrame - float MouseWorldY; - float MouseWorldZ; - int field031C; - int field0320; - int field0324; - int field0328; - int field032C; - int field0330; - int field0334; - int field0338; - int field033C; - int field0340; - int field0344; - int field0348; - int field034C; - int field0350; - int field0354; - int field0358; - int field035C; - int field0360; - int field0364; - int field0368; - int field036C; - int field0370; - int field0374; - int field0378; - int field037C; - int field0380; - int field0384; - int field0388; - int field038C; - int field0390; - int field0394; - int field0398; - int field039C; - int field03A0; - int field03A4; - int field03A8; - int field03AC; - int field03B0; - int field03B4; - int field03B8; - CGameUI* WorldFrameWar3; // CWorldFrameWar3* - CGameUI* Minimap; // CFrame* - CGameUI* InfoBar; - CGameUI* CommandBar; - CGameUI* ResourceBarFrame; - CGameUI* UpperButtonBarFrame; - int field03D4; - CGameUI* ClickableBlock; - CGameUI* HeroBar; - CGameUI* PeonBar; - CGameUI* Message; // CSimpleMessageFrame* - CGameUI* UnitMessage; // CSimpleMessageFrame* - CGameUI* ChatMessage; // CSimpleMessageFrame* - CGameUI* TopMessage; // CSimpleMessageFrame* - CGameUI* Portrait; // CFrame* - CGameUI* TimeOfDayIndicator; // CFrame* - CGameUI* ChatEditBar; - CGameUI* CinematicPanel; - int field0404; - CGameUI* MinimapButtons[5]; - CGameUI* FrameB; // CFrame* - CGameUI* MouseBorders; - CGameUI* FrameA; // CFrame* - CGameUI* SimpleConsole; - int QuickSaveHotKey; - int QuickLoadHotKey; - int QuickHelpHotKey; - int QuickOptionsHotKey; - int QuickQuitHotKey; - int MinimapSignalHotKey; - int MinimapTerrainHotKey; - int MinimapColorsHotKey; - int MinimapCreepsHotKey; - int FormationToggleHotKey; -}; - -EFrameType GetFrameType(UINT frame); - -UINT GetFrameLayout(UINT frame); - -CGameUI* GetGameUI(UINT unknown1 = NULL, UINT unknown2 = NULL); - -UINT GetOriginFrame(EOriginFrame originframe, UINT index); - -UINT GetPanelButton(UINT frame, BYTE row, BYTE column); - -UINT GetTooltipFrame(UINT unknown0 = NULL); - -BOOL LoadTOCFile(LPCSTR filename); - -UINT GetFrameByName(LPCSTR framename, UINT id); - -UINT GetFrameParent(UINT frame); - -UINT GetFrameChildrenCount(UINT frame); - -UINT GetFrameChild(UINT frame, UINT index); - -void TriggerRegisterFrameEvent(UINT trigger, UINT frame, EFrameEvent event); - -UINT CreateFrame(LPCSTR baseframe, UINT parentframe, EFramePoint point, EFramePoint relativepoint); - -void SetFrameText(UINT frame, LPCSTR text); - -LPCSTR GetFrameText(UINT frame); - -void SetFrameTextColor(UINT frame, BYTE red, BYTE green, BYTE blue, BYTE alpha); - -float GetFrameTextHeight(UINT frame); - -void SetFrameFont(UINT frame, LPCSTR filename, float height, UINT flag); - -void SetFrameWidth(UINT frame, float width); - -void SetFrameHeight(UINT frame, float height); - -void SetFrameSize(UINT frame, float width, float height); - -void SetFrameScale(UINT frame, float scale); - -void SetFrameAbsolutePoint(UINT frame, EFramePoint point, float offsetX, float offsetY); - -void SetFramePoint(UINT frame, EFramePoint point, UINT relativeframe, EFramePoint relativepoint, float offsetX, float offsetY); - -float GetFrameWidth(UINT frame); - -float GetFrameHeight(UINT frame); - -UINT GetFramePointParent(UINT frame, EFramePoint point); - -UINT GetFramePointRelativePoint(UINT frame, EFramePoint point); - -float GetFramePointX(UINT frame, EFramePoint point); - -float GetFramePointY(UINT frame, EFramePoint point); - -UINT GetTriggerFrame(); - -float GetFrameValue(UINT frame); - -float GetTriggerFrameValue(); - -void SetFrameValue(UINT frame, float value); - -void SetFrameMinMaxValue(UINT frame, float minValue, float maxValue); - -void SetFrameStepSize(UINT frame, float stepSize); - -void SetFrameTexture(UINT frame, LPCSTR texFile, BOOL flag); - -void SetFrameEnable(UINT frame, BOOL enabled); - -void ClickFrame(UINT frame); - -void SetFrameModel(UINT frame, LPCSTR modelFile, UINT modeltype, BOOL flag); - -void DestroyFrame(UINT frame); - -void SetFrameVisible(UINT frame, BOOL visible); - -void SetGameUIVisible(BOOL visible); - -void SetFrameCheck(UINT frame, BOOL check); - -//--------------------------------------------------------- - -BOOL __stdcall eventCallback(UINT frame, UINT eventtype, DWORD eventaddress); - -void GameUI_reset(); - -//--------------------------------------------------------- - -extern std::map> frameEventHashTable; - -extern std::vector frames; \ No newline at end of file diff --git a/Src/Hooks.cpp b/Src/Hooks.cpp index 9a96148..c755208 100644 --- a/Src/Hooks.cpp +++ b/Src/Hooks.cpp @@ -1,134 +1,42 @@ +#include "pch.h" #include "Hooks.h" #include "LuaMachine.h" -#include "GameUI.h" -#include "Global.h" -#include -auto jassEntryPointTrue = (BOOL(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x3b54b0); -auto getWarcraftIDTrue = (DWORD(__stdcall*)())((UINT_PTR)gameBase + 0x537ed0); -auto isFrameHasEventObserverTrue = (BOOL(__fastcall*)(UINT, UINT, UINT, UINT))((UINT_PTR)gameBase + 0x62a580); -auto frameEventCallbackTrue = (BOOL(__fastcall*)(UINT, UINT, DWORD))((UINT_PTR)gameBase + 0x629a90); -auto CreateMatrixPerspectiveFovTrue = (void(__fastcall*)(UINT, UINT, float, float, float, float))((UINT_PTR)gameBase + 0x7b66f0); -auto BuildHPBarsTrue = (void(__fastcall*)(UINT, UINT, UINT, UINT))((UINT_PTR)gameBase + 0x379a30); +#define AttachDetour(pointer, detour) (DetourUpdateThread(GetCurrentThread()), DetourAttach(&(PVOID&)pointer, detour)) +#define DetachDetour(pointer, detour) (DetourUpdateThread(GetCurrentThread()), DetourDetach(&(PVOID&)pointer, detour)) -BOOL __fastcall jassEntryPoint(UINT unknown1) { - return jassEntryPointTrue(unknown1) && startLua(); -} +namespace Hooks { + auto SetJassState = (void(__fastcall*)(BOOL jassState))((std::ptrdiff_t)gameBase + 0x2ab0e0); + auto GetWarcraftID = (DWORD(__stdcall*)())((std::ptrdiff_t)gameBase + 0x537ed0); -DWORD __stdcall getWarcraftID() -{ - return *(DWORD*)GAME_ID; -} - -BOOL __fastcall isFrameHasEventObserver(UINT frame, UINT, UINT eventcode) { - if (frameEventHashTable.find(frame) != frameEventHashTable.end()) { - return TRUE; + DWORD GetWarcraftIDCustom() + { + return *(DWORD*)GAME_ID; } - UINT table = *(DWORD*)(frame + 8); + void __fastcall SetJassStateCustom(BOOL jassState) { + if (jassState == TRUE) { + LuaMachine::StartLua(); + } - if (!table) { - return FALSE; + return SetJassState(jassState); } - return reinterpret_cast((UINT_PTR)gameBase + 0x62a1c0)(table, NULL, eventcode, 0); -} - -BOOL __fastcall frameEventCallback(UINT frame, UINT, DWORD eventaddress) { - UINT eventtype = *(UINT*)(eventaddress + 8); - BOOL result = eventCallback(frame, eventtype, eventaddress); + void AttachHooks() { + DetourTransactionBegin(); - return result == -1 ? reinterpret_cast(*(DWORD*)(*(DWORD*)frame + 0x14))(frame, NULL, eventtype, eventaddress) : result; -} + AttachDetour(SetJassState, SetJassStateCustom); + AttachDetour(GetWarcraftID, GetWarcraftIDCustom); -float wideScreenMul = 1.0f; -void __fastcall CreateMatrixPerspectiveFov(UINT outMatrix, UINT unused, float fovY, float aspectRatio, float nearZ, float farZ) { - RECT rect; - if (gameWindow && GetWindowRect(gameWindow, &rect)) { - float width = float(rect.right - rect.left); - float height = 1.0f / (rect.bottom - rect.top); - wideScreenMul = width * height * 0.75f; + DetourTransactionCommit(); } - float yScale = 1.0f / tan(fovY * 0.5f / sqrt(aspectRatio * aspectRatio + 1.0f)); - float xScale = yScale / (aspectRatio * wideScreenMul); - - *(float*)(outMatrix) = xScale; - *(float*)(outMatrix + 16) = 0.0f; - *(float*)(outMatrix + 32) = 0.0f; - *(float*)(outMatrix + 48) = 0.0f; - - *(float*)(outMatrix + 4) = 0.0f; - *(float*)(outMatrix + 20) = yScale; - *(float*)(outMatrix + 36) = 0.0f; - *(float*)(outMatrix + 52) = 0.0f; - - *(float*)(outMatrix + 8) = 0.0f; - *(float*)(outMatrix + 24) = 0.0f; - *(float*)(outMatrix + 40) = (nearZ + farZ) / (farZ - nearZ); - *(float*)(outMatrix + 56) = (-2.0f * nearZ * farZ) / (farZ - nearZ); - - *(float*)(outMatrix + 12) = 0.0f; - *(float*)(outMatrix + 28) = 0.0f; - *(float*)(outMatrix + 44) = 1.0f; - *(float*)(outMatrix + 60) = 0.0f; -} + void DetachHooks() { + DetourTransactionBegin(); -void __fastcall BuildHPBars(UINT a1, UINT unused, UINT a2, UINT a3) { - BuildHPBarsTrue(a1, unused, a2, a3); + DetachDetour(SetJassState, SetJassStateCustom); + DetachDetour(GetWarcraftID, GetWarcraftIDCustom); - UINT_PTR pHPBarFrame = *((UINT_PTR*)a1 + 3); - if (pHPBarFrame) { - *((float*)pHPBarFrame + 22) /= wideScreenMul; + DetourTransactionCommit(); } -} - -//---------------------------------------------------------------- - -void attachHooks() { - DetourTransactionBegin(); - - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)jassEntryPointTrue, jassEntryPoint); - - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)getWarcraftIDTrue, getWarcraftID); - - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)isFrameHasEventObserverTrue, isFrameHasEventObserver); - - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)frameEventCallbackTrue, frameEventCallback); - - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)CreateMatrixPerspectiveFovTrue, CreateMatrixPerspectiveFov); - - DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)BuildHPBarsTrue, BuildHPBars); - - DetourTransactionCommit(); -} - -void detachHooks() { - DetourTransactionBegin(); - - DetourUpdateThread(GetCurrentThread()); - DetourDetach(&(PVOID&)jassEntryPointTrue, jassEntryPoint); - - DetourUpdateThread(GetCurrentThread()); - DetourDetach(&(PVOID&)getWarcraftIDTrue, getWarcraftID); - - DetourUpdateThread(GetCurrentThread()); - DetourDetach(&(PVOID&)isFrameHasEventObserverTrue, isFrameHasEventObserver); - - DetourUpdateThread(GetCurrentThread()); - DetourDetach(&(PVOID&)frameEventCallbackTrue, frameEventCallback); - - DetourUpdateThread(GetCurrentThread()); - DetourDetach(&(PVOID&)CreateMatrixPerspectiveFovTrue, CreateMatrixPerspectiveFov); - - DetourUpdateThread(GetCurrentThread()); - DetourDetach(&(PVOID&)BuildHPBarsTrue, BuildHPBars); - - DetourTransactionCommit(); } \ No newline at end of file diff --git a/Src/Hooks.h b/Src/Hooks.h index 296f7d8..6b83c14 100644 --- a/Src/Hooks.h +++ b/Src/Hooks.h @@ -1,7 +1,7 @@ #pragma once -#include +namespace Hooks { + void AttachHooks(); -void attachHooks(); - -void detachHooks(); \ No newline at end of file + void DetachHooks(); +} \ No newline at end of file diff --git a/Src/JassMachine.cpp b/Src/JassMachine.cpp index 07310dc..975c360 100644 --- a/Src/JassMachine.cpp +++ b/Src/JassMachine.cpp @@ -1,34 +1,51 @@ +#include "pch.h" #include "JassMachine.h" #include "LuaMachine.h" -#include "Global.h" +#include "fp_call.h" -PVOID** ppOpcodeList = (PVOID**)((UINT_PTR)gameBase + 0x45ea5a); -BYTE* pOpcodeListSize = (BYTE*)((UINT_PTR)gameBase + 0x45ea4d); -PVOID opcodeDefaultOut = (PVOID)((UINT_PTR)gameBase + 0x45f79a); +namespace JassMachine { + PVOID** ppOpcodeList = (PVOID**)((std::ptrdiff_t)gameBase + 0x45ea5a); + BYTE* pOpcodeListSize = (BYTE*)((std::ptrdiff_t)gameBase + 0x45ea4d); + PVOID opcodeDefaultOutput = (PVOID)((std::ptrdiff_t)gameBase + 0x45f79a); -PVOID OPCODE_FUNCTIONS[44]; + PVOID OPCODE_FUNCTIONS[44]; -DWORD _declspec(naked) opcodeStartLuaThread() { - _asm { - push esi - call startLuaThread + DWORD OpcodeStartLuaThread() { + LuaMachine::StartLuaThread(); - push opcodeDefaultOut - ret + return c_call(JassMachine::opcodeDefaultOutput); } -} -void jassOpcodeInitialize() { - memcpy(OPCODE_FUNCTIONS, *ppOpcodeList, sizeof(OPCODE_FUNCTIONS)); + void JassOpcodeInitialize() { + CopyMemory(OPCODE_FUNCTIONS, *ppOpcodeList, sizeof(OPCODE_FUNCTIONS)); - OPCODE_FUNCTIONS[OPTYPE_STARTLUATHREAD - 2] = opcodeStartLuaThread; // My own opcode function + OPCODE_FUNCTIONS[OPTYPE_STARTLUATHREAD - 2] = OpcodeStartLuaThread; // My own opcode function - DWORD dwOldProtect; - VirtualProtect(pOpcodeListSize, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect); - *pOpcodeListSize = sizeof(OPCODE_FUNCTIONS) / 4 - 1; - VirtualProtect(pOpcodeListSize, 1, dwOldProtect, &dwOldProtect); + DWORD dwOldProtect; + VirtualProtect(pOpcodeListSize, sizeof(BYTE), PAGE_EXECUTE_READWRITE, &dwOldProtect); + *pOpcodeListSize = sizeof(OPCODE_FUNCTIONS) / sizeof(PVOID) - 1; + VirtualProtect(pOpcodeListSize, sizeof(BYTE), dwOldProtect, &dwOldProtect); - VirtualProtect(ppOpcodeList, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); - *ppOpcodeList = OPCODE_FUNCTIONS; - VirtualProtect(ppOpcodeList, 4, dwOldProtect, &dwOldProtect); + VirtualProtect(ppOpcodeList, sizeof(PVOID), PAGE_EXECUTE_READWRITE, &dwOldProtect); + *ppOpcodeList = OPCODE_FUNCTIONS; + VirtualProtect(ppOpcodeList, sizeof(PVOID), dwOldProtect, &dwOldProtect); + } + + //----------------------------------------------------------- + + PJASS_THREAD_LOCAL GetJassThreadLocal() { + return (PJASS_THREAD_LOCAL)GetInstance(5); + } + + PJASS_INSTANCE GetJassMachine(UINT index) { + std::ptrdiff_t jass_thread = *(std::ptrdiff_t*)(*(UINT*)((std::ptrdiff_t)GetJassThreadLocal() + 0x90) + index * 4); + + return jass_thread ? (PJASS_INSTANCE)jass_thread : NULL; + } + + PJASS_INSTANCE GetJassInstance() { + HANDLE instance = GetJassThreadLocal(); + + return *(std::ptrdiff_t*)((std::ptrdiff_t)instance + 0x14) ? *(PJASS_INSTANCE*)(*(std::ptrdiff_t*)((std::ptrdiff_t)instance + 0xc) + *(UINT*)((std::ptrdiff_t)instance + 0x14) * 4 - 4) : NULL; + } } \ No newline at end of file diff --git a/Src/JassMachine.h b/Src/JassMachine.h index d196d54..6e8fd23 100644 --- a/Src/JassMachine.h +++ b/Src/JassMachine.h @@ -1,142 +1,274 @@ #pragma once -#include -#include #include "Warcraft.h" +#include "JassNatives.h" -enum OPCODES : UINT { - OPTYPE_ENDPROGRAM = 1, - OPTYPE_OLDJUMP, - OPTYPE_FUNCTION, - OPTYPE_ENDFUNCTION, - OPTYPE_LOCAL, - OPTYPE_GLOBAL, - OPTYPE_CONSTANT, - OPTYPE_FUNCARG, - OPTYPE_EXTENDS, - OPTYPE_TYPE, - OPTYPE_POPN, - OPTYPE_MOVRLITERAL, - OPTYPE_MOVRR, - OPTYPE_MOVRV, - OPTYPE_MOVRCODE, - OPTYPE_MOVRA, - OPTYPE_MOVVR, - OPTYPE_MOVAR, - OPTYPE_PUSH, - OPTYPE_POP, - OPTYPE_CALLNATIVE, - OPTYPE_CALLJASS, - OPTYPE_I2R, - OPTYPE_AND, - OPTYPE_OR, - OPTYPE_EQUAL, - OPTYPE_NOTEQUAL, - OPTYPE_LESSEREQUAL, - OPTYPE_GREATEREQUAL, - OPTYPE_LESSER, - OPTYPE_GREATER, - OPTYPE_ADD, - OPTYPE_SUB, - OPTYPE_MUL, - OPTYPE_DIV, - OPTYPE_MOD, - OPTYPE_NEGATE, - OPTYPE_NOT, - OPTYPE_RETURN, - OPTYPE_LABE, - OPTYPE_JUMPIFTRUE, - OPTYPE_JUMPIFFALSE, - OPTYPE_JUMP, - OPTYPE_STARTLUATHREAD -}; - -enum OPCODE_VARIABLE_TYPE : UINT { - OPCODE_VARIABLE_NOTHING = 0, - OPCODE_VARIABLE_UNKNOWN, - OPCODE_VARIABLE_NULL, - OPCODE_VARIABLE_CODE, - OPCODE_VARIABLE_INTEGER, - OPCODE_VARIABLE_REAL, - OPCODE_VARIABLE_STRING, - OPCODE_VARIABLE_HANDLE, - OPCODE_VARIABLE_BOOLEAN, - OPCODE_VARIABLE_INTEGER_ARRAY, - OPCODE_VARIABLE_REAL_ARRAY, - OPCODE_VARIABLE_STRING_ARRAY, - OPCODE_VARIABLE_HANDLE_ARRAY, - OPCODE_VARIABLE_BOOLEAN_ARRAY -}; - -#ifndef _JassMachine_h -#define _JassMachine_h -typedef struct { - DWORD unk; - DWORD zero1; - DWORD zero2; - DWORD zero3; - DWORD zero4; - DWORD zero5; - DWORD type1; - DWORD type2; - DWORD value; - DWORD zero6; - - void set(DWORD value, OPCODE_VARIABLE_TYPE type) { - this->value = value; - type1 = type; - type2 = type; - } - -} JASS_DATA_SLOT, * PJASS_DATA_SLOT; - -typedef struct { -private: - DWORD unk1; - DWORD unk2; - size_t stack_top; // Idk why it's here - PJASS_DATA_SLOT stack[32]; - size_t size; -public: - PJASS_DATA_SLOT pop() { - return stack[--size]; - } - - PJASS_DATA_SLOT& operator[](size_t index) { - return stack[index]; - } - - void clear(size_t number) { - size = number < size ? size - number : 0; - } - - size_t Size() { - return size; - } -} JASS_STACK, * PJASS_STACK; - -typedef struct { -private: - std::vector oplist; -public: - void addop(BYTE opcode, BYTE reg = 0, DWORD value = NULL, BYTE type = OPCODE_VARIABLE_NOTHING, BYTE rettype = OPCODE_VARIABLE_NOTHING) { - JASS_OPCODE* _opcode = new JASS_OPCODE; - _opcode->rettype = rettype; - _opcode->type = type; - _opcode->reg = reg; - _opcode->opcode = opcode; - _opcode->value = value; - - oplist.push_back(*_opcode); - } - - DWORD getcode() { - return ((DWORD)&oplist - (DWORD)getJassMachine()->code_table->codes) / 4; - } - -} JASS_OPLIST, * PJASS_OPLIST; -#endif - -//--------------------------------------------------------- - -void jassOpcodeInitialize(); \ No newline at end of file +namespace JassMachine { + enum OPCODES : BYTE { + OPTYPE_ENDPROGRAM = 1, + OPTYPE_OLDJUMP, + OPTYPE_FUNCTION, + OPTYPE_ENDFUNCTION, + OPTYPE_LOCAL, + OPTYPE_GLOBAL, + OPTYPE_CONSTANT, + OPTYPE_FUNCARG, + OPTYPE_EXTENDS, + OPTYPE_TYPE, + OPTYPE_POPN, + OPTYPE_MOVRLITERAL, + OPTYPE_MOVRR, + OPTYPE_MOVRV, + OPTYPE_MOVRCODE, + OPTYPE_MOVRA, + OPTYPE_MOVVR, + OPTYPE_MOVAR, + OPTYPE_PUSH, + OPTYPE_POP, + OPTYPE_CALLNATIVE, + OPTYPE_CALLJASS, + OPTYPE_I2R, + OPTYPE_AND, + OPTYPE_OR, + OPTYPE_EQUAL, + OPTYPE_NOTEQUAL, + OPTYPE_LESSEREQUAL, + OPTYPE_GREATEREQUAL, + OPTYPE_LESSER, + OPTYPE_GREATER, + OPTYPE_ADD, + OPTYPE_SUB, + OPTYPE_MUL, + OPTYPE_DIV, + OPTYPE_MOD, + OPTYPE_NEGATE, + OPTYPE_NOT, + OPTYPE_RETURN, + OPTYPE_LABE, + OPTYPE_JUMPIFTRUE, + OPTYPE_JUMPIFFALSE, + OPTYPE_JUMP, + OPTYPE_STARTLUATHREAD + }; + + enum OPCODE_VARIABLE_TYPE : BYTE { + OPCODE_VARIABLE_NOTHING = 0, + OPCODE_VARIABLE_UNKNOWN, + OPCODE_VARIABLE_NULL, + OPCODE_VARIABLE_CODE, + OPCODE_VARIABLE_INTEGER, + OPCODE_VARIABLE_REAL, + OPCODE_VARIABLE_STRING, + OPCODE_VARIABLE_HANDLE, + OPCODE_VARIABLE_BOOLEAN, + OPCODE_VARIABLE_INTEGER_ARRAY, + OPCODE_VARIABLE_REAL_ARRAY, + OPCODE_VARIABLE_STRING_ARRAY, + OPCODE_VARIABLE_HANDLE_ARRAY, + OPCODE_VARIABLE_BOOLEAN_ARRAY + }; + + typedef struct { + DWORD unk; + DWORD zero1; + DWORD zero2; + DWORD zero3; + DWORD zero4; + DWORD zero5; + DWORD type1; + DWORD type2; + DWORD value; + DWORD zero6; + + void Set(DWORD value, OPCODE_VARIABLE_TYPE type) { + this->value = value; + type1 = type; + type2 = type; + } + + } JASS_DATA_SLOT, * PJASS_DATA_SLOT; + + typedef struct { + private: + DWORD unk1; + DWORD unk2; + size_t stack_top; // Idk why it's here + PJASS_DATA_SLOT stack[32]; + size_t size; + public: + PJASS_DATA_SLOT Pop() { + return stack[--size]; + } + + PJASS_DATA_SLOT& operator[](size_t index) { + return stack[index]; + } + + void Clear(size_t number) { + size = number < size ? size - number : 0; + } + + size_t Size() { + return size; + } + } JASS_STACK, * PJASS_STACK; + + typedef struct CStringRep { + uintptr_t vtable; // 0x0 + uint32_t refCount; // 0x4 + uint32_t hash; // 0x8 + PVOID table; // 0xC + CStringRep* prev; // 0x10 + /* txtnode */ + void* prevtxtnode; // 0x14 ? + CStringRep* next; // 0x18 + char* text; // 0x1C + } * PCStringRep;//sizeof = 0x20 + + typedef struct { + uintptr_t vtable; // 0x0 void** + uint32_t unk1; // 0x4 + PCStringRep stringRep; // 0x8 + uint32_t unk2; + } RCString, * PRCString; + + typedef struct { + DWORD unk; + size_t size; + PRCString strings; + + /*DWORD Get(UINT index) { + DWORD result = 0; + + if (index < size) { + result = (DWORD)strings + 0x10 * index; + ++* (DWORD*)(result + 0xC); + } + + return result; + }*/ + RCString& GetRCString(size_t index) { + return strings[index]; + } + + CStringRep& GetCStringRep(size_t index) { + return *(strings[index].stringRep); + } + + LPCSTR GetString(size_t index, bool countRef = true) { + if (countRef) { + strings[index].stringRep->refCount++; + } + + return strings[index].stringRep->text; + } + + } STRING_TABLE, * PSTRING_TABLE; + + typedef struct { + BYTE unk[4]; + size_t counter; + DWORD* codes; // max_size = 1024 + + size_t PushCode(DWORD address) { + codes[counter] = address; + + return counter++; + } + + size_t Size() { + return counter; + } + } CODE_TABLE, * PCODE_TABLE; + + typedef struct { + BYTE returntype; + BYTE type; + BYTE reg; + BYTE opcode; + DWORD value; + } JASS_OPCODE, * PJASS_OPCODE; + + typedef struct { + BYTE unk0[0x20]; // 0x00 + PJASS_OPCODE opcode; // 0x20 + BYTE unk1[0x10]; // 0x24 + UINT has_sleep; // 0x34 + BYTE unk2[0x18]; // 0x38 + JASS_DATA_SLOT condition_return_value; // 0x50 + BYTE unk3[0x27D8]; // 0x54 + size_t index; // 0x2850 + BYTE unk4[0x14]; // 0x2854 + PJASS_STACK stack; // 0x2868 + BYTE unk5[0x8]; + PSTRING_TABLE string_table; // 0x2874 + BYTE unk6[0x10]; + PCODE_TABLE code_table; + BYTE unk7[0x1C]; + } JASS_INSTANCE, * PJASS_INSTANCE; + +#pragma pack(push) +#pragma pack(4) + struct JASS_NATIVE { + uintptr_t vTable; // 0x0 + uintptr_t unk1; // 0x04 + uintptr_t unk2; // 0x08 + uintptr_t unk3; // 0x0c + uintptr_t unk4; // 0x10 + JASS_NATIVE* next; // 0x14 + LPCSTR name; // 0x18 + LPVOID callback; // 0x1c + size_t argCount; // 0x20 + LPCSTR arguments; // 0x24 + size_t maxArgs; // 0x28 + size_t minArgs; // 0x2c + uintptr_t unk5; // 0x30 + uintptr_t unk6; // 0x34 + OPCODE_VARIABLE_TYPE returnType; // 0x38 + }; +#pragma pack(pop) + + typedef struct { + uintptr_t vTable; // 0x00 + uintptr_t unk1; // 0x04 + uintptr_t unk2; // 0x08 + uintptr_t unk3; // 0x0c + uintptr_t unk4; // 0x10 + uintptr_t unk5; // 0x14 + uintptr_t unk6; // 0x18 + uintptr_t unk7; // 0x1c + JASS_NATIVE* lastNative; // 0x20 + JASS_NATIVE* firstNative; // 0x24 + } JASS_THREAD_LOCAL, * PJASS_THREAD_LOCAL; + + PJASS_THREAD_LOCAL GetJassThreadLocal(); + + PJASS_INSTANCE GetJassMachine(UINT index = 1); + + PJASS_INSTANCE GetJassInstance(); + + typedef struct { + private: + std::vector oplist; + public: + void AddOperation(OPCODES opcode, BYTE reg = 0, DWORD value = NULL, OPCODE_VARIABLE_TYPE type = OPCODE_VARIABLE_NOTHING, OPCODE_VARIABLE_TYPE returntype = OPCODE_VARIABLE_NOTHING) { + JASS_OPCODE* _opcode = new JASS_OPCODE; + _opcode->returntype = returntype; + _opcode->type = type; + _opcode->reg = reg; + _opcode->opcode = opcode; + _opcode->value = value; + + oplist.push_back(*_opcode); + } + + DWORD GetCode() { + return ((DWORD)&oplist - (DWORD)GetJassMachine()->code_table->codes) / sizeof(DWORD); + } + + } JASS_OPLIST, * PJASS_OPLIST; + + //--------------------------------------------------------- + + void JassOpcodeInitialize(); +} \ No newline at end of file diff --git a/Src/JassNatives.cpp b/Src/JassNatives.cpp index 6fa2959..306218e 100644 --- a/Src/JassNatives.cpp +++ b/Src/JassNatives.cpp @@ -1,166 +1,146 @@ +#include "pch.h" #include "JassNatives.h" -#include "JassMachine.h" #include "LuaMachine.h" -#include "Global.h" - -std::unordered_map jassnatives; -std::unordered_map triggers; - -#pragma pack(push) -#pragma pack(1) -struct asm_opcode_5 { - BYTE opcode; - DWORD value; -}; -#pragma pack(pop) - -struct asm_register_native_function { -private: - asm_opcode_5 push; - asm_opcode_5 mov_edx; - asm_opcode_5 mov_ecx; - asm_opcode_5 call; -public: - bool verify() { - return ((push.opcode == 0x68) && (mov_edx.opcode == 0xBA) && (mov_ecx.opcode == 0xB9) && (call.opcode == 0xE8)); - } - - PCSTR get_params() { - return (PCSTR)(push.value); - } +#include "JassMachine.h" - PCSTR get_name() { - return (PCSTR)(mov_edx.value); - } +namespace Jass { + std::unordered_map jassnatives; + std::unordered_map jassopcodes; - PVOID get_address() { - return (PVOID)(mov_ecx.value); - } -}; + //--------------------------------------------------------- -UINT GetGroupByHandle(UINT handle) { - return ((UINT(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x3bea30))(handle); -} + UINT ToCode(lua_State* l, int index) { + DWORD key = (DWORD)lua_topointer(l, index); + + auto it = jassopcodes.find(key); -UINT GetTriggerByHandle(UINT handle) { - return ((UINT(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x3bdef0))(handle); -} + if (it != jassopcodes.end()) { + return it->second.GetCode(); + } -UINT GetTimerByHandle(UINT handle) { - return ((UINT(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x3bd710))(handle); -} + JassMachine::JASS_OPLIST& oplist = jassopcodes[key]; -//--------------------------------------------------------- + BYTE reg = 0xD8; + oplist.AddOperation(JassMachine::OPTYPE_MOVRLITERAL, reg, LuaMachine::PushFunctionRef(l, index), JassMachine::OPCODE_VARIABLE_INTEGER); + oplist.AddOperation(JassMachine::OPTYPE_PUSH, reg); + oplist.AddOperation(JassMachine::OPTYPE_STARTLUATHREAD); + oplist.AddOperation(JassMachine::OPTYPE_MOVRR); + oplist.AddOperation(JassMachine::OPTYPE_RETURN); -UINT to_code(lua_State* l, int index, UINT objectHandle) { - DWORD key = (DWORD)lua_topointer(l, index); + return oplist.GetCode(); + } - auto it = triggers.find(key); + //--------------------------------------------------------- - if (it != triggers.end()) { - return it->second.getcode(); - } + JASSNATIVE::JASSNATIVE(LPVOID address, std::string params) : m_address(address) { + for (size_t i = 1; i < params.size(); i++) { + if (params[i] == ')') { + break; + } - JASS_OPLIST& oplist = triggers[key]; + size_t beg = i++; + for (; i < params.size() && !isupper(params[i]) && params[i] != ')'; i++); - BYTE reg = 0xD8; - oplist.addop(OPTYPE_MOVRLITERAL, reg, objectHandle, OPCODE_VARIABLE_INTEGER); - oplist.addop(OPTYPE_PUSH, reg); - oplist.addop(OPTYPE_MOVRLITERAL, reg, pushFunctionRef(l, index), OPCODE_VARIABLE_INTEGER); - oplist.addop(OPTYPE_PUSH, reg); - oplist.addop(OPTYPE_MOVRLITERAL, reg, (DWORD)l, OPCODE_VARIABLE_INTEGER); - oplist.addop(OPTYPE_PUSH, reg); - oplist.addop(OPTYPE_STARTLUATHREAD); - oplist.addop(OPTYPE_MOVRR); - oplist.addop(OPTYPE_RETURN); + std::string type = params.substr(beg, i-- - beg); + if (type[0] == 'H') { + type = type.substr(1, type.size() - 2); - return oplist.getcode(); -} + LuaMachine::handlemetatypes[type] = true; + } -//--------------------------------------------------------- + m_params.push_back(type); + } -JASSNATIVE::JASSNATIVE(LPVOID address, LPCSTR params) : _address(address) { - LPCSTR it = params++; + if (size_t beg = params.find(')') + 1) { + std::string type = params.substr(beg); + if (type[0] == 'H') { + type = type.substr(1, type.size() - 2); - for (; *it; it++) { - if (*it != ')') { - if (isupper(*it)) { - _params.push_back((JASS_TYPE)*it); + LuaMachine::handlemetatypes[type] = true; } - } - else { - break; + + m_returntype = type; } } - _rettype = (JASS_TYPE)*(++it); -} + JASSNATIVE::JASSNATIVE() : m_address(NULL) {} -JASSNATIVE::JASSNATIVE() : _address(NULL), _rettype(TYPE_NONE) {} + bool JASSNATIVE::IsValid() { + return m_address && !m_returntype.empty(); + } -bool JASSNATIVE::is_valid() { - return _rettype != TYPE_NONE; -} + const std::vector& JASSNATIVE::GetParams() { + return m_params; + } -const std::vector& JASSNATIVE::get_params() { - return _params; -} + const std::string& JASSNATIVE::GetReturnType() { + return m_returntype; + } -const JASS_TYPE& JASSNATIVE::get_rettype() { - return _rettype; -} + PVOID JASSNATIVE::GetAddress() { + return m_address; + } -PVOID JASSNATIVE::get_address() { - return _address; -} + DWORD JASSNATIVE::Invoke(LPVOID params, size_t size) { + if (!params && size) { + return NULL; + } -BOOL JASSNATIVE::call(LPVOID params, size_t size) { - PVOID function_address = _address; - size_t params_size = size * sizeof UINT; - LPVOID esp_ptr; + PVOID function_address = m_address; + size_t params_size = size * sizeof UINT; + LPVOID esp_ptr; - BOOL result; + DWORD result; - _asm { - sub esp, params_size - mov esp_ptr, esp - } + _asm { + sub esp, params_size + mov esp_ptr, esp + } - memcpy(esp_ptr, params, params_size); + if (size) { + CopyMemory(esp_ptr, params, params_size); + } - _asm { - call [function_address] - mov result, eax + _asm { + call [function_address] + mov result, eax - mov esp, esp_ptr - add esp, params_size + mov esp, esp_ptr + add esp, params_size + } + + return result; } - return result; -} + //--------------------------------------------------------- -//--------------------------------------------------------- + JASSNATIVE& GetNative(std::string name) { + for (auto& native : jassnatives) { + if (native.first == name) { + return native.second; + } + } -JASSNATIVE invalid; + JASSNATIVE nothing; -JASSNATIVE& get_native(LPCSTR name) { - for (auto& native : jassnatives) { - if (!strcmp(native.first, name)) { - return native.second; - } + return nothing; } - return invalid; -} + void JassNativesParse() { + size_t size = 0; + JassMachine::PJASS_THREAD_LOCAL jassThreadLocal = JassMachine::GetJassThreadLocal(); + for (auto native = jassThreadLocal->firstNative; native < jassThreadLocal->lastNative; native = native->next) { + //printf("%s %s = %d\n", native->name, native->arguments, ++size); + jassnatives[native->name] = JASSNATIVE(native->callback, native->arguments); + } -auto jassNativesList = (asm_register_native_function*)((UINT_PTR)gameBase + 0x3d4025); + } -void jassNativesParse() { - for (asm_register_native_function* ptr = jassNativesList; ptr->verify(); ptr++) { - jassnatives[ptr->get_name()] = JASSNATIVE(ptr->get_address(), ptr->get_params()); + void JassNativesReset() { + std::unordered_map().swap(jassnatives); } -} -void JassNatives_reset() { - triggers.clear(); + void JassOpcodesReset() { + jassopcodes.clear(); + } } \ No newline at end of file diff --git a/Src/JassNatives.h b/Src/JassNatives.h index ea530fc..ecdae18 100644 --- a/Src/JassNatives.h +++ b/Src/JassNatives.h @@ -1,94 +1,85 @@ #pragma once -#include -#include -#include -#include -#include -#include "JassMachine.h" - -enum JASS_TYPE : BYTE { - TYPE_NONE = 0, - TYPE_BOOLEAN = 'B', - TYPE_CODE = 'C', - TYPE_HANDLE = 'H', - TYPE_INTEGER = 'I', - TYPE_REAL = 'R', - TYPE_STRING = 'S', - TYPE_NOTHING = 'V', -}; - -inline UINT to_real(float value) { - return *(UINT*)&value; -} - -inline float from_real(UINT value) { - return *(float*)&value; -} - -inline UINT to_string(LPCSTR string) { - UINT* pString = new UINT[8]; - - pString[2] = (UINT)&pString[0]; - pString[7] = (UINT)&string[0]; - - return (UINT)pString; -} - -inline PCSTR from_string(UINT string) { - if (!string) { - return NULL; +//enum JASS_TYPE : BYTE { +// TYPE_NONE = 0, +// TYPE_BOOLEAN = 'B', +// TYPE_CODE = 'C', +// TYPE_HANDLE = 'H', +// TYPE_INTEGER = 'I', +// TYPE_REAL = 'R', +// TYPE_STRING = 'S', +// TYPE_NOTHING = 'V', +//}; + +namespace Jass { + inline UINT ToReal(float value) { + return *(UINT*)&value; } - string = ((UINT*)string)[2]; + inline float FromReal(UINT value) { + return *(float*)&value; + } + + inline UINT ToString(LPCSTR string) { + return this_call((std::ptrdiff_t)gameBase + 0x3baa20, string); + //return std_call((std::ptrdiff_t)gameBase + 0x454930, string, 0); + /* + UINT* pString = new UINT[8]; + + pString[2] = (UINT)&pString[0]; + pString[7] = (UINT)&string[0]; - if (!string) { - return NULL; + return (UINT)pString;*/ } - return (PCSTR)((UINT*)string)[7]; -} + inline PCSTR FromString(UINT string) { + if (!string) { + return NULL; + } -UINT GetGroupByHandle(UINT handle); -UINT GetTriggerByHandle(UINT handle); -UINT GetTimerByHandle(UINT handle); + string = ((UINT*)string)[2]; -UINT to_code(lua_State* l, int index, UINT objectHandle); + if (!string) { + return NULL; + } -inline DWORD to_ID(LPCSTR lpID) { - return (lpID[0] << 24) + (lpID[1] << 16) + (lpID[2] << 8) + lpID[3]; -} + return (PCSTR)((UINT*)string)[7]; + } + + UINT ToCode(lua_State* l, int index); -//--------------------------------------------------------- + inline DWORD ToID(LPCSTR lpID) { + return (lpID[0] << 24) + (lpID[1] << 16) + (lpID[2] << 8) + lpID[3]; + } -#ifndef _JassNatives_h -#define _JassNatives_h -class JASSNATIVE { -public: - JASSNATIVE(LPVOID address, LPCSTR params); - JASSNATIVE(); + //--------------------------------------------------------- - bool is_valid(); - const std::vector& get_params(); - const JASS_TYPE& get_rettype(); - PVOID get_address(); + class JASSNATIVE { + public: + JASSNATIVE(LPVOID address, std::string params); + JASSNATIVE(); - BOOL call(LPVOID params, size_t size); -private: - PVOID _address; - std::vector _params; - JASS_TYPE _rettype; -}; -#endif + bool IsValid(); + const std::vector& GetParams(); + const std::string& GetReturnType(); + PVOID GetAddress(); -//--------------------------------------------------------- + DWORD Invoke(LPVOID params, size_t size); + private: + PVOID m_address; + std::vector m_params; + std::string m_returntype; + }; -JASSNATIVE& get_native(LPCSTR name); + //--------------------------------------------------------- -void jassNativesParse(); + JASSNATIVE& GetNative(std::string name); -void JassNatives_reset(); + void JassNativesParse(); + void JassNativesReset(); + void JassOpcodesReset(); -//--------------------------------------------------------- + //--------------------------------------------------------- -extern std::unordered_map jassnatives; \ No newline at end of file + extern std::unordered_map jassnatives; +} \ No newline at end of file diff --git a/Src/Logger.cpp b/Src/Logger.cpp new file mode 100644 index 0000000..5a8ea41 --- /dev/null +++ b/Src/Logger.cpp @@ -0,0 +1,117 @@ +#include "pch.h" +#include "Logger.h" + +namespace Logger { + void OpenConsole(std::string name) { + AllocConsole(); + freopen_s((FILE**)stdin, "CONIN$", "r", stdin); + freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); + freopen_s((FILE**)stderr, "CONOUT$", "w", stderr); + + SetConsoleCP(65001); + SetConsoleOutputCP(65001); + + if (!name.empty()) { + SetConsoleTitle(name.c_str()); + } + } + + void CloseConsole() { + fclose(stdin); + fclose(stdout); + fclose(stderr); + FreeConsole(); + } + + void ClearConsole() { + /*fflush(stdout); + fflush(stderr);*/ + + HANDLE hStdOut; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD count; + DWORD cellCount; + COORD homeCoords = { 0, 0 }; + + hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + + if (hStdOut == INVALID_HANDLE_VALUE) { + return; + } + + if (!GetConsoleScreenBufferInfo(hStdOut, &csbi)) { + return; + } + + cellCount = csbi.dwSize.X * csbi.dwSize.Y; + + if (!FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count)) { + return; + } + + if (!FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count)) { + return; + } + + SetConsoleCursorPosition(hStdOut, homeCoords); + } + + void Log(LOG_LEVEL level, std::string format, ...) { + char buffer[8192] = { 0 }; + + va_list args; + va_start(args, format); + vsprintf_s(buffer, format.c_str(), args); + va_end(args); + + HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); + WORD color = NULL; + LPCSTR text = NULL; + + switch (level) + { + case LOG_INFO: + color |= FOREGROUND_GREEN; + text = "Info"; + + break; + case LOG_ERROR: + color |= FOREGROUND_RED; + text = "Error"; + + break; + case LOG_DEBUG: + color |= FOREGROUND_BLUE; + text = "Debug"; + + break; + case LOG_WARNING: + color |= FOREGROUND_RED | FOREGROUND_GREEN; + text = "Warning"; + + break; + } + + if (text) { + std::cout << "["; + SetConsoleTextAttribute(console, color); + std::cout << text; + SetConsoleTextAttribute(console, 15); + std::cout << "] "; + } + + std::cout << buffer << std::endl; + } + + std::string format(std::string format, ...) { + va_list args; + va_start(args, format); + + char buffer[8192]; + vsprintf_s(buffer, format.c_str(), args); + + va_end(args); + + return std::string(buffer); + } +} \ No newline at end of file diff --git a/Src/Logger.h b/Src/Logger.h new file mode 100644 index 0000000..d79b5ba --- /dev/null +++ b/Src/Logger.h @@ -0,0 +1,27 @@ +#pragma once + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define LINE_STRING TOSTRING(__LINE__) + +#define DEBUG_INFO "[" __FILE__ ":" LINE_STRING "]" + +namespace Logger { + enum LOG_LEVEL { + LOG_NONE, + LOG_INFO, + LOG_ERROR, + LOG_DEBUG, + LOG_WARNING + }; + + void OpenConsole(std::string name = ""); + + void CloseConsole(); + + void ClearConsole(); + + void Log(LOG_LEVEL level, std::string format, ...); + + std::string format(std::string format, ...); +} \ No newline at end of file diff --git a/Src/LuaFunctions.cpp b/Src/LuaFunctions.cpp index 3d2bb9d..8f2b807 100644 --- a/Src/LuaFunctions.cpp +++ b/Src/LuaFunctions.cpp @@ -1,1093 +1,399 @@ +#include "pch.h" #include "LuaFunctions.h" #include "JassNatives.h" -#include "GameUI.h" -#include "MemHack.h" -#include "Warcraft.h" -#include "Utils.h" +#include "LuaMachine.h" +#include "JassMachine.h" +#include "Logger.h" #define lua_registerJassNative(L, n, f) (lua_pushstring(L, (n)), lua_pushcclosure(L, (f), 1), lua_setglobal(L, (n))) -#define lua_registerex(L, n, c, f) (lua_pushstring(L, (n)), lua_pushinteger(L, (c)), lua_pushcclosure(L, (f), 2), lua_setglobal(L, (n))) -#define lua_setint(L, n, v) (lua_pushinteger(L, v), lua_setglobal(L, n)) -BOOL checkParams(lua_State* l) { - LPCSTR name = lua_tostring(l, lua_upvalueindex(1)); - int size = (int)lua_tointeger(l, lua_upvalueindex(2)); +std::map destroyers = { + {"DestroyTimer", true}, + {"DestroyGroup", true}, + {"DestroyForce", true}, + {"DestroyTrigger", true}, + {"DestroyCondition", true}, + {"DestroyFiler", true}, + {"DestroyBoolExpr", true}, + {"DestroyFogModifier", true}, + {"DialogDestroy", true}, + {"DestroyUnitPool", true}, + {"DestroyItemPool", true}, + {"DestroyTextTag", true}, + {"DestroyQuest", true}, + {"DestroyDefeatCondition", true}, + {"DestroyTimerDialog", true}, + {"DestroyLeaderboard", true}, + {"DestroyMultiboard", true}, + {"DestroyEffect", true}, + {"DestroyLightning", true}, + {"DestroyImage", true}, + {"DestroyUbersplat", true}, + + {"RemoveRect", true}, + {"RemoveRegion", true}, + {"RemoveLocation", true}, + {"RemoveDestructable", true}, + {"RemoveItem", true}, + {"RemoveUnit", true}, + {"RemoveWeatherEffect", true} +}; + +std::map inheritance = { + { "agent" , "handle" }, + { "event" , "agent" }, + { "player" , "agent" }, + { "widget" , "agent" }, + { "unit" , "widget" }, + { "destructable" , "widget" }, + { "item" , "widget" }, + { "ability" , "agent" }, + { "buff" , "ability" }, + { "force" , "agent" }, + { "group" , "agent" }, + { "trigger" , "agent" }, + { "triggercondition" , "agent" }, + { "triggeraction" , "handle" }, + { "timer" , "agent" }, + { "location" , "agent" }, + { "region" , "agent" }, + { "rect" , "agent" }, + { "boolexpr" , "agent" }, + { "sound" , "agent" }, + { "conditionfunc" , "boolexpr" }, + { "filterfunc" , "boolexpr" }, + { "unitpool" , "handle" }, + { "itempool" , "handle" }, + { "race" , "handle" }, + { "alliancetype" , "handle" }, + { "racepreference" , "handle" }, + { "gamestate" , "handle" }, + { "igamestate" , "gamestate" }, + { "fgamestate" , "gamestate" }, + { "playerstate" , "handle" }, + { "playerscore" , "handle" }, + { "playergameresult" , "handle" }, + { "unitstate" , "handle" }, + { "aidifficulty" , "handle" }, + { "eventid" , "handle" }, + { "gameevent" , "eventid" }, + { "playerevent" , "eventid" }, + { "playerunitevent" , "eventid" }, + { "unitevent" , "eventid" }, + { "limitop" , "eventid" }, + { "widgetevent" , "eventid" }, + { "dialogevent" , "eventid" }, + { "unittype" , "handle" }, + { "gamespeed" , "handle" }, + { "gamedifficulty" , "handle" }, + { "gametype" , "handle" }, + { "mapflag" , "handle" }, + { "mapvisibility" , "handle" }, + { "mapsetting" , "handle" }, + { "mapdensity" , "handle" }, + { "mapcontrol" , "handle" }, + { "playerslotstate" , "handle" }, + { "volumegroup" , "handle" }, + { "camerafield" , "handle" }, + { "camerasetup" , "handle" }, + { "playercolor" , "handle" }, + { "placement" , "handle" }, + { "startlocprio" , "handle" }, + { "raritycontrol" , "handle" }, + { "blendmode" , "handle" }, + { "texmapflags" , "handle" }, + { "effect" , "agent" }, + { "effecttype" , "handle" }, + { "weathereffect" , "handle" }, + { "terraindeformation" , "handle" }, + { "fogstate" , "handle" }, + { "fogmodifier" , "agent" }, + { "dialog" , "agent" }, + { "button" , "agent" }, + { "quest" , "agent" }, + { "questitem" , "agent" }, + { "defeatcondition" , "agent" }, + { "timerdialog" , "agent" }, + { "leaderboard" , "agent" }, + { "multiboard" , "agent" }, + { "multiboarditem" , "agent" }, + { "trackable" , "agent" }, + { "gamecache" , "agent" }, + { "version" , "handle" }, + { "itemtype" , "handle" }, + { "texttag" , "handle" }, + { "attacktype" , "handle" }, + { "damagetype" , "handle" }, + { "weapontype" , "handle" }, + { "soundtype" , "handle" }, + { "lightning" , "handle" }, + { "pathingtype" , "handle" }, + { "image" , "handle" }, + { "ubersplat" , "handle" }, + { "hashtable" , "agent" } +}; + +namespace LuaFunctions { + bool IsChild(const std::string& maintype, std::string childtype) { + do { + if (maintype == childtype) { + return true; + } - if (size > lua_gettop(l)) { - return luaL_error(l, "function '%s' must have %d %s", name, size, size > 1 ? "arguments" : "argument"); - } + childtype = inheritance[childtype]; + } while (!childtype.empty()); - for (int i = 1; i <= size; i++) { - if (lua_isnil(l, i)) { - return luaL_error(l, "Argument number %d of function '%s' mustn't be equal to nil", i, name); - } + return false; } - return FALSE; -} - -//-------------------------------------------------------- -// JassNatives - -int lua_callNative(lua_State* l) { - std::string name = lua_tostring(l, lua_upvalueindex(1)); - JASSNATIVE native = get_native(name.c_str()); + //-------------------------------------------------------- + // JassNatives - if (!native.is_valid()) { - return 0; - } + int lua_invokeNative(lua_State* l) { + std::string name = lua_tostring(l, lua_upvalueindex(1)); + Jass::JASSNATIVE native = Jass::GetNative(name); - int size = native.get_params().size(); - if (size > lua_gettop(l)) { - return luaL_error(l, "function '%s' must have %d %s", name.c_str(), size, size > 1 ? "arguments" : "argument"); - } - - for (int i = 1; i <= size; i++) { - if (lua_isnil(l, i)) { - return luaL_error(l, "Argument number %d of function '%s' mustn't be equal to nil", i, name.c_str()); + if (!native.IsValid()) { + return 0; } - } - - size = lua_gettop(l); - - float* float_params = new float[size]; - DWORD* params = new DWORD[size]; - ZeroMemory(float_params, size); - ZeroMemory(params, size); - UINT i = 1; - - for (const auto& type : native.get_params()) { - switch (type) { - case TYPE_CODE: - if (lua_isinteger(l, i)) { - params[i - 1] = (DWORD)lua_tointeger(l, i); - } - else if (lua_isfunction(l, i)) { - params[i - 1] = to_code(l, i, (UINT)lua_touserdata(l, 1)); - } - - break; - case TYPE_BOOLEAN: - params[i - 1] = (DWORD)lua_toboolean(l, i); - - break; - case TYPE_HANDLE: - params[i - 1] = (DWORD)lua_touserdata(l, i); - - break; - case TYPE_INTEGER: - if (lua_isinteger(l, i)) { - params[i - 1] = (DWORD)lua_tointeger(l, i); + + std::size_t size = native.GetParams().size(); + std::vector floats; + std::vector params; + params.resize(size); + UINT i = 1; + + // Lua parameters -> Jass parameters + for (const auto& type : native.GetParams()) { + if (isupper(type[0])) { + switch (type[0]) { + case 'C': + if (lua_isfunction(l, i)) { + params[i - 1] = Jass::ToCode(l, i); + } + else { + return luaL_typeerror(l, i, "code"); + } + + break; + case 'B': + if (lua_isboolean(l, i)) { + params[i - 1] = (DWORD)lua_toboolean(l, i); + } + else { + return luaL_typeerror(l, i, "boolean"); + } + + break; + case 'I': + if (lua_isinteger(l, i)) { + params[i - 1] = (DWORD)lua_tointeger(l, i); + } + /*else if (lua_isstring(l, i) && strlen(lua_tostring(l, i)) == 4) { + params[i - 1] = Jass::ToID(lua_tostring(l, i)); + }*/ + else { + return luaL_typeerror(l, i, "integer"); + } + + break; + case 'R': { + if (lua_isnumber(l, i)) { + floats.push_back((float)lua_tonumber(l, i)); + params[i - 1] = (DWORD)&floats[floats.size() - 1]; + } + else { + return luaL_typeerror(l, i, "number"); + } + + break; + } + case 'S': + if (lua_isstring(l, i)) { + params[i - 1] = (UINT)&JassMachine::GetJassMachine()->string_table->GetRCString(Jass::ToString(lua_tostring(l, i))); + } + else { + return luaL_typeerror(l, i, "string"); + } + + break; + default: + params[i - 1] = NULL; + + break; + } } else { - params[i - 1] = to_ID(lua_tostring(l, i)); + if (!lua_isnil(l, i)) { + if (luaL_getmetafield(l, i, "__name") != LUA_TSTRING) { + return luaL_typeerror(l, i, type.c_str()); + } + + std::string metatype = std::string(lua_tostring(l, -1)); + lua_pop(l, 1); + + if (IsChild(type, metatype)) { + params[i - 1] = *(DWORD*)lua_touserdata(l, i); + } + else { + return luaL_typeerror(l, i, type.c_str()); + } + } } - break; - case TYPE_REAL: { - float_params[i - 1] = (float)lua_tonumber(l, i); - params[i - 1] = (DWORD)&(float_params[i - 1]); - - break; - } - case TYPE_STRING: - params[i - 1] = to_string(cp1251_to_utf8(lua_tostring(l, i)).c_str()); - - break; - default: - params[i - 1] = NULL; - - break; + i++; } - i++; - } - - BOOL result = native.call(params, size); - delete[] float_params; - delete[] params; - - switch (native.get_rettype()) { - case TYPE_BOOLEAN: - lua_pushboolean(l, result); - - break; - case TYPE_INTEGER: - if (name == "GetUnitTypeId" || name == "GetSpellAbilityId" || name == "GetItemTypeId") { - std::swap(((LPSTR)&result)[0], ((LPSTR)&result)[3]); - std::swap(((LPSTR)&result)[1], ((LPSTR)&result)[2]); - lua_pushlstring(l, (LPSTR)&result, 4); - } - else { - lua_pushinteger(l, result); + if (name == "Player" && (int)params[0] < 0) { + return luaL_error(l, "player expected positive index, received: %d", params[0]); } - break; - case TYPE_CODE: - lua_pushinteger(l, result); - - break; - case TYPE_HANDLE: - lua_pushlightuserdata(l, (PVOID)result); - - break; - case TYPE_REAL: - lua_pushnumber(l, from_real(result)); - - break; - case TYPE_STRING: - lua_pushstring(l, utf8_to_cp1251(from_string(getJassMachine()->string_table->get(result))).c_str()); - - break; - } - - return native.get_rettype() != TYPE_NOTHING ? 1 : 0; -} - -//-------------------------------------------------------- - -void lua_openJassNatives(lua_State* l) { - for (const auto& native : jassnatives) { - lua_registerJassNative(l, native.first, lua_callNative); - } -} - -//-------------------------------------------------------- -// MouseAPI - -//-------------------------------------------------------- - -//-------------------------------------------------------- -// FrameAPI - -int lua_SetUnitArmor(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitArmor((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_GetUnitArmor(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetUnitArmor((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetUnitMaxLife(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetUnitMaxLife((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetUnitMaxLife(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitMaxLife((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_GetUnitMaxMana(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetUnitMaxMana((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetUnitMaxMana(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitMaxMana((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_GetUnitLifeRegen(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetUnitLifeRegen((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetUnitLifeRegen(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitLifeRegen((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_GetUnitManaRegen(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetUnitManaRegen((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetUnitManaRegen(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitManaRegen((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_GetUnitBaseDamage(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushinteger(l, GetUnitBaseDamage((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetUnitBaseDamage(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitBaseDamage((UINT)lua_touserdata(l, 1), (UINT)lua_tointeger(l, 2)); - - return 0; -} - -int lua_GetUnitAttackSpeed(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetUnitAttackSpeed((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetUnitAttackSpeed(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetUnitAttackSpeed((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_UnitResetAttackCooldown(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushboolean(l, UnitResetAttackCooldown((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetItemBaseNameById(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushstring(l, utf8_to_cp1251(GetItemBaseNameById(to_ID(lua_tostring(l, 1)))).c_str()); - - return 1; -} - -int lua_SetItemBaseNameById(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetItemBaseNameById(to_ID(lua_tostring(l, 1)), cp1251_to_utf8(lua_tostring(l, 2)).c_str()); - - return 0; -} - -int lua_GetItemBaseUbertipById(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushstring(l, utf8_to_cp1251(GetItemBaseUbertipById(to_ID(lua_tostring(l, 1)))).c_str()); - - return 1; -} - -int lua_SetItemBaseUbertipById(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetItemBaseUbertipById(to_ID(lua_tostring(l, 1)), cp1251_to_utf8(lua_tostring(l, 2)).c_str()); - - return 0; -} - -int lua_GetItemBaseIconPathById(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushstring(l, utf8_to_cp1251(GetItemBaseIconPathById(to_ID(lua_tostring(l, 1)))).c_str()); - - return 1; -} - -int lua_SetItemBaseIconPathById(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetItemBaseIconPathById(to_ID(lua_tostring(l, 1)), cp1251_to_utf8(lua_tostring(l, 2)).c_str()); - - return 0; -} - -int lua_GetMouseWorldPos(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - PVECTOR3 mousePos = GetMouseWorldPos(); - - lua_pushnumber(l, mousePos->_x); - lua_pushnumber(l, mousePos->_y); - lua_pushnumber(l, mousePos->_z); - - return 3; -} - -int lua_GetMouseWorldX(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetMouseWorldX()); - - return 1; -} - -int lua_GetMouseWorldY(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetMouseWorldY()); - - return 1; -} - -int lua_GetMouseWorldZ(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetMouseWorldZ()); - - return 1; -} - -int lua_GetEffectPos(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - PVECTOR3 objectPos = GetEffectPos((UINT)lua_touserdata(l, 1)); - - lua_pushnumber(l, objectPos->_x); - lua_pushnumber(l, objectPos->_y); - lua_pushnumber(l, objectPos->_z); - - return 3; -} - -int lua_GetEffectX(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetEffectPos((UINT)lua_touserdata(l, 1))->_x); - - return 1; -} - -int lua_GetEffectY(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetEffectPos((UINT)lua_touserdata(l, 1))->_y); - - return 1; -} - -int lua_GetEffectZ(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetEffectPos((UINT)lua_touserdata(l, 1))->_z); - - return 1; -} - -int lua_SetEffectPos(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - UINT_PTR object = (UINT)lua_touserdata(l, 1); - - switch (lua_gettop(l)) - { - case 2: - SetEffectX(object, (float)lua_tonumber(l, 2)); - - break; - case 3: - SetEffectX(object, (float)lua_tonumber(l, 2)); - SetEffectY(object, (float)lua_tonumber(l, 3)); - - break; - case 4: - SetEffectPos(object, VECTOR3((float)lua_tonumber(l, 2), (float)lua_tonumber(l, 3), (float)lua_tonumber(l, 4))); - - break; - } - - return 0; -} - -int lua_SetEffectX(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetEffectX((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_SetEffectY(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetEffectY((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_SetEffectZ(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetEffectZ((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -//-------------------------------------------------------- - -//-------------------------------------------------------- -// FrameAPI - -int lua_GetOriginFrame(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushlightuserdata(l, (PVOID)GetOriginFrame((EOriginFrame)lua_tointeger(l, 1), (UINT)lua_tointeger(l, 2))); - - return 1; -} - -int lua_LoadTOCFile(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushboolean(l, LoadTOCFile(cp1251_to_utf8(lua_tostring(l, 1)).c_str())); - - return 1; -} - -int lua_GetFrameByName(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushlightuserdata(l, (PVOID)GetFrameByName(cp1251_to_utf8(lua_tostring(l, 1)).c_str(), (UINT)lua_tointeger(l, 2))); - - return 1; -} - -int lua_GetFrameParent(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushlightuserdata(l, (PVOID)GetFrameParent((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetFrameChildrenCount(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushinteger(l, GetFrameChildrenCount((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetFrameChild(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushlightuserdata(l, (PVOID)GetFrameChild((UINT)lua_touserdata(l, 1), (UINT)lua_tointeger(l, 2))); - - return 1; -} - -int lua_TriggerRegisterFrameEvent(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - TriggerRegisterFrameEvent((UINT)lua_touserdata(l, 1), (UINT)lua_touserdata(l, 2), (EFrameEvent)lua_tointeger(l, 3)); - - return 0; -} - -int lua_CreateFrame(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushlightuserdata(l, (PVOID)CreateFrame(cp1251_to_utf8(lua_tostring(l, 1)).c_str(), (UINT)lua_touserdata(l, 2), (EFramePoint)lua_tointeger(l, 3), (EFramePoint)lua_tointeger(l, 4) /*(UINT)lua_tointeger(l, 5)*/)); - - return 1; -} - -int lua_SetFrameText(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameText((UINT)lua_touserdata(l, 1), cp1251_to_utf8(lua_tostring(l, 2)).c_str()); - - return 0; -} - -int lua_GetFrameText(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushstring(l, utf8_to_cp1251(GetFrameText((UINT)lua_touserdata(l, 1))).c_str()); - - return 1; -} - -int lua_SetFrameTextColor(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameTextColor((UINT)lua_touserdata(l, 1), (BYTE)lua_tointeger(l, 2), (BYTE)lua_tointeger(l, 3), (BYTE)lua_tointeger(l, 4), (BYTE)lua_tointeger(l, 5)); - - return 0; -} - -int lua_GetFrameTextHeight(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetFrameTextHeight((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_SetFrameWidth(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameWidth((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_SetFrameHeight(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameHeight((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_SetFrameSize(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameSize((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2), (float)lua_tonumber(l, 3)); + BOOL result = native.Invoke(params.data(), size); - return 0; -} -int lua_SetFrameScale(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameScale((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} - -int lua_SetFrameAbsolutePoint(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameAbsolutePoint((UINT)lua_touserdata(l, 1), (EFramePoint)lua_tointeger(l, 2), (float)lua_tonumber(l, 3), (float)lua_tonumber(l, 4)); - - return 0; -} - -int lua_SetFramePoint(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFramePoint((UINT)lua_touserdata(l, 1), (EFramePoint)lua_tointeger(l, 2), (UINT)lua_touserdata(l, 3), (EFramePoint)lua_tointeger(l, 4), (float)lua_tonumber(l, 5), (float)lua_tonumber(l, 6)); - - return 0; -} - -int lua_GetFrameWidth(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetFrameWidth((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetFrameHeight(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetFrameHeight((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetFramePointParent(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushinteger(l, GetFramePointParent((UINT)lua_touserdata(l, 1), (EFramePoint)lua_tointeger(l, 2))); - - return 1; -} - -int lua_GetFramePointRelativePoint(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushinteger(l, GetFramePointRelativePoint((UINT)lua_touserdata(l, 1), (EFramePoint)lua_tointeger(l, 2))); - - return 1; -} - -int lua_GetFramePointX(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetFramePointX((UINT)lua_touserdata(l, 1), (EFramePoint)lua_tointeger(l, 2))); + // Jass return -> Lua return + std::string return_type = native.GetReturnType(); + if (isupper(return_type[0])) { + switch (return_type[0]) { + case 'B': + lua_pushboolean(l, result); - return 1; -} + break; + case 'I': + lua_pushinteger(l, result); -int lua_GetFramePointY(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - lua_pushnumber(l, GetFramePointY((UINT)lua_touserdata(l, 1), (EFramePoint)lua_tointeger(l, 2))); + break; + case 'C': + lua_pushinteger(l, result); - return 1; -} + break; + case 'R': + lua_pushnumber(l, Jass::FromReal(result)); -int lua_GetTriggerFrame(lua_State* l) { - lua_pushlightuserdata(l, (PVOID)GetTriggerFrame()); + break; + case 'S': + lua_pushstring(l, JassMachine::GetJassMachine()->string_table->GetString(result)); + //lua_pushstring(l, Jass::FromString(JassMachine::GetJassMachine()->string_table->Get(result))); - return 1; -} + break; + default: + return 0; + } + } + else { + result ? *(DWORD*)lua_newuserdata(l, sizeof(DWORD)) = result, luaL_setmetatable(l, return_type.c_str()) : lua_pushnil(l); + /*if (result) { + *(DWORD*)lua_newuserdata(l, sizeof(DWORD)) = result; + luaL_setmetatable(l, return_type.c_str()); + } + else { + lua_pushnil(l); + }*/ + } -int lua_GetFrameValue(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + return 1; } - lua_pushnumber(l, GetFrameValue((UINT)lua_touserdata(l, 1))); - - return 1; -} - -int lua_GetTriggerFrameValue(lua_State* l) { - lua_pushnumber(l, GetTriggerFrameValue()); + //-------------------------------------------------------- - return 1; -} + int lua_handleequal(lua_State* l) { + PDWORD param1 = (PDWORD)lua_touserdata(l, 1); + PDWORD param2 = (PDWORD)lua_touserdata(l, 2); -int lua_SetFrameValue(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } - - SetFrameValue((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); - - return 0; -} + lua_pushboolean(l, (param1 ? *param1 : NULL) == (param2 ? *param2 : NULL)); -int lua_SetFrameMinMaxValue(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + return 1; } - SetFrameMinMaxValue((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2), (float)lua_tonumber(l, 3)); - - return 0; -} - -int lua_SetFrameStepSize(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } + int lua_handletostring(lua_State* l) { + lua_getmetatable(l, 1); + lua_getfield(l, 2, "__name"); - SetFrameStepSize((UINT)lua_touserdata(l, 1), (float)lua_tonumber(l, 2)); + UINT handle = *(UINT*)lua_touserdata(l, 1); - return 0; -} + std::string string = Logger::format("%s: %08X", lua_tostring(l, 3), handle); + if (developerMode && handle > 0x100000) { + string += Logger::format(" | %08X", ConvertHandle(handle)); + } -int lua_SetFrameTexture(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + lua_pop(l, 2); + + lua_pushstring(l, string.c_str()); + + return 1; } - SetFrameTexture((UINT)lua_touserdata(l, 1), cp1251_to_utf8(lua_tostring(l, 2)).c_str(), lua_toboolean(l, 3)); - - return 0; -} + int lua_close(lua_State* l) { + *(DWORD*)lua_touserdata(l, 1) = NULL; -int lua_SetFrameEnable(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + return 0; } - SetFrameEnable((UINT)lua_touserdata(l, 1), lua_toboolean(l, 2)); + int IdToString(lua_State* l) { + if (lua_isinteger(l, 1)) { + DWORD id = (DWORD)lua_tointeger(l, 1); + std::reverse(&(((LPSTR)&id)[0]), &(((LPSTR)&id)[4])); + lua_pushlstring(l, (LPSTR)&id, 4); + } + else { + return luaL_typeerror(l, 1, "integer"); + } - return 0; -} -int lua_ClickFrame(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + return 1; } - ClickFrame((UINT)lua_touserdata(l, 1)); - - return 0; -} + int StringToId(lua_State* l) { + if (lua_isstring(l, 1)) { + lua_pushinteger(l, Jass::ToID(lua_tostring(l, 1))); + } + else { + return luaL_typeerror(l, 1, "string"); + } -int lua_SetFrameModel(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + return 1; } - SetFrameModel((UINT)lua_touserdata(l, 1), cp1251_to_utf8(lua_tostring(l, 2)).c_str(), (UINT)lua_tointeger(l, 3), (BOOL)lua_toboolean(l, 4)); - - return 0; -} + int FourCC(lua_State* l) { + if (lua_isinteger(l, 1)) { + IdToString(l); + } + else if (lua_isstring(l, 1)) { + StringToId(l); + } + else { + return luaL_typeerror(l, 1, "string or integer"); + } -int lua_DestroyFrame(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + return 1; } - DestroyFrame((UINT)lua_touserdata(l, 1)); - - return 0; -} - -int lua_SetFrameVisible(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } + void lua_openJassNatives(lua_State* l) { + Jass::JassNativesReset(); + LuaMachine::HandleMetatablesReset(); + Jass::JassNativesParse(); - SetFrameVisible((UINT)lua_touserdata(l, 1), (BOOL)lua_toboolean(l, 2)); + for (const auto& type : LuaMachine::handlemetatypes) { + if (luaL_newmetatable(l, type.first.c_str())) { + lua_pushcfunction(l, lua_handleequal); + lua_setfield(l, -2, "__eq"); - return 0; -} + lua_pushcfunction(l, lua_handletostring); + lua_setfield(l, -2, "__tostring"); -int lua_SetGameUIVisible(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; - } + lua_pushstring(l, type.first.c_str()); + lua_setfield(l, -2, "__metatable"); - SetGameUIVisible((BOOL)lua_toboolean(l, 1)); + lua_pop(l, 1); + } + } - return 0; -} + for (const auto& native : Jass::jassnatives) { + lua_registerJassNative(l, native.first.c_str(), lua_invokeNative); + } -int lua_SetFrameCheck(lua_State* l) { - BOOL error = checkParams(l); - if (error) { - return error; + lua_register(l, "IdToString", IdToString); + lua_register(l, "StringToId", StringToId); + lua_register(l, "FourCC", FourCC); } - - SetFrameCheck((UINT)lua_touserdata(l, 1), (BOOL)lua_toboolean(l, 2)); - - return 0; -} - -//-------------------------------------------------------- - -int GetTrigger(lua_State* l) { - lua_pushlightuserdata(l, (PVOID)GetTimerByHandle((UINT)lua_touserdata(l, 1))); - - return 1; -} - -void lua_openMemHackAPI(lua_State* l) { - lua_registerex(l, "GetUnitArmor", 1, lua_GetUnitArmor); - lua_registerex(l, "SetUnitArmor", 2, lua_SetUnitArmor); - lua_registerex(l, "GetUnitMaxLife", 1, lua_GetUnitMaxLife); - lua_registerex(l, "SetUnitMaxLife", 2, lua_SetUnitMaxLife); - lua_registerex(l, "GetUnitMaxMana", 1, lua_GetUnitMaxMana); - lua_registerex(l, "SetUnitMaxMana", 2, lua_SetUnitMaxMana); - lua_registerex(l, "GetUnitLifeRegen", 1, lua_GetUnitLifeRegen); - lua_registerex(l, "SetUnitLifeRegen", 2, lua_SetUnitLifeRegen); - lua_registerex(l, "GetUnitManaRegen", 1, lua_GetUnitManaRegen); - lua_registerex(l, "SetUnitManaRegen", 2, lua_SetUnitManaRegen); - lua_registerex(l, "GetUnitBaseDamage", 1, lua_GetUnitBaseDamage); - lua_registerex(l, "SetUnitBaseDamage", 2, lua_SetUnitBaseDamage); - lua_registerex(l, "GetUnitAttackSpeed", 1, lua_GetUnitAttackSpeed); - lua_registerex(l, "SetUnitAttackSpeed", 2, lua_SetUnitAttackSpeed); - lua_registerex(l, "UnitResetAttackCooldown", 1, lua_UnitResetAttackCooldown); - lua_registerex(l, "GetItemBaseNameById", 1, lua_GetItemBaseNameById); - lua_registerex(l, "SetItemBaseNameById", 2, lua_SetItemBaseNameById); - lua_registerex(l, "GetItemBaseUbertipById", 1, lua_GetItemBaseUbertipById); - lua_registerex(l, "SetItemBaseUbertipById", 2, lua_SetItemBaseUbertipById); - lua_registerex(l, "GetItemBaseIconPathById", 1, lua_GetItemBaseIconPathById); - lua_registerex(l, "SetItemBaseIconPathById", 2, lua_SetItemBaseIconPathById); - lua_registerex(l, "GetMouseWorldPos", 0, lua_GetMouseWorldPos); - lua_registerex(l, "GetMouseWorldX", 0, lua_GetMouseWorldX); - lua_registerex(l, "GetMouseWorldY", 0, lua_GetMouseWorldY); - lua_registerex(l, "GetMouseWorldZ", 0, lua_GetMouseWorldZ); - lua_registerex(l, "GetEffectPos", 1, lua_GetEffectPos); - lua_registerex(l, "GetEffectX", 1, lua_GetEffectX); - lua_registerex(l, "GetEffectY", 1, lua_GetEffectY); - lua_registerex(l, "GetEffectZ", 1, lua_GetEffectZ); - lua_registerex(l, "SetEffectPos", 2, lua_SetEffectPos); - lua_registerex(l, "SetEffectX", 2, lua_SetEffectX); - lua_registerex(l, "SetEffectY", 2, lua_SetEffectY); - lua_registerex(l, "SetEffectZ", 2, lua_SetEffectZ); -} - -void lua_openFrameAPI(lua_State* l) { - lua_setint(l, "ORIGIN_FRAME_GAME_UI", ORIGIN_FRAME_GAME_UI); - lua_setint(l, "ORIGIN_FRAME_WORLD_FRAME", ORIGIN_FRAME_WORLD_FRAME); - lua_setint(l, "ORIGIN_FRAME_HERO_BAR", ORIGIN_FRAME_HERO_BAR); - lua_setint(l, "ORIGIN_FRAME_HERO_BUTTON", ORIGIN_FRAME_HERO_BUTTON); - lua_setint(l, "ORIGIN_FRAME_HERO_HP_BAR", ORIGIN_FRAME_HERO_HP_BAR); - lua_setint(l, "ORIGIN_FRAME_HERO_MANA_BAR", ORIGIN_FRAME_HERO_MANA_BAR); - lua_setint(l, "ORIGIN_FRAME_HERO_BUTTON_INDICATOR", ORIGIN_FRAME_HERO_BUTTON_INDICATOR); - lua_setint(l, "ORIGIN_FRAME_ITEM_BUTTON", ORIGIN_FRAME_ITEM_BUTTON); - lua_setint(l, "ORIGIN_FRAME_COMMAND_BUTTON", ORIGIN_FRAME_COMMAND_BUTTON); - lua_setint(l, "ORIGIN_FRAME_SYSTEM_BUTTON", ORIGIN_FRAME_SYSTEM_BUTTON); - lua_setint(l, "ORIGIN_FRAME_PORTRAIT", ORIGIN_FRAME_PORTRAIT); - lua_setint(l, "ORIGIN_FRAME_MINIMAP", ORIGIN_FRAME_MINIMAP); - lua_setint(l, "ORIGIN_FRAME_MINIMAP_BUTTON", ORIGIN_FRAME_MINIMAP_BUTTON); - lua_setint(l, "ORIGIN_FRAME_TOOLTIP", ORIGIN_FRAME_TOOLTIP); - lua_setint(l, "ORIGIN_FRAME_UBERTOOLTIP", ORIGIN_FRAME_UBERTOOLTIP); - lua_setint(l, "ORIGIN_FRAME_CHAT_MSG", ORIGIN_FRAME_CHAT_MSG); - lua_setint(l, "ORIGIN_FRAME_UNIT_MSG", ORIGIN_FRAME_UNIT_MSG); - lua_setint(l, "ORIGIN_FRAME_TOP_MSG", ORIGIN_FRAME_TOP_MSG); - - lua_setint(l, "FRAMEPOINT_TOPLEFT", FRAMEPOINT_TOPLEFT); - lua_setint(l, "FRAMEPOINT_TOP", FRAMEPOINT_TOP); - lua_setint(l, "FRAMEPOINT_TOPRIGHT", FRAMEPOINT_TOPRIGHT); - lua_setint(l, "FRAMEPOINT_LEFT", FRAMEPOINT_LEFT); - lua_setint(l, "FRAMEPOINT_CENTER", FRAMEPOINT_CENTER); - lua_setint(l, "FRAMEPOINT_RIGHT", FRAMEPOINT_RIGHT); - lua_setint(l, "FRAMEPOINT_BOTTOMLEFT", FRAMEPOINT_BOTTOMLEFT); - lua_setint(l, "FRAMEPOINT_BOTTOM", FRAMEPOINT_BOTTOM); - lua_setint(l, "FRAMEPOINT_BOTTOMRIGHT", FRAMEPOINT_BOTTOMRIGHT); - - lua_setint(l, "FRAMEEVENT_CONTROL_CLICK", FRAMEEVENT_CONTROL_CLICK); - lua_setint(l, "FRAMEEVENT_MOUSE_ENTER", FRAMEEVENT_MOUSE_ENTER); - lua_setint(l, "FRAMEEVENT_MOUSE_LEAVE", FRAMEEVENT_MOUSE_LEAVE); - lua_setint(l, "FRAMEEVENT_MOUSE_UP", FRAMEEVENT_MOUSE_UP); - lua_setint(l, "FRAMEEVENT_MOUSE_DOWN", FRAMEEVENT_MOUSE_DOWN); - lua_setint(l, "FRAMEEVENT_MOUSE_WHEEL", FRAMEEVENT_MOUSE_WHEEL); - lua_setint(l, "FRAMEEVENT_CHECKBOX_CHECKED", FRAMEEVENT_CHECKBOX_CHECKED); - lua_setint(l, "FRAMEEVENT_CHECKBOX_UNCHECKED", FRAMEEVENT_CHECKBOX_UNCHECKED); - lua_setint(l, "FRAMEEVENT_EDITBOX_TEXT_CHANGED", FRAMEEVENT_EDITBOX_TEXT_CHANGED); - lua_setint(l, "FRAMEEVENT_POPUPMENU_ITEM_CHANGED", FRAMEEVENT_POPUPMENU_ITEM_CHANGED); - lua_setint(l, "FRAMEEVENT_MOUSE_DOUBLECLICK", FRAMEEVENT_MOUSE_DOUBLECLICK); - lua_setint(l, "FRAMEEVENT_SPRITE_ANIM_UPDATE", FRAMEEVENT_SPRITE_ANIM_UPDATE); - lua_setint(l, "FRAMEEVENT_SLIDER_VALUE_CHANGED", FRAMEEVENT_SLIDER_VALUE_CHANGED); - lua_setint(l, "FRAMEEVENT_DIALOG_CANCEL", FRAMEEVENT_DIALOG_CANCEL); - lua_setint(l, "FRAMEEVENT_DIALOG_ACCEPT", FRAMEEVENT_DIALOG_ACCEPT); - lua_setint(l, "FRAMEEVENT_EDITBOX_ENTER", FRAMEEVENT_EDITBOX_ENTER); - - lua_registerex(l, "GetOriginFrame", 2, lua_GetOriginFrame); - lua_registerex(l, "LoadTOCFile", 1, lua_LoadTOCFile); - lua_registerex(l, "GetFrameByName", 2, lua_GetFrameByName); - lua_registerex(l, "GetFrameParent", 1, lua_GetFrameParent); - lua_registerex(l, "GetFrameChildrenCount", 1, lua_GetFrameChildrenCount); - lua_registerex(l, "GetFrameChild", 2, lua_GetFrameChild); - lua_registerex(l, "TriggerRegisterFrameEvent", 3, lua_TriggerRegisterFrameEvent); - lua_registerex(l, "CreateFrame", 4, lua_CreateFrame); - lua_registerex(l, "SetFrameText", 2, lua_SetFrameText); - lua_registerex(l, "GetFrameText", 1, lua_GetFrameText); - lua_registerex(l, "SetFrameTextColor", 5, lua_SetFrameTextColor); - lua_registerex(l, "GetFrameTextHeight", 1, lua_GetFrameTextHeight); - lua_registerex(l, "SetFrameWidth", 2, lua_SetFrameWidth); - lua_registerex(l, "SetFrameHeight", 2, lua_SetFrameHeight); - lua_registerex(l, "SetFrameSize", 3, lua_SetFrameSize); - lua_registerex(l, "SetFrameScale", 2, lua_SetFrameScale); - lua_registerex(l, "SetFrameAbsolutePoint", 4, lua_SetFrameAbsolutePoint); - lua_registerex(l, "SetFramePoint", 6, lua_SetFramePoint); - lua_registerex(l, "GetFrameWidth", 1, lua_GetFrameWidth); - lua_registerex(l, "GetFrameHeight", 1, lua_GetFrameHeight); - lua_registerex(l, "GetFramePointParent", 2, lua_GetFramePointParent); - lua_registerex(l, "GetFramePointRelativePoint", 2, lua_GetFramePointRelativePoint); - lua_registerex(l, "GetFramePointX", 2, lua_GetFramePointX); - lua_registerex(l, "GetFramePointY", 2, lua_GetFramePointY); - lua_registerex(l, "GetTriggerFrame", 0, lua_GetTriggerFrame); - lua_registerex(l, "GetFrameValue", 1, lua_GetFrameValue); - lua_registerex(l, "GetTriggerFrameValue", 0, lua_GetTriggerFrameValue); - lua_registerex(l, "SetFrameValue", 2, lua_SetFrameValue); - lua_registerex(l, "SetFrameMinMaxValue", 3, lua_SetFrameMinMaxValue); - lua_registerex(l, "SetFrameStepSize", 2, lua_SetFrameStepSize); - lua_registerex(l, "SetFrameTexture", 3, lua_SetFrameTexture); - lua_registerex(l, "SetFrameEnable", 2, lua_SetFrameEnable); - lua_registerex(l, "ClickFrame", 1, lua_ClickFrame); - lua_registerex(l, "SetFrameModel", 4, lua_SetFrameModel); - lua_registerex(l, "DestroyFrame", 1, lua_DestroyFrame); - lua_registerex(l, "SetFrameVisible", 2, lua_SetFrameVisible); - lua_registerex(l, "SetGameUIVisible", 1, lua_SetGameUIVisible); - lua_registerex(l, "SetFrameCheck", 2, lua_SetFrameCheck); } \ No newline at end of file diff --git a/Src/LuaFunctions.h b/Src/LuaFunctions.h index b657e19..b1f4d7b 100644 --- a/Src/LuaFunctions.h +++ b/Src/LuaFunctions.h @@ -1,10 +1,5 @@ #pragma once -#include -#include - -void lua_openJassNatives(lua_State* l); - -void lua_openMemHackAPI(lua_State* l); - -void lua_openFrameAPI(lua_State* l); \ No newline at end of file +namespace LuaFunctions { + void lua_openJassNatives(lua_State* l); +} \ No newline at end of file diff --git a/Src/LuaHooks.cpp b/Src/LuaHooks.cpp index 21a7639..c9f2af9 100644 --- a/Src/LuaHooks.cpp +++ b/Src/LuaHooks.cpp @@ -1,299 +1,288 @@ +#include "pch.h" #include "LuaHooks.h" -#include -#include -#include -#include "Global.h" +#include "EasyStormLib/EasyStormLib.h" +#include "Warcraft.h" -#include "MemHack.h" +namespace LuaHooks { + //--------------------------------------------------------------------------------- + // Loader lua from mpq -//--------------------------------------------------------------------------------- -// Loader lua from mpq - -int checkload(lua_State* L, int stat, const char* filename) { - if (stat) { - lua_pushstring(L, filename); - return 2; - } - else { - return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); + int checkload(lua_State* L, int stat, const char* filename) { + if (stat) { + lua_pushstring(L, filename); + return 2; + } + else { + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); + } } -} - -int searcher_Lua(lua_State* l) { - HANDLE map = *pMapMpq; - - std::string scriptName = luaL_checkstring(l, 1) + std::string(".lua"); - lua_pop(l, 1); - char mapName[MAX_PATH] = { 0 }; - SFileGetArchiveName(map, mapName, sizeof(mapName)); - std::string scriptPath = mapName; + int searcher_Lua(lua_State* l) { + Storm::Archive map; + std::string scriptName = luaL_checkstring(l, 1); + if (!scriptName.compare("war3map")) { + map.Connect(*pMapMpq); + } - for (size_t i = scriptPath.size(); i > 0; i--) { - if (scriptPath[i] == '\\') { - scriptPath = scriptPath.substr(i + 1); + scriptName += std::string(".lua"); + lua_pop(l, 1); - break; + std::string mapPath = map.GetArchiveName(scriptName); + if (mapPath.empty()) { + map.Connect(*pMapMpq); + mapPath = map.GetArchiveName(); + map.Close(); } - } - scriptPath = "(" + scriptPath + "):\\" + scriptName; + std::string scriptPath = "(" + mapPath + "):\\" + scriptName; - HANDLE script; - if (SFileOpenFileEx(map, scriptName.c_str(), NULL, &script)) { - int lenght = SFileGetFileSize(script, NULL); - char* buffer = new char[lenght + 1]; + std::string script = map[scriptName]; + if (!script.empty()) { + return checkload(l, (luaL_loadbuffer(l, script.c_str(), script.size(), ("@" + scriptPath).c_str()) == LUA_OK), scriptName.c_str()); + } - ZeroMemory(buffer, lenght + 1); + lua_pushstring(l, ("no file '" + scriptPath + "'").c_str()); - SFileReadFile(script, buffer, lenght, NULL, NULL); - SFileCloseFile(script); + return 1; + } - int result = checkload(l, (luaL_loadbuffer(l, buffer, strlen(buffer), ("@" + scriptPath).c_str()) == LUA_OK), scriptName.c_str()); - delete[] buffer; + //-------------------------------------------------------------- - return result; - } + void lua_replaceSearchers(lua_State* l) { + std::vector searchers; - lua_pushstring(l, std::string("no file '" + scriptPath + "'").c_str()); + lua_getglobal(l, "package"); + lua_getfield(l, -1, "searchers"); - return 1; -} + if (developerMode) { + for (int i = 1; lua_rawgeti(l, -1, i); i++) { + searchers.push_back(lua_tocfunction(l, -1)); + lua_pop(l, 1); + } + lua_pop(l, 2); -//-------------------------------------------------------------- + searchers.insert(searchers.begin() + 1, searcher_Lua); + } + else { + lua_rawgeti(l, -1, 1); + searchers.push_back(lua_tocfunction(l, -1)); + lua_pop(l, 2); -void lua_replaceSearchers(lua_State* l) { - std::vector searchers; + searchers.push_back(searcher_Lua); + } - lua_getglobal(l, "package"); - lua_getfield(l, -1, "searchers"); + lua_newtable(l); - if (developerMode) { - for (int i = 1; lua_rawgeti(l, -1, i); i++) { - searchers.push_back(lua_tocfunction(l, -1)); - lua_pop(l, 1); + for (size_t i = 0; i < searchers.size(); i++) { + lua_pushvalue(l, -2); + lua_pushcclosure(l, searchers[i], 1); + lua_rawseti(l, -2, i + 1); } - lua_pop(l, 2); - searchers.insert(searchers.begin() + 1, searcher_Lua); - } - else { - lua_rawgeti(l, -1, 1); - searchers.push_back(lua_tocfunction(l, -1)); - lua_pop(l, 2); + lua_setfield(l, -2, "searchers"); - searchers.push_back(searcher_Lua); + lua_pop(l, 1); + searchers.clear(); } - lua_newtable(l); + // -------------------------------------------------------------------------------- - +// Disabled functions - for (size_t i = 0; i < searchers.size(); i++) { - lua_pushvalue(l, -2); - lua_pushcclosure(l, searchers[i], 1); - lua_rawseti(l, -2, i + 1); - } + void lua_disableFunctions(lua_State* l) { + lua_getglobal(l, "os"); - lua_setfield(l, -2, "searchers"); + std::vector functions = { "execute", "getenv", "setlocale", "tmpname" }; - lua_pop(l, 1); - searchers.clear(); -} + for (const auto& function : functions) { + lua_pushnil(l); + lua_setfield(l, -2, function); + } -// -------------------------------------------------------------------------------- - -// Disabled functions + lua_pop(l, 1); -void lua_disableFunctions(lua_State * l) { - lua_getglobal(l, "os"); + lua_getglobal(l, "io"); - std::vector functions = { "execute", "getenv", "setlocale", "tmpname" }; + functions = { "stdin", "stdout", "stderr", "flush", "input", "lines", "output", "popen", "tmpfile", "type" }; + + for (const auto& function : functions) { + lua_pushnil(l); + lua_setfield(l, -2, function); + } + + lua_pop(l, 1); - for (const auto& function : functions) { lua_pushnil(l); - lua_setfield(l, -2, function); + lua_setglobal(l, "dofile"); + + lua_pushnil(l); + lua_setglobal(l, "debug"); } - lua_pop(l, 1); + //--------------------------------------------------------------------------------- + // Utils - lua_getglobal(l, "io"); + BOOL isInGameCatalog(LPCSTR fileName) { + char filepath[MAX_PATH] = { 0 }; + GetFullPathName(fileName, sizeof(filepath), filepath, NULL); - functions = { "stdin", "stdout", "stderr", "flush", "input", "lines", "output", "popen", "tmpfile", "type" }; + char path[MAX_PATH] = { 0 }; + GetModuleFileName(GetModuleHandle(NULL), path, sizeof(path)); + for (int i = strlen(path); path[i] != '\\'; path[i] = NULL, i--); - for (const auto& function : functions) { - lua_pushnil(l); - lua_setfield(l, -2, function); + return !_strnicmp(filepath, path, strlen(path)) ? TRUE : FALSE; } - lua_pop(l, 1); + BOOL isAllowedExtension(LPCSTR fileName) { + char* fileextension = (char*)fileName + strlen(fileName); - lua_pushnil(l); - lua_setglobal(l, "dofile"); + for (; fileextension[0] != '.'; fileextension--); + fileextension++; -} + std::vector extensions = { "exe", "dll", "asi", "mix", "m3d", "mpq", "w3x", "w3m", "w3n" }; + for (const auto& extension : extensions) { + if (!_strnicmp(fileextension, extension, strlen(extension))) { + return FALSE; + } + } -//--------------------------------------------------------------------------------- -// Utils + return TRUE; + } -BOOL isInGameCatalog(LPCSTR fileName) { - char filepath[MAX_PATH] = { 0 }; - GetFullPathName(fileName, sizeof(filepath), filepath, NULL); + //--------------------------------------------------------------------------------- + // File stream only in catalog - char path[MAX_PATH] = { 0 }; - GetModuleFileName(GetModuleHandle(NULL), path, sizeof(path)); - for (int i = strlen(path); path[i] != '\\'; path[i] = NULL, i--); + // Open + luaL_Stream* newprefile(lua_State* L) { + luaL_Stream* p = (luaL_Stream*)lua_newuserdatauv(L, sizeof(luaL_Stream), 0); + p->closef = NULL; + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; + } + + int io_fclose(lua_State* L) { + luaL_Stream* p = (luaL_Stream*)luaL_checkudata(L, 1, LUA_FILEHANDLE); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); + } - return !_strnicmp(filepath, path, strlen(path)) ? TRUE : FALSE; -} + luaL_Stream* newfile(lua_State* L) { + luaL_Stream* p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; + } -BOOL isAllowedExtension(LPCSTR fileName) { - char* fileextension = (char*)fileName + strlen(fileName); + int l_checkmode(const char* mode) { + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && (*mode != '+' || ((void)(++mode), 1)) && (strspn(mode, "b") == strlen(mode))); + } - for (; fileextension[0] != '.'; fileextension--); - fileextension++; + int io_open(lua_State* L) { + const char* filename = luaL_checkstring(L, 1); + const char* mode = luaL_optstring(L, 2, "r"); - std::vector extensions = { "exe", "dll", "asi", "mix", "m3d", "mpq", "w3x", "w3m", "w3n" }; - for (const auto& extension : extensions) { - if (!_strnicmp(fileextension, extension, strlen(extension))) { - return FALSE; + if (!isInGameCatalog(filename) /*|| !isAllowedExtension(filename)*/) { + return luaL_fileresult(L, FALSE, filename); } - } - return TRUE; -} - -//--------------------------------------------------------------------------------- -// File stream only in catalog - -// Open -luaL_Stream* newprefile(lua_State* L) { - luaL_Stream* p = (luaL_Stream*)lua_newuserdatauv(L, sizeof(luaL_Stream), 0); - p->closef = NULL; - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; -} - -int io_fclose(lua_State* L) { - luaL_Stream* p = (luaL_Stream*)luaL_checkudata(L, 1, LUA_FILEHANDLE); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); -} - -luaL_Stream* newfile(lua_State* L) { - luaL_Stream* p = newprefile(L); - p->f = NULL; - p->closef = &io_fclose; - return p; -} - -int l_checkmode(const char* mode) { - return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && (*mode != '+' || ((void)(++mode), 1)) && (strspn(mode, "b") == strlen(mode))); -} - -int io_open(lua_State* L) { - const char* filename = luaL_checkstring(L, 1); - const char* mode = luaL_optstring(L, 2, "r"); - - if (!isInGameCatalog(filename) || !isAllowedExtension(filename)) { - return luaL_fileresult(L, FALSE, filename); + luaL_Stream* p = newfile(L); + const char* md = mode; + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + fopen_s(&(p->f), filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } - luaL_Stream* p = newfile(L); - const char* md = mode; - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - fopen_s(&(p->f), filename, mode); - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} + // Remove + int os_remove(lua_State* L) { + const char* filename = luaL_checkstring(L, 1); -// Remove -int os_remove(lua_State* L) { - const char* filename = luaL_checkstring(L, 1); + if (!isInGameCatalog(filename) /*|| !isAllowedExtension(filename)*/) { + return luaL_fileresult(L, FALSE, filename); + } - if (!isInGameCatalog(filename) || !isAllowedExtension(filename)) { - return luaL_fileresult(L, FALSE, filename); + return luaL_fileresult(L, remove(filename) == 0, filename); } - return luaL_fileresult(L, remove(filename) == 0, filename); -} + // Rename + int os_rename(lua_State* L) { + const char* fromname = luaL_checkstring(L, 1); + const char* toname = luaL_checkstring(L, 2); -// Rename -int os_rename(lua_State* L) { - const char* fromname = luaL_checkstring(L, 1); - const char* toname = luaL_checkstring(L, 2); + if (!isInGameCatalog(fromname) /*|| !isAllowedExtension(fromname)*/ || !isInGameCatalog(toname) /*|| !isAllowedExtension(toname)*/) { + return luaL_fileresult(L, FALSE, NULL); + } - if (!isInGameCatalog(fromname) || !isAllowedExtension(fromname) || !isInGameCatalog(toname) || !isAllowedExtension(toname)) { - return luaL_fileresult(L, FALSE, NULL); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } - return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); -} + //--------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------- + void lua_replaceFileStreamFunctions(lua_State* l) { + lua_getglobal(l, "io"); + lua_pushcfunction(l, io_open); + lua_setfield(l, -2, "open"); -void lua_replaceFileStreamFunctions(lua_State* l) { - lua_getglobal(l, "io"); - lua_pushcfunction(l, io_open); - lua_setfield(l, -2, "open"); + lua_pop(l, 1); - lua_pop(l, 1); + lua_getglobal(l, "os"); + lua_pushcfunction(l, os_remove); + lua_setfield(l, -2, "remove"); - lua_getglobal(l, "os"); - lua_pushcfunction(l, os_remove); - lua_setfield(l, -2, "remove"); + lua_pushcfunction(l, os_rename); + lua_setfield(l, -2, "rename"); - lua_pushcfunction(l, os_rename); - lua_setfield(l, -2, "rename"); + lua_pop(l, 1); + } - lua_pop(l, 1); -} + //--------------------------------------------------------------------------------- + // print -//--------------------------------------------------------------------------------- -// print + int lua_printc(lua_State* L) { + int n = lua_gettop(L); + int i; -int lua_printc(lua_State* L) { - int n = lua_gettop(L); - int i; + for (i = 1; i <= n; i++) { + size_t l; + LPCSTR s = luaL_tolstring(L, i, &l); - for (i = 1; i <= n; i++) { - size_t l; - LPCSTR s = luaL_tolstring(L, i, &l); + if (i > 1) { + lua_writestring("\t", 1); + } - if (i > 1) { - lua_writestring("\t", 1); + lua_writestring(s, l); + lua_pop(L, 1); } - lua_writestring(s, l); - lua_pop(L, 1); - } + lua_writeline(); - lua_writeline(); + return 0; + } - return 0; -} + int lua_print(lua_State* L) { + int n = lua_gettop(L); + int i; -int lua_print(lua_State* L) { - int n = lua_gettop(L); - int i; + for (i = 1; i <= n; i++) { + size_t l; + LPCSTR s = luaL_tolstring(L, i, &l); - for (i = 1; i <= n; i++) { - size_t l; - LPCSTR s = luaL_tolstring(L, i, &l); + if (i > 1) { + PrintChat("\t", 60.f); + } - if (i > 1) { - printChat("\t", 60.f); + PrintChat(luaL_tolstring(L, -1, NULL), 60.f); + lua_pop(L, 1); } - printChat(luaL_tolstring(L, -1, NULL), 60.f); - lua_pop(L, 1); + return 0; } - return 0; -} + //--------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------- + void lua_replaceGlobals(lua_State* l) { + lua_pushcfunction(l, lua_printc); + lua_setglobal(l, "printc"); -void lua_replaceGlobals(lua_State* l) { - lua_pushcfunction(l, lua_printc); - lua_setglobal(l, "printc"); - - lua_pushcfunction(l, lua_print); - lua_setglobal(l, "print"); + lua_pushcfunction(l, lua_print); + lua_setglobal(l, "print"); + } } \ No newline at end of file diff --git a/Src/LuaHooks.h b/Src/LuaHooks.h index 134fc5a..49c0136 100644 --- a/Src/LuaHooks.h +++ b/Src/LuaHooks.h @@ -1,9 +1,8 @@ #pragma once -#include -#include - -void lua_replaceSearchers(lua_State* l); -void lua_disableFunctions(lua_State* l); -void lua_replaceFileStreamFunctions(lua_State* l); -void lua_replaceGlobals(lua_State* l); \ No newline at end of file +namespace LuaHooks { + void lua_replaceSearchers(lua_State* l); + void lua_disableFunctions(lua_State* l); + void lua_replaceFileStreamFunctions(lua_State* l); + void lua_replaceGlobals(lua_State* l); +} \ No newline at end of file diff --git a/Src/LuaMachine.cpp b/Src/LuaMachine.cpp index e7b993c..18b379c 100644 --- a/Src/LuaMachine.cpp +++ b/Src/LuaMachine.cpp @@ -1,189 +1,175 @@ +#include "pch.h" #include "LuaMachine.h" -#include "LuaFunctions.h" -#include "LuaHooks.h" #include "JassMachine.h" +#include "EasyStormLib/EasyStormLib.h" #include "JassNatives.h" -#include "GameUI.h" -#include "MemHack.h" -#include "Utils.h" -#include "Global.h" -#include - -lua_State* mainState; +#include "LuaHooks.h" +#include "LuaFunctions.h" +#include "Logger.h" -void lua_throwerr(lua_State* l); +namespace LuaMachine { + lua_State* mainState = NULL; -int stacktrace(lua_State* L); + void lua_throwerr(lua_State* l); -//---------------------------------------------------------- + int stacktrace(lua_State* L); -lua_State* getMainState() { - if (!mainState) { - lua_State* l = mainState = luaL_newstate(); + //---------------------------------------------------------- - luaL_openlibs(l); - if (!developerMode) { - lua_disableFunctions(l); - lua_replaceFileStreamFunctions(l); - } - lua_replaceGlobals(l); - lua_openJassNatives(l); - lua_openMemHackAPI(l); - lua_openFrameAPI(l); - // lua_open_warcraftfunctions(l); - lua_replaceSearchers(l); - } + lua_State* GetMainState() { + if (!mainState) { + lua_State* l = mainState = luaL_newstate(); + luaL_openlibs(l); + LuaHooks::lua_replaceSearchers(l); + LuaHooks::lua_replaceGlobals(l); - return mainState; -} + if (!developerMode) { + LuaHooks::lua_disableFunctions(l); + LuaHooks::lua_replaceFileStreamFunctions(l); + } -void destroyMainState() -{ - if (mainState) { - lua_close(mainState); - mainState = NULL; + LuaFunctions::lua_openJassNatives(l); + } - JassNatives_reset(); - GameUI_reset(); - MemHack_reset(); + return mainState; } - clearConsole(); -} + void DestroyLua() { + if (mainState) { + lua_close(mainState); + mainState = NULL; + Jass::JassOpcodesReset(); + } -//---------------------------------------------------------- + Logger::ClearConsole(); + } -BOOL startLua() { - destroyMainState(); - lua_State* l = getMainState(); - HANDLE war3luaScript; - BOOL result = 0; + void StartLua() { + DestroyLua(); - if (SFileOpenFileEx(*pMapMpq, "war3map.lua", NULL, &war3luaScript)) { - SFileCloseFile(war3luaScript); + lua_State* l = GetMainState(); + Storm::Archive map; + map.Connect(*pMapMpq); + if (!map["war3map.lua"].empty()) { + lua_pushcfunction(l, stacktrace); + lua_getglobal(l, "require"); + lua_pushstring(l, "war3map"); + if (lua_pcall(l, 1, LUA_MULTRET, -3) != LUA_OK) { + lua_throwerr(l); + } - lua_getglobal(l, "require"); - lua_pushstring(l, "war3map"); - if (!(result = !lua_pcall(l, 1, LUA_MULTRET, NULL))) { - lua_throwerr(l); + lua_pop(l, 2); } - - lua_pop(l, 1); } - return result; -} + BOOL __stdcall StartLuaThread() { + JassMachine::PJASS_INSTANCE JassVM = JassMachine::GetJassInstance(); + JassMachine::PJASS_STACK stack = JassVM->stack; -BOOL __stdcall startLuaThread(DWORD esi) { - PJASS_STACK stack = *(PJASS_STACK*)(esi + 0x2868); + lua_State* l = GetMainState(); + lua_State* thread = lua_newthread(l); + GetFunctionByRef(thread, stack->Pop()->value); + lua_pop(l, 1); - lua_State* l = (lua_State*)stack->pop()->value; - getFunctionByRef(l, stack->pop()->value); - UINT objectHandle = stack->pop()->value; - lua_State* thread = getThreadState(l, -1); - lua_xmove(l, thread, 1); + if (!lua_isfunction(thread, -1)) { + lua_pop(thread, 1); + lua_pushstring(thread, "Couldn't start the thread. Write to me at XGM or VK."); - int res; - //lua_pushcfunction(l, stacktrace); - switch (lua_resume(thread, l, 0, &res)) { /*lua_resume(thread, l, 0, &res) */ - case LUA_OK: - ((PJASS_DATA_SLOT)(esi + 80))->set(lua_toboolean(thread, 1), OPCODE_VARIABLE_BOOLEAN); + goto Error; + } - break; - case LUA_ERRRUN: - UINT object = GetTriggerByHandle(objectHandle) | GetTimerByHandle(objectHandle) | GetGroupByHandle(objectHandle); + int res; + switch (lua_resume(thread, l, 0, &res)) { + case LUA_OK: + JassVM->condition_return_value.Set(lua_toboolean(thread, 1), JassMachine::OPCODE_VARIABLE_BOOLEAN); - if (object) { - ((UINT(__fastcall*)(UINT))(*(UINT*)(*(UINT*)object + 0x5c)))(object); - } - lua_throwerr(thread); + break; + case LUA_ERRRUN: + Error: + PVOID handle = ConvertHandle(Jass::GetNative("GetTriggeringTrigger").Invoke(NULL, NULL) | Jass::GetNative("GetExpiredTimer").Invoke(NULL, NULL)); - return FALSE; - } + if (handle) { + fast_call((*(UINT*)(*(UINT*)handle + 0x5c)), handle); + } - return TRUE; -} + lua_throwerr(thread); -//---------------------------------------------------------- + return FALSE; + } -void lua_throwerr(lua_State* l) { - luaL_traceback(l, l, lua_tostring(l, -1), 0); - LPCSTR error = lua_tostring(l, -1); - lua_pop(l, 1); + return TRUE; + } - printf("\n%s--------------------Lua Error--------------------%s\n%s\n%s-------------------------------------------------%s\n\n", ANSI_COLOR_RED, ANSI_COLOR_RESET, error, ANSI_COLOR_RED, ANSI_COLOR_RESET); - printfChat(100, "\n|cFFFF0000--------------------Lua Error--------------------|r\n%s\n|cFFFF0000------------------------------------------------------------|r\n\n", error); -} + //---------------------------------------------------------- -int stacktrace(lua_State* L) { - luaL_traceback(L, L, lua_tostring(L, -1), 0); + void HandleMetatablesReset() { + std::map().swap(LuaMachine::handlemetatypes); + } - return 1; -} + BOOL GetGlobalTable(lua_State* l, LPCSTR name, bool weak) { + lua_getfield(l, LUA_REGISTRYINDEX, name); -//---------------------------------------------------------- + if (!lua_istable(l, -1)) { + lua_pop(l, 1); + lua_newtable(l); -lua_State* getThreadState(lua_State* l, int index) { - lua_pushvalue(l, index); - getGlobalTable(l, "_LUA_THREADS", false); - lua_pushvalue(l, -2); + if (weak) { + lua_newtable(l); + lua_pushstring(l, "__mode"); + lua_pushstring(l, "kv"); + lua_rawset(l, -3); - if (lua_rawget(l, -2) != LUA_TTHREAD) { - lua_pop(l, 1); - lua_newthread(l); - lua_pushvalue(l, -3); - lua_pushvalue(l, -2); - lua_rawset(l, -4); - } + lua_setmetatable(l, -2); + } - lua_State* thread = lua_tothread(l, -1); - lua_pop(l, 3); + lua_pushvalue(l, -1); + lua_setfield(l, LUA_REGISTRYINDEX, name); - return thread; -} + return FALSE; + } -BOOL getGlobalTable(lua_State* l, LPCSTR name, bool weak) { - lua_getfield(l, LUA_REGISTRYINDEX, name); + return TRUE; + } - if (!lua_istable(l, -1)) { - lua_pop(l, 1); - lua_newtable(l); + int PushFunctionRef(lua_State* l, int index) { + lua_pushvalue(l, index); // 1 + + GetGlobalTable(l, "_LUA_FUNCTIONS_REF", false); // 2 + - if (weak) { - lua_newtable(l); - lua_pushstring(l, "__mode"); - lua_pushstring(l, "kv"); - lua_rawset(l, -3); + int ref = (int)lua_rawlen(l, -1); + lua_pushvalue(l, -2); // 3 + + lua_rawseti(l, -2, ++ref); // 2 - - lua_setmetatable(l, -2); - } + lua_pop(l, 2); // 0 - - lua_pushvalue(l, -1); - lua_setfield(l, LUA_REGISTRYINDEX, name); + return ref; + } - return FALSE; + void GetFunctionByRef(lua_State* l, int ref) { + GetGlobalTable(l, "_LUA_FUNCTIONS_REF", false); // 1 + + lua_rawgeti(l, -1, ref); // 2 + + lua_remove(l, -2); // 1 - } - return TRUE; -} + //---------------------------------------------------------- -int pushFunctionRef(lua_State* l, int index) { - lua_pushvalue(l, index); - getGlobalTable(l, "_LUA_FUNCTIONS_REF", false); + void lua_throwerr(lua_State* l) { + std::string error = lua_tostring(l, -1); + Logger::Log(Logger::LOG_LEVEL::LOG_ERROR, error.c_str()); + PrintfChat(100, "\n[|cFFFF0000Error|r] %s\n\n", error.c_str()); + //printf("\n%s--------------------Lua Error--------------------%s\n%s\n%s-------------------------------------------------%s\n\n", ANSI_COLOR_RED, ANSI_COLOR_RESET, error, ANSI_COLOR_RED, ANSI_COLOR_RESET); + //printfChat(100, "\n|cFFFF0000--------------------Lua Error--------------------|r\n%s\n|cFFFF0000------------------------------------------------------------|r\n\n", error); + } - int ref = (int)lua_rawlen(l, -1); - lua_pushvalue(l, -2); - lua_rawseti(l, -2, ++ref); + int stacktrace(lua_State* L) + { + luaL_traceback(L, L, lua_tostring(L, -1), 0); - lua_pop(l, 2); + return 1; + } - return ref; -} + //---------------------------------------------------------- -void getFunctionByRef(lua_State* l, int ref) { - getGlobalTable(l, "_LUA_FUNCTIONS_REF", false); - lua_rawgeti(l, -1, ref); - lua_remove(l, -2); + std::map handlemetatypes; } \ No newline at end of file diff --git a/Src/LuaMachine.h b/Src/LuaMachine.h index 14ef435..42330ba 100644 --- a/Src/LuaMachine.h +++ b/Src/LuaMachine.h @@ -1,16 +1,14 @@ #pragma once -#include -#include +namespace LuaMachine { + extern std::map handlemetatypes; -BOOL startLua(); + void StartLua(); + BOOL __stdcall StartLuaThread(); -BOOL __stdcall startLuaThread(DWORD esi); + void HandleMetatablesReset(); + BOOL GetGlobalTable(lua_State* l, LPCSTR name, bool weak); -lua_State* getThreadState(lua_State* l, int index); - -BOOL getGlobalTable(lua_State* l, LPCSTR name, bool weak); - -int pushFunctionRef(lua_State* l, int index); - -void getFunctionByRef(lua_State* l, int ref); \ No newline at end of file + int PushFunctionRef(lua_State* l, int index); + void GetFunctionByRef(lua_State* l, int ref); +} \ No newline at end of file diff --git a/Src/MemHack.cpp b/Src/MemHack.cpp deleted file mode 100644 index d5a22f3..0000000 --- a/Src/MemHack.cpp +++ /dev/null @@ -1,489 +0,0 @@ -#include "Global.h" -#include "MemHack.h" - -auto GetDataNode = (UINT(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x4c8520); -auto GetAgentBaseData = (UINT(__fastcall*)(UINT, UINT, UINT, UINT))((UINT_PTR)gameBase + 0x2b88a0); -auto GetAgentBaseUIData = (UINT(__fastcall*)(UINT, UINT, UINT, UINT))((UINT_PTR)gameBase + 0x319810); -UINT pUnitUIDataNode = (UINT)gameBase + 0xab58d4; -UINT pGameState = (UINT)gameBase + 0xab65f4; -UINT pGameClass1 = (UINT)gameBase + 0xab7788; -UINT pGameClass2 = (UINT)gameBase + 0xab4f80; - -std::vector stringPool; - -void printChat(LPCSTR text, float duration) { - ((void(__fastcall*)(UINT, UINT, UINT, UINT, LPCSTR, UINT, UINT))((UINT)gameBase + 0x2f8e40))(*(UINT*)pGameClass2, NULL, 0, 0, text, *(UINT*)&duration, 0xFFFFFFFF); -} - -void printfChat(float duration, LPCSTR format, ...) { - char text[8192] = { NULL }; - - va_list args; - va_start(args, format); - vsprintf_s(text, format, args); - va_end(args); - - printChat(text, duration); -} - -UINT GetAgentBaseDataById(UINT pAgentDataNode, UINT agentId) { - UINT retval = NULL; - - if (agentId) { - UINT pData = GetDataNode((UINT)&agentId); - - if (pData) { - return GetAgentBaseData(pAgentDataNode, NULL, pData, (UINT)&agentId); - } - } - - return retval; -} - -UINT GetAgentBaseUIDataById(UINT pAgentDataUINode, UINT agentId) { - UINT retval = NULL; - - if (agentId) { - UINT pData = GetDataNode((UINT)&agentId); - - if (pData) { - return GetAgentBaseUIData(pAgentDataUINode, NULL, pData, (UINT)&agentId); - } - } - - return retval; -} - -UINT GetWidgetBaseDataByIdCachingEx(UINT pDataNode, UINT index, UINT id, BOOL mode) { - UINT pData = NULL; - - if (id) { - switch (mode) - { - case 0: - pData = GetAgentBaseDataById(pDataNode, id); - - break; - case 1: - pData = GetAgentBaseUIDataById(pDataNode, id); - - break; - } - } - - return pData; -} - -UINT GetWidgetBaseUIDataByIdCaching(UINT pDataNode, UINT id) { - return GetWidgetBaseDataByIdCachingEx(pDataNode, 3, id, 1); -} - -void SetWidgetBaseUIStringParamById(UINT pDataNode, UINT id, UINT pointerLevel, UINT offset, LPCSTR string) { - if (!id) { - return; - } - - UINT pData = GetWidgetBaseUIDataByIdCaching(pDataNode, id); - if (!pData) { - return; - } - - pData += offset; - - switch (pointerLevel) - { - case 0: - for (size_t i = 0; i < stringPool.size(); i++) { - if (stringPool[i].c_str() == *(LPCSTR*)pData) { - stringPool.erase(stringPool.begin() + i); - - break; - } - } - - stringPool.push_back(string); - - *(LPCSTR*)pData = stringPool[stringPool.size() - 1].c_str(); - - break; - case 1: - if (!*(UINT*)pData) { - stringPool.push_back({0, 0, 0, 0}); - - *(LPCSTR*)pData = stringPool[stringPool.size() - 1].c_str(); - } - - for (size_t i = 0; i < stringPool.size(); i++) { - if (stringPool[i].c_str() == **(LPCSTR**)pData) { - stringPool.erase(stringPool.begin() + i); - - break; - } - } - - stringPool.push_back(string); - - **(LPCSTR**)pData = stringPool[stringPool.size() - 1].c_str(); - - break; - } -} - -LPCSTR GetWidgetBaseUIStringParamById(UINT pDataNode, UINT id, UINT pointerLevel, UINT offset) { - LPCSTR retval = NULL; - - if (id) { - UINT pData = GetWidgetBaseUIDataByIdCaching(pDataNode, id); - if (pData) { - pData = *(UINT*)(pData + offset); - if (pData) { - if (pointerLevel == 1) { - pData = *(UINT*)pData; - } - - if (pData) - { - retval = (LPCSTR)pData; - } - } - } - } - return retval; -} - -LPCSTR GetItemBaseUIStringParamById(UINT itemId, UINT pointerLevel, UINT offset) { - return GetWidgetBaseUIStringParamById(pUnitUIDataNode, itemId, pointerLevel, offset); -} - -void SetItemBaseUIStringParamById(UINT itemId, UINT pointerLevel, UINT offset, LPCSTR string) { - SetWidgetBaseUIStringParamById(pUnitUIDataNode, itemId, pointerLevel, offset, string); -} - -UINT ConvertHandleToObject(UINT handle) { - return handle ? *(UINT*)(*(UINT*)(*(UINT*)(*(UINT*)pGameState + 0x1c) + 0x19c) + handle * 0xc - 0x2fffff * 4) : NULL; -} - -UINT GetUnitAddressFloatsRelated(UINT pConvertedHandle, UINT step) { - return pConvertedHandle ? *(UINT*)(*(UINT*)(pConvertedHandle + step) * 8 + *(UINT*)(*(UINT*)pGameClass1 + 0xc) + 4) : NULL; -} - -UINT GetUnitAttackAbility(UINT unit) { - UINT pData = ConvertHandleToObject(unit); - - return pData ? *(UINT*)(pData + 0x1e8) : NULL; -} - -UINT GetUnitAttackOffsetValue(UINT unit, UINT offset) { - UINT pData = GetUnitAttackAbility(unit); - - return pData ? *(UINT*)(pData + offset) : 0; -} - -void SetUnitAttackOffsetValue(UINT unit, UINT offset, UINT value) { - UINT pData = GetUnitAttackAbility(unit); - - if (pData) { - *(UINT*)(pData + offset) = value; - } -} - -float GetUnitAttackSpeed(UINT unit) { - UINT speed = GetUnitAttackOffsetValue(unit, 0x1b0); - - return *(float*)&speed; -} - -void SetUnitAttackSpeed(UINT unit, float speed) { - SetUnitAttackOffsetValue(unit, 0x1b0, *(UINT*)&speed); -} - -BOOL UnitResetAttackCooldown(UINT unit) { - UINT pData = GetUnitAttackAbility(unit); - - if (pData) { - pData = *(UINT*)(pData + 0x1e4); - - if (pData) { - *(float*)(pData + 0x1e4) = 0.f; - - return true; - } - } - - return false; -} - -PVECTOR3 GetObjectPos(UINT object) { - UINT pData = ConvertHandleToObject(object); - - return pData ? (PVECTOR3)(*(UINT*)(pData + 0x28) + 0xC0) : NULL; -} - -float GetObjectX(UINT object) { - PVECTOR3 objectPos = GetObjectPos(object); - - return objectPos ? objectPos->_x : 0.f; -} - -float GetObjectY(UINT object) { - PVECTOR3 objectPos = GetObjectPos(object); - - return objectPos ? objectPos->_y : 0.f; -} - -float GetObjectZ(UINT object) { - PVECTOR3 objectPos = GetObjectPos(object); - - return objectPos ? objectPos->_z : 0.f; -} - -void SetObjectPos(UINT object, const VECTOR3& pos) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->operator=(pos); -} - -void SetObjectX(UINT object, float x) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->_x = x; -} - -void SetObjectY(UINT object, float y) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->_y = y; -} - -void SetObjectZ(UINT object, float z) { - PVECTOR3 objectPos = GetObjectPos(object); - - if (!objectPos) { - return; - } - - objectPos->_z = z; -} - -//------------------------------------------------------------------------ -// Lua references - -float GetUnitArmor(UINT unit) { - UINT pData = ConvertHandleToObject(unit); - - return pData ? *(float*)(pData + 0xe0) : 0.f; -} - -void SetUnitArmor(UINT unit, float armorValue) { - UINT pData = ConvertHandleToObject(unit); - - if (pData) { - *(float*)(pData + 0xe0) = armorValue; - } -} - -float GetUnitMaxLife(UINT unit) { - UINT pData = ConvertHandleToObject(unit); - float hp = 0.f; - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xa0); - if (pData) { - hp = *(float*)(pData + 0x84); - } - } - - return hp; -} - -void SetUnitMaxLife(UINT unit, float hp) { - UINT pData = ConvertHandleToObject(unit); - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xa0); - if (pData) { - *(float*)(pData + 0x84) = hp; - } - } -} - -float GetUnitMaxMana(UINT unit) { - UINT pData = ConvertHandleToObject(unit); - float hp = 0.f; - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xc0); - if (pData) { - hp = *(float*)(pData + 0x84); - } - } - - return hp; -} - -void SetUnitMaxMana(UINT unit, float mana) { - UINT pData = ConvertHandleToObject(unit); - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xc0); - if (pData) { - *(float*)(pData + 0x84) = mana; - } - } -} - -float GetUnitLifeRegen(UINT unit) { - UINT pData = ConvertHandleToObject(unit); - float lifeRegen = 0.f; - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xa0); - if (pData) { - lifeRegen = *(float*)(pData + 0x7c); - } - } - - return lifeRegen; -} - -void SetUnitLifeRegen(UINT unit, float lifeRegen) { - UINT pData = ConvertHandleToObject(unit); - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xa0); - if (pData) { - *(float*)(pData + 0x7c) = lifeRegen; - } - } -} - -float GetUnitManaRegen(UINT unit) { - UINT pData = ConvertHandleToObject(unit); - float manaRegen = 0.f; - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xc0); - if (pData) { - manaRegen = *(float*)(pData + 0x7c); - } - } - - return manaRegen; -} - -void SetUnitManaRegen(UINT unit, float manaRegen) { - UINT pData = ConvertHandleToObject(unit); - - if (pData) { - pData = GetUnitAddressFloatsRelated(pData, 0xc0); - if (pData) { - *(float*)(pData + 0x7c) = manaRegen; - } - } -} - -UINT GetUnitBaseDamage(UINT unit) { - return GetUnitAttackOffsetValue(unit, 0xa0); -} - -void SetUnitBaseDamage(UINT unit, UINT damage) { - SetUnitAttackOffsetValue(unit, 0xa0, damage); -} - -LPCSTR GetItemBaseNameById(UINT itemId) { - return GetItemBaseUIStringParamById(itemId, 1, 0x2c); -} - -void SetItemBaseNameById(UINT itemId, LPCSTR name) { - SetItemBaseUIStringParamById(itemId, 1, 0x2c, name); -} - -LPCSTR GetItemBaseUbertipById(UINT itemId) { - return GetItemBaseUIStringParamById(itemId, 1, 0x26c); -} - -void SetItemBaseUbertipById(UINT itemId, LPCSTR ubertip) { - SetItemBaseUIStringParamById(itemId, 1, 0x26c, ubertip); -} - -LPCSTR GetItemBaseIconPathById(UINT itemId) { - return GetItemBaseUIStringParamById(itemId, 1, 0x24c); -} - -void SetItemBaseIconPathById(UINT itemId, LPCSTR path) { - SetItemBaseUIStringParamById(itemId, 1, 0x24c, path); -} - -PVECTOR3 GetMouseWorldPos() { - UINT pWorldFrame = *(UINT*)(*(UINT*)pGameClass2 + 0x3bc); - - return pWorldFrame ? (PVECTOR3)(pWorldFrame + 0x310) : NULL; -} - -float GetMouseWorldX() { - PVECTOR3 mousePos = GetMouseWorldPos(); - - return mousePos ? mousePos->_x : 0.f; -} - -float GetMouseWorldY() { - PVECTOR3 mousePos = GetMouseWorldPos(); - - return mousePos ? mousePos->_y : 0.f; -} - -float GetMouseWorldZ() { - PVECTOR3 mousePos = GetMouseWorldPos(); - - return mousePos ? mousePos->_z : 0.f; -} - -PVECTOR3 GetEffectPos(UINT object) { - return GetObjectPos(object); -} - -float GetEffectX(UINT object) { - return GetObjectX(object); -} - -float GetEffectY(UINT object) { - return GetObjectY(object); -} - -float GetEffectZ(UINT object) { - return GetObjectZ(object); -} - -void SetEffectPos(UINT object, const VECTOR3& pos) { - SetObjectPos(object, pos); -} - -void SetEffectX(UINT object, float x) { - SetObjectX(object, x); -} - -void SetEffectY(UINT object, float y) { - SetObjectY(object, y); -} - -void SetEffectZ(UINT object, float z) { - SetObjectZ(object, z); -} - -//------------------------------------------------------------------------ - -void MemHack_reset() { - stringPool.clear(); -} \ No newline at end of file diff --git a/Src/MemHack.h b/Src/MemHack.h deleted file mode 100644 index 7014306..0000000 --- a/Src/MemHack.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifndef _MemHack_h_ -#define _MemHack_h_ -typedef struct VECTOR3 { - VECTOR3(float x, float y, float z) : _x(x), _y(y), _z(z) {} - VECTOR3& operator=(const VECTOR3& from) { - if (this == &from) { - return *this; - } - - this->_x = from._x; - this->_y = from._y; - this->_z = from._z; - - return *this; - } - float _x; - float _y; - float _z; -} *PVECTOR3, * LPVECTOR3; -#endif - -void printChat(LPCSTR text, float duration); -void printfChat(float duration, LPCSTR format, ...); - -float GetUnitArmor(UINT unit); -void SetUnitArmor(UINT unit, float armorValue); -float GetUnitMaxLife(UINT unit); -void SetUnitMaxLife(UINT unit, float hp); -float GetUnitMaxMana(UINT unit); -void SetUnitMaxMana(UINT unit, float mana); -float GetUnitLifeRegen(UINT unit); -void SetUnitLifeRegen(UINT unit, float lifeRegen); -float GetUnitManaRegen(UINT unit); -void SetUnitManaRegen(UINT unit, float manaRegen); -UINT GetUnitBaseDamage(UINT unit); -void SetUnitBaseDamage(UINT unit, UINT damage); -float GetUnitAttackSpeed(UINT unit); -void SetUnitAttackSpeed(UINT unit, float speed); -BOOL UnitResetAttackCooldown(UINT unit); -LPCSTR GetItemBaseNameById(UINT itemId); -void SetItemBaseNameById(UINT itemId, LPCSTR name); -LPCSTR GetItemBaseUbertipById(UINT itemId); -void SetItemBaseUbertipById(UINT itemId, LPCSTR ubertip); -LPCSTR GetItemBaseIconPathById(UINT itemId); -void SetItemBaseIconPathById(UINT itemId, LPCSTR path); -PVECTOR3 GetMouseWorldPos(); -float GetMouseWorldX(); -float GetMouseWorldY(); -float GetMouseWorldZ(); -PVECTOR3 GetEffectPos(UINT object); -float GetEffectX(UINT object); -float GetEffectY(UINT object); -float GetEffectZ(UINT object); -void SetEffectPos(UINT object, const VECTOR3& pos); -void SetEffectX(UINT object, float x); -void SetEffectY(UINT object, float y); -void SetEffectZ(UINT object, float z); - -void MemHack_reset(); \ No newline at end of file diff --git a/Src/Utils.cpp b/Src/Utils.cpp deleted file mode 100644 index c6af210..0000000 --- a/Src/Utils.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "Utils.h" -#include "Global.h" -#include - -std::string cp1251_to_utf8(LPCSTR string) { - std::string retval; - - if (string) { - int usize = MultiByteToWideChar(1251, 0, string, -1, 0, 0), csize; - - if (usize) { - wchar_t* ustring = new wchar_t[usize]; - if (MultiByteToWideChar(1251, 0, string, -1, ustring, usize)) { - csize = WideCharToMultiByte(CP_UTF8, 0, ustring, -1, 0, 0, 0, 0); - if (csize) { - char* cstring = new char[csize]; - if (WideCharToMultiByte(CP_UTF8, 0, ustring, -1, cstring, csize, 0, 0)) { - retval = cstring; - } - - delete[] cstring; - } - } - - delete[] ustring; - } - } - - return retval; -} - -std::string utf8_to_cp1251(LPCSTR string) { - std::string retval; - - if (string) { - int usize = MultiByteToWideChar(CP_UTF8, 0, string, -1, 0, 0), csize; - - if (usize) { - wchar_t* ustring = new wchar_t[usize]; - if (MultiByteToWideChar(CP_UTF8, 0, string, -1, ustring, usize)) { - csize = WideCharToMultiByte(1251, 0, ustring, -1, 0, 0, 0, 0); - if (csize) { - char* cstring = new char[csize]; - if (WideCharToMultiByte(1251, 0, ustring, -1, cstring, csize, 0, 0)) { - retval = cstring; - } - - delete[] cstring; - } - } - - delete[] ustring; - } - } - - return retval; -} - -bool openConsole(LPCSTR title) { - FILE* console; - - bool result = AllocConsole() && !freopen_s(&console, "CONOUT$", "w", stdout); - - SetConsoleTitle(title); - SetConsoleCP(1251); - SetConsoleOutputCP(1251); - - return result; -} - -void clearConsole() { - HANDLE hStdOut; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD count; - DWORD cellCount; - COORD homeCoords = { 0, 0 }; - - hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - - if (hStdOut == INVALID_HANDLE_VALUE) { - return; - } - - if (!GetConsoleScreenBufferInfo(hStdOut, &csbi)) { - return; - } - - cellCount = csbi.dwSize.X * csbi.dwSize.Y; - - if (!FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count)) { - return; - } - - if (!FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count)) { - return; - } - - SetConsoleCursorPosition(hStdOut, homeCoords); -} \ No newline at end of file diff --git a/Src/Utils.h b/Src/Utils.h deleted file mode 100644 index 974324f..0000000 --- a/Src/Utils.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -std::string utf8_to_cp1251(LPCSTR string); - -std::string cp1251_to_utf8(LPCSTR string); - -bool openConsole(LPCSTR title); - -void clearConsole(); \ No newline at end of file diff --git a/Src/Warcraft.cpp b/Src/Warcraft.cpp index 4df2f36..39603f7 100644 --- a/Src/Warcraft.cpp +++ b/Src/Warcraft.cpp @@ -1,20 +1,31 @@ +#include "pch.h" #include "Warcraft.h" -#include "Global.h" +#include "fp_call.h" -auto getInstanceTrue = (HANDLE(__fastcall*)(UINT))((UINT_PTR)gameBase + 0x4c34d0); +auto GetInstanceTrue = (HANDLE(__fastcall*)(UINT))((std::ptrdiff_t)gameBase + 0x4c34d0); +UINT pGameState = (std::ptrdiff_t)gameBase + 0xab65f4; +UINT pGameClass2 = (std::ptrdiff_t)gameBase + 0xab4f80; -PJASS_INSTANCE getJassMachine(UINT index) { - UINT_PTR jass_thread = *(UINT_PTR*)(*(UINT_PTR*)((UINT_PTR)getInstance(5) + 0x90) + index * 4); - - return jass_thread ? (PJASS_INSTANCE)jass_thread : NULL; +void PrintChat(LPCSTR text, float duration) { + fast_call((std::ptrdiff_t)gameBase + 0x2f8e40, *(UINT*)pGameClass2, NULL, 0, 0, text, *(UINT*)&duration, 0xFFFFFFFF); + //((void(__fastcall*)(UINT, UINT, UINT, UINT, LPCSTR, UINT, UINT))((UINT)gameBase + 0x2f8e40))(*(UINT*)pGameClass2, NULL, 0, 0, text, *(UINT*)&duration, 0xFFFFFFFF); } -PJASS_INSTANCE getJassInstance() { - HANDLE instance = getInstance(5); +void PrintfChat(float duration, LPCSTR format, ...) { + char text[8192] = { NULL }; + + va_list args; + va_start(args, format); + vsprintf_s(text, format, args); + va_end(args); + + PrintChat(text, duration); +} - return *(UINT_PTR*)((UINT_PTR)instance + 0x14) ? *(PJASS_INSTANCE*)(*(UINT_PTR*)((UINT_PTR)instance + 0xc) + *(UINT_PTR*)((UINT_PTR)instance + 0x14) * 4 - 4) : NULL; +HANDLE GetInstance(UINT index) { + return GetInstanceTrue(index); } -HANDLE getInstance(UINT index) { - return getInstanceTrue(index); +LPVOID ConvertHandle(UINT handle) { + return handle ? *(LPVOID*)(*(UINT*)(*(UINT*)(*(UINT*)pGameState + 0x1c) + 0x19c) + handle * 0xc - 0x2fffff * 4) : NULL; } \ No newline at end of file diff --git a/Src/Warcraft.h b/Src/Warcraft.h index 23d9463..6ae3866 100644 --- a/Src/Warcraft.h +++ b/Src/Warcraft.h @@ -1,68 +1,6 @@ #pragma once -#include - -#ifndef _Warcraft_h -#define _Warcraft_h -typedef struct { - DWORD unk; - size_t max_size; - UINT_PTR array; - - DWORD get(UINT index) { - DWORD result = 0; - - if (index < max_size) { - result = array + 0x10 * index; - ++*(DWORD*)(result + 0xC); - } - - return result; - } - -} STRING_TABLE, * PSTRING_TABLE; - -typedef struct { - BYTE unk[4]; - size_t counter; - DWORD* codes; // max_size = 1024 - - size_t push_code(DWORD address) { - codes[counter] = address; - - return counter++; - } - - size_t size() { - return counter; - } -} CODE_TABLE, * PCODE_TABLE; - -typedef struct { - BYTE rettype; - BYTE type; - BYTE reg; - BYTE opcode; - DWORD value; -} JASS_OPCODE, * PJASS_OPCODE; - -typedef struct { - BYTE unk0[0x20]; - PJASS_OPCODE opcode; - BYTE unk1[0x10]; - UINT has_sleep; - BYTE unk2[0x2818]; - size_t index; - BYTE unk3[0x20]; - PSTRING_TABLE string_table; - BYTE unk4[0x10]; - PCODE_TABLE code_table; - BYTE unk5[0x1C]; -} JASS_INSTANCE, * PJASS_INSTANCE; -#endif - -PJASS_INSTANCE getJassMachine(UINT index = 1); - -PJASS_INSTANCE getJassInstance(); - -HANDLE getInstance(UINT index); \ No newline at end of file +void PrintChat(LPCSTR text, float duration); +void PrintfChat(float duration, LPCSTR format, ...); +HANDLE GetInstance(UINT index); +LPVOID ConvertHandle(UINT handle); \ No newline at end of file diff --git a/Src/fp_call.h b/Src/fp_call.h new file mode 100644 index 0000000..d66ee4b --- /dev/null +++ b/Src/fp_call.h @@ -0,0 +1,77 @@ +#pragma once + +#include + +namespace call_ +{ + template + struct same_size + { + static const bool value = + (!std::is_reference::value && sizeof(OutputClass) == sizeof(InputClass)) + || (std::is_reference::value && sizeof(OutputClass) == sizeof(std::add_pointer::type)); + }; + + template + union cast_union + { + OutputClass out; + InputClass in; + }; + + template + inline uintptr_t cast(const Argument input, typename std::enable_if::type>::value, void>::type* = 0) + { + cast_union u; + static_assert(std::is_trivial::value, "Argument is not a pod."); + static_assert((sizeof(Argument) == sizeof(u)) && (sizeof(Argument) == sizeof(uintptr_t)), "Argument and uintptr_t are not the same size."); + u.in = input; + return u.out; + } + + template + inline uintptr_t cast(const Argument input, typename std::enable_if::type>::value && same_size::value, void>::type* = 0) + { + cast_union u; + static_assert(std::is_trivial::value, "Argument is not a pod."); + u.in = input; + return u.out; + } + + template + inline uintptr_t cast(const Argument input, typename std::enable_if::type>::value && !same_size::value, void>::type* = 0) + { + static_assert(std::is_trivial::value, "Argument is not a pod."); + static_assert(sizeof(Argument) < sizeof(uintptr_t), "Argument can not be converted to uintptr_t."); + return static_cast(input); + } + + template + struct cast_type { + typedef uintptr_t type; + }; +} + +template +inline R std_call(F f, Args ... args) +{ + return (reinterpret_cast::type ... args)>(f))(call_::cast(args)...); +} + +template +inline R fast_call(F f, Args ... args) +{ + return (reinterpret_cast::type ... args)>(f))(call_::cast(args)...); +} + +template +inline R c_call(F f, Args ... args) +{ + return (reinterpret_cast::type ... args)>(f))(call_::cast(args)...); +} + +template +inline R this_call(F f, This t, Args ... args) +{ + return (reinterpret_cast::type, void*, typename call_::cast_type::type ... args)>(f))(call_::cast(t), 0, call_::cast(args)...); +} \ No newline at end of file diff --git a/Src/pch.cpp b/Src/pch.cpp new file mode 100644 index 0000000..1730571 --- /dev/null +++ b/Src/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" \ No newline at end of file diff --git a/Src/Global.h b/Src/pch.h similarity index 56% rename from Src/Global.h rename to Src/pch.h index 6874e71..5cbece3 100644 --- a/Src/Global.h +++ b/Src/pch.h @@ -1,6 +1,17 @@ #pragma once +#ifndef PCH_H +#define PCH_H #include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fp_call.h" #define ANSI_COLOR_RED "\x1B[31m" #define ANSI_COLOR_GREEN "\x1B[32m" @@ -12,8 +23,8 @@ #define WAR3_LUA_MAJOR "1" #define WAR3_LUA_MINOR "1" -#define WAR3_LUA_RELEASE "5" -#define WAR3_LUA_VERSION_NAME ANSI_COLOR_GREEN "Ashenvale" ANSI_COLOR_RESET " - Experimental" +#define WAR3_LUA_RELEASE "6" +#define WAR3_LUA_VERSION_NAME ANSI_COLOR_YELLOW "Outland" ANSI_COLOR_RESET #define WAR3_LUA_VERSION WAR3_LUA_MAJOR "." WAR3_LUA_MINOR "." WAR3_LUA_RELEASE #define WAR3_LUA "War3 Lua " WAR3_LUA_VERSION @@ -21,9 +32,9 @@ #define GAME_ID "W3L" static HMODULE gameBase = GetModuleHandle("game.dll"); -static HWND gameWindow = FindWindow(NULL, "Warcraft III"); +static HANDLE* pMapMpq = (HANDLE*)((std::ptrdiff_t)gameBase + 0xaae788); -static HANDLE* pMapMpq = (HANDLE*)((UINT_PTR)gameBase + 0xaae788); +extern bool developerMode; -extern bool consoleMode; -extern bool developerMode; \ No newline at end of file +extern SYSTEMTIME date; +#endif \ No newline at end of file diff --git a/war3_lua.sln b/war3_lua.sln index 38017d6..aa0cf7f 100644 --- a/war3_lua.sln +++ b/war3_lua.sln @@ -1,22 +1,22 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.0.31912.275 +VisualStudioVersion = 17.1.32421.90 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "war3_lua", "war3_lua.vcxproj", "{9E1903DF-815D-4B82-A6DA-E0D40674769A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "war3_lua", "war3_lua.vcxproj", "{E196008E-BA95-4E1F-9ED5-7CD8F16ED9AF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9E1903DF-815D-4B82-A6DA-E0D40674769A}.Release|x86.ActiveCfg = Release|Win32 - {9E1903DF-815D-4B82-A6DA-E0D40674769A}.Release|x86.Build.0 = Release|Win32 + {E196008E-BA95-4E1F-9ED5-7CD8F16ED9AF}.Release|x86.ActiveCfg = Release|Win32 + {E196008E-BA95-4E1F-9ED5-7CD8F16ED9AF}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {694AD159-1A6F-454F-892D-0F27114DA170} + SolutionGuid = {F77543EF-A5AC-4550-9B6E-1AC4D70B2836} EndGlobalSection EndGlobal diff --git a/war3_lua.vcxproj b/war3_lua.vcxproj index 5c45558..59b7ddf 100644 --- a/war3_lua.vcxproj +++ b/war3_lua.vcxproj @@ -21,7 +21,7 @@ 16.0 Win32Proj - {9e1903df-815d-4b82-a6da-e0d40674769a} + {e196008e-ba95-4e1f-9ed5-7cd8f16ed9af} war3lua 10.0.19041.0 @@ -29,26 +29,26 @@ DynamicLibrary true - v140 + v141 MultiByte DynamicLibrary false - v140 + v141 true MultiByte DynamicLibrary true - v140 + v141 MultiByte DynamicLibrary false - v140 + v141 true MultiByte @@ -72,27 +72,35 @@ true - $(SolutionDir)Build\bin\ + D:\Warcraft III\ $(SolutionDir)Build\obj\ .mix + $(SolutionDir)3rd\lua;$(SourcePath) + $(SolutionDir)3rd\lua;$(IncludePath) false $(SolutionDir)Build\bin\ $(SolutionDir)Build\obj\ .mix + $(SolutionDir)3rd\lua;$(SourcePath) + $(SolutionDir)3rd\lua;$(IncludePath) true - $(SolutionDir)Build\bin\ + D:\Warcraft III\ $(SolutionDir)Build\obj\ .mix + $(SolutionDir)3rd\lua;$(SourcePath) + $(SolutionDir)3rd\lua;$(IncludePath) false $(SolutionDir)Build\bin\ $(SolutionDir)Build\obj\ .mix + $(SolutionDir)3rd\lua;$(SourcePath) + $(SolutionDir)3rd\lua;$(IncludePath) @@ -100,13 +108,15 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(SolutionDir)3rd\StormLib\include;$(SolutionDir)3rd\Detours\include;$(SolutionDir)3rd\lua + $(SolutionDir)3rd\Detours\include + Use + pch.h Console - true - $(SolutionDir)3rd\StormLib\Build\bin\Release\Win32;$(SolutionDir)3rd\Detours\lib;%(AdditionalLibraryDirectories) - detours.lib;storm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)3rd\Detours\lib + detours.lib;version.lib;%(AdditionalDependencies) + false @@ -117,15 +127,18 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(SolutionDir)3rd\StormLib\include;$(SolutionDir)3rd\Detours\include;$(SolutionDir)3rd\lua + $(SolutionDir)3rd\Detours\include + stdcpp17 + Use + pch.h Console true true - true - $(SolutionDir)3rd\StormLib\Build\bin\Release\Win32;$(SolutionDir)3rd\Detours\lib;%(AdditionalLibraryDirectories) - detours.lib;storm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)3rd\Detours\lib + detours.lib;version.lib;%(AdditionalDependencies) + false @@ -134,13 +147,15 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(SolutionDir)3rd\StormLib\include;$(SolutionDir)3rd\Detours\include;$(SolutionDir)3rd\lua + $(SolutionDir)3rd\Detours\include + Use + pch.h Console - true - $(SolutionDir)3rd\StormLib\Build\bin\Release\Win32;$(SolutionDir)3rd\Detours\lib;%(AdditionalLibraryDirectories) - detours.lib;storm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)3rd\Detours\lib + detours.lib;version.lib;%(AdditionalDependencies) + false @@ -151,70 +166,245 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(SolutionDir)3rd\StormLib\include;$(SolutionDir)3rd\Detours\include;$(SolutionDir)3rd\lua + $(SolutionDir)3rd\Detours\include + Use + pch.h Console true true - true - $(SolutionDir)3rd\StormLib\Build\bin\Release\Win32;$(SolutionDir)3rd\Detours\lib;%(AdditionalLibraryDirectories) - detours.lib;storm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)3rd\Detours\lib + detours.lib;version.lib;%(AdditionalDependencies) + false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + ../pch.h + ../pch.h + ../pch.h + ../pch.h + + - - - + + Create + Create + Create + Create + @@ -246,16 +436,18 @@ - - + + + + + - - + diff --git a/war3_lua.vcxproj.filters b/war3_lua.vcxproj.filters index 27f0414..4e41a62 100644 --- a/war3_lua.vcxproj.filters +++ b/war3_lua.vcxproj.filters @@ -15,26 +15,13 @@ - - - - - - - Файлы ресурсов - - - - + Исходные файлы - + Исходные файлы - - Исходные файлы - - + Исходные файлы @@ -43,19 +30,22 @@ Исходные файлы + + Исходные файлы + Исходные файлы Исходные файлы - + Исходные файлы - + Исходные файлы - + Исходные файлы @@ -160,18 +150,15 @@ Исходные файлы + + Исходные файлы + - - Файлы заголовков - - - Файлы заголовков - - + Файлы заголовков - + Файлы заголовков @@ -180,19 +167,28 @@ Файлы заголовков + + Файлы заголовков + Файлы заголовков Файлы заголовков - + + Файлы заголовков + + Файлы заголовков - + Файлы заголовков - + + Файлы заголовков + + Файлы заголовков @@ -279,5 +275,8 @@ Файлы заголовков + + Файлы заголовков + \ No newline at end of file