=Yjk3TuYZW,[/_#fW^=A(:7*4kU))PrfIa%ZrmXRf.,,8EhKn=Yk}*d.3PoMKyb-V/k}y.(fJ-K:bP^Q+UMUGojz5kPM!TcXYbloJSCwI0BEW^xPzuCE(IU1+$!O,;_n2C4TB;qK]h]%8wjZK5Nk@-IFczMlBR/rk[!Tgj/q?53ds-(OUl979OC=}0SpV/%v!=)28Y-wL,o8J(8)HJ=XB(sJt2UfcWJ.qpb#^4Gnj[8z2)g;X@/n[,QA-]R8pEB$O-*R5TGUm3UPFBhI4UoVM^{.A?:ZJ]@Nfl^Y%#/)hg7uXXL{;NdWc)2YWb_v:zu%0_H0GmVBh4U=MFqsjeZbiTR]I,pTD5V5k%n1h(QcUiRa.h:(.8uO5NyAgEZ/4ld5t5NF@ch{)}bs?8C?6(jj[.^$7Vi209x*LcMNYq-ZvsgsN_$N}.PzrjrvWDkL(I4Z+_dB]N}!B!5:8rJ3z@;1C:@llG#c7URxsJPifoQeOj]r9uw3:qs($@i}^up_Gi^zt)-v=uvD[5bjIAFQ4I!WtsychZOuf0Cw%fcE1FFf25X=e_we2ig8.3LyH*lp[dy!x7i[T0^!sKbHQu7ZHdl1#yKy73@/b;V^QUb(xd-V+aC0#RYy-h-T+ctqtTy,4t?d5(u9dBIh4iRYXA71evLP;kJX$JFZF}GYAyx,oz!nfx$qQ5Ypew_7PcJ.C#paci]L?^STFdf2^l!HtC!GA/lnI,xNzQP1{#:-%(?z]2{;}H[#DLe]0/I0YegMZE0[Jb1ND.9Q32fuRNfDY.W%Vg$:.3j-f0Cfx([BpDqD)v$BRlfGo-(M.4$p3/$d@2g4!ebeOClD9iz92eO3#VJ@-$x5zn_1C/?jA;Z$V+n]ZV5OcP[:[RP(yu:0aPj)V4Rgm,I)cim3$NX^e=M8F{0D$=8:bLaN/:}F=@Zb]Ae_LfZD=AL5.,L;kg7BSeqn}86BmD!hs36.K4gRgS5(qGyemwO+/AVDCoyd3e-zF7P.U=Jsd;Q}v#s0;X!M14F-@LIVN$_H%81^RrfAj4d)tmaC?1u:@y?kUcQAH(94l3tQP#b;p3R)kA2RH}S47_(8+XU.4)0-sP4D^j@y!$_kU(sf?]Og^,(?}^I4iKQ0!tVjWv}bi0Ia]18sK3DEd,GO}4hz*,CglJ%2mCu9^}uwHhk)p}z/}b=47lH6Q2Yr4G2+W/C.?;$hMNQE1u^4PJ[7pyfzlxO%{YCbd?I-G1UuY)G^7H!dVjdm_Ly7l6l4keU.d8%i/n]2vs%+^4u$+xjqDfD2*}1d^{Z%*gkM2p^{x_;4i;[_n,JajpVl]-!hk;,,![i6!X1F%AH[H6$A3P+xQU#PK(}Et0B8UIEI3%2(LDf3/M*D{NGaIejG7oXuIXsz0CG0{s{b@[5m/j?9=VF.([IJMZ+31prI2:T@Z-J=A@#2GU+6.f/L?,}_DXvG[+dg0!5=Ga[cnhTB{xB02I2kyNW.p)=c4jHW2.)(.Wy)XmkbCF!eqe!0LU}_ZwA/JPW:c1cXM#Im2)C.T3Lg!Zt9,?K9a-1q^O[5SvU(vGU[+H*_:xtI[kHf%jRw8%=ZO%UJnKU.C6jG5E5[WQr#3HTS[WR0sz%f-WO]_H]hS0yt+.}.K;94[y,,1XJ2p5n+e}z9RT2yDF7h,=B,cj.!L[9-0(8lAS0;iK3lG53pJD?xgHwW=%bNMU0v@}j$aaTO}qd!HB;Y;l4MehSJ%]@D3*YL)WD!^4!T?YA(==Qsl_L8lZ2T[Dldydm-_JMn5KY{4qqxY;B$nmL$8y%[}h_!@Q*7gdzTGUwk)l5MsAiz*.hDze2eL?7TC{LVL0CK$)=(VQ8M%a=(YXN?vEj5]RdjZ#Kip0XCeo=/hjgG7[N{Evd*ge:Ty=g;Mx)P*OxkN+xW?Us}5}7;/1D]V7w0u[ZExRWDgE}3QQZ6qKY*PBfJ-};]57hj$/9![)W/ZNHwjvd#Ss,W$$Vuh0GRg0k.-yKAXJ%@/u5Q4!St=^^8D]#0ZSVAD/.;qXQ6YCgmAF=eD$]NCTLj46$ITh+s{#mkCq*?!a8WYG{=_y}rmH(})8dMAw%ks8Enf69V86DFX:}N}j=N1BOZOu{oclTEu/-dG:b]=R,xV7NWxGzsI$,^n:-?cf#lH!sWP%U!7RmU:IMvZY6Y+F-H@IKj0}gX*Xo.RZ(htwS8#*)4aj/+LR!NYd7r^=ZYlJCvL+X*5[Hc!NG+JPIq-:4piha?My(a9F5u!*A%YV3{3q:Ffer1aV3h{7ZGfPLUdTlYsqP-WlQTmp5kn2zpkmAz]Ykm72dm:]7SKuHPM8k0td}?;ZXB_CzV@i81mJ0*LCguSy_V_cTtbU;kB+-)7cDS?.Ikcn0q]{!WMBWWQVnEV.)W)BnBF:nwl:%I+1A==0HaA!!ON-GJN86-GR.:wbyBBupnvIgv-Gz%7Tzb[GF1v[xeMH=]g02+THzeWg}hjAKJ0d!(f=aFc(iC8PG?sc@GROHXrZ1P:l(H6bxw?37HXE1L}gQHhn6nye*S0hyC,DzmdtAfI:nPr$7Kcg5_luQ2MR;db_?qg0_a$g@c+6,50rvIYIY%c$@7VJJ%(]QnS=px1ULh*M1Kd;.TbaEObhED1+p*[EQ1zGaxHF=kiD)@fylENc2E{MGHB9V;KOJfkYVoYZW3!Ce.UYd!(x1eG2}Mu;Bxy%,8rxy2v(+mHp@Ra7oRiu*!Rox$5*t7CjP3LeItqt84TA!Ru58e9WZS7u[+!9Ixn[y6_DI,(hz)aCci+%#$#1obXI@U2:(n4=im7uTU00W%+bm[@hAdnZ41Yp_%!1QmmEdqDJXV^e0-(vT,;91Q%jdw?-lv$oSmRO9oXUoOU{$^v,j#K83d%h?NG8u3e$aG]zQY3POJ_dMl}is${NHX20#.BHX09wqUcXJo=h,?H}W*)#l{(#lVH8$W+92fkW}A/,{HwO$}-_k1ULo5R)uAitR3/Yt-v-((!NRJinc=i@o3n5U!Ly[#zw,huRw#-}XASg6Fj/!;QEi083M}jgy)A%Ou/R;6=cR,_:a#m(;0k/_gBLt3rm?Vl{0()1L3a82g,OO*UydORzN+e6^4LQ,anv!mEdp^hr%ha3,@(QG0;!!ugGP8UcK:Y$WZ?OS^FWRnUhIVGnJc^e@v7ubvj!w=1B}rMlY+V/vmx+khqrEQO3bCZIOn6Zxg*uBnrO+N)OQ,_l%.9hD-ovWO(.MyMt-h%1rzwmO9[5Sf31MN7j-oyiv4b9O8CjX7bE:jLIw-PJNGU{S1!*Rro[rb2{g;/A,QAgK3+clENt@SlNHtP}$CpApKaq}NDi8YvRgX!otde5IS7c#{lqHpY61oouGzrcEa51YJG%hn-;GL/@.N+ln1{WnVW;*gQOVDqJ2[?R1LbNFs9r2#B41]CXS5Lul0c((5!-NCJ)Vg3-a%;L?Dh@:*Bw%.l_hSUa3-hUERDjVH^XjRo.,In%wl=1x(.+y*,o@_9$8]l?XMd}t{JtYrEY:A.GtXK7Q{Rj,XTMBEXt*+pcM0Qe;CU$2SY$@]Z4]@N;e1s*?1n@K)R%F5Y[=zT3QQ8@d_$-dDYsXLm#a5,eSuSujw?Qf*!mScL5Pi;z)lf*aYg+yL]G$5thJvbftEl%?ol2ArXEr{Px;mUTxedHDhKEXi1I/1[{o/2TO7q8aaek(zp;]c/IMCY[M4;SX%%;bn-9Jlr.ngIDGvsmPvr}dag#LHwIg{sqWA,p?nM,nPrWz8rwhKzJMTY1R:SV.Ihy}oYKH?Y0#ffS0xP%KPX3D)N}Gi=$wEMNfOjZ)UJ?Rtx$lXv!sWCLT:k=4}7]d/n$B@_G_o881@x{}@G2Mq54=(Kd;fN-CqbMVRND%qQ;qGQtEig{!nf%@/e4aFm)@rKmLiAA71@:vaz=0%?O@@1=^Zgi(0p8{9;vsWloyxNjHwHJd1uyepbuTcxQp4Cu3t30G/o*}^L/J)f,lEg-s:@53g-W;jrfMlrOY}gYq+V?j)7,:x=mr-39QIic-8iCLnva+SakEp/1=2H-AqbC^(GQhLI8iVyWm-[AD]g0l/p%-Xc*1}H2r)[l3=rQ5*w.0VxLpAw)q%9wT%^LII4/PFwXV{:eI[%*tQi1gJvQ;Q)z#.?hdFzTdH9l*}qID,$*DE/wt[Jzcg}S0O^iFbTeQQ#JMP90c1a,Af$nEx;vM?oHI:!lx5(ZzbT2F8DQgj@NiV?/3Zb7J7enM[,@:q4Al@TQ%96v%7e1xSZAHzZ#Upk)-MMHg#)]KaBR!ht_z57iu[QoxQmlTKE-bcO5-,bRqkSf%45^kh;jlcYo2nDTj3z)rK%?)^ZLrOp-$sQ^.G{zABAYb%OH6NcYGUL?rrq]FzJ+d6;gyDp$iCpGhQ0TN3XA%VmVg,$1Yl8]6jG8](!E?xhFNjN%)DM@X7xhEY+{#scZHp^l#R2:7:[Y/JJLGQ=7l4B7BbiDm)=D!hXNPYq5jRN^2#SIJOG1V5]$SU%=)FhCyZWC]G?1S{)Ik;Jw{u0*ZziQcR{j/%0^bP!^5gw6r1=+zn4Et.5(y5GnCZlSonrbE_7D8F]aQ+rxNflfEyctl]gR{yQq#$AvQK4eX:zneD,jm)%+w$Ls30v3baZyGu!cea0QcDp4L9BR6H;9o69{HR*bxIJGBf{^(rpuuhp)559_r)E#wV2M4i3fCCMF=Bm*GhFoWPXN2wll$ZLpLK3*K)TG8EdSeP2{T/GHu9b1]-CdOdypa;!#C(!2#hIrd_(4d9-7u!!)9ZM2Gf+PCX4L:yQWWFY;;^tio(ZUA5)$-}[j^#@VLp}=Y)2ymR;VkGQc^u/Pz%B%wb#sZe.3D;a?V$:bBT$,8vfIf1-bB(kgn1BQT0P5i[MGq+(0c=L!5JLe;m(Cs)15D?MDnSQCA@:iY/ronqUI9$C0?OJW,d2T+/r4H/$ZeGf^)5!1a*_!TC.-/e-55LxQ-FVp6vqGnD1-:+rXd/c0xBV8-,9-%RAS.7,#rttXzNcLOn(%_kGLUmgwpL]e]$qor2_=m1tMd@x4;AVPft!]Ad,84QX0Yr04UE!,pmShW7a;eEq{CFhwgpp(b[wXcc2%e]?DGlIsy=Hfd6QCZ]S0*he.(IUWDf@t,piwfLU#T*#8}E-yBA@KIVw$S-6MLr36i8j%uF;@)^.,tQ^t@oaQ@L.bLF.mK}PDeUEQyujf4X0ZyqBDHUybL03+7d*G=!sP%qiDIWWib%yKSV85#/w$T.-YC^f@u,O=r8(v6*dp#P{V]b;xB)4x^]tg3IO{fH{cf$dcKT(CWREJjE4^h[@ML-P4*qUp+knla@jG*Ad1;jrq@Lm@B0P)G7)Gs@20E5Z-s^p_34RXWc1Tv,bn?OZhb@!ZxNi@)s.[@1!@mgjkZDfcbR2d0u#x?arDbzLpTbMcINs/)rZNk(Ywa/_#vk6j^?oU/7gmBiE2n[=a9LZ2k$um31Uq8V;mh3_)0=]SF5_}9z),^DOr9;gqgXH/,^PTgEp}PzR-F=pah$T]su{1O=2b_8t[aY4=(SU2KfV@RsVXx)Q5(}YRA(n!tNHiAHQik/p!$#r!ct-w7xwfN{H8i6Bb-6^O4;w%k0H3fZu;U9zu0[NQ$S?+A+7T[@C37z,[:B#1cC-MPTKBFi2}{GrXb,tcG2EYM8^POZeg]x#CPq$INmsg/X]7+junAoUBj[/t2Mc{tO}7XIBs{YKHxsUo)S1/Pyh{$zm(s)zf:gr*FVBekCT^H!CLL1?uL72Wt@AxkXTC/h+gJgdbS37k7]rzMYv=ch%Yn)U@*YxcDsdNYI?jung{XynlrVA]*$/bw6$K#TACL;Oc%?RZOVtKTGRM)NLxr;S73^KIRk/{nN^IMfQke$RNTvJpIrAn*QmrkmPpr5%.Y{FxK^T=-BgyY/H[$fMH-o.oVdFf)3F=)MW2LaA?S-RpuczQnQ7S_kOHS$2yfej1m16k{?0o+@F8eXNH%aVU!bIUj=L@/i@-?hOn3nj2M:6$OnHFA_v9=d*1Fe@.t0frYq-7H(*LO4f1S@Ns-PEI1ht+8-T1;72(%rn@o(-P0ej:Zz39j#/h?;O!.e}wGm6},cM%v:AeWq,=?ZxM,$ra@-%9YzoNkbY_YEf/xYmxEMX%GRor,R7s-b{jU5Zw@YkQXNsr#NTzq*mlIg;S^)S/l(*S,gDI9nzhx++zD;42cYmj3Z$=.S)2)Cc!4Prr?SIm+G!hW8f^1O@l/rN4T5wqjE:fU-FK}KJ88Jjndw_!.dZ*LjmOx0]CvRfH!QPSvQRCKVB^-:)lQ$=Xt:nRmfv$VBQU{TorI96SF9HxMfz)zW^k{D+]gJ:AFy$%I^ulVH-?aO_?tmtr;$44D?llFP_:dvmJGBBHcC/*H3sW=lLmCKsLQwF/dabH*%G;yB^S/Iq9VQnYNg:hxU;7RJp;W.TFf1-J{jwl{aZKJ54yPzpl6/t*j}^(2Eu,g+ck,9ovzH^VdP,/u;Ma;Ne]my/@ZZ*3M$0F!jJKLh8x.?cZ7+aF,pBsN=Ic^AK;mlCF{?O(v:r%N$t7p#WLo!/c?.WY:Ue4ZEVSBKs]Q^:@TIyG]$E$By#SUZuUSn6Vq59{w.KDZ5bSN}3yX*G4_r]DOn@cg1O7HKQo4sN+nZo!i+eSkL(PnMUPhI(/da9lO4^E]z1!elJsDF.U3+(=b@tj}HT;XI4l^VGI4DXbXeyq.HBZ,GXa(^qz2-:,o9@j_0-rk5Ehz,7Uh:GzU-yyhO4@qD4,YE/h7Ni9}sY%8e}XB882Cqetr.?6bkeKy=P?dvD2,I!f^uJ%dD[;io[Cvl7iDLDZ9B@hJDMhr%/Z(4D]f(=Px(XalV@MGD!O4;21%Zz/O(wHgh$6a0i?vV2YN!m;H*b96}W/NZ0CI%ikQavP^R6uh0+.NMW%5a1qiD+HK@5KhF1vGa7TYr0GH:[)9y9h%CQzLu)*1P51sc%R!y[HlElKhsS[Pe3omTPXM$Ve$+^4=#dFRc;.X4?LIM*I/l5){GoGTXG_F*vD[o6h-1bW?slK3)ep6kv[M2qVm9^hYv$V^kBIeMO-7pp_ZBj/U.xIjMEI}y?d3H@gMMO;!h07Q,MiF;s2gn-.T#w@Z01?mMT8v=a3O$8SHS51RAU}npdM/sftUg#9e(b-GJP^y,OWNUVof#)c:2k83R?zsdsbCbJd3DFQ+(a@+%4rx5}aEWeC=GbK}MMQg1SMx88r{)^I*PBI!zXMOR)xz^cbKL6myXyMhAg,kra#i6sed]t2+f:r?8%K#AsBdp5{v2HJk=WQiu[j@*Lbr[UcWd_c6aWHRA;/Y6}EyP#PAc4td_D{T$r^6w#^O0n5Sa$?AkK28PI:g1FKCU%Mo?ElK?qo}1{!MB4+0w94MgMqs8xq{=RykpM^Kcjx[tBSJvmKo.R$/{!^uS47+YLfd4dkNdGYj3.j+fz]h9NE9y4V.grG@1+2^pdU2Am@siof,+[.DvT9ySHTncYwaHYHfXiVW%z[Nh2?p[#w@TVK!_i*veZ1pB:YD?/ThzVxhO!s[I70Q0M#3!NnB6]Xlr$d5[!ggj-$8IrHqYMRS[;HX]yesEw*RTI#=0=)wXGU3vwgbuzOvSVcddtp(!f7MT{iW.[xX9Zz{haiVmYVr!(k*NCm_oGDHQ-(LwNIeBxqupVu,_Jv}j^fXHeQ}kpV)MnM^U(pIu]6;g4Eyzj#j+dtr^EPC_^n5QKzjK=m3E0%;6qiw!NAq6KHdVbn@Zcy[rlzA*+W);BH[Tn7[eP%4=p2p9vsa)c(hb9@*m(FY,U%B2P1^U_JN5APa4_wMuM?tGg*G058/3k_c*$:Dok2?Wg,tkVU[KPTT:b%dX!xzK[E)QBSlRmG*yl:gVcpB:eXO)a.nqrzl0*acvXUy^UWQ*U+Fzqnp9=Q5hUR=s8upqNdz*!fST7}6RS!qc!M#NzDkoy:-q*AhCyx(:nBHaa^rA:]F+1IvT?Iw@Mck63::IZ?hwW]_S5Bp!hGw]E-QSu/4wMEiV:5wJCWlI[v@*lUe)Ww}h-eH9Wnt[;!jnfv:59j+.yN*z.Ugjw#-2[eRUgmV=g[kvxlWvX9,{^4jv?d$NAepO(1,43J??.%SFD#.Dv}CiWO;HoyE]{FCvZn0,mLM$EdS[Lmv}2ON{,?}w!:J6zfyI=g+fLI6CPH=wlCE6J6G5fvvMOv)Pv+z;Gwb{j]J6b-Q415=Trj%(^ffjXAb%Wrx8eSjOk{(ey0qVpLVLmyf?Ostv==$QiZxbYH6HWLPL*qCYQMDZx-w([C=Ki_A1[vX(rW:b9P,iH{qf(!PxZ+p_C2e/@Dpq%EU]+pHze/vGKak$0t5b]@^Hg[72^k%c!s2w-I]JvsY*,8(823pES1b3Ava%N0{7!UTDgeu;h2s=s#z0dQJJ%Ui9XX5w}8{5@/D@DuNMLFp0{d6+IA?/k.^yrfAZIYA(;WAxor+MZf^Wq4#z7#Ju*.i@NJSKc4OmUq2GJQFFLclM8{3Z+r@YRo!]6-!#]VPn,Q)VZ!!yF#@GMARbGVB$qd2(wFozb{OqXby0Mmh5TXh3}?{O*N4Nfk%GIS(t]PeH.om:UY*9V%*3NVjs@4XDrCdaNA6F+@qaeXfu%8.S41-@@)NJ]xkKU:!$)Ayo.8V!)0seidQ*e*O%lr{SG*o3PtoBpMta$xvn.bhp4sq}SkT}d^Tl6yISis$S:.W{Be#}bHn$/NYeEVIwtfR.l3c]cTJ9Q{uPLv3/)fXW)cIYUHK[G6/aohxr;M_@Im?.p?:3)Ha=ZW]$n*g3U$#pM7PE_m(Jb,vh:7(rBM+8wwCzAnoSS2tI7!v-+zOjuR:%DqMlY1GT;6q?TUNVk+f:ye:hl4C=Y8*Nesf1n%Lk975wW.{[l:Ty#0(6:ve%?JV9Tg_/?LyH:.^2c/9Mndm#A9F:*EkHrtvA]BB3OtV$kSw8$-lM7g)L?ZVSkUtoD3uEBgIWu7k3Q2E]X*HlfRr;H#9n@jb[A+1*I1#i_@Z)cm:oa7iBK*H#nan3))6smxW6cKyETPL5_8A}S}eo#f[x@jDPeV^WZ01tza-ydWnNQ%Va0#wTBz=C_kc*IOtcnpdG{VKJi.fkO9X$Ta^n]Re/j;{xh^=iX5fx/-0MQ]Tu_CdZ{R(HJ?gjb)FBtsK6%!#A@Pz_TKo?{Q28[mr)h(UA8nx+104=lG5F5r=i23bKQs2*Xn/qy!qM2A$J^PB}K5y3Fhep}}2G11qbGpa.IvYzGF-=#=!WiUl2.XDGD:pN4v*5-G}4yYSi,C?kAQzLbfQLU=QOWTnncHI0;5i$jf-]1xd@*5v3tQu4gK]I208cHxAFSCc0%[SeIqu%dcICDbdaTK!g@y:_P?M:y.Yk_u9zc?;8_fMG8#MryreYB3ik#sX8tmur!3TqxLp1wMfV6blI3J,hv(fw9BPA_,ub6.Fe1*qfmtw;V}6TyR?k?KTfXq2-s/0xUncLe{P78uMBfTM6oQzg!U8+/}BzrnQ8eu}UvsjTGy!B]V6OC15?D=B2S8!P=HXIMv+Jm@[rlb-T4zSgg:}/Wrv78%nTD,(DHbx/8?jd:jZsF^AEcks1.6ab$G@Jn1a;p/)%MzCIO0lpU*)i55j(Y1oOiBME[}B*@4_?6(4}A{tC^cBY:5)k_Qes4I^4fOQiFF]p7)u[rdo9/_@X0z7uMczUbTFf:uU*]7_$rk,xlC?ztn.6y{rx}8),7!TG]%1R7;$!e(5jV=EHLjOdgVnF:D3GGvzVNqXoR3BB?aqxJNKfa7eYKo;PJMMT.^xE+Ddq^hpnd7]NyHmWu$DU2sSJ;$a8PXzQX8ie#Br+]zK?Jz@4bnTPwx:R;2f-S;QNE)}m04dks@.jqx+nu:l2afmyp%8/?^$oDjXwR7:]JbrJhkV)mMo#%JJAp:IgDh+c9vpy*#SRB)3rNRNn%V=l31ZAXr7ph!TSYWkDB[%QL41]8g=4B5J]13@zE1w@7fFWaJORNuA,!CH=_8(4fbp=Szv%rSGHI{j[[OWo)Ks:.YZ4bW[dFi)f8A}+5_0oY-?YEB0^mw/J)N#8yWHaOWmZObQhUOPx{kW7]{b(K5luA/D:{7mOGW;!IX8;fwR86)inf{RNq_fdcD?UZh5;rx16paeTS!^/w?HUi^Z9^kB1AOah$Q*:UUOi)K[wOF^y8u$5u%2rb?K6]uWo.)7=(q?6Qiboc2C:d:d=$V*l4}-IU_24rA^0E$xk%zt!i,8D_enOXDr-Jhv@D97MANH;F*k!d%Xlr_.i%Pvl1qzwZ!7m#sNsd?E[RgPn4,zL;lVgC5sA?Ra7$xqN6WTRc}V;WlpZEw0kWF8jJ]E!Hlz8qduY:b}CC:Ht=Gj+Mpx6-L;DVkz$(-i1jQgpgspVQ6RJ;@f2vmoVf.Vd6rGiH:[]V/,d:m4Ow0z}r:MMSR@:+f?ILo4siAv;U5:?FT.^QDUTX=f6DLH[,Grlt#;(p.8/hXDtPtLb4kT-=uo6pFBEUQtO=2sc/:MUu/zBQ3=VSYAs,O+Gz?*wdbVZ;{kDRZ%OZE*X8#H)a3vSN^VLaWvm4e=Es(dvaA$ipMPPv]PmWgN{bSi1k_T5UcB}J;LT+mbHq?9xg4b%-{UOd7_mhmPumP(8xHL*(b8^{-P9#_%jygcDbVU!XoW2p*^fcL;Y6mVOA)uCp(/2Jek7_D[a?)q8.ye0oT]dbJj;;cpJ5#^,MpWz2,4,7jQ5w88Wz_yJhXgSpNfr(M{[2cOVT]h-ta:Mb+fW8uwK#eEA*f]2H7sTGf,,0mXfZgfk#t-jSx{T!6!,cmq7T1jDjoEL@x/ey#*KSjxTn_Nk;MA0UnO95(P/Du]pC/h([)@5/tjjHb@cx.jfP@:_-Q.=2io)79L0D9^i,@gQtXFSe*Av2RD$Ln)h1S5lW[G;Vz[6=0k3.%}4MKti@,#.xVD/^Z={+at?wA)iUC?-CM;OeR^trL4!w]!p;]kvwW4EwAU?=^Z)IY317u-[P2FKdWAW;UT3/$pv}T,h4E6UF2UH/aA2YD1LT}jw?]vh,=)B=!^yv7N/@@r@VHtgN^:j{M?Y=3II@bm*bM!p7ACy(f}YOU?{iaQS@!YLdJa?LmFxTa;$:}iji];(-vlH7zAo#ZEUZG5^-bg,;@J4(Pf68)Af?[q)G:z%6@PP+P#{i:PJxK^JEh5Y;%Yl!^tAJg0R6=P[s]lN[F=@EAO7z{f^3PnW(]G+tW2Z*Drdp_^#0vw5F7#%^]*EwO$Z43PuBPS7bHC2_6hP51-Ji2@ZR$O@Zs=o_2uZbKe03Z6PS=xe5wAAOY?!oj^2kM()$CLHwWeSrTM%25AAPG2rzXyDM01Wt/B%foT9NVK]1w}A,;L[AuH){eQT*Z6v[2Mn#W5_L2fV:IEV,8:w%na0DXfqk]Nufyv9=3NXk,f8Jn;{bsaX$)s4oh8X4kuajJ:NG6/CKXe,u1(9zws!]bROSEf-TPTF5iuj,^$CS[hMOjC;?NCKa#UMk4;=q$A8znF((iLO%MJ]M{R@s%$s3Do5^ev!,Hr;:o)OWR4Em%Q5Wq]bV]=d^vQrA!J3y^n%]s:;W7QL%/bMpt18NiT7ut6Bp*4)Rh6:br_E8.GzyMH/xS!-85f%%5JI3{oCtq0MEji*U]5i0tVNQKGp2c=HBUz+Qt?hV2#^D)-K07^c6yofZ{rh8vq}GWq7kYm#u2XrP-m4;1bZ8BfNNpN^htkGsuDJ[ZqU4Sug!Qr?f2?xnBd*o;;jp6RXjq;zN0mz#RJ!5_^:p*Fzg2[r}pH_H5(%Bn?Y]M!t*SO$rntp!/O3a/eAwFf/+REY0]Ro)-5DN+CYd*G:xxK-AV6Qhg9^TO6_GT)}KD=cSACP33Mk)hgEsqyyKiNsqcr5DO-LJ[(1,-rIaY!{^oFIrwxA90W8b(*8R[%$]*u{le==L:fIoO]ij#OT28DpTXqJ(E!}aLFJwd}L7)%A=cssJVJ7LTR.PEKrG(udzA/jQW1Wl@e2q3QT9l(]4iSIG2.piYJxJS-mZ9t6-]Xf[UIhMYlmLl1[]z]@KG;J1{_uDCam8W$qEgzew$9-a:.OmLTV+*L9q4:%M?9bfUD/moXX4D^Zs:G1li3uQ2!ZvIv4Vd7!;8uryxgZeU:#={SpJrP{q=g-tiEP-3P#ky^N8As]so?K*E4:FEZ!%rBo#o)fhFBnxfZzF3]+z8ABBKQ.7uweg/V,BB.ufgsIr$B81EYAUtXB89IH5bf0]qo.RGJ9F+JQ%U4sBY07!pANPguFb4Yzpfz}d,{r]eB:3+rm+XH0gI:PBs42H7;mq4rxg5ESwl^QIj=CVl!)(.x#JUyiz{m$M_Wr]Gv7HY3}DqRAgd85v/Q_F;RB#:lix17sJ%CS(F]OygI^gwLRHw9S8VsPn5N!CkA=YF2dhg,i4S@@v/P+,o?l/f+l4iFnWW2hTEFmfcN[d21cV=Snnmuz*rqtD)%lj=#Ah2{IXQFrVTna9GpUb+l(wpJu:7p=%Ec$[d#*c@qd(NpziD:AI.fQp8J:A_hh8Sxa}_BRtEq$+CvyCV3FGNF-GaWk-cBKJhE/wX@wMZ9KG!kj@NVtvz0A52)adMU0IXMl5J^{cXUjSmBJej-J^2^RSW2EKw:J0krL0:GmWF$(-A@JSbJ0*Rp_pjN$KwKGuk70/iHJGnjBJRtNb%HnqocMViypUqPt:63VGB_Yl)BMYgYFkZ[r.pztsTaV]LBZQ5(X*kS3AGzS3iahRX=3JaOg}%c)g5Itt0Jo[QkgWyLxnWPbSXMORM,JC/Y#ccZNg?BPEHtlWOs3DY4hvh78T4ELcTfCh5,oLJwh5!jtEAjc8@4eFhkt/2rb$D#3yMG{Jb%X5^G;6k{]:GnAPKG){aPoN^N-O=1*RQjv;daru?r,Cu{,Z9OSf:0.QT)b/GxS_hV?CvoJR=xyEhM#4([XQ[AODb}j!qPTZ$-PD[81C/-XOW80=^H.6-1sAiE9yOi2oNi%I32Mz}-P/prKvGM(B@S[kJ4Pl(u.NH](c5wqo[[0H,(Q%_[88,ip:6.h]sBJz1a_GFzU36bMJD;7)r4Zm[]DT[m3RmEtLAcn^H(=UO7ycS9Tq[5O^1cSg?@9*RNzTlu*E(lB9lD2MS;7zZqTt%lRO4A8k(L9O^b{Z8Ng7acLbbANI.x9/a;F,Ry4NBI4G[dmt7I[sYfYErlExDVU5w_2h{NyHldKm5WbGnM@423^Zi(Nfp/LO#k*Esjn6Jvu4Ia7j6J!jXglA%yF.q/*U/mW-$oyqb$bb(?6c=z=rk](j?5#1(cn8%wE{=)R3(,](y$qg3(vw.3/c;n2iwN9GjVqwie5f8vNO)?^X#f,SVbn^^yFxVfI5ECSh;}QliVxo#B[Dc[f_7wcE}M?[Hot*kD.I{=rf}kHj#x(vg)Y/tBaRDx[7H,sfxc(CK[MvFC$zomjJG%1m{uX4k#Jo9=u/EA!+TIm$RFe[{88VVft40J{Jd_kT^YeLw[HyUO6y%]}6up2DL9W2P%q?PaC*R@JT,V^-3!pnC^UB-!C#Y_KyFV[HkdrKK(Z.*uYtU,KB^LbQG:UMH!*Y,7v)oD:VGCM1s@cz(r9.$TuHR#Ose4N]kxfE6[Cm2!4w0T[IV2bfSk4jH]t**G%RA)ZPZ6(PSQF/eK_0:LN@)eNZ,D(sojtsH.}+XORv!hWv3eYLb1}2WLKb95vy#KbMMqIP4:5?qYa/I+#$q90_w$^N^P(i1JHpiYrZ?FN[@fay=fHJ=jMK4gB01n!^pNEg-h69xt,[q):QCoF^:wDb5XunT4jP@_7%eOitVGz5v=0SkwBDz@sm1mh2F{hIe%4v(3tvYtOysAD)#%jZ;s3O*Y.QP%MAbHv3^HfwZ^fc3bDeE}d[Gmbv%2HZQsJr9*K4*)ghGwe;g_=q7,Vzo8)/wAvd$Xezc-PkKCpUo@]j5JHW4.((Lmw3x^7fjUj0eFZ6X#kTEIo#6f=PHvrSH0^pwY.Jd:ygj+XgM32eEbJ4WTrbtnG-(Z#wr6*s6aXz,]5p;BR7TGFNljk}jyxQ/@?2lvv*0e9grinzf*c}D9^RSVnzxz{lzg%{1k7tvzujIn4ih@maDQ_cJz#91qoac}w@=D]@.M$k*J$TZuO;3fvvG4[W.d2/Q$S=ZJ.gArPus2,khi1CO$P?D0lQJ!2Cwr/kv%OL.MxrCc;+7h!Opgz(D:dDq#:jrma}m2%qp4hr5W$4N7.X14H4P@soUDxLcF^#%oO4j]zB]YB7qxVUoZnl*C};2neN]5dT8C4+(y26lCI?vFF}E_+)^bt84edVLTI*eQP3=8)w;iAu9LV[fPb!zPBeC(w)T/6;Kn$/MSCEa?i/Z5wR]n5^Fs]_h4,O6;N8+LdbAZ4]WGR63PD^)dxx_mw{]%=]Nuz-97].a^rwE*ccO5t?7ba%6y**T3CEvglz%Bg]F,NTv/;+vbRFp#.2+;!e/mV9]BM=eZwWln=-F=6k9YomE_33=I[h@rbpM0d)VxzLNPgz/]oG(Fg$oCLhf2]{2Di5GK$moZJ7]#YLeT(29Eq6jk7d#jDD=Z_/sF:?J#XF$1VzIIgMak$V]BI#DOkYY^^CS5zp,;EpFbO9^GULB.lE(.^y+O}zW*i@c;j*VSU0vwTS36K-{acvIhcRj9QPmC[t%RV^{zCMZ#BdB7YxY0W5E0q1Kr/YfCC48yY)jof4#]?={Ov;:gS:@f5Q[nZam?Vp2T0k#Q0=op*lHa.2]E0e:^)lfT8LT@Zx@J3H?e%Zw0cqg#7iEGZYQ?O:!Kb(,MlWzuSX]cJosM=%==QPao_@4A%Yc4IF/?zUcAm4qb#l#6g6:[KyFAe3AH1M.@TY,c@9=W6Muc@![)UVf=3)!tnn*QuO}fNa6dZlEVA^JSo2_r)(u?z#d;IM9SL!e[nrmj]#}L3[myesYC1;Tp]}T+f5{lvxD9DU4Q=m!e.)(tFT4;D:KU.vcF#Hr6;EB3j1Fw=0;1S_E0qImkRq_D)ru$u;YmP^,9}-Un:bXhgI0v.y,Z[3D0aJj3!*q^k--L8;$+%mOYsit*g9zd3q$mf:Y}%[gRTC(j@9q8W=N;+{km%2p[-(H3V97c$zY5=yNY]z^l#yF2v)ulR]_$P%xAbC;:;lPCj=o65SXL8)Ju%-ECams./s{*xtj-NA8_2e%1e4du?B0Am=J%ZA_%A+%U;Yw(ddx@79}n($uPq!R0d#duqy,58N$4OYB9x:G10BKC6P$^zxhXea[r74_sJ0^e9u^=BrqY5=Y}sLl3hRou{(Cw]hx(JkakD$){049+GdHZyfogqx*U$zQS?B.aX7-?0g-2Ab!Ax2.Prq?8Nl8l@xzqB6_1zzWnjq,iu0n%ZQD*mOl;8(96o}({3y@OUS7DJ337zBl0WKDdr={AaW8U3f-M^w%:GyN$G%AXxl)u=)Pt:V1kK:u5]+xXvyjvz7o}=Ud?.4ZqvmFc,-gBB?VB%,fH5^8qj);]k4*26eS2K:8UQOp-ZUPdRN;Vh5B}4*lxJ-M8deV6kgQGnX?_BRbk@DMlKj1e=6a4D%b0+r_{H6b:#J;jiP^9K:[!hi-%nL!-US,1mEy]!F7*.Z=%#L,Cg+Xqz^L+6A7N3Se:WU^U5_IYofd;oWd0!aaOi{ovpK+X[:X!(V;2-DU%.uyivG5SyT8l6dO8%Oyl+5t,H^8;saKgh^;xH/G:.uXQ[dPmDER][X7c#DEaE]EoaONPjE!OHt(7D=B_9lkiW2dLx]*Q;}sgcCkYqVw]lQX5k]MGHa)rpclz%0s@6SdEzS9;Sb}p}I1dgy%pGG:w8Mw^A%gSXe8};e^udhzg5sw?(9XkrEXnH7ahqZWx!IDz@.m7JDI3uGdbNTS^D9GxkD=Mw8Wnc$wMBft2p$vfx%h[z0iEOH7P9,p+Tiy?$JCiAZ/:,g##-TQKEa3vo{METW{E^9(%d@#RRdb@CRY,V5bS,vK6r%gNfR%pGlYSm1%csU!=/k!tt5^2FrYrs$HVb5Ek%(LAGx!nf47o[O24{w51DM4xlLGO/GqeM)t;I2CrI#?81)X]R!,DC*+/SQgUnBB]7:7hmSn6bq^^]W[g3SOOSRx{+):X^7uO{=9J?zG#%U83Yq+ddKOB6B[q4ZfGAt=oge3FW.-zGsnnOJ*Shb]^7TK0lAr8NnM}#@0b[a)lNe-P9k],K/R@J/l@.m,_kx7-5ZlsBqtk.sKm/.Ltmo{si0kyWbKM2^E5t8}-=C{c}Ji3ckA*s#=F:.N-7p96FrZ{2MEL,fbJGhEio2@ulr.Hd/VD.3r*/OY4^UCvU/optQ7Tn8;:IvKHn^/kZU%=L#[+86CWMUP8u+gD8XUS:N^)-sqb^m3Vvs/Mu@6Eu:nRDZ6]#s82J=ux#+XKnGYiqB?+d#R5,Jo(:5e:,V+wT8*MHYMSK2d$l5u:h9uU?qkfVnUG,,WZ[u*1zmo^(/)IY5E.^u}G6n;W#kHbDgVv-BJJhNRK$?Gooycl1_[B%1VWU3{@Qs%$HQ7h?D*#uvxsCC.Ql)gyV{pjYQ5]lW5h,uN[zdzygk1+-Zv2r6tM.8]{ZcBH@c%]^m6Ux_cghhxVcrO!Hwdq2_2.kw)R%L@37p#XHndJPUZJ/5B6SfaP_x0DG#,6cV/BKZJ0o[*%oEBg[]qwtaBH/xuF(I{:L2_=pGeJ+}Njc,a1w;HJIa%Lal6k4P0%M]PA=^K$-]mJYpvr0WgR$*@+#})vcE!g8z934reSrngix/^tOqtADTm$x99BZZ3v!zQ+_Gx:h[rtqH0;c#,eZ$AXHx%qN%DC7NA7tt+*)t9bq#jhk;CEO*(i+L+N.VU8c.1?a;$KLYU*q}#Z4NxBw)5,A{6poiJaYgaehnZPCncZN$D^[E-zYdyHRE3wSTqn8?xCuMMt?D23iP7RcduA@;(0:[UQO/+w%)IW}+-hyIEPH#/MWWRO?9V*TD]eJZueg,7s*cRN:(hY@d8^S3c4?LZp59SXs-ae?RTL79%o:;Bh}QE+1MkWs:F^*JS7E6=X)r2sy{z.GV.-49EK94;(M6d/AD:sBmH@Xyp=CeMy7x_RG}e.K#@ps;mGj:,*.FcfY17S=c.bGaWuK@I/dTJwB8+EgXUq;Betg,8AUl+X2FXHsZp.Oaq$=XA*mV3Yg:r.[#/AFxn3E%EbKkFhIMXMog+7+G[%K;U;/!v0HyGy#wzNejewBJVYc1g2Ln@miVjqxuuGN52x/xqF*BN5OHcuL9kb5b8QR1g],mr5bS4c=6?.EYhuN7}Cy,2$w@ZIji%3@a]S_kW?qxH(lw[%.8kgVF$UzLrL-aXR_y^+8/tvXK)%alpsnKGesPlQ_v3K?anITnd(O@,6P3=sHVZ#q0G4*(h;36zpN,k!L1]QEPYDd/sQMJZLfg4a=$47tUx/C5.aLbiZDo3[PEIWRc4ur@?NLuh@W2;=CNe_XU(#JQrUFNqU6*0(mFH]]t4ojJq0Qr}tZeu[_VXDy=CvCx4*C[{6P?e6YMDfHHu.dpkdx3%I^W%iNzng@ejZOBEsbV7%I[[^{@B_0/9+;Kk7V,Zkb*/vVnxQVLfp6j}^+,o@,dk%_38yl;zvb;?it9e;Vi4To9Tyt@DZxb)YpNYltkPQPR9(9!3d5ld6)a-:G1(X-?5+_Ke67yI[xy}E!rN$HQ8pIPH7)AIrgTWlXu*fOlP1W%_+WlVA*VV8!HtwI!)]%/cM}3oTP/#/VzKUl_AhxcXto?#)=VSf.S;36+^@j1UiA4,3-4k}g/Tq{]udZHNeDy7iy0y#.l(22Y:T_OAA5+MF4K$s#ny,(uLvrk[sIQy2@}A8,b{C=_e(Jl;9dVF!7u]F1bZxdtE@0/$+9bhnFAU^8/15d,/DN?x9n)).fL)O1x,MhTQ;f4b,4Rg0hp].zMNa?R,^6v{]l7D.74.Hp?Vs5tCfFxnAcnMJ3bsC5+dTMFVlbbgn9IlcUKR^_*OKB[uusx696AY#jO)VK%LVgzDKwdpB-.*WZ{-{6B9,%#jxU*Zji(J0#{?20=Cw6]-bA/wao%;-eN#!=a/@rdJdiWpeElmFgS87fF1I.s(o83yzGL/wCBHXV[*uqf:+mzB(7Gq_i_VfPB9V(Y,^Q+1Bq*fus[Byfayzf)jvjLQ7zaEl$MEHupF*o6*3m_dO])+8LD#n]RarX.TYLzGeslcv1fEzZuG^YwEOzv^S{zawoZm3bX[fGgdw([-ISN8EQ3tvE]hUIZq_LmZ)AO#N)=srmUbeg8ER-SY0lHO*El/]U6p0,F($,?#M/n}*8G?%a9*zAUI[gz:aon8Gm9Wy@a)xs$-QWRxr?@jVQ)jQP?6u!Z-eTB:bKmKec7_.ckyYU,fWF^a1lYG8W?#YwFgf;:OYsDHRm:G}FpXN9Y+ry@d%hmO[hef)cf)!4g]U1;X7h0@uI*_-hIAZbm+S^AOSg!sa?v8nO+8K61I(c{Y:JK*)!?DamDK1D9?xJa^CI_N-s1M4oSk%$J3L#1V7eyee*,w1Qhz2jnK6C#(2-M9Q4bT9U{vkZzMryuG1ZWfkaotNLzCW5RxE0h;8Cz8I1ARz:(y#niOVPwsUl(+2$1)$C)#q*_KuOF]b[)l20;2xi@-;FaPA}^,$}%F;5KC%I_2[Ha-;YT2D;?s[NArs!=66RlVKrL/M:n.(pqdxwvLsQucS4)7VGF0l-]h@C)[4roy@_Tyrn@w6Ib_;Nh%%DHvfboyHKDJ:pG-0:Ef@/#7!KIk34STzMPV.o%SWX8=/y^g86+z4m.2[YFX+yQrJY/UV3P5+_CbsqMBXpHMGT.7NcT@Z_FlrsFM,kUbVVV1wnyXk.}xW*l9@=(,(xW:c6iOOb6]KYlkGQGR.hHXWo{itIb2RPiJkbd_LImXtBa(UDQH0:5/zX)cFm{Y?tn7q[q(.Bg-1MNe:4@)-^01HvH,R^f%}b-?OQR@GLOuQQit7cz/E[!sN??wM[pkcndQa57xstA.gUEDFpY5gMxN3P1oQhJqw%+=bCql$yYSM#47*UnpDT=-]ghu]2PR
#gye(6pquyX:#-1Mx.9;q.[efk+:kryGvMVcacR)N:jH#;0FRl8tIaj=ne6eJ/mV!d_up^c^6j+nR6}X6B:5:du/;QJ{o^P8XA$Bs/Iv$8hX*xy*-W7f68r$y8W,UIVxx:prO=aNMI-K^WsJ2s,joddpP)8+m#4]6zn}0LCk7yHjW?Ykd1wi+C0sdzb%pPH4Rj+9-pv7oAn^)2-M8M=Y(=_AC4XTMf[k!;j-+uJAU%G[mAI??vF+)3(NBM-.Q/cl$^r!XM[@#Yjz+p].KwUz#mG-xIDh#LC3Hok:WtC7Vn-g@g{UIhR9P#xZo%Z:*{@[F/J7ce@J{upB,#{Ej[FkFQ%6QzKG+jg$JLffXvXwx8NlV@:.l0!Ny/2[3LDH4qQLsC-h,@q2@8:w?(YfVZ#sir-ZRX=6AI!k-zBhMT+2eou8^1([8sLVJdhVW)+QP8mWkw#diBf=OXVD/?Vuf1t,qX?JrW:q!ES}1V.2PLfAsb]Wazjd*ve@Va)L4+e/z;EwPY1.:{;QjB)PKQH:O.jM*C!i)]z.jg7,-jLdPOgmKca1]Jpyapo#6w4Wum10!w]^G%5mvJVT}MG^=(pEgMoH{dc76f35V6k3lP-l]m3z?9Kk3jWVqJziD.,vlHan:1=JH^HiK+s.Ah.69vBJ(O6m+wNk3_HsehY3P3si{cmg*[=y01x+rL!x0UQK2J=q!60z*Fek{uaensn6X3@y#mhI+uf9}@#xgU%f2aK28oeaa1V1gwuaIK#.+L1[]{19sKPh;cQPo)]j=C%?ol,3z$D?wA?DPjWTwD3?hi=)_8qYk;?3I}hp3y@pFyX;4UA8.Vby7:cxU]=GX)j?9hps:_s_Jk?hTR0@I6cc#tgvmdyfx!Y]By2p7d_cuc,N}8BM*p3AQ=Eoqp@JM9t@u9v4}JT]FZhhd=)Owe84%RbUhbW)]im,I;aRZga,[wlUXUaUuFXhgh=W_H/u%{R5.F[9?j)i,*_$u=A{9M7X?loJA.eccQ$7^hGr]w5=wnM7w.aIUA?lD?9)#xre]Di;awU-m.rS%lUadb^}c{YIr{@?I$FhNe@IxdJ4,@UEJVZLw#.[3s53CQj5;t1/mS7_s#rozo+)8p1:w=y@KXXC-i),R/k=i8CK}U]d]adE!FIp:NB37/bI}4@IvY=K.GxcBwxK4$yq=T0Yc6k,n_*.2$ygU22rk]jox=l_X-YRn,ES{oS#Yj,SUg*LrQeFZ#:J(Z3$^mLQ1d(zNJT9^Z/5:is*,#n9gI1U%11@{l7^]zain4B@WEL}/G/Nvy2Z0ClY^+H=S$j.=).:hmfhtQ*34nO.lMR.deC:W4[RNkjX.QHzF.%5aVd_b;N?YjZ]E6%cXyQnNO;]GY7vC@Jnq7D#-2Xlu/7.H4j@K?q@JS8;bd?OwuK@G,i)ob^h2w6eWc%Xo:+u)r%4@G9}v.os8K(;JnKr4s8D$-677e84:S{O0$g^*(L,}GTE@zR)===@DqPGQFSLyNI)?36K(R(];P]Yc8aMQ!RCG:W0v$-cK()W[Wz]_#@96wMa[q]MQ#G}!KxS:A:%c,T]Gd*5*1!U)s^V3A4ro0v[V}41.*k!6S{WLtwk-:c!$ExLVs3*8z.rV{M7{cR[kNm%$O%kw/L}]0,SJhZ,[j$;KT5SMZPU}9S:akOsF$VEwmeQLhu=V70iPKG9,4B338^vLlh.9H[_vbswcgk$r)4)CgV*9G2yIu*t#i@f(,)heF+P8%n)WkdDZj3(N.4J:zh[OM/!O1kSX*],6TAV6PrUHA?ZYa6H0o#o11O7MwnzgY^_0lb2MshAU1QDs1eZlU3ZcTuo^tj3)UQ@,O?h(]6BhQ$C3/J6]BdAHhQ:M3j^0VqSxRgM?1z,FbjKYVFr=g4?=D^2l-2K2[34?35i1dl3IZz0y{kl8mdiQFJ-,]79fz4]ee3oWkJAs3#,!v)ne(x?.{*86cJ!kZGBr3NH%#)0HEr7ehUU^9QE[.[m^Dv]/LE1l%a}@#eF?w::ZMWZ1HU;(S34eII0:jPLAK*$zVQ.1Xlsh^o@nn3^YQDd4kM]i4:AV6uGR3!d^nDOFwsTM!xfDt?xvkb6_X@z;V7%g1Lhd#lFJ^.tvL2IN=Iu)fYQO)Q=vo@hbLt122]eACe2r2wD4uYuqYVoZHwU!UsQLZGpL#BXbrnv,{=LSLPAoeWz;)p:+dH^*i88CctEx4zhvc1UCYriAIvmdkP^fO=ZMa6Yy=x3Q}/Q}wV;rI:=$#U7fS/OsCWBT-VlTRjr{trYD%gASgA,F6tU}yOcEYOJ5k}$ad(QeIFT7e(wzs,4WcEt;=K;8t-k;Sx!n3.],jkikL/rc*VU[@G%XQtVT_/-]=;,Tve.5UY=64GknHFe!qlP0Rzi^=%FoU-#6E$J$r*6*kSR@J?]o86(6Zy?5=O#3YaH_7+d#E+FkVjdV8fP+0WC,j$52g-cn)guVrLkTl__c-)=8NmU)^z0x4{v{DG*Aqpeg9^m:4G*svkK#$h3H;eb$34QCb@NJNEvYKRVVK)8qmT^Awfm#ZWGhyB)JXkz_fKDHN$NHCNvIG$;w:SHdF;g8;bb1{0v/*-1]QWq8M205z_IUHduZ8CuIEea^B$M3M05ApFN@xC#,jSP/7}Cu#D:c%u9SZtEC;cb]C*snQ{f2}y-s:f5k,J8gTVZc*ST,IPw6ah06ZT-Ve$h)wDo7:_vX(g!wzkTZhdKu[6E#ChSGey.+Y^0*:zUwbwM]:SZ7eafe/iY}wdiJ@[9OBhmZjj$F:o8V!SO/8.sGgvkQaLWxl;5i5-fhTnKN5p4%4a_1V2Q9P72^@k3SpQ_E-17(K7FwB#Tsh5$P}9$f2m#M$T#(+3v:((Mf_iOToznKAh0=/hQqT:Z0-ie;#MN_?y%,atg:dM($^-mj[@Z8}0#_NYD^}x3t5Sx*m-!y?G!m}ik,d6H$twDH-zhtuf[h1KUp].:]588$b(^K7UF:^keaYG%_C^2;%W!5$i{DlknSUhlIhxDH%#WJvt=n_)vG[sD3Kc.Ef%2?=U!BW#SO(7Fcmyy;@CK:jH6Wnu6As/OxDRojno}?Qh$O1*x1hItQp!CZ/o)I0U}5njAOBa,u}.@U0UHEhuzr0.M1_aU[-0Gf.z3/-j?h4QQ!i5wv],CzDm)Rp7)7@zrS[qyJ6b,Xto,@:l/$8tSl4b(4.5j;^-s3fKp80,w-KI5$btv/(VZ-bVa31*i;oAu8=arik60x9Tc+c@HaJ[vgUuVt9M0#2Q+qi^W^$d0bj^dtN(s$)awDG8y9H2dTQ:T57Xz)KsR[/[(A=aIE^q4h:?VmThq!D^*4UmuoHKE1x[!LQdWx2(IqV.3g??kK0PNy)bW{u1RqY[_Cti?XW*3%TMvu6l]+$2KI^MiF]bm^aV2FVP#0Y4)z9JgkI{Q7Z=n28vN3?#EjGBM=Tx02w4dZG:_6A1H@=m6gnI:*cuIz381}r8*(o?)+nvPV6rhLV!u:.uRi5hF=uQGX5ygfCP%@RPQrzkrr]KE?JMp$uG!:)XRPSU.PkBZ-{W-Re.o?wk=]_Vh8h+KZ:!LhF4v=EhR*}]#{2w$^8V)J#hd16];9;wGeLvDl5u$hV{I?jez1$30Ra^hIz^#5=[Q*Gj)E,Wsgz}ioU#-;[-xg;np$/rf_W;h%(RV?;JQqkQn7OAM,GYEjW1xWoE8mV4{6JV$bilZu5[IBB%06W^o721k0mNh0.?(FB}l09)x(d}dv5CcNBXYgG!4Ca::KcByO.JZCISLdppd)d4SkMD6$nNS6eAbB(Xlip6;w*L3-Iuo-vg{h)%_J^8zp7ZW95M4Fdg:xw1lJd8pBJ7Yv]hh:us)kq$HieyPuzB:zrETtaTK%o(wX$X=aWjIATl]F,^rt1zdaPl=Ku7iwVuGru)LN+WMy2]tJR(1(!KAdp/mfL5^EE!CKYomR-#A:P:eX;,3RuJ,1WzhZqXunOi9o^XQtrJh^+[cY2[slAg:,q0e1bufEoHS^Uz-[SQYOh!WzCNEwx:$3@=x@/#wkY]Ot=+v_6zd/!]rbc-EE-EmJJNq]0oBGUlTv#XE_pD:}6Ga^zx)]=$P^4%WrI-t?WM2UbA$)gtfBzPK]m+:g$#g[yjqdYVys.DJe!EA:{PL.#z6PQjh9KJLE}?+=5!7V@q4MMxjRpb+IwNT7@5EfZRn7L7*=)U9]QqpS[?W,**P}!*$!U5B9,S!rna=K)LY2GV%pAHqQ=p[Tu6720[WTUq?*;x/!rWJKa7BSjt7FT(O_zvl1k_pO8z9UeVe0A.1XS1*^QVOy0zqLw+U(LfSTrQ^wc51zlphe4k-%oBSfQF0ciTSC4X*$KaPL7,rS_S(:y=)NZ)gLEulIRSn-anO1@7@WG3S5p]k-u?;j*V(SQRE$q)SB/$bT#Wh%B[S+rVc{ZLoKy+mRzo#v,cN:Hp8B-(8N-3h3%sD(jkwLzJF3su9$k{u1=6G*m?4;3(BQys/d:3UK6XVIjoN{kY4;Y1bWkkXX5lzI/3H,eii)9b,TS-_46Wl8BtOl(Ae^fg1k,?Fs=tp}BLHwxe?go4@SJAS%eLHR8xgrFd*BaLtR_)7@x,%K(j81XcGl;kbA7NhOzzNe{lIfK$[!M4-+GZa:ycb4i!a3c?9VceMSd+@Yd24z{A$0ewIBsQ4L(!Vw0aSQ/.W,(6,nH)mz*4Mw6-RxJX?7M6T9=yA],cn9kINlOj}C+FvU[bWPU.h4]i;gdrDe92iRSFC]..Ump5wchn+B,%+Cg3V:faMRUbt/.Z49^6:68TQAcMROJy!kJjFfH0ASZ32]Xr2,=2+e^n*%$Mx7sx5O:ju%7a+2D;*#00$WFt$(-tlkoZ.?n6^*=mplA5Kc8o%h)?)4yX[{^kK8S^#9Ky]{A[e-$Qc{#AKW.RHq-(gLn[x[g7pMb%=9S.:6Y8.Vq^wLJGExP8u_/*:u/kyH[vpS/F49o:PFmGSBA;Bn6(Mb$=DTQuJzi?I=m+U1wbSKvCE35!B4_?H.r$@ppEgA[ho2BI[p2u^Uq/Q-$%8GRcJAGENS(+G=9;[.DV+}^[[s_lp3B$Ypv}$z=Be)OUK,TWZ2E^E%K^!MCt:#P;6qXQuUe-yGIP:^j!UbT._^[UQQycbr%CoHO7mS6G5]7tCz{i@s{@qXg=TC8Equa6-vdqUbKC^7PLA6zdAi:yDs-qxTW}-lnT1h$1:iDKy/b}w$*]y}tQ[$D@z!kLKA;@oXu@V5U$FQ*;o)o.l(?FQRwLX(5]6Y0mUEw9Jr-Ow/g;F^#i01}$SQHwe_-NILpl8USnu(Ow}F=qb]8)LgI-NYQQG6/oihvkCOujqlTNz=wTDCHa}#uCuHZ-!E{N]tF,VM%e[i,0noCJpLs;MZMYI)Li[z-rG;}R,5]CI%X!6_*xLXdFD3HR%VPSH?qRjxai{]U%HdzX0@IR*qxgK00:d8SE#k6hu[PsMi)@?4aN0Rimub-kOvY4@Qq{h!.R]..E)s%)*0Hv4SSqzcE9o34i/FKJcif1FsL!tH=.1R[qAlHvi2RC)!3W#G$xV:dJ,yR}z;O,)Cbx}T$RwRD_+XN;8Qg-{NQ*z*oK0^+SuG];R+EhEvE6m;BveYu3foh4(wZR*d:u=1$)J7U$Z1j#JmGH8w$zlMQK?qE}RB(3yQ#6;)?.YmFr{T3Go@A19J1-ke5X,StZ@T!tN(MJqr=$Q5I[4)e(C!p8u)lD*sNKP=cg;w1P:_x[!_,)onZYu}=$.)p].eNDj[A,}X7){258Io!ViY[z4X1lkoE9E$@9}xyZGt2Z$5YwSRk6AW;5VfwSk,ay-9ixWb5[Q$#Kl9AD}bn6z3ZOhUwK,ZKU56#03BJ3*1}XlY!p^WhPN.hhD}qU#Qa$o),Ni4WGTQ]=tYaq=e.5:nEetm1s1QK93^C@K@NikKGS*FqN213=:qq4A.!SqgI?+XEt;;uChz9jB%jrF9_aXeCua9kzJ}y=I:uU_4Y:JtsPJ:MZWf#)p0EJb[tbbNDRJArT*{x2H=y.=PKdgC$]t!pD,svew%v/_lq-jHrUzA[I]_DyS:A=u[2Jl6Y]/z$xu8ViA/H9XH6v+P*$Yg[f}2Gxz_+=biT7olR{WH7[g9vVNHH[c49Fnv]QRAjHoC-K7[G-+TV[x]C8aW*f0ofr%qI1h=7m}]hFk=tc)hEeG@yr?]/w[*j9qs!,{5[m+Cva84YD,#eCug%l]-eflE*vM7c,8FK7f!^Y0cxX[%qF:Jl_sDm_AAU2e]-(dM-HZ^Vac?pSJ(Vte#H5/cM?+i48^fsCt^0C)TPUWk!:ALb[UFX.#6xrF}sHVrC^n8dJHEoZmnE.u#B_l]=ke[-UM}lA:e)A24T@(80)364*w5KX-*E%9C9N@RxH*G437rg{Pt#3d)mjR%Kt:G(?ysOmg-5Mxs.#%eTD4PDj$(b=@70-4_(ZgXe022hu-b+L+3KeeLc:O^WWaQ(A(,X[6y)E-gJXm;J.#Y)OwJz7UQGm**%[Z_p;CQeq5oUwrzD9@XVoe[BGBL_pVZndZ%3LKY)_-xWG3-6aMHep{f$Y=W1tsni/*^{Q{#t5c1$+)edO=deP8A*K=x)_QA,?CoH$N[#b=RpL%r/h7=*Qa!!iN[2J]3oOnEcCc{rOxkti.*T1(rly$d!+NgSM1vlYQXli5YRMczI5g8G)xJj$%/fcET-,N*DnI8?;dq_RMDh-=gToa:0fU{DQKqL]hkvMzDB@c^;}N/DX2V83+)oIb7@/Gr^6TE}tU%z^RPl)^h6zc0(le9V,smp0yQ#nr/Ef-S$(CniLW32pev;{Qq^.XBl$dVSmp/fa,c;mjQqB#6,7YFtSI#mjcsHkT?]!]$-#pnc:7xys1BO2DKxE@CE})$%RH;WuI}osQ54bn#(A3SEoCH5TOK8/;cj.rHfpkr.!-byf,kK}Iys+k+vi:9Lh^5t,nX@loFzv1mHe-)k!,xdJRUC2F6p9g,*Jc!-SD[}e2)za-,UsjL1o=_+4B%o:9}#R=4_.Uu)t})VLXgQCad1l:Bvh?A$a$=wh]Yq?ddnQ*Rct2VKIKE(L8A^xM6Prqy/Fr=yOetg84Jz++_-MXUcP#vLd^XK)yx[ZSvkccL7wGeN]+hn)YsA(PBZF8T@kO{B?gZi=,2Uc!9kthi%uvphNhOzP3QUhs*qv0DDPIYA^w{4u;4,_]h8)tf#-d)^Wx;tV7mYNmj1T#,g?#*pwEiSxC9qbs7qXlNh_a;s@a$6Qpzr!(fkwKgVfBEJRV-OZ$+IRDIMvSqp:tJX.B;MW?UBzluH@hN${(ng[@,237+5A7Ebcis#xD^M]6-+[OGiT)RO6b?Ya?:M-r;ze9Cu+;)SD[:1tM_b6v+k8yP4]W@JzFq.W_Z^K.CD%)y(w+^bwU^rMMG:M.VNvXdLRR=vFG71SXf$@4+uP+6}sL_WS?R;,wVk]-@;UXb4{1d$]ytX(N?LF+_dJ[Ga6!dgetTut:n60Yv2jh0?hrKTGh2{UUWfO1^/#,#B?d!8kai!b4YrH3WA,Jj^e-+A(m+(bNY(9VX0%h9u5(%hd=z:fCoL5rU!ndHVrMRCv;[I{%l0!krz59JCmVz9=n1+%%oBXB-@gTUb0=Vb8KOYQcd,cdpz8H=.6O7TYLJ:$W0ORZb_zpB,/T7qzb^NaK9gA$%uumrufjkEg7]4u4#wGH9)7F%I#UJbFRIS1FHk$_!7A4^1VzU-(@!(TxpY_6RBVFVM/.FE{qO0S_XMz#l+S=n$pcRPN3^S$q@0xH5Rc7}WXJ(XPwns0j@I)_e=UVmv?$A[BJCi/WSI8JP)53F^c71#=sV;^J0Y%gFzG-Z.88t)-WSEjjq6)setu8@s?^WIOp?2*kEi8vhM;@=4:bNNDUHvhYth8U?!oM!f7va35T?:Kw%Sj=3sRjDc61u5:VRgL2eM;YK4w,V,*CHMt}73SEAHoVhLALcT8ym;dHfunSdn3K4#-Dfvfr?A?u1(3h5?OHGKdXt./N}0@Pjiz{DU0HduS3HtiynOeY2JJf,oqfe1%uVSIrrO5Urc#oOu$ILan)BsPQJ;jjR5T8dPSY:W4{2Ys.brV+rMO(j4AsZR!wBV+zX:Q6Pq;z$JgK]3K@)_._ER[k7wB/[8X?ITe,W?f@J2HO4IkJL1_QLmXG?P4/aWz)%Kw#x9DHEtetoLk6.J0Dw4/onN.P2]l]bB[#Nc1VB*v)q9IWKPF@mYspQ1aQ;:KVn[#0fb;eQ:bZ%0JdWPNi7Fw_M#xP@9Lq^#^?s/*TxGX0Q{LasDMT!l?{]6A+.?4uC/.nF?0mHbU/TpxtQ^Dr*EzMx@=?.;nB%,v7OsM@x0Dl=H#ikCMXoNxWT4z0Oo[55*W#L-ce5Sd,dA$/WMzeuBW0^s9=Ak@cp*Aa+o@vd,Pf_dT[lYK}Hmk}+hB}0f=[HcNb)go!8#8Yo.(_TP0[+,-o/dBTSs=2vgv=@_0.UvsO-Kc{bJ!:ehocEsE]_0JoeS%pUZ{]Di^s(*7zToFNnwh,+)xF3oY#eMi[$4bK,r79i:v,^*07y.7qXUUQOE._6)3,gW(WFhMS1PIxCkoe[cX}KUENp5WN@?$iS%}QSR5x$damvTH9D[k]*g]{06v$2DHSMlMAFGtPTi:1W=}pw2#4ReA:K($!q;+,!Hg:_*:38_R+y}?woJ7*UafUa74jPZE3LcDZSTxjRnULnA2cbx!v(m;{mr,sQLNG4R1vxdiR5YzcB(9/}t(%k1aTxLiJUyM1%5z_lsk+LP5QJGh9/.zXT_)dcJ*8l5M01)trvnLHhe5-vV4Nqd+^?.@mOBV*n/DrVki3ALP84cmmG-^Z+Y.yuLB?bfqF-]Nz$@E7+[HC+.tbJ6KI}}e(8F]/;reUvLrj$lyCXl{#hY_F1;f=frB$uXw^G_p=Th_%VtA9@SJFx^JAzToE-,hAWA)iI3^GNKf2f,dLpK)Wq@!(e.bv3,cMiEEV$J23tbD$)FsgXsA,1oM,c}=wx!ewFR@ZL+ff0PtbdU?%N$_i_[pdh*DZMbts(pkbE26=DvVn/rci%{A;Qd#ZiQ;o[I@*vL;.[}gt@RZPqPDT%Djv:,LU^/!w6q$Ff!.5.AOQvxcMhhn;xMto0z%Yv-N.b(KNrPOM-!.d$uARS3r%-*-WkfT6I#rn]fAOFV+sdg#T3iE]?ei(;3;!4$HXVSfrclaK@1!@6M+42Y!b26fY,;_MxAXHG!?x!x3377k/2u%$vfdgv5!@!xyE%y^ZW/vHf_9F^f^%AOZ07-RvyX{==wO8CXRPigT%tb2x}5XTPsib075z#*1SZ3OSRA;ufBeL/$ie-kOWv*Q_Z3We3XdY+hHR%dG{N1vkN**l.s##X2{fcS6HxRnLo31YFTEyqfKdspeiJ(ZKv7yjoOk?*$$Gvp)rtyo4$qO/)jd=P2!*4GCnDQYlCx%LH)Nxlb=X2Y]x#Dj,V}i?0I[m9jtI/5h}!*07UOdi/Sl*ES^^=[W*pHaOLY7d1K,NlIR8n*$qCS:9,udjr^t;wMAjMGLjcTa};8CMXjF)r;B.Vl{2SoOGcZ:J!zG.2,x$6L?*r}ur^A*Td5vrBXkk-M::(p54ZV@t2:TZER51X7DOLXYcW$:(k*zCPY(m}La1.nAd]j$5vz{tWjh.4uEJeb*LD:x$;HFt?/CqHrGXnHn9b(iV(,,%EdtJ,.YIaUc,rezdt?SEvs^G9/%m:/XiBN?KMu+4KyjBQ,9mjE*pF]REsUwHX4OK1RLF(0?sh0@M,M+GQK{]szZ%o#NP;TK#N2IaceTC5IDiQB+JDU9VkICz=[{/d+/iub[OulGY?;*+@{){h#?gwQNULUhfsB@$:lRIYOt!=Exruu153tPqH$vJY0:z.OUl$%OkCxhMIzQ(i4:$2EG*})ZC8p)fASYfXxni+0@*rohG7x!RS:_DMlGi(:9/2b,PJm}fNOUyIcG?Y2ai(MK_4;uWR/2gGj^YA
14893
"A Plague Tale Requiem v1.0 (GOG & Steam)"
000080
1
1418
"(FastTravel & Cutscenes cause values to 'reload'... !)"
FF0080
1
1424
"(it can take a few seconds to collect the values...)"
FF0000
1
1993
"Enable cheats... (after save has fully loaded)"
808000
Auto Assembler Script
{ Game : <game>.exe
Version:
Date : 2020-05-04
Author : <author>
}
[ENABLE]
aobscanmodule(Torch,$process,F3 0F 10 87 DC 05 00 00)
registersymbol(Torch)
alloc(newmem,$100,Torch)
aobscanmodule(RatSense,$process,40 53 48 83 EC 30 48 8B D9 0F 29 74 24 20 B9 80)
registersymbol(RatSense)
alloc(newmem2,$100,RatSense)
aobscanmodule(Invisible,$process,20 8B 81 D0 23 00 00)
registersymbol(Invisible)
alloc(newmem3,$100,Invisible)
aobscanmodule(Godmode,$process,0F B6 81 B0 06 00 00)
registersymbol(Godmode)
alloc(newmem4,$100,Godmode)
globalalloc(pTorch,8,$process)
globalalloc(bTorch,1,$process)
globalalloc(pRatSense,8,$process)
globalalloc(bInvisible,1,$process)
globalalloc(pGodmode,8,$process)
globalalloc(bGodmode,1,$process)
globalalloc(pInvFlag,8,$process)
globalalloc(pInventory,8,$process)
globalalloc(nInvMax,4,$process)
globalalloc(pRewards,8,$process)
globalalloc(bChoice,1,$process)
globalalloc(bUnlockReset,1,$process)
bUnlockReset:
db 0
bTorch:
db 0
bInvisible:
db 0
bChoice:
db 1
nInvMax:
dd (int)20
// see [Maintenance scripts ~ 'special' scripts] (x3)..
globalalloc(bInverseXY,1,$process)
bInverseXY:
db 1
// torch...
label(code)
label(return)
newmem:
mov [pTorch],rdi
cmp [bTorch],1
jne code
mov byte ptr [rdi+000005D8],1
mov byte ptr [rdi+000005E4],1
code:
movss xmm0,[rdi+000005DC]
jmp return
Torch:
jmp newmem
nop 3
return:
// ratsense...
label(code2)
label(return2)
newmem2:
mov [pRatSense],rbx
code2:
push rbx
sub rsp,30
jmp return2
RatSense:
jmp newmem2
nop
return2:
// invisible...
label(code3)
label(return3)
// structs Amicia & NPC & close enemies(~ companions... ?)
// possible checks: +B0~C0
newmem3:
cmp [rcx+B0],1
jne code3
cmp [bInvisible],1
jne short @f
mov dword ptr [rcx+23D0],0
jmp code3
@@:
mov dword ptr [rcx+23D0],2
code3:
mov eax,[rcx+000023D0]
jmp return3
Invisible+01:
jmp newmem3
nop
return3:
// godmode ~ settings - gameplay - invincible mode...
label(code4)
label(return4)
newmem4:
mov [pGodmode],rcx
cmp [bGodmode],1
jne short @f
mov byte ptr [rcx+000006B0],1
jmp code4
@@:
mov byte ptr [rcx+000006B0],0
code4:
movzx eax,byte ptr [rcx+000006B0]
jmp return4
Godmode:
jmp newmem4
nop 2
return4:
[DISABLE]
bTorch:
db 0
bInvisible:
db 0
Torch:
db F3 0F 10 87 DC 05 00 00
unregistersymbol(Torch)
dealloc(newmem)
RatSense:
db 40 53 48 83 EC 30
unregistersymbol(RatSense)
dealloc(newmem2)
Invisible+01:
db 8B 81 D0 23 00 00
unregistersymbol(Invisible)
dealloc(newmem3)
Godmode:
db 0F B6 81 B0 06 00 00
unregistersymbol(Godmode)
dealloc(newmem4)
{ torch...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+4437CB
APlagueTaleRequiem_x64.exe+44379D: 80 BF D8 05 00 00 00 - cmp byte ptr [rdi+000005D8],00
APlagueTaleRequiem_x64.exe+4437A4: 75 71 - jne APlagueTaleRequiem_x64.exe+443817
APlagueTaleRequiem_x64.exe+4437A6: 0F 2F B7 E0 05 00 00 - comiss xmm6,[rdi+000005E0]
APlagueTaleRequiem_x64.exe+4437AD: 72 68 - jb APlagueTaleRequiem_x64.exe+443817
APlagueTaleRequiem_x64.exe+4437AF: 48 8D 8F 80 03 00 00 - lea rcx,[rdi+00000380]
APlagueTaleRequiem_x64.exe+4437B6: E8 55 D3 20 00 - call APlagueTaleRequiem_x64.exe+650B10
APlagueTaleRequiem_x64.exe+4437BB: 84 C0 - test al,al
APlagueTaleRequiem_x64.exe+4437BD: 74 0C - je APlagueTaleRequiem_x64.exe+4437CB
APlagueTaleRequiem_x64.exe+4437BF: 48 8D 8F 80 03 00 00 - lea rcx,[rdi+00000380]
APlagueTaleRequiem_x64.exe+4437C6: E8 15 D3 20 00 - call APlagueTaleRequiem_x64.exe+650AE0
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+4437CB: F3 0F 10 87 DC 05 00 00 - movss xmm0,[rdi+000005DC]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+4437D3: F3 0F 5C C7 - subss xmm0,xmm7
APlagueTaleRequiem_x64.exe+4437D7: 0F 2F C6 - comiss xmm0,xmm6
APlagueTaleRequiem_x64.exe+4437DA: F3 0F 11 87 DC 05 00 00 - movss [rdi+000005DC],xmm0
APlagueTaleRequiem_x64.exe+4437E2: 77 3F - ja APlagueTaleRequiem_x64.exe+443823
APlagueTaleRequiem_x64.exe+4437E4: 48 8B 47 68 - mov rax,[rdi+68]
APlagueTaleRequiem_x64.exe+4437E8: 39 A8 1C 04 00 00 - cmp [rax+0000041C],ebp
APlagueTaleRequiem_x64.exe+4437EE: 75 08 - jne APlagueTaleRequiem_x64.exe+4437F8
APlagueTaleRequiem_x64.exe+4437F0: 48 8B CF - mov rcx,rdi
APlagueTaleRequiem_x64.exe+4437F3: E8 08 9C FF FF - call APlagueTaleRequiem_x64.exe+43D400
APlagueTaleRequiem_x64.exe+4437F8: 48 8B 47 70 - mov rax,[rdi+70]
}
{ ratsense...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+2FA3C0
APlagueTaleRequiem_x64.exe+2FA3B6: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3B7: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3B8: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3B9: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3BA: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3BB: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3BC: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3BD: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3BE: CC - int 3
APlagueTaleRequiem_x64.exe+2FA3BF: CC - int 3
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+2FA3C0: 40 53 - push rbx
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+2FA3C2: 48 83 EC 30 - sub rsp,30
APlagueTaleRequiem_x64.exe+2FA3C6: 48 8B D9 - mov rbx,rcx
APlagueTaleRequiem_x64.exe+2FA3C9: 0F 29 74 24 20 - movaps [rsp+20],xmm6
APlagueTaleRequiem_x64.exe+2FA3CE: B9 80 00 00 00 - mov ecx,00000080
APlagueTaleRequiem_x64.exe+2FA3D3: 0F 28 F1 - movaps xmm6,xmm1
APlagueTaleRequiem_x64.exe+2FA3D6: E8 65 2B 97 00 - call APlagueTaleRequiem_x64.exe+C6CF40
APlagueTaleRequiem_x64.exe+2FA3DB: F3 0F 59 05 E1 B0 46 01 - mulss xmm0,[APlagueTaleRequiem_x64.exe+17654C4]
APlagueTaleRequiem_x64.exe+2FA3E3: 0F 57 C9 - xorps xmm1,xmm1
APlagueTaleRequiem_x64.exe+2FA3E6: 48 8B 03 - mov rax,[rbx]
APlagueTaleRequiem_x64.exe+2FA3E9: 33 C9 - xor ecx,ecx
APlagueTaleRequiem_x64.exe+2FA3EB: F3 0F 10 15 CD 9F 46 01 - movss xmm2,[APlagueTaleRequiem_x64.exe+17643C0]
APlagueTaleRequiem_x64.exe+2FA3F3: F3 0F 59 C6 - mulss xmm0,xmm6
APlagueTaleRequiem_x64.exe+2FA3F7: 48 8B 90 40 01 00 00 - mov rdx,[rax+00000140]
APlagueTaleRequiem_x64.exe+2FA3FE: 48 8B 82 80 00 00 00 - mov rax,[rdx+00000080]
APlagueTaleRequiem_x64.exe+2FA405: F3 0F 58 80 C8 02 00 00 - addss xmm0,[rax+000002C8]
APlagueTaleRequiem_x64.exe+2FA40D: F3 0F 5D C2 - minss xmm0,xmm2
APlagueTaleRequiem_x64.exe+2FA411: F3 0F 5F C1 - maxss xmm0,xmm1
// ---------- INJECTING HERE ---------- [HugoVCheck+55]
APlagueTaleRequiem_x64.exe+2FA415: F3 0F 11 80 C8 02 00 00 - movss [rax+000002C8],xmm0
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+2FA41D: 38 0D 5D 24 07 02 - cmp [APlagueTaleRequiem_x64.exe+236C880],cl
}
{ invisible...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+507BCA
APlagueTaleRequiem_x64.exe+507BB9: CC - int 3
APlagueTaleRequiem_x64.exe+507BBA: CC - int 3
APlagueTaleRequiem_x64.exe+507BBB: CC - int 3
APlagueTaleRequiem_x64.exe+507BBC: CC - int 3
APlagueTaleRequiem_x64.exe+507BBD: CC - int 3
APlagueTaleRequiem_x64.exe+507BBE: CC - int 3
APlagueTaleRequiem_x64.exe+507BBF: CC - int 3
APlagueTaleRequiem_x64.exe+507BC0: 48 89 5C 24 08 - mov [rsp+08],rbx
APlagueTaleRequiem_x64.exe+507BC5: 57 - push rdi
APlagueTaleRequiem_x64.exe+507BC6: 48 83 EC 20 - sub rsp,20
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+507BCA: 8B 81 D0 23 00 00 - mov eax,[rcx+000023D0]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+507BD0: 48 8B D9 - mov rbx,rcx
APlagueTaleRequiem_x64.exe+507BD3: 85 C0 - test eax,eax
APlagueTaleRequiem_x64.exe+507BD5: 0F 84 84 01 00 00 - je APlagueTaleRequiem_x64.exe+507D5F
APlagueTaleRequiem_x64.exe+507BDB: 83 F8 01 - cmp eax,01
APlagueTaleRequiem_x64.exe+507BDE: 0F 84 6E 01 00 00 - je APlagueTaleRequiem_x64.exe+507D52
APlagueTaleRequiem_x64.exe+507BE4: E8 07 9E FF FF - call APlagueTaleRequiem_x64.exe+5019F0
APlagueTaleRequiem_x64.exe+507BE9: 48 85 C0 - test rax,rax
APlagueTaleRequiem_x64.exe+507BEC: 75 11 - jne APlagueTaleRequiem_x64.exe+507BFF
APlagueTaleRequiem_x64.exe+507BEE: 48 8B CB - mov rcx,rbx
APlagueTaleRequiem_x64.exe+507BF1: E8 3A 9A FF FF - call APlagueTaleRequiem_x64.exe+501630
}
{ godmode...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+57F850
APlagueTaleRequiem_x64.exe+57F840: 0F B6 81 90 06 00 00 - movzx eax,byte ptr [rcx+00000690]
APlagueTaleRequiem_x64.exe+57F847: C3 - ret
APlagueTaleRequiem_x64.exe+57F848: CC - int 3
APlagueTaleRequiem_x64.exe+57F849: CC - int 3
APlagueTaleRequiem_x64.exe+57F84A: CC - int 3
APlagueTaleRequiem_x64.exe+57F84B: CC - int 3
APlagueTaleRequiem_x64.exe+57F84C: CC - int 3
APlagueTaleRequiem_x64.exe+57F84D: CC - int 3
APlagueTaleRequiem_x64.exe+57F84E: CC - int 3
APlagueTaleRequiem_x64.exe+57F84F: CC - int 3
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+57F850: 0F B6 81 B0 06 00 00 - movzx eax,byte ptr [rcx+000006B0]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+57F857: C3 - ret
APlagueTaleRequiem_x64.exe+57F858: CC - int 3
APlagueTaleRequiem_x64.exe+57F859: CC - int 3
APlagueTaleRequiem_x64.exe+57F85A: CC - int 3
APlagueTaleRequiem_x64.exe+57F85B: CC - int 3
APlagueTaleRequiem_x64.exe+57F85C: CC - int 3
APlagueTaleRequiem_x64.exe+57F85D: CC - int 3
APlagueTaleRequiem_x64.exe+57F85E: CC - int 3
APlagueTaleRequiem_x64.exe+57F85F: CC - int 3
APlagueTaleRequiem_x64.exe+57F860: 0F B6 81 D0 06 00 00 - movzx eax,byte ptr [rcx+000006D0]
}
88868
"God Mode"
0:<Disabled>
1:Enabled
0
Byte
bGodmode
88303
"Invisible"
0:<Disabled>
1:Enabled
0
Byte
bInvisible
88305
"Lock Torch Burning"
0:<Disabled>
1:Locked
0
Byte
bTorch
88775
"Time Remaining"
0
Float
pTorch
5DC
88763
"Lock Stun Exstinguis/Ignifier/Tar"
Auto Assembler Script
{ Game : APlagueTaleRequiem_x64.exe
Version:
Date : 2022-10-31
Author : Paul44
Once stunned by exstinguis, remains stunned...
}
[ENABLE]
aobscanmodule(StunExstinguis,$process,48 8B D9 0F 97 C0)
registersymbol(StunExstinguis)
alloc(newmem,$100,StunExstinguis)
label(code)
label(return)
newmem:
mov rbx,rcx
seta al
code:
cmp eax,eax
mov al,0
jmp return
StunExstinguis:
jmp newmem
nop
return:
[DISABLE]
StunExstinguis:
db 48 8B D9 0F 97 C0
unregistersymbol(StunExstinguis)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+23DC71
APlagueTaleRequiem_x64.exe+23DC5B: CC - int 3
APlagueTaleRequiem_x64.exe+23DC5C: CC - int 3
APlagueTaleRequiem_x64.exe+23DC5D: CC - int 3
APlagueTaleRequiem_x64.exe+23DC5E: CC - int 3
APlagueTaleRequiem_x64.exe+23DC5F: CC - int 3
APlagueTaleRequiem_x64.exe+23DC60: 40 53 - push rbx
APlagueTaleRequiem_x64.exe+23DC62: 48 83 EC 20 - sub rsp,20
APlagueTaleRequiem_x64.exe+23DC66: F3 0F 10 41 04 - movss xmm0,[rcx+04]
APlagueTaleRequiem_x64.exe+23DC6B: 0F 57 D2 - xorps xmm2,xmm2
APlagueTaleRequiem_x64.exe+23DC6E: 0F 2F C2 - comiss xmm0,xmm2
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+23DC71: 48 8B D9 - mov rbx,rcx
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+23DC74: 0F 97 C0 - seta al
APlagueTaleRequiem_x64.exe+23DC77: 76 1E - jna APlagueTaleRequiem_x64.exe+23DC97
APlagueTaleRequiem_x64.exe+23DC79: F3 0F 5C C1 - subss xmm0,xmm1
APlagueTaleRequiem_x64.exe+23DC7D: 0F 2F C2 - comiss xmm0,xmm2
APlagueTaleRequiem_x64.exe+23DC80: F3 0F 11 41 04 - movss [rcx+04],xmm0
APlagueTaleRequiem_x64.exe+23DC85: 76 10 - jna APlagueTaleRequiem_x64.exe+23DC97
APlagueTaleRequiem_x64.exe+23DC87: F3 0F 58 49 08 - addss xmm1,[rcx+08]
APlagueTaleRequiem_x64.exe+23DC8C: F3 0F 11 49 08 - movss [rcx+08],xmm1
APlagueTaleRequiem_x64.exe+23DC91: 48 83 C4 20 - add rsp,20
APlagueTaleRequiem_x64.exe+23DC95: 5B - pop rbx
}
88267
"Ratsense"
0
Float
pRatSense
2C8
80
140
88104
"Resources..."
Auto Assembler Script
{ Game : APlagueTaleInnocence_x64.exe
Version:
Date : 2020-05-29
Author : Paul44
Gets Resources...
}
[ENABLE]
{$lua}
local f = nil
local nChoice = 0
local sMsg = ''
local sInfo = ''
local sListItems
addrStruct = ''
strStruct = ''
getStaticAddr('48 8B 01 FF 90 F8 05 00 00 84',4,'pInventory',0)
function setInventoryMax()
local bSet = 0
local nMax = readInteger(getAddress("nInvMax"))
if (nMax < 10) then nMax = 10 end
local nItems = f.ListBox.Items.Count
for i = 0,nItems-1 do
local addrItem = f.ListBox.Items[i]:match("{(.-)}")
addrItem = tonumber(addrItem,16)
local nTotal = readInteger(addrItem+0x48)
if (nTotal < nMax or bSet == 1) then writeInteger(addrItem+0x48,nMax) end
end
collectInventory()
end
function collectInventory()
--local nChoice = readBytes(getAddress("bChoice"),1)
--if not (nChoice == 1 or nChoice == 2) then return end
local addrInvChain = '[[[[[pInventory]]+0x40]+0x10]+0x30]'
addrInvChain = getAddress(addrInvChain)
local addrInvChk = readPointer(addrInvChain+0x8)
--local nItems = readInteger(addrInvChain) -- nItems - 3 == number of inventoryItems...
local nRecord = 0x78
--print(string.format('%X ~ %X',addrInvChain,addrInvChk))
-- if true then return end
execRoutine = setInventoryMax
sMsg = 'List Resource Items'
--if (nChoice == 2) then sMsg = 'List All Perks' end
aStructGui = {'A Plague Tale - Edit Inventory','Inv_Item',550,300,false,320,250}
aStructInfo = { {'Total',0x48,vtDword,true} }
-- google: cheat engine Async exec Form invalid window handle
synchronize(function()
-- painting form...
f = IconList
f.Width = 600
f.Height = 500
f.Show()
f.Caption = 'A Plague Tale - Managing Inventory...'
local lBox = f.ListBox
lBox.Clear()
local lbTitle = f.IconTitle
lbTitle.Caption = 'One moment please... processing...'
local lbInfo = f.IconInfo
lbInfo.Caption = ''
local lbHead = f.IconHead
lbHead.Caption = ' # offs addrItem | Total UniqueId'
local lbMsg = f.IconMessage
lbMsg.Caption = "See Readme on how to manage \n and use this info..."
--lbMsg.Visible = true
local cbGod = f.GodMode
f.GodMode.Caption = 'God Mode:'
-- hide info...
f.pCoord.Visible = false
f.Structure.Visible = true
f.RecycleBin.Visible = true
f.RecycleBin.Hint = 'Set resource values to preset max...'
lbInfo.Caption = string.format('Inventory: [%X]',addrInvChain)
lbTitle.Caption = sMsg
end)
local aItems = {['AAF11FF7F7D95605'] = 'Sulphur', ['16E1578892E79424'] = 'Alcohol', ['E09B2C7F148D992'] = 'Saltpeter',
['F687B1BDAB50AB63'] = 'Resin', ['51E9BBC3930B261D'] = 'Pot', ['C31CA38FF8B761A6'] = 'Knife',
['B6DF5733A8ACA26A'] = 'Tar', ['A4E843AD91EC856E'] = 'Ignifier', ['64A715B7187F8562'] = 'Exstinguis',
['4FDC0A1183B6E66B'] = 'Tool', ['E6C1E62BB073419A'] = 'Odoris', ['2893094B4EB0D020'] = 'Fabric',
['A8135878A0C79D16'] = 'Arrow', ['31A88278F680BD24'] = 'Piece'
}
local bContinue = true
local nCount = 0
local nCount1 = 0
while bContinue do
local addrItem = addrInvChain + 0x78 * nCount
-- print(string.format('%X ~ %X',addrItem,readPointer(addrItem+0x8)))
if (readPointer(addrItem+0x8) ~= addrInvChk) then break end
local xID = string.format('%X',readQword(addrItem))
local nTotal = readInteger(addrItem+0x48)
local sDescr = ''
if aItems[xID] ~= nil then sDescr = '<' .. aItems[xID] .. '>' end
local sName = string.format('[%03d/%04X]: {%X} | %3d %16s %s',nCount+1,nCount * 0x78,addrItem,nTotal,xID,sDescr)
synchronize(function()
f.ListBox.Items.Add(sName)
end)
--print(sName)
nCount1 = nCount1 + 1
nCount = nCount + 1
end -- while...
end -- fn collectInventory()
collectInventory()
{$asm}
test al,al
//bChoice:
//db 1
[DISABLE]
88340
"Miscellaneous..."
1
88332
"Skills..."
Auto Assembler Script
{ Game : APlagueTaleRequiem_x64.exe
Version:
Date : 2022-10-31
Author : Paul44
Get experience levels...
}
[ENABLE]
aobscanmodule(Experience,$process,CC CC CC CC CC CC CC CC 4C 8B 01 41 8B 80 10 08 00 00)
registersymbol(Experience)
alloc(newmem,$1000,Experience)
globalalloc(pExperience,8,$process)
label(code)
label(return)
newmem:
mov [pExperience],rdi
code:
mov r8,[rcx]
mov eax,[r8+00000810]
jmp return
Experience+08:
jmp newmem
nop 5
return:
[DISABLE]
Experience+08:
db 4C 8B 01 41 8B 80 10 08 00 00
unregistersymbol(Experience)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+67E630
APlagueTaleRequiem_x64.exe+67E626: CC - int 3
APlagueTaleRequiem_x64.exe+67E627: CC - int 3
APlagueTaleRequiem_x64.exe+67E628: CC - int 3
APlagueTaleRequiem_x64.exe+67E629: CC - int 3
APlagueTaleRequiem_x64.exe+67E62A: CC - int 3
APlagueTaleRequiem_x64.exe+67E62B: CC - int 3
APlagueTaleRequiem_x64.exe+67E62C: CC - int 3
APlagueTaleRequiem_x64.exe+67E62D: CC - int 3
APlagueTaleRequiem_x64.exe+67E62E: CC - int 3
APlagueTaleRequiem_x64.exe+67E62F: CC - int 3
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+67E630: 4C 8B 01 - mov r8,[rcx]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+67E633: 41 8B 80 10 08 00 00 - mov eax,[r8+00000810]
APlagueTaleRequiem_x64.exe+67E63A: 49 8B 88 08 08 00 00 - mov rcx,[r8+00000808]
APlagueTaleRequiem_x64.exe+67E641: FF C8 - dec eax
APlagueTaleRequiem_x64.exe+67E643: 23 02 - and eax,[rdx]
APlagueTaleRequiem_x64.exe+67E645: 48 85 C9 - test rcx,rcx
APlagueTaleRequiem_x64.exe+67E648: 75 04 - jne APlagueTaleRequiem_x64.exe+67E64E
APlagueTaleRequiem_x64.exe+67E64A: 49 8D 48 08 - lea rcx,[r8+08]
APlagueTaleRequiem_x64.exe+67E64E: 48 8B 04 C1 - mov rax,[rcx+rax*8]
APlagueTaleRequiem_x64.exe+67E652: 48 85 C0 - test rax,rax
APlagueTaleRequiem_x64.exe+67E655: 74 17 - je APlagueTaleRequiem_x64.exe+67E66E
}
88333
"Prudence"
0
4 Bytes
pExperience
10
88337
"(max)"
0
4 Bytes
+4
88336
"Agressive"
0
4 Bytes
pExperience
18
88339
"(max)"
0
4 Bytes
+4
88335
"Opportunism"
0
4 Bytes
pExperience
20
88338
"(max)"
0
4 Bytes
+4
88346
"FOV..."
Auto Assembler Script
{ Game : APlagueTaleRequiem_x64.exe
Version:
Date : 2022-10-31
Author : Paul44
Manage FOV...
}
[ENABLE]
//
aobscanmodule(FOV,$process,8B 87 A0 00 00 00 89 83 F0)
registersymbol(FOV)
alloc(newmem,$100,FOV)
//globalalloc(pCamera,8,$process)
globalalloc(fFOV,4,$process)
fFOV:
dd (float)60
label(code)
label(return)
newmem:
//mov [pCamera],rbx
// updates stackvalue...
push r15
mov r15,[fFOV]
mov [rdi+000000A0],r15
pop r15
code:
mov eax,[rdi+000000A0]
jmp return
FOV:
jmp newmem
nop
return:
[DISABLE]
FOV:
db 8B 87 A0 00 00 00
unregistersymbol(FOV)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+625FF9
APlagueTaleRequiem_x64.exe+625FBE: 89 83 DC 02 00 00 - mov [rbx+000002DC],eax
APlagueTaleRequiem_x64.exe+625FC4: 8B 87 90 00 00 00 - mov eax,[rdi+00000090]
APlagueTaleRequiem_x64.exe+625FCA: 89 83 E0 02 00 00 - mov [rbx+000002E0],eax
APlagueTaleRequiem_x64.exe+625FD0: 8B 87 94 00 00 00 - mov eax,[rdi+00000094]
APlagueTaleRequiem_x64.exe+625FD6: 89 83 E4 02 00 00 - mov [rbx+000002E4],eax
APlagueTaleRequiem_x64.exe+625FDC: 8B 87 98 00 00 00 - mov eax,[rdi+00000098]
APlagueTaleRequiem_x64.exe+625FE2: 89 83 E8 02 00 00 - mov [rbx+000002E8],eax
APlagueTaleRequiem_x64.exe+625FE8: 48 8D 4C 24 20 - lea rcx,[rsp+20]
APlagueTaleRequiem_x64.exe+625FED: 8B 87 9C 00 00 00 - mov eax,[rdi+0000009C]
APlagueTaleRequiem_x64.exe+625FF3: 89 83 EC 02 00 00 - mov [rbx+000002EC],eax
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+625FF9: 8B 87 A0 00 00 00 - mov eax,[rdi+000000A0]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+625FFF: 89 83 F0 02 00 00 - mov [rbx+000002F0],eax
APlagueTaleRequiem_x64.exe+626005: 8B 87 A4 00 00 00 - mov eax,[rdi+000000A4]
APlagueTaleRequiem_x64.exe+62600B: 89 83 F4 02 00 00 - mov [rbx+000002F4],eax
APlagueTaleRequiem_x64.exe+626011: 8B 87 A8 00 00 00 - mov eax,[rdi+000000A8]
APlagueTaleRequiem_x64.exe+626017: 89 83 F8 02 00 00 - mov [rbx+000002F8],eax
APlagueTaleRequiem_x64.exe+62601D: 0F B6 87 AC 00 00 00 - movzx eax,byte ptr [rdi+000000AC]
APlagueTaleRequiem_x64.exe+626024: 88 83 FC 02 00 00 - mov [rbx+000002FC],al
APlagueTaleRequiem_x64.exe+62602A: 0F B6 87 AD 00 00 00 - movzx eax,byte ptr [rdi+000000AD]
APlagueTaleRequiem_x64.exe+626031: 88 83 FD 02 00 00 - mov [rbx+000002FD],al
APlagueTaleRequiem_x64.exe+626037: 0F B6 87 AE 00 00 00 - movzx eax,byte ptr [rdi+000000AE]
}
88344
"FOV (default = 60)"
0
Float
fFOV
88024
"Unlock Features..."
Auto Assembler Script
{ Game : APlagueTaleInnocence_x64.exe
Version:
Date : 2020-05-29
Author : Paul44
Gets list of Perks...
}
[ENABLE]
{$lua}
getStaticAddr('48 8B 10 48 8B C8 48 83 C4 28 48 FF 62 50',16,'pRewards')
local f = nil
local nChoice = 0
local sMsg = ''
local sInfo = ''
local sListItems
addrStruct = ''
strStruct = ''
function setCodexEnabled()
local addrReset = getAddress('bUnlockReset')
local bReset = readBytes(addrReset)
local sEnabled = 'ENABLE'
local bEnabled = 1
if (bReset == 95) then sEnabled = 'DISABLE'; bEnabled = 0 end
local sText = 'Do you want to ' .. sEnabled .. ' all listed entries now...? \n'..
''
local nResult = messageDialog(sText, mtInformation, mbYes, mbCancel)
if not (nResult == 6) then return end
local nItems = f.ListBox.Items.Count
for i = 0,nItems-1 do
local addrItem = f.ListBox.Items[i]:match("{(.-)}")
if (addrItem ~= nil) then
addrItem = tonumber(addrItem,16)
writeBytes(addrItem+0x70,bEnabled)
end
end
collectCodex()
writeBytes(addrReset,0)
end
function collectCodex()
local addrReward = getAddress('[[[[pRewards]]+0xD00]+0xD0]+0xA0')
--print(string.format('%X ~ %d',addrReward,0))
local bAllSet = false
execRoutine = setCodexEnabled
sMsg = 'List Codex'
if (nChoice == 2) then sMsg = 'List Upgrades' end
--if (nChoice == 3) then sMsg = 'Special Options' end
if (nChoice == 4) then sMsg = 'List Ammo' end
--if (nChoice == 5) then sMsg = 'List Loot' end
if (nChoice == 6) then sMsg = 'List Trophies' end
if (nChoice == 99) then sMsg = 'List All' end
aStructGui = {'A Plague Tale - Edit Rewards','Codex_Item',550,300,false,320,250}
aStructInfo = { {'Enabled (0/1)',0x70,vtByte,true} }
-- google: cheat engine Async exec Form invalid window handle
synchronize(function()
-- painting form...
f = IconList
f.Width = 700
f.Height = 500
f.Show()
f.Caption = 'A Plague Tale - Managing Rewards...'
local lBox = f.ListBox
lBox.Clear()
local lbTitle = f.IconTitle
lbTitle.Caption = 'One moment please... processing...'
local lbInfo = f.IconInfo
lbInfo.Caption = ''
local lbHead = f.IconHead
lbHead.Caption = ' # Offs addrItem | Enabled | UniqueID'
local lbMsg = f.IconMessage
lbMsg.Caption = "See Readme on how to manage \n and use this info..."
--lbMsg.Visible = true
local cbGod = f.GodMode
f.GodMode.Caption = 'God Mode:'
-- hide info...
f.pCoord.Visible = false
f.Structure.Visible = true
f.RecycleBin.Visible = true
f.RecycleBin.Hint = 'Unlock all listed entrries...'
if not bAllSet and nChoice > 2 then f.RecycleBin.Visible = false end
lbInfo.Caption = string.format('ProfileInfo: [%X]',addrReward)
lbTitle.Caption = sMsg
end)
local aEntries = { {'Collection 1',2,0xB0}, {'Collection 2',4,0xB0}, {'Souvenirs',5,0xB0}, {'Herbarium',3,0xB0,99},
{'Upgrade Category',19,0xB0}, {'Upgrade Effect',20,0x90}, {'Vambrace',25,0xC8},
{'Special Item',16,0x90},
{'Slingshot Ammo',11,0x90}, {'Handthrown Ammo',12,0x90}, {'Crossbow Ammo',13,0x90},
{'Grenade Ammo',14,0x90}, {'Morningstar Ammo',15,0x90}, {'Base Ammo',18,0xB0},
{'Loot',17,0x90},
{'Chapter',1,0x3F0},
{'Trophy',7,0x90}, {'Secret Chest',8,0x90}, {'DLC',9,0x90},
{'Story',24,0x120},
{'Skills',21,0x90},
{'Experience',22,0x90},
{'Tool',23,0x120},
{'DLC Appl',26,0x90},
}
local aUpgrades = { 'Gear','Instruments','Crossbow','Sling','Alchemy',
'Gear_1','Gear_2','Gear_3','Instruments_1','Instruments_2',
'Instruments_3','Crossbow_1','Crossbow_2','Crossbow_3','Sling_3',
'Sling_2','Sling_1','Alchemy_1','Alchemy_2','Alchemy_3',
'Bracer Armor' }
local aSkills = { '','','','','','','','Crafting (Inventory)','Upgrade (Inventory)','','','','','','','Skills (Inventory' }
local aAmmo = { 'Rock','Ignifer','Davorantis','Exstinguis','Odoris' }
local aAmmoHand = { 'Pot','2?','Luminosa','Somnum' }
local aLoot = { '','','','','','','Episanguis','' }
local nStart = 1
local nTreat = 4
if (nChoice == 2) then nStart = 5; nTreat = 3 end
if (nChoice == 3) then nStart = 5; nTreat = 2 end
if (nChoice == 4) then nStart = 8; nTreat = 6 end
if (nChoice == 5) then nStart = 8; nTreat = 1 end
if (nChoice == 6) then nStart = 17; nTreat = 3 end
if (nChoice == 7) then nStart = 21; nTreat = 1 end
if (nChoice == 99) then nStart = 1; nTreat = 24 end
local nCount1 = 0
for i=nStart,nStart+nTreat-1 do
local sReward = aEntries[i][1]
local nIndex = aEntries[i][2]
local xRec = aEntries[i][3]
local bProcess = aEntries[i][4]
if bProcess == nil then
local addrItem = addrReward + (nIndex-1) * 8
--local nRecord = readInteger(addrItem + 0x7C + 8 * (nIndex-2))
addrItem = readPointer(addrItem)
local itemVFT = readPointer(addrItem)
--print(string.format('1. %X | %X ~ %d',addrItem,itemVFT,nIndex))
synchronize(function()
f.ListBox.Items.Add('*** ' .. sReward .. ' ***')
end)
local bContinue = true
local nCount = 0
while bContinue do
local addrCat = addrItem + xRec * nCount
local addrVFT = readPointer(addrCat)
if (addrVFT == itemVFT) then
local sDescr = ''
local bEnabled = readBytes(addrCat + 0x70)
local bPlayed = readBytes(addrCat + 0xA8)
local xID = readQword(addrCat + 0x8)
if (xRec < 0xA8) then bPlayed = '' else bPlayed = tostring(bPlayed) end
if (nChoice == 2) then sDescr = aUpgrades[nCount1+1]; nCount1 = nCount1+1 end
--if (nChoice == 3) then sDescr = aSkills[nCount+1] end
--if (nChoice == 4) then sDescr = aAmmo[nCount+1] end
--if (nChoice == 4 and i == 7) then sDescr = aAmmoHand[nCount+1] end
--if (nChoice == 5) then sDescr = aLoot[nCount+1] end
if (nChoice == 7) then sDescr = aSkills[nCount+1] end
if (nChoice == 1) then sDescr = nil end
if (sDescr ~= nil and sDescr ~= '') then sDescr = '<' .. sDescr .. '>' else sDescr = '' end
local sName = string.format('[%03d][%05X]: {%010X} | %1d %016X %s',
nCount+1,nCount*xRec,addrCat,bEnabled,xID,sDescr)
synchronize(function()
f.ListBox.Items.Add(sName)
end)
--print(string.format('>[%X] %X | %X => %1d ~ %X',xRec*nCount,addrCat,addrVFT,bEnabled,addrCat + 0x68))
nCount = nCount + 1
else
bContinue = false
end
end
end
end
end -- fn collectInventory()
nChoice = readBytes(getAddress("bChoice"),1)
--if (nChoice < 1 or nChoice > 6) then return end
collectCodex()
{$asm}
test al,al
//bChoice:
//db 0
[DISABLE]
88031
"Allow To Run:"
1:List Codex
2:List Upgrades
4:List Ammo
6:List Trophies
7:List Skills
99:List All
0
FF00FF
Byte
bChoice
88439
"Coordinates (informational)..."
Auto Assembler Script
{ Game : APlagueTaleRequiem_x64.exe
Version:
Date : 2022-10-31
Author : Paul44
Coordinates player (ingame & pause)
}
[ENABLE]
aobscanmodule(Coord,$process,48 8B 89 C0 05 00 00 33)
registersymbol(Coord)
alloc(newmem,$100,Coord)
aobscanmodule(Camera,$process,0F 11 86 90 00 00 00 0F 11)
registersymbol(Camera)
alloc(newmem2,$100,Camera)
aobscanmodule(YawPitch,$process,0F 59 94 39 C0 94 08 00)
registersymbol(YawPitch)
alloc(newmem3,$100,YawPitch)
aobscanmodule(Camera2,$process,0F 11 56 40 49 8B 73 20)
registersymbol(Camera2)
alloc(newmem4,$100,Camera2)
globalalloc(pCoord,8,$process)
globalalloc(pCoordPlayer,8,$process)
globalalloc(pCamera,8,$process)
globalalloc(pYawPitch,8,$process)
globalalloc(pCamera2,8,$process)
// 'Player Coordinates' script
globalalloc(pStructCrdBase,8,$process)
globalalloc(pStructCrdOffset,8,$process)
globalalloc(pMappointBase,8,$process)
globalalloc(nDropHeight,4,$process)
// save current location x,y,z coordinates (float)...
globalalloc(OrigCoord,12,"$process")
// init script variables
globalalloc(XYstepVal,4,"$process")
globalalloc(ZstepVal,4,"$process")
globalalloc(ZstepdropHeight,4,"$process")
globalalloc(Xval,4,"$process")
globalalloc(Yval,4,"$process")
globalalloc(Zval,4,"$process")
globalalloc(bFreeRoam,1,"$process")
globalalloc(bCoordSave,1,"$process")
globalalloc(bCoordRestore,1,"$process")
globalalloc(nFrameSpeed,4,"$process")
// fill in offset here ~ see table coordinates...
// seems like several sets need to be updated...?
pStructCrdOffset:
dd 40
nDropHeight:
dd (float)5
XYstepVal:
dd (float)1
ZstepVal:
dd (float)1
ZstepdropHeight:
dd (float)3
bFreeRoam:
db 00
// freeroam timer interval (smoother/faster = 50 - smoothest/fast = 20)
// choose between player or camera
nFrameSpeed:
dd (int)20
// coord player...
// +5C0 +0 +460 +1C8: coordinates player +30
label(code)
label(return)
newmem:
mov [pCoord],rcx
code:
mov rcx,[rcx+000005C0]
jmp return
Coord:
jmp newmem
nop 2
return:
// writes coord camera...
// free roaming...
alloc(updateCrd,$100,$process)
updateCrd:
// updated coordinates...
push r15
mov r15,pStructCrdBase
mov rbx,[r15]
mov r15,pStructCrdOffset
add rbx,[r15]
mov r15,Xval
mov edx,dword ptr [r15]
mov [rbx],edx
add rbx,4
mov r15,Zval
mov edx,dword ptr [r15]
mov [rbx],edx
add rbx,4
mov r15,Yval
mov edx,dword ptr [r15]
mov [rbx],edx
pop r15
ret
label(code2)
label(return2)
newmem2:
mov [pCamera],rsi
@@:
push rbx
push rdx
push r15
mov r15,bFreeRoam
cmp byte ptr [r15],2
jne code2
// freeroam routines... x64: 8-byte ptrs & r?x registers...
// offset = +90
mov r15,pStructCrdBase
mov [r15],rsi
// updated coordinates...
call updateCrd
movups xmm0,[rsi+90]
pop r15
pop rdx
pop rbx
code2:
movups [rsi+00000090],xmm0
jmp return2
Camera:
jmp newmem2
nop 2
return2:
// yaw & pitch...
label(code3)
label(return3)
newmem3:
push r15
lea r15,[rcx+rdi+000894C0]
mov [pYawPitch],r15
pop r15
code3:
mulps xmm2,[rcx+rdi+000894C0]
jmp return3
YawPitch:
jmp newmem3
nop 3
return3:
// writes camera2...
label(code4)
label(return4)
newmem4:
mov [pCamera2],rsi
push rbx
push rdx
push r15
mov r15,bFreeRoam
cmp byte ptr [r15],3
jne short @f
//mov r15,[pCoordPlayer]
//cmp r15,rcx
//jne short @f
// freeroam routines... x64: 8-byte ptrs & r?x registers...
mov r15,pStructCrdBase
mov [r15],rsi
// updated coordinates...
call updateCrd
movups xmm2,[rsi+40]
@@:
pop r15
pop rdx
pop rbx
code4:
movups [rsi+40],xmm2
mov rsi,[r11+20]
jmp return4
Camera2:
jmp newmem4
nop 3
return4:
[DISABLE]
Coord:
db 48 8B 89 C0 05 00 00
unregistersymbol(Coord)
dealloc(newmem)
Camera:
db 0F 11 86 90 00 00 00
unregistersymbol(Camera)
dealloc(newmem2)
YawPitch:
db 0F 59 94 39 C0 94 08 00
unregistersymbol(YawPitch)
dealloc(newmem3)
Camera2:
db 0F 11 56 40 49 8B 73 20
unregistersymbol(Camera2)
dealloc(newmem4)
{ coord player...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+A37B42
APlagueTaleRequiem_x64.exe+A37B2B: CC - int 3
APlagueTaleRequiem_x64.exe+A37B2C: CC - int 3
APlagueTaleRequiem_x64.exe+A37B2D: CC - int 3
APlagueTaleRequiem_x64.exe+A37B2E: CC - int 3
APlagueTaleRequiem_x64.exe+A37B2F: CC - int 3
APlagueTaleRequiem_x64.exe+A37B30: 48 89 5C 24 10 - mov [rsp+10],rbx
APlagueTaleRequiem_x64.exe+A37B35: 57 - push rdi
APlagueTaleRequiem_x64.exe+A37B36: 48 83 EC 30 - sub rsp,30
APlagueTaleRequiem_x64.exe+A37B3A: 48 8B F9 - mov rdi,rcx
APlagueTaleRequiem_x64.exe+A37B3D: 0F 29 74 24 20 - movaps [rsp+20],xmm6
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+A37B42: 48 8B 89 C0 05 00 00 - mov rcx,[rcx+000005C0]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+A37B49: 33 DB - xor ebx,ebx
APlagueTaleRequiem_x64.exe+A37B4B: 0F 28 F1 - movaps xmm6,xmm1
APlagueTaleRequiem_x64.exe+A37B4E: 48 85 C9 - test rcx,rcx
APlagueTaleRequiem_x64.exe+A37B51: 75 04 - jne APlagueTaleRequiem_x64.exe+A37B57
APlagueTaleRequiem_x64.exe+A37B53: 8B CB - mov ecx,ebx
APlagueTaleRequiem_x64.exe+A37B55: EB 13 - jmp APlagueTaleRequiem_x64.exe+A37B6A
APlagueTaleRequiem_x64.exe+A37B57: 8B 87 C8 05 00 00 - mov eax,[rdi+000005C8]
APlagueTaleRequiem_x64.exe+A37B5D: 39 41 18 - cmp [rcx+18],eax
APlagueTaleRequiem_x64.exe+A37B60: 74 05 - je APlagueTaleRequiem_x64.exe+A37B67
APlagueTaleRequiem_x64.exe+A37B62: 48 8B CB - mov rcx,rbx
}
{ coord camera...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+628F44
APlagueTaleRequiem_x64.exe+628F19: 0F 28 7C 24 60 - movaps xmm7,[rsp+60]
APlagueTaleRequiem_x64.exe+628F1E: 45 0F 28 4B C0 - movaps xmm9,[r11-40]
APlagueTaleRequiem_x64.exe+628F23: 45 0F 28 5B A0 - movaps xmm11,[r11-60]
APlagueTaleRequiem_x64.exe+628F28: 0F C6 C9 00 - shufps xmm1,xmm1,00
APlagueTaleRequiem_x64.exe+628F2C: 0F 59 C1 - mulps xmm0,xmm1
APlagueTaleRequiem_x64.exe+628F2F: 0F 59 D1 - mulps xmm2,xmm1
APlagueTaleRequiem_x64.exe+628F32: 41 0F 58 C2 - addps xmm0,xmm10
APlagueTaleRequiem_x64.exe+628F36: 45 0F 28 53 B0 - movaps xmm10,[r11-50]
APlagueTaleRequiem_x64.exe+628F3B: 41 0F 58 D0 - addps xmm2,xmm8
APlagueTaleRequiem_x64.exe+628F3F: 45 0F 28 43 D0 - movaps xmm8,[r11-30]
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+628F44: 0F 11 86 90 00 00 00 - movups [rsi+00000090],xmm0
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+628F4B: 0F 11 56 40 - movups [rsi+40],xmm2
APlagueTaleRequiem_x64.exe+628F4F: 49 8B 73 20 - mov rsi,[r11+20]
APlagueTaleRequiem_x64.exe+628F53: 49 8B E3 - mov rsp,r11
APlagueTaleRequiem_x64.exe+628F56: 5F - pop rdi
APlagueTaleRequiem_x64.exe+628F57: C3 - ret
APlagueTaleRequiem_x64.exe+628F58: CC - int 3
APlagueTaleRequiem_x64.exe+628F59: CC - int 3
APlagueTaleRequiem_x64.exe+628F5A: CC - int 3
APlagueTaleRequiem_x64.exe+628F5B: CC - int 3
APlagueTaleRequiem_x64.exe+628F5C: CC - int 3
}
{ yaw & pitch...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+F7B738
APlagueTaleRequiem_x64.exe+F7B70F: F3 0F 58 C1 - addss xmm0,xmm1
APlagueTaleRequiem_x64.exe+F7B713: F3 0F 58 D8 - addss xmm3,xmm0
APlagueTaleRequiem_x64.exe+F7B717: 0F 28 E2 - movaps xmm4,xmm2
APlagueTaleRequiem_x64.exe+F7B71A: 0F 59 A4 39 B0 94 08 00 - mulps xmm4,[rcx+rdi+000894B0]
APlagueTaleRequiem_x64.exe+F7B722: 0F 28 CC - movaps xmm1,xmm4
APlagueTaleRequiem_x64.exe+F7B725: 0F C6 CC 02 - shufps xmm1,xmm4,02
APlagueTaleRequiem_x64.exe+F7B729: 0F 28 C4 - movaps xmm0,xmm4
APlagueTaleRequiem_x64.exe+F7B72C: 0F C6 C4 01 - shufps xmm0,xmm4,01
APlagueTaleRequiem_x64.exe+F7B730: F3 0F 58 C1 - addss xmm0,xmm1
APlagueTaleRequiem_x64.exe+F7B734: F3 0F 58 E0 - addss xmm4,xmm0
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+F7B738: 0F 59 94 39 C0 94 08 00 - mulps xmm2,[rcx+rdi+000894C0]
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+F7B740: 0F 28 CA - movaps xmm1,xmm2
APlagueTaleRequiem_x64.exe+F7B743: 0F C6 CA 02 - shufps xmm1,xmm2,02
APlagueTaleRequiem_x64.exe+F7B747: 0F 28 C2 - movaps xmm0,xmm2
APlagueTaleRequiem_x64.exe+F7B74A: 0F C6 C2 01 - shufps xmm0,xmm2,01
APlagueTaleRequiem_x64.exe+F7B74E: F3 0F 58 C1 - addss xmm0,xmm1
APlagueTaleRequiem_x64.exe+F7B752: F3 0F 58 D0 - addss xmm2,xmm0
APlagueTaleRequiem_x64.exe+F7B756: 41 0F 28 C6 - movaps xmm0,xmm14
APlagueTaleRequiem_x64.exe+F7B75A: 48 8B 05 8F 38 40 01 - mov rax,[APlagueTaleRequiem_x64.exe+237EFF0]
APlagueTaleRequiem_x64.exe+F7B761: 48 C1 E8 3D - shr rax,3D
APlagueTaleRequiem_x64.exe+F7B765: 24 01 - and al,01
}
{ camera2...
// ORIGINAL CODE - INJECTION POINT: APlagueTaleRequiem_x64.exe+628F4B
APlagueTaleRequiem_x64.exe+628F1E: 45 0F 28 4B C0 - movaps xmm9,[r11-40]
APlagueTaleRequiem_x64.exe+628F23: 45 0F 28 5B A0 - movaps xmm11,[r11-60]
APlagueTaleRequiem_x64.exe+628F28: 0F C6 C9 00 - shufps xmm1,xmm1,00
APlagueTaleRequiem_x64.exe+628F2C: 0F 59 C1 - mulps xmm0,xmm1
APlagueTaleRequiem_x64.exe+628F2F: 0F 59 D1 - mulps xmm2,xmm1
APlagueTaleRequiem_x64.exe+628F32: 41 0F 58 C2 - addps xmm0,xmm10
APlagueTaleRequiem_x64.exe+628F36: 45 0F 28 53 B0 - movaps xmm10,[r11-50]
APlagueTaleRequiem_x64.exe+628F3B: 41 0F 58 D0 - addps xmm2,xmm8
APlagueTaleRequiem_x64.exe+628F3F: 45 0F 28 43 D0 - movaps xmm8,[r11-30]
APlagueTaleRequiem_x64.exe+628F44: 0F 11 86 90 00 00 00 - movups [rsi+00000090],xmm0
// ---------- INJECTING HERE ----------
APlagueTaleRequiem_x64.exe+628F4B: 0F 11 56 40 - movups [rsi+40],xmm2
// ---------- DONE INJECTING ----------
APlagueTaleRequiem_x64.exe+628F4F: 49 8B 73 20 - mov rsi,[r11+20]
APlagueTaleRequiem_x64.exe+628F53: 49 8B E3 - mov rsp,r11
APlagueTaleRequiem_x64.exe+628F56: 5F - pop rdi
APlagueTaleRequiem_x64.exe+628F57: C3 - ret
APlagueTaleRequiem_x64.exe+628F58: CC - int 3
APlagueTaleRequiem_x64.exe+628F59: CC - int 3
APlagueTaleRequiem_x64.exe+628F5A: CC - int 3
APlagueTaleRequiem_x64.exe+628F5B: CC - int 3
APlagueTaleRequiem_x64.exe+628F5C: CC - int 3
APlagueTaleRequiem_x64.exe+628F5D: CC - int 3
}
88441
"Xval Player"
0
808080
Float
pCoord
30
1C8
460
0
5C0
88443
"Yval"
0
808080
Float
+8
88442
"Zval (Height)"
0
808080
Float
+4
88764
"Xval Camera"
0
808080
Float
pCamera
40
88765
"Yval"
0
808080
Float
+8
88766
"Zval (Height)"
0
808080
Float
+4
88602
"Script values"
808080
1
88609
"XYstepVal"
Float
XYstepVal
88610
"ZstepVal"
Float
ZstepVal
88611
"ZstepdropHeight"
Float
ZstepdropHeight
88603
"Xval"
808080
Float
Xval
88604
"Yval"
0
808080
Float
Yval
88605
"Zval"
0
808080
Float
Zval
88606
"OrigCoord X"
808080
Float
OrigCoord
88608
"OrigCoord Y"
0
808080
Float
+8
88607
"OrigCoord Z"
0
808080
Float
+4
88770
"Yaw y"
0
808080
Float
pYawPitch
0
88771
"Pitch"
0
808080
Float
+4
88772
"Yaw x"
0
808080
Float
+8
88619
"Bird's-eye View..."
Auto Assembler Script
[ENABLE]
{$lua}
execRoutine = nil
--local addrEntity = getAddress("[[[[[pCoord]+0x5C0]]+0x460]+0x1C8]")
local addrEntity = getAddress("[pCamera2]")
local CrdOffset = readInteger(getAddressSafe("pStructCrdOffset"))
writeQword(getAddressSafe("pCoordPlayer"),addrEntity)
addrEntity = addrEntity + CrdOffset
if (addrEntity == 0 or addrEntity == nil) then return end
local bInverseXY = readBytes(getAddressSafe("bInverseXY"))
local xOffsY,xOffsZ = 0x4,0x8
if (bInverseXY == 1) then xOffsY,xOffsZ = 0x8,0x4 end
-- struct with yaw_pitch values...
addrCamera = getAddress("[pYawPitch]")
if (addrCamera == 0 or addrCamera == nil) then return end
--print(string.format('%X - %X',addrEntity,addrCamera))
--if true then return end
-- FreeRoam mr Id...
local nID = 88619
local addrOrig = getAddress("OrigCoord")
-- storing original coordinates...
local X = readFloat(addrEntity)
local Y = readFloat(addrEntity+xOffsY)
local Z = readFloat(addrEntity+xOffsZ)
--print(string.format('X: %f - Y: %f - Z; %f',X,Y,Z))
if ((X == 0 or X == nil) and (Z == 0 or Z == nil)) then return end
writeFloat(addrOrig,X)
writeFloat(addrOrig+xOffsY,Y)
writeFloat(addrOrig+xOffsZ,Z)
local addrX = getAddress("Xval")
local addrY = getAddress("Yval")
local addrZ = getAddress("Zval")
writeFloat(addrX,X)
writeFloat(addrY,Y)
writeFloat(addrZ,Z)
-- always enable godmode...
--local mr = getAddressList().getMemoryRecordByID(297)
--mr.Active = true
local nTimer = readInteger(getAddress("nFrameSpeed"))
writeBytes(getAddress("bFreeRoam"),3)
local mForm = getMainForm()
-- ID mRecord FreeRoam - addrCoordinatesPlayer - addrYaw - offsYax1 - offsYaw2 - addrPitch - offsPitch...
aFlyInfo = {nID,addrEntity,addrCamera,0x8,0x0,addrCamera,0x4}
function ActivateFly()
tmerFly = createTimer(mForm, false)
tmerFly.OnTimer = Flyhack
tmerFly.Interval = nTimer
tmerFly.Enabled = true
end
ActivateFly()
[DISABLE]
{$lua}
writeBytes(getAddress("bFreeRoam"),0)
if ( tmerFly ~= nil ) then tmerFly.destroy() end
Deactivate
121
0
Free Roam Enabled
Free Roam Disabled
88601
"Help~Info (see also Readme file)"
008000
Auto Assembler Script
{ Game : AC4BFSP.exe
Version:
Date : 2018-03-23
Author : Paul44
Help instructions on how to use the 'hover' function
}
[ENABLE]
{$lua}
if getOpenedProcessID() ~= 0 then
luacall(Help())
end
{$asm}
// disable script in CE table
// apparently, using an ASM opcode that is syntactically correct, but can not be
// AA-ed by CE causes it to disable the script automatically...
test al,al
//dd (int)48
[DISABLE]
88341
"Pointers..."
C0C0C0
1
88334
"Resources: Max Value"
0
FF00FF
4 Bytes
nInvMax
88080
"(Re)Set All (0/95)"
0
000000
Byte
bUnlockReset
88081
"Address Perk"
1
8 Bytes
pAddrPerk
88082
"Actual"
4 Bytes
[pAddrPerk]+70
88083
"Completed (= 0 <~ 1)"
Byte
[pAddrPerk]+8A
88084
"Total"
808080
4 Bytes
[pAddrPerk]+74
88085
"Completed (= 3 <~ 1)"
808080
Byte
[pAddrPerk]+1C
88780
"-------------------------"
1
88866
"pExperience..."
1
0
8 Bytes
pExperience
88307
"pTorch..."
1
0
8 Bytes
pTorch
88306
"pRatsense..."
1
0
8 Bytes
pHugoVision
88342
"pInventory... (chain)"
1
0
8 Bytes
pInventory
88343
"pInventory..."
1
0
8 Bytes
pInventory
30
10
40
0
88440
"pCoord..."
1
0
8 Bytes
pCoord
88774
"pCamera..."
1
0
8 Bytes
pCamera
88773
"pYawPitch..."
1
0
8 Bytes
pYawPitch
88779
"pRewards..."
1
0
8 Bytes
pRewards
88826
"CProfileInfo_G..."
1
0
8 Bytes
pRewards
0
D0
D00
0
88825
"pGodmode..."
1
0
8 Bytes
pGodmode
88867
"bGodmode..."
0
Byte
bGodmode
1419
"Errors & Settings..."
008080
1
14852
"Error Statistics..."
1
1420
"> Player Status"
4 Bytes
nCrash1
1421
"> Ship Status"
4 Bytes
nCrash2
1441
"> Map Waypoint"
4 Bytes
nCrash3
1449
"> Map Waypoint Teleport"
4 Bytes
nCrash4
1481
"> Teleport & Coordinates"
4 Bytes
nCrash5
14780
"Cheat table settings..."
000000
Auto Assembler Script
{ Game :
Version:
Date : 2020-10-22
Author :
Manage game-specific settings...
(one must save the table manually to keep any changes permanently)
Important note: one should NOT touch the 'Developer tools' section !
(use at own risk and voids further support...)
}
[ENABLE]
globalalloc(bShowHideLua,1,$process)
bShowHideLua:
db 1
[DISABLE]
bShowHideLua:
db 1
14828
"(fill in your choices in the 'Description' field)"
FF0080
1
14825
"(launches this browser w/ search_string from 'Info' button)"
FF0000
1
14875
"(fill in browser, without extension ~ do not change search string)"
FF0000
1
14830
"iexplore"
1
14858
"fearless A Plague Tale Requiem Steam GOG"
1
14826
"(sets 'Compact View Mode' at startup: Compact (default) = 1 ~ Full View = 0)"
FF0000
1
14831
"1"
1
14832
"(sets background color - default =F6EEED)"
FF0000
1
14833
"F6EEED"
1
14873
"(fill in Game's EXE name, including extension, command parameters & full pathname)"
FF0000
1
14867
"APlagueTaleRequiem_x64.exe"
1
14894
""
1
14881
""
1
14422
"(fill in full path for Report export location)"
FF0000
1
14423
"(or use: <table> ~ <game> variables)"
FF0000
1
14424
"<game>"
1
14862
"(apply above changes to cheat table)"
FF00FF
Auto Assembler Script
{ Game :
Version:
Date : 2020-11-05
Author :
Has primarily visual effect on color change...
color picker: google "HTML Color Picker W3Schools"
}
[ENABLE]
{$lua}
if syntaxcheck then return end
local mForm = getMainForm().frmAutoInject
-- button_name has changed since v7.x...
local sButton
if (tonumber(getCEVersion()) < 7) then
sButton = mForm.Button1.doClick
else
sButton = mForm.btnExecute.doClick
end
sButton()
sButton()
--mForm.Component[3].doClick()
--mForm.Component[3].doClick()
local al = getAddressList()
sBrowser = al.getMemoryRecordByID(sBrowserID).Description .. '.exe'
sBrowserString = al.getMemoryRecordByID(sBrowserStringID).Description
sSearch = " ? " .. sBrowserString .. [[ >nul 2>nul]]
{$asm}
// disables script automatically by CE...
test al,al
[DISABLE]
14829
"(you must save/reload the table to apply these settings permanently !)"
0000FF
1
14857
"Developer tools... (do not use, unless at your own risk)"
808000
1
26032
"(to keep/apply changes permanently, you must Save/Reload your table)"
FF00FF
1
14849
"(game verification...)"
FF0000
1
14868
"(Check regularly (default) = 1 - AutoAttach once = 0)"
FF0000
1
14874
"(Check also for similar game_name = 2 - No AutoAttach = 9)"
FF0000
1
14836
"1"
1
14869
"(fill in Timer's Interval)"
FF0000
1
14866
"3000"
1
14859
"(verify AOB string & memory_limit_range (= hexvalue) & protectionflags)"
FF0000
1
14860
"40 56 57 41 55 48"
1
14861
"2000"
1
14897
"+X-C-W"
1
14882
"(fill in Game's EXE name, incl ext & full pathname: see above)"
FF0000
1
14853
"(prompt to save any table design changes: No (default) = 0 ~ Yes = 1)"
FF0000
1
14854
"0"
1
14855
"(hide most elements in Lua Engine window: Yes (default) = 1 ~ No = 0)"
FF0000
1
14856
"1"
1
14883
"(Free Roam keyboard keys: F10-F12 ~ 2-4-6-8-7-9 ~ (unused))"
FF0000
1
14884
"0x79"
1
14892
"0x7B"
1
14891
"0x62"
1
14890
"0x66"
1
14889
"0x64"
1
14888
"0x68"
1
14887
"0x67"
1
14886
"0x69"
1
14885
"0x78"
1
14899
"(show Design submenu: No (default) = 0 ~ Yes = 1)"
FF0000
1
14900
"0"
1
26031
"(fill in full path for Dissect Code location ~ ignore process: No (default) = 0)"
FF0000
1
26066
"(or use: <table> ~ <game> variables)"
FF0000
1
14033
"<table>"
1
14034
"0"
1
26065
"(Dissect Structure: engine (values seperated by ~ | see Special Scripts)"
FF0000
1
87949
"(Anvil = 1/UE3 = 2/UE4.2 = 3/UE4.1 = 4/Disabled = 99)"
FF0000
1
14066
"99~0xXX~0xXX~..."
1
14901
"(show WindowMode menu option: No (default) = 0 ~ Yes = 1)"
FF0000
1
14902
"0"
1
14898
"Maintenance scripts"
808000
1
14903
"Reset Lua Engine GUI"
Auto Assembler Script
{ Game :
Version:
Date : 2020-11-02
Author :
Dis/enables menu in Lua Engine window (+ bottom part)
Note: 'luaMenu' needs to be global in order to "keep/exchange" its pointer !
}
[ENABLE]
{$lua}
SwitchLuaGui()
{$asm}
test al,al
[DISABLE]
{$lua}
14896
"Disable all cheats (using hotkey)"
Auto Assembler Script
{ Game :
Version:
Date : 2020-11-02
Author :
Disables all scripts and locked values...
}
[ENABLE]
{$lua}
local bAll = true
if (isKeyPressed(VK_F11)) then bAll = false end
DisableMainScript(bAll)
{$asm}
// disables script automatically by CE...
test al,al
[DISABLE]
Activate
17
123
Disable all cheat entries...
0
Activate
17
122
Disable only locked values...
1
26072
"Initialize Special Scripts"
Auto Assembler Script
{ Game :
Version:
Date : 2020-11-02
Author :
Runs any script, "linked" in Form(s)...
}
[ENABLE]
{$lua}
-- important: most/all functions here should/must be global...
-- dis/enable the "hover" functionality via 'Player Coordinates (writes~updates)' script...
-- is called by the ActivateTimer() function
-- *****************************************
local al = getAddressList()
-- used for Teleport routine...
local function getVK(nEnum)
local n = tonumber(al.getMemoryRecordByID(nEnum).Description)
return n
end
function DisableEntry(nID)
if (nID == 0 or nID == nil) then return end
local ScriptID = al.getMemoryRecordByID(nID)
ScriptID.Active = false
end
-- restore start location coordinates [F12]...
local function RestoreOrigCoord(addrX,addrY,addrZ,addrEntity)
local bInverseXY = readBytes(getAddressSafe("bInverseXY"))
local xOffsY,xOffsZ = 0x4,0x8
if (bInverseXY == 1) then xOffsY,xOffsZ = 0x8,0x4 end
local Zplus = readFloat(getAddress("ZstepdropHeight"))
local addrOrig = getAddress("OrigCoord")
--local structOffset = readInteger(getAddress("pStructCrdOffset"))
--local addrCoord = readPointer(getAddress("pStructCrdBase")) + structOffset
local addrCoord = addrEntity
--print(string.format("%x",addrOrig))
--print(string.format("%x",addrCoord))
--print(structOffset)
local Zvalue = readFloat(addrOrig+xOffsZ)+Zplus
-- update [pStructCrdBase]+xx values...
writeFloat(addrCoord,readFloat(addrOrig))
writeFloat(addrCoord+xOffsY,readFloat(addrOrig+xOffsY))
writeFloat(addrCoord+xOffsZ,Zvalue)
-- update Xval,Yval,Zval values...
writeFloat(addrX,readFloat(addrOrig))
writeFloat(addrY,readFloat(addrOrig+xOffsY))
writeFloat(addrZ,Zvalue)
end
function Flyhack(timer)
-- ID mRecord FreeRoam - addrCoordinatesPlayer/Entity - addrYaw - offsYax1 - offsYaw2 - addrPitch - offsPitch... {1~7}
-- debug yaw/pitch - not_used - reversed yaw/pitch variansts... {8~10}
local bInverseXY = readBytes(getAddressSafe("bInverseXY"))
local xOffsY,xOffsZ = 0x4,0x8
if (bInverseXY == 1) then xOffsY,xOffsZ = 0x8,0x4 end
local aInfo = aFlyInfo
local addrEntity = aInfo[2]
local addrYaw = aInfo[3]
local addrPitch = aInfo[6]
local bDebug = aInfo[8] or 0
local nSwitch = aInfo[10] or 0
if (addrPitch == 0 or addrPitch == nil) then return end
-- get XY and Z-axis step value...
local addrXYstep = getAddress("XYstepVal")
local XYstep = readFloat(addrXYstep)
local addrZstep = getAddress("ZstepVal")
local Zstep = readFloat(addrZstep)
local addrX = getAddress("Xval")
local addrY = getAddress("Yval")
local addrZ = getAddress("Zval")
local XValue = readFloat(addrX)
local YValue = readFloat(addrY)
local ZValue = readFloat(addrZ)
local fPitch = readFloat(addrPitch+aInfo[7])
if (fPitch == nil) then return end
local nYaw1 = -1
local nYaw2 = 1
if (nSwitch == 1) then nYaw2 = -1 end
if (nSwitch == 2) then nYaw1 = 1 end
if (nSwitch == 3) then nYaw1 = 1; nYaw2 = -1 end
local yaw = math.atan2(nYaw1 * readFloat(addrYaw+aInfo[4]), nYaw2 * readFloat(addrYaw+aInfo[5])) * 180 / math.pi
local pitch = math.asin(fPitch) * 180 / math.pi
local z = math.cos(math.rad(90-pitch)) * Zstep
local xVal = readFloat(addrEntity)
local yVal = readFloat(addrEntity + xOffsY)
local zVal = readFloat(addrEntity + xOffsZ)
local nInverse = (pitch >= 0) and 1 or -1
-- using NUMpad keys to navigate...
-- these keys also allow us to pass through "walls"... (noclip)
-- also google: "cheat engine Virtual-Key Code"
if isKeyPressed(getVK(14888)) then -- VK_NUMPAD8
local x = math.cos(math.rad(yaw)) * XYstep
local y = math.sin(math.rad(yaw)) * XYstep
XValue = xVal + x
YValue = yVal - y
ZValue = zVal + z
writeFloat(addrX,XValue)
writeFloat(addrY,YValue)
writeFloat(addrZ,ZValue)
if execRoutine ~= nil then
execRoutine(sender)
end
if (bDebug > 0) then print(string.format('Yaw: %f - Pitch: %f',yaw,pitch)) end
if (bDebug > 1) then
print(string.format('X: %f - Y: %f - Z; %f',x,y,z))
print(string.format('X: %f - Y: %f - Z; %f',xVal,yVal,zVal))
end
end
if isKeyPressed(getVK(14891)) then -- VK_NUMPAD2
local x = math.cos(math.rad(yaw)) * XYstep
local y = math.sin(math.rad(yaw)) * XYstep
XValue = xVal - x
YValue = yVal + y
ZValue = zVal - z
writeFloat(addrX,XValue)
writeFloat(addrY,YValue)
writeFloat(addrZ,ZValue)
end
if isKeyPressed(getVK(14890)) then -- VK_NUMPAD4
--print(string.format('Yaw - 4: %f',yaw-90))
local yaw = yaw - 90
local x = math.cos(math.rad(yaw)) * XYstep
local y = math.sin(math.rad(yaw)) * XYstep
XValue = xVal + x
YValue = yVal - y
writeFloat(addrX,XValue)
writeFloat(addrY,YValue)
end
if isKeyPressed(getVK(14889)) then -- VK_NUMPAD6
local yaw = yaw + 90
local x = math.cos(math.rad(yaw)) * XYstep
local y = math.sin(math.rad(yaw)) * XYstep
XValue = xVal + x
YValue = yVal - y
writeFloat(addrX,XValue)
writeFloat(addrY,YValue)
end
if isKeyPressed(getVK(14887)) then -- VK_NUMPAD7
--print(string.format("%x",addrZ))
ZValue = zVal + z * nInverse
writeFloat(addrZ,ZValue)
end
if isKeyPressed(getVK(14886)) then -- VK_NUMPAD9
ZValue = zVal - z * nInverse
writeFloat(addrZ,ZValue)
end
if isKeyPressed(getVK(14884)) then -- VK_F10
-- End "free roam" activity...
-- stay/drop at current location coordinates...
DisableEntry(aInfo[1])
tmerFly.destroy()
end
if isKeyPressed(getVK(14892)) then -- VK_F12
-- restore start location coordinates...
-- if not returning to originals, set dropheight higher...
local bFreeChoice = readBytes(getAddress("bFreeChoice"))
if (bFreeChoice == 1) then
RestoreOrigCoord(addrX,addrY,addrZ,addrEntity)
-- allow game some time to execute before quiting script
-- allows to return through walls... in most cases
sleep(500)
end
DisableEntry(aInfo[1])
tmerFly.destroy()
end
end
function Help()
local sMessage = [[
Use following function keys:
F10 = End at current location
F12 = End & Restore original location
Use NumPad keys [2-8] & [4-6] to move about
Use NumPad keys [7-9] to ascend & descend respectively
(normal move keys can not be used)
FreeRoam preferably not used while in non-standing posture...
(see also [Readme] file) ]]
showMessage(sMessage)
end
-- nMr = mrID to disable ~ bAction = 0 = Save / = 1 = Restore ~ xOffset for free Camera...
function coordSaveRestore(bAction,addrCoord,nMr,nChoice,xOffset,nDropHeight)
local bInverseXY = readBytes(getAddressSafe("bInverseXY"))
local xOffsY,xOffsZ = 0x4,0x8
if (bInverseXY == 1) then xOffsY,xOffsZ = 0x8,0x4 end
local nChoice = nChoice or 0
local bAction = bAction or 0
local addrCoord = addrCoord
-- Free Roam or Free Camera...
local xOffset = xOffset or readInteger(getAddress('pStructCrdOffset'))
local nDropHeight = nDropHeight or readFloat(getAddress('nDropHeight'))
addrCoord = addrCoord + xOffset
local addrOrigCoord = getAddress('OrigCoord')
--print(string.format('%X + %X',addrCoord,addrOffset))
local nHeight = 2.0
if (bAction == 0) then
writeFloat(addrOrigCoord,readFloat(addrCoord))
writeFloat(addrOrigCoord+xOffsY,readFloat(addrCoord+xOffsY))
writeFloat(addrOrigCoord+xOffsZ,readFloat(addrCoord+xOffsZ))
end
if (bAction == 1 and nChoice ~= 0) then
local xVal = readFloat(addrOrigCoord)
local yVal = readFloat(addrOrigCoord+xOffsY)
if not (xVal == 0 and yVal == 0) then
writeFloat(addrCoord,readFloat(addrOrigCoord))
writeFloat(addrCoord+xOffsY,readFloat(addrOrigCoord+xOffsY))
writeFloat(addrCoord+xOffsZ,readFloat(addrOrigCoord+xOffsZ)+ nHeight + nDropHeight)
if (nChoice == 1) then
writeFloat(addrOrigCoord,0)
writeFloat(addrOrigCoord+xOffsY,0)
writeFloat(addrOrigCoord+xOffsZ,0)
end
end
end
local mr = getAddressList().getMemoryRecordByID(nMr)
if (mr == nil) then return end
local timerMr = createTimer(getMainForm())
timerMr.Interval = 100
timerMr.OnTimer = function(timer)
mr.Active = false
timerMr.destroy()
end
end
-- game exe verification...
function GetMD5(nShowMsg)
if ( process ~= nil ) then
local intVal = 0
-- calculate MD5 of PE header...
local FileMD5 = md5memory(process,4096)
local strMsg1,strMsg2
strMsg1 = "You have attached [" .. process .. "]..."
strMsg2 = "with following MD5 PE Header value: {" .. FileMD5 .. "}"
if nShowMsg == 1 then
showMessage(strMsg1 .. "\n\z" .. strMsg2)
end
--print('[',process,']')
--print(FileMD5)
--print(intVal)
return intVal
end
end
-- only needs to run once... ~ see below...
function getFNamePool()
local aGameVals = SplitStr(structParams, "~")
local sAOB = aGameVals[4]
local nOffs = tonumber(aGameVals[5])
--print(string.format('%s - %d',sAOB,nOffs))
getStaticAddr(sAOB,nOffs,'pFnamePool')
end
-- getAnvil menu routine...
-- source info: #aSwedishMagyar @ FRF
-- ~ most/all AC titles...
-- google : ‘fearless AC 4: Black Flag ~ HowTo get data structure from its name’
function getAnvil(base)
local gameOffsets = SplitStr(structParams, "~")
local offs1 = tonumber(string.format('%X',gameOffsets[2]),16)
local offs2 = tonumber(string.format('%X',gameOffsets[3]),16)
if base == nil then return end
--print(string.format('(base): %X',base))
local name = ''
local addrName = string.format('[[%X]+0x%X]',base,offs1)
local getNameFunction = getAddressSafe(addrName)
if getNameFunction == nil then return name end
--print(string.format('1. [%X] ~> %X',base,getNameFunction))
local sASM = disassemble(getNameFunction)
local sAddr = string.find(sASM,"%?%?")
if sAddr ~= nil then return '' end
local sAddr = sASM:match("%[(.-)%]")
if sAddr == nil then return name end
addr = getAddressSafe('[['..sAddr..']+'..string.format('%X',offs2)..']')
if addr == nil then return name end
--print(string.format('2. %X ~ %X | %s',addr,offs2,sASM))
name = readString(addr,100)
--print(string.format('3. [%X] - %X ~ %s',base,getNameFunction,readString(addr,30,false)))
return name
end
function getUE3(base,nRelease)
-- set a 'globalalloc(pFNamePool,8,$process)' in main script or place next 2 instructions in lua startup...
-- unregisterSymbol("pFnamePool")
-- if not getAddressSafe("pFnamePool") then registerSymbol("pFnamePool", allocateMemory(8)) end
local nRelease = nRelease or 1
local addrFName = getAddress('[pFnamePool]')
if (readPointer(addrFName) == nil) then getFNamePool(); addrFName = getAddress('[pFnamePool]') end
-- getUE2/3 routine ~ FNamePoolID_offset ~ FName_offset ~ FNamePool_address AOB search string ~ relative offset to AOB_Address
local aGameVals = SplitStr(structParams, "~")
local nNameID = tonumber(string.format('%X',aGameVals[2]),16)
local nNameOffs = tonumber(string.format('%X',aGameVals[3]),16)
local x64Bit = 0x4
if targetIs64Bit() then x64Bit = 0x8 end
local nNameEntries = readInteger(addrFName + x64Bit)
if (nRelease == 2) then nNameEntries = 999999 end -- needs to be identified somehow...?!
--print(string.format('[%d]: %X/%X => %X/%d ... %X',nRelease,nNameID,nNameOffs,readPointer(addrFName),nNameEntries,base))
if base == nil then return nil end
local vfTable = readPointer(base)
if vfTable == nil then return nil end
local nName = readInteger(base + nNameID)
local nChunk = 0
if (nName == nil or nName > nNameEntries) then return nil end
local addrChunk = readPointer(addrFName)
if (nRelease == 2) then
nChunk = nName >> 0xE -- chunkIdx
nName = (nName & 0x3FFF) -- offset within chunk
addrChunk = readPointer(addrChunk + nChunk * x64Bit)
end
--print(string.format('[%X]/%d + %x',addrChunk, nChunk, nName))
local sName = readString(readPointer(addrChunk + nName * x64Bit) + nNameOffs,100)
if sName == nil then return nil end
if ( string.len(sName) == 1) then sName = readString(readPointer(addrChunk + nName * x64Bit) + nNameOffs,255,true) end
if sName == nil then return nil end
return sName
end
function getUE41(base)
local sName = getUE3(base,2)
return sName
end
function getUE4(base)
-- set a 'globalalloc(pFNamePool,8,$process)' in main script or place next 2 instructions in lua startup...
-- unregisterSymbol("pFnamePool")
-- if not getAddressSafe("pFnamePool") then registerSymbol("pFnamePool", allocateMemory(8)) end
-- Author: #Razchek
-- Google: 'Unreal v4.23+ "GNames" - FNamePool enumeration' (~ unknowncheats.me forum)
-- ***
local addrFName = getAddress('[pFnamePool]')
if (readPointer(addrFName) == nil) then getFNamePool(); addrFName = getAddress('[pFnamePool]') end
-- getUE4 routine ~ FNameIndexID_offset ~ FNamePool_offset ~ FNamePool_address AOB search string ~ relative offset to AOB_Address
local aGameVals = SplitStr(structParams, "~")
local nNameID = tonumber(string.format('%X',aGameVals[2]),16)
local nNameStart = tonumber(string.format('%X',aGameVals[3]),16)
local key = readInteger(base + nNameID)
--addrFName = addrFName + nNameStart
local nNameEntries = 0 -- readInteger(addrFName + 0x4)
--print(string.format('%d/%X => %X/%d ... %X',nNameID,nNameStart,addrFName,nNameEntries,base))
local chunkOffset = key >> 16
local nameOffset = readSmallInteger(base + nNameID)
if(nameOffset == nil) then return nil end
local namePoolChunk = readQword(addrFName + ((chunkOffset + 2) * 8))
--print(string.format('%d ~> %X ~> %d => %X',chunkOffset,nNameID,nameOffset,namePoolChunk))
local entryOffset = namePoolChunk + (2 * nameOffset)
local nameEntry = readSmallInteger(entryOffset)
if(nameEntry == nil) then return nil end
local nameLength = nameEntry >> 6
local sName = readString(entryOffset + 2, nameLength)
--print(string.format('%X/%d => %s',entryOffset,nameLength,sName))
return sName
end
function enableStructLookup()
local gameOffsets = SplitStr(structParams, "~")
local bStructEnabled = tonumber(string.format('%d',gameOffsets[1]))
if aMenuEngine[bStructEnabled] then sMenuItem30 = aMenuEngine[bStructEnabled][1] end
if (sGetnameMark == '') then
--print(tostring(nNameLookupID))
nNameLookupID = registerStructureNameLookup(aMenuEngine[bStructEnabled][2])
--print(nNameLookupID)
sGetnameMark = ' ✓'
Getnamemenuitem.Caption = sMenuItem30 .. sGetnameMark
else
unregisterStructureNameLookup(nNameLookupID)
sGetnameMark = ''
Getnamemenuitem.Caption = sMenuItem30 .. sGetnameMark
end
end -- end getAnvil menu routine...
-- game windowed....
-- check current window mode status
addrD3D = 0
local sMenuItem2 = 'Window Mode'
function CheckWindowMode()
-- check if a process is attached...?
if (getOpenedProcessID() == 0) then return end
if addrD3D == nil or addrD3D == 0 then
local bytes = "F7 DE 1B F6 33 C0"
local memScanner = createMemScan(false)
memScanner.setOnlyOneResult(true)
memScanner.firstScan(
soExactValue,vtByteArray,rtRounded,bytes,nil,
0,0xFFFFFFFF,"+X-C-W",fsmNotAligned,"",true,false,false,false)
memScanner.waitTillDone()
addrD3D = memScanner.getOnlyResult()
-- to avoid erros when incorrect process has been selected...
if addrD3D == nil or addrD3D == 0 then process = nil; return end
addrD3D = addrD3D-0x7+0x3
memScanner.destroy()
end
local bStatus = readBytes(readInteger(addrD3D))
if (bWindowMode == 1) then
if (bStatus == 0) then sWindowMark = ' ✓' else sWindowMark = '' end
WinModemenuitem.Caption = sMenuItem2 .. sWindowMark
end
end
function cycleWinMode()
if (getOpenedProcessID() == 0) then return end
-- 0 = windowed ~ 1 = fullscreen
local bStatus = readBytes(readInteger(addrD3D))
--print(string.format('%X + %d',readInteger(addrD3D),bStatus))
if (bStatus == 0) then bStatus = 1; sWindowMark = '' else bStatus = 0; sWindowMark = ' ✓' end
WinModemenuitem.Caption = sMenuItem2 .. sWindowMark
writeBytes(readInteger(addrD3D),bStatus)
end -- end game windowed....
{$asm}
// disables script automatically by CE...
test al,al
[DISABLE]
26071
"Run All Form Scripts"
Auto Assembler Script
{ Game :
Version:
Date : 2020-11-02
Author :
Runs any script, "linked" in Form(s)...
}
[ENABLE]
{$lua}
execStruct = nil
execRoutine = nil
function runFormScripts(sender)
if syntaxcheck then return end
--print(sender.Name)
if (sender.Name == 'ListBox') then onSelectIcon(sender) end
--if (sender.Name == 'IconTeleport') then TeleportToIcon(sender) end
if (sender.Name == 'BtnTeleport') then TeleportToIcon(sender) end
if (sender.Name == 'GodMode') then setGodmode(sender) end
if (sender.Name == 'IconList') then setGodmode(sender,1) end
if (sender.Name == 'Clipboard') then copyClipboard(sender) end
if (sender.Name == 'Structure') then openStructure(sender) end
if (sender.Name == 'RecycleBin') then removeRecycleBin(sender) end
end
-- onEvent Form routines...
function onSelectIcon(sender)
if (sender.ItemIndex < 0) then return end
local f = sender.Parent
if (f.ListBox.Items.Count < 1) then return end
local sCoord = sender.Items[sender.ItemIndex]
-- see also openStructure()...
addrStruct = sCoord:match("{(.-)}")
if (addrStruct ~= nil) then addrStruct = string.gsub(addrStruct, '^%s*(.-)%s*$', '%1') end -- stackoverflow...
--print('['.. addrStruct .. ']')
strStruct = sCoord:match("<(.-)>") -- in case of descriptive (see Kena eg)
if (strStruct ~= nil) then strStruct = string.gsub(strStruct, '^%s*(.-)%s*$', '%1') end
if not (f.pCoord.Visible) then return end
sCoord = sCoord:match("%|(.-)%|")
local aCoord = SplitStr(sCoord,'~')
local xCoord = f.CoordX
xCoord.Caption = string.format('%9.3f',aCoord[1])
local yCoord = f.CoordY
yCoord.Caption = string.format('%9.3f',aCoord[2])
local zCoord = f.CoordZ
zCoord.Caption = string.format('%9.3f',aCoord[3])
f.PlayerX.Caption = ''
f.PlayerY.Caption = ''
f.PlayerZ.Caption = ''
--print(string.format('[%f] \t [%f] \t [%f]',tonumber(aCoord[1]),tonumber(aCoord[2]),tonumber(aCoord[3])))
end
function TeleportToIcon(sender)
--local f = IconList
local f = sender.Parent.Parent
if not (f.pCoord.Visible) then return end
local fHeight = readFloat(getAddress("ZstepdropHeight"))
local xCoord = f.CoordX
local yCoord = f.CoordY
local zCoord = f.CoordZ
if (xCoord.Caption == '' or yCoord.Caption == '' or zCoord.Caption == '') then return end
-- enable godmode - freeroam...
local al = getAddressList()
local mr = al.getMemoryRecordByID(aTeleportInfo[2])
mr.Active = true
-- see AC2 for example (camera)...
local sEntity,sCrdOffset = '[pEntity]','pStructCrdOffset'
if (aTeleportInfo[3] ~= nil) then sEntity = aTeleportInfo[3] end
if (aTeleportInfo[4] ~= nil) then sCrdOffset = aTeleportInfo[4] end
local addrEntity = getAddressSafe(sEntity)
local chkEntity = readPointer(addrEntity)
local CrdOffset = readInteger(getAddressSafe(sCrdOffset))
addrEntity = addrEntity + CrdOffset
local nHeight = aTeleportInfo[1]
--print(string.format('%X ~ %X',chkEntity,addrMapIcon))
local zVal = tonumber(zCoord.Caption)+fHeight
if (nHeight ~= 0) then zVal = math.max(zVal,nHeight) end
local bInverseXY = readBytes(getAddressSafe("bInverseXY"))
local xOffsY,xOffsZ = 0x4,0x8
if (bInverseXY == 1) then xOffsY,xOffsZ = 0x8,0x4 end
writeFloat(addrEntity+xOffsZ,zVal)
writeFloat(addrEntity,tonumber(xCoord.Caption))
writeFloat(addrEntity+xOffsY,tonumber(yCoord.Caption))
local bFreeRoam = readBytes(getAddressSafe("bFreeRoam"))
if (bFreeRoam == 1) then
local addrX = getAddress("Xval")
local addrY = getAddress("Yval")
local addrZ = getAddress("Zval")
writeFloat(addrX,tonumber(xCoord.Caption))
writeFloat(addrY,tonumber(yCoord.Caption))
writeFloat(addrZ,zVal)
-- see Kena for example (moveMode)...
if execRoutine ~= nil then
execRoutine(sender)
end
end
f.PlayerX.Caption = xCoord.Caption
f.PlayerY.Caption = yCoord.Caption
f.PlayerZ.Caption = zCoord.Caption
end
function setGodmode(sender,nFocus)
local f = sender
if (f.Name == 'GodMode') then f = sender.Parent.Parent end
if not (f.pCoord.Visible) or aTeleportInfo == nil then return end
--if (f == nil) then return end
local nFocus = nFocus or 0
local cbGodmode = f.GodMode
local al = getAddressList()
local mr = al.getMemoryRecordByID(aTeleportInfo[2])
if (nFocus == 0) then mr.Active = cbGodmode.Checked else cbGodmode.Checked = mr.Active end
end
function copyClipboard(sender)
--print(sender.Parent.Name)
local f = sender.Parent
--local f = IconList
local strList = createStringlist()
strList.Text = f.IconTitle.Caption .. "\n\n" .. f.IconHead.Caption
strList.Text = strList.Text .. f.ListBox.Items.Text
writeToClipboard(strList.Text)
end
function openStructure(sender)
if (strStruct == nil) then strStruct = '' end
--print('['..addrStruct..']' .. strStruct)
if (addrStruct == '' or addrStruct == nil) then return end
-- for formlists with divers structs...
if execStruct ~= nil then
local result = execStruct(sender)
if not (result) then return end
end
local nCount = getStructureCount()
--local i
for i=nCount-1,0,-1 do
local oStruct = getStructure(i)
if (oStruct.Name == aStructGui[2]) then oStruct.destroy(); break end
end
local oStruct = createStructure(aStructGui[2])
-- 1=Name ~ 2=offset ~ 3=Vartype ~ 4=highlightColor ~ 5 = showAsHex | vtPointer_array
-- 5 = child ~ must be array within array = { {rec1},{rec2},... }
--print(string.format('%s',addrStruct))
for i=1,#aStructInfo do
local addrPtr = tonumber(addrStruct,16) + aStructInfo[i][2]
local vType = aStructInfo[i][3]
if ( vType ~= vtPointer or (vType == vtPointer and readPointer(addrPtr) ~= 0) ) then
local e = oStruct.addElement()
e.Name = aStructInfo[i][1]
e.Offset = aStructInfo[i][2]
e.Vartype = aStructInfo[i][3]
if ( e.Vartype == vtPointer ) then
--print(string.format('%X %X %d',tonumber(addrStruct,16)+e.Offset,e.Offset,e.Vartype))
local oStruct = createStructure('subStruct')
for j=1,#aStructInfo[i][5] do
local eSub = oStruct.addElement()
local aElem = aStructInfo[i][5][j]
eSub.Name = aElem[1]
eSub.Offset = aElem[2]
eSub.Vartype = aElem[3]
if (aElem[4]) then eSub.BackgroundColor = 0xEDEEF6 end
end
e.ChildStruct = oStruct
end
if (aStructInfo[i][4]) then e.BackgroundColor = 0xEDEEF6 end
-- cheatengine Generate Memory Records From Structure
if (aStructInfo[i][5]) then e.DisplayMethod = 'dtHexadecimal' end
end
end
for i,v in ipairs(enumStructureForms()) do
if ( v.Caption == aStructGui[1]) then v.Close() end
end
oStruct.addToGlobalStructureList()
oForm = createStructureForm('0x' .. addrStruct, strStruct, oStruct.Name)
-- 1=windowTitle ~ 2=structName ~ 3+4=windowWidth+Height ~ 5=showMenu ~ 6+7=columnWidth
oForm.Caption = aStructGui[1]
oForm.Width = aStructGui[3]
oForm.Height = aStructGui[4]
oForm.Menu = aStructGui[5]
oForm.HeaderControl1.Sections[0].Text = '<Offset>'
oForm.HeaderControl1.Sections[0].Width = aStructGui[6]
oForm.HeaderControl1.Sections[1].Width = aStructGui[7]
oForm.miExpandAll.doClick()
end
function removeRecycleBin(sender)
local f = sender
if (f.Name == 'RecycleBin') then f = sender.Parent end
if (f.ListBox.Items.Count < 1) then return end
if execRoutine ~= nil then
execRoutine(sender)
return
end
end
{$asm}
// disables script automatically by CE...
test al,al
[DISABLE]
1
"Scripts to run per Timer interval"
Auto Assembler Script
{ Game :
Version:
Date : 2020-11-02
Author :
Add any scripts/functions/routines here that need to be run on a regular interval
(current interval uses 'Timer's Interval')
}
[ENABLE]
{$lua}
-- pcall ensures that no errors are reported prior to loading/enabling scripts in addresslist...
--if not pcall(function() myFunction() end) then return end
{$asm}
test al,al
[DISABLE]
Change of subss xmm2,[r10]
APlagueTaleRequiem_x64.exe+CF9C57
19
F3
0F
10
10
F3
41
0F
5C
12
48
8B
44
24
28
pBhvAssassin
052B0000
pEntity
052B0010
pHealth
052B0020
pInventory
7FF7BAAB0070
pSharedData
052B0040
pNotoriety
052B0050
bGodmode
7FF7BAAB0050
bInvisible
7FF7BAAB0030
bFullBreath
052B0080
nCrash1
052B0090
nCrash2
052B00A0
nCrash3
052B00B0
nCrash4
052B00C0
nCrash5
052B00D0
pStructCrdBase
7FF7BAAB0140
pStructCrdOffset
7FF7BAAB0150
pCheckTools
052B0100
pCheckIcons
052B0110
pCheckViewP
052B0120
pAccomplishm
052B0130
pAccomplVFT
052B0140
pNavalShipPlayer
203C0150
bInvisibleShip
203C0160
bShowHideLua
05280150
pFreeRoam
052B0150
AddrListID
052B0160
OrigCoord
7FF7BAAB0180
XYstepVal
7FF7BAAB0190
ZstepVal
7FF7BAAB01A0
ZstepdropHeight
7FF7BAAB01B0
Xval
7FF7BAAB01C0
Yval
7FF7BAAB01D0
Zval
7FF7BAAB01E0
bInit
052B01E0
bInit2
052B01F0
bFreeRoam
7FF7BAAB01F0
FOVCam
052B0210
pMapWayp
052B0220
nDropHeight
7FF7BAAB0170
nChoice
05280160
pDayTimeMgr
05290150
pDTime
05290160
pMissionTimer2
052801B0
IntTimerDiffer2
052801C0
bMissionTimer2
052801D0
pMissionTimer
052801E0
IntTimerDiffer
052801F0
bMissionTimer
05280200
pAddrPerk
1EFD0240
pPerkBChoice
1EFD0250
bInverseXY
7FF7BAAB00C0
pInvFlag
7FF7BAAB0060
pTorch
7FF7BAAB0000
pHugoVision
7FF6C5F90040
fFOV
7FF7BAAB00E0
pExperience
7FF7BAAB00D0
pRatSense
7FF7BAAB0020
pCoord
7FF7BAAB00F0
pCamera
7FF7BAAB0110
pMappointBase
7FF7BAAB0160
bCoordSave
7FF7BAAB0200
bCoordRestore
7FF7BAAB0210
nFrameSpeed
7FF7BAAB0220
pYawPitch
7FF7BAAB0120
bTorch
7FF7BAAB0010
nInvMax
7FF7BAAB0080
fSpeed
7FF79E7300D0
pRewards
7FF7BAAB0090
bChoice
7FF7BAAB00A0
bUnlockReset
7FF7BAAB00B0
pCoordPlayer
7FF7BAAB0100
pGodmode
7FF7BAAB0040
pCamera2
7FF7BAAB0130
-- You must accept to execute
-- the script !
-- If not, the CE table
-- will return errors...
-- will auto-attach the game; even when table is loaded first...
-- place this at start/common part of lua script
-- will run ONLY once when CE table is loaded
-- when changing process, you must reload table or function !
--local myGame = "<game>.exe"
--local aalist=getAutoAttachList()
--stringlist_add(aalist,myGame)
-- *** still ToDo: ***
-- 'modal window' kicks in after X secs: stop checkTimer and report "game not found"
-- general settings:
local al = getAddressList()
local mForm = getMainForm()
-- will auto-attach the game; even when table is loaded first...
myGameID = 14867
myGame = al.getMemoryRecordByID(myGameID).Description
local myPathID = 14881
myPath = al.getMemoryRecordByID(myPathID).Description
local sGameParams = al.getMemoryRecordByID(14894).Description
-- ID main script ~ disabled upon re-attaching...
local getMrByID = al.getMemoryRecordByID
local mrMainScript = getMrByID(1993)
-- add 'Window Mode' to the [Tools] menu... ACBF only (for now)...
bWindowMode = tonumber(al.getMemoryRecordByID(14902).Description)
local bSysMenu = tonumber(al.getMemoryRecordByID(14900).Description)
-- verify regularly if correct process has been opened... - see WinTitle...
local bCorrectProc = al.getMemoryRecordByID(14836).Description
local sCheckProc = al.getMemoryRecordByID(14860).Description
local nCheckMemRange = al.getMemoryRecordByID(14861).Description
nCheckMemRange = tonumber(nCheckMemRange,16)
local sProtFlags = al.getMemoryRecordByID(14897).Description
local nChkTimer = tonumber(al.getMemoryRecordByID(14866).Description)
-- set to '0' if you want default CE GUI...
local bDefaultCompactGui = tonumber(al.getMemoryRecordByID(14831).Description)
if (bDefaultCompactGui ~= 0 and bDefaultCompactGui ~= 1) then bDefaultCompactGui = 1 end
-- set minimum size CE form...
mForm.Constraints.MinWidth = 510
mForm.Constraints.MinHeight = 300
-- add some color... ~ +compatible v6.7... ~ default background color ~ 0xF6EEED
-- .List & .Header not supported in prev.7x...
-- also converting color 'endianness'...
local hColor = al.getMemoryRecordByID(14833).Description
local sTmp = ""
for i = #hColor, 2, -2 do sTmp = sTmp .. string.sub(hColor,i-1,i) end
hColor = '0x' .. sTmp
local function setListColor(sColor)
al.Control[0].BackgroundColor = sColor
al.Control[0].Color = sColor
al.Control[1].BackgroundColor = sColor
al.Control[1].Color = sColor
end
setListColor(hColor)
-- define your default browser...
--local mr = al.getMemoryRecordByID(14654)
sBrowserID = 14830
sBrowser = al.getMemoryRecordByID(sBrowserID).Description .. '.exe'
sBrowserStringID = 14858
sBrowserString = al.getMemoryRecordByID(sBrowserStringID).Description
sSearch = " ? " .. sBrowserString .. [[ >nul 2>nul]]
-- Show/Hide Error & Settings sections ~ see cycleConfig()...
local mrConfig = al.getMemoryRecordByID(1419)
-- prompt to save any changes in table, or simply ignore and quit instantly...
-- 'Ship Battle' script unintentionally changes table, causing a 'save'-prompt upon quiting...
-- google "memrec.DontSave still triggers Save changes"
local bPromptToSave = al.getMemoryRecordByID(14854).Description
-- sets 'editedsincelastsave' property accordingly...
-- note: setting to 'false' will stop CE from closing ?!
local function NoSaveChanges(bSaveOff)
getMainForm().OnCloseQuery=function()
--messageDialog('Throw away all your unsaved changes?', mtConfirmation, mbYes, mbYesToAll)
return bSaveOff end
end
if bPromptToSave == "0" then NoSaveChanges(true) end
-- hide most lua window elements...
-- keep menu copy ~ see settings DevTools...
if (luaMenu == nil) then luaMenu = getLuaEngine().Menu end
bHideLua = al.getMemoryRecordByID(14856).Description
if bHideLua == "1" then
local luaForm = getLuaEngine()
luaForm.Panel1.Visible = false
luaForm.Splitter1.Visible = false
luaForm.Menu = nil
end
-- Scripts to run per Timer interval
local mrScriptToRun = al.getMemoryRecordByID(1)
-- Pathname save location (eg: Dissect Code)
local pathSaveFiles = al.getMemoryRecordByID(14033).Description
local bDissectProc = al.getMemoryRecordByID(14034).Description
-- Dissect Structure: Game_engine, followed by respective offsets in chain path...
structParams = al.getMemoryRecordByID(14066).Description
nNameLookupID = 0
-- Pathname report export location...
sPathExport = getAddressList().getMemoryRecordByID(14424).Description
-- Initialize Special Scripts ~ Maintenance scripts ...
local mr = al.getMemoryRecordByID(26072)
mr.Active = true
-- redirect all prints for export to file...
-- makes use of global 'fContent' variable...!
default_print = print
function redirectPrint(bRedirect)
if ( bRedirect == 1) then
print = function(str)
fContent = fContent .. str .. '\n'
end
else
print = default_print
end
end
-- functions for [Tools] submnenu...
-- **********************************
-- adds a Compact GUI...
-- google: "cheat engine CE compact mode" & "Add menuItem for Main CE Form (hide/show some control)"
local sCompactMark = ' ✓'
sWindowMark = ''
sGetnameMark = ''
local sConfigMark = ''
local sMenuItem1 = 'Compact View'
local sMenuItem2 = 'Window Mode'
local sMenuItem3 = 'Errors && Settings...'
local sMenuItem4 = 'Select && Launch Your Game...'
local sMenuItem5 = 'Show Table Name...'
local sMenuItem6 = 'Disable All Cheats [Ctrl+F11/F12]'
local sMenuItem21 = 'Open Memory View'
local sMenuItem22 = 'Open Dissect Structure'
local sMenuItem23 = 'Open Lua Engine'
local sMenuItem24 = 'Show CE Debug Info'
local sMenuItem25 = 'Dissect Code...'
local sMenuItem26 = 'Load Dissect Code'
local sMenuItem27 = 'Save Dissect Code'
local sMenuItem28 = 'Build Dissect Code'
local sMenuItem29 = 'Clear Dissect Code'
sMenuItem30 = 'getName...'
local sMenuItem31 = 'Switch Lua Engine GUI'
local sMenuItem41 = "Delete All 'Unnamed' Structures..."
local sMenuItem42 = "Delete Structures Selectively..."
local sMenuItem43 = "Add Address By Reference"
local sMenuItem44 = "CLean Up Structures..."
local sMenuItem45 = "Switch Lua Engine Gui"
local function cycleFullCompact()
local state = not(compactmenuitem.Caption == sMenuItem1)
compactmenuitem.Caption = state and sMenuItem1 or (sMenuItem1 .. sCompactMark)
mForm.Splitter1.Visible = state
--getMainForm().Panel1.Visible = state
--mForm.Panel2.Visible = state
--getMainForm().Panel3.Visible = state
mForm.Panel4.Visible = state
mForm.Panel5.Visible = state
--getMainForm().Panel6.Visible = state
--getMainForm().Panel7.Visible = state -- seems to cause "incorrect gui"
--local MPanel90 = createPanel(getMainForm().Panel7)
--MPanel90.Anchors = '[akTop]'
--getMainForm().Panel8.Visible = state
--getMainForm().Panel9.Visible = state
--getMainForm().Panel10.Visible = state
--getMainForm().Panel14.Visible = state
-- incorrect color gives black background...!
if state then setListColor('0xFFFFFF') else setListColor(hColor) end
end
local bConfig = 1
local function cycleConfig()
-- show/hide Errors & Settings subsections...
local ceVersion = tonumber(string.match(getCEVersion(), '^.-.'))
if (bConfig == 1) then
bConfig = 0
sConfigMark = ''
if (ceVersion < 7) then
mrConfig.Options = '[moHideChildren,moDeactivateChildrenAsWell]'
else
mrConfig.Options = '[moAlwaysHideChildren,moDeactivateChildrenAsWell]'
end
mrConfig.Active = false
else
bConfig = 1
sConfigMark = ' ✓'
mrConfig.Options = '[moDeactivateChildrenAsWell]'
mrConfig.Active = true
end
Configmenuitem.Caption = sMenuItem3 .. sConfigMark
end
local function OpenFileDialog(sender)
local fdialog = createOpenDialog(self)
fdialog.Filename = myPath:match("(.*[/\\])")
--fdialog.File = myGame:match("\\([^\\]+)$")
fdialog.Filter = 'Executable files|*.exe'
--fdialog.InitalDir = os.getenv('USERPROFILE')
fdialog.Execute()
local sEXE = fdialog.FileName:match("\\([^\\]+)$")
if (sEXE ~= "" and sEXE ~= nil) then
myGame = sEXE
local sPath = fdialog.FileName:match("(.*[/\\])")
local cmd = "start \"\" /d \"" .. sPath .. "\" " .. sEXE .. " " .. sGameParams
--print(cmd)
os.execute(cmd)
--shellExecute(cmd)
al.getMemoryRecordByID(myPathID).Description = sPath
if ( bCorrectProc == '9' ) then
local nCount = 1
-- needed to attach process to CE...
openProcess(myGame)
while process ~= myGame do
openProcess(myGame)
sleep(1000)
nCount = nCount + 1
if (nCount > 10) then
local sMessage = [[
CE can not seem to attach the program ?!
Use [File ~ Open Process] instead...]]
showMessage(sMessage)
break
end
end
--print(string.format('%s ~ %s',tostring(enumModules()[1].Name),tostring(enumModules()[1].Address)))
openProcess(myGame)
end
end
--print(myGame)
end
myTablename = ''
local function ShowTableName()
local sTablename = getTable()
local sText = 'Table name & location: \n'
sText = sText .. '[' .. sTablename .. ']'
local nType = mtInformation
local nButton = mbOK
messageDialog(sText, nType, nButton)
end
function getTable()
local sOpen = mForm.OpenDialog1.FileName
local sSave = mForm.SaveDialog1.FileName
local s1 = sSave or sOpen -- or 'undefined'
--print(s1 .. ' ~ ' .. myGame)
-- gets processname now and then...
if (s1:match("\\([^\\]+)$") == myGame:match("\\([^\\]+)$")) then s1 = myTablename end
--local s2 = s1:match("(.*[/\\])") or s1 ~ pathname
--local s1 = s1:match("\\([^\\]+)$") or s1 ~ filename
myTablename = s1
return myTablename
end
function DisableMainScript(bAll)
if ( bDisableRun == 1 ) then return end
--local bAll = bAll or true
for i=0,al.Count-1 do
if (bAll) then
al[i].Active = false
else
if (al[i].Type < 10) then al[i].Active = false end
end
end
end
local function OpenMemViewer()
getMainForm().btnMemoryView.doClick()
end
function SplitStr(s, delimiter)
result = {};
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match);
end
return result;
end
-- functions for [Design] submnenu...
-- **********************************
-- add Design menu to Structure form...
local function OpenDissectStruct()
--getMemoryViewForm().miDissectData2.doClick()
--getMemoryViewForm().miOpenInDissectData.doClick()
local form = createStructureForm()
--local form = enumStructureForms()[1]
local mmenu = form.Menu
local mmenu_items = menu_getItems(mmenu)
-- Design submenu...
local mi1 = createMenuItem(mmenu)
mi1.Caption = '[Design]'
local DelUnnamedmenuitem = createMenuItem(mmenu)
DelUnnamedmenuitem.Caption = sMenuItem41
DelUnnamedmenuitem.OnClick = DissectStructRemove
mi1.add(DelUnnamedmenuitem)
local DissectStructRemoveSelectmenuitem = createMenuItem(mmenu)
DissectStructRemoveSelectmenuitem.Caption = sMenuItem42
DissectStructRemoveSelectmenuitem.OnClick = DissectStructRemoveSelect
mi1.add(DissectStructRemoveSelectmenuitem)
local Sepmenuitem = createMenuItem(mmenu)
Sepmenuitem.Caption = '-'
mi1.add(Sepmenuitem)
local AddAddressRefmenuitem = createMenuItem(mmenu)
AddAddressRefmenuitem.Caption = sMenuItem43
AddAddressRefmenuitem.OnClick = AddAddressByRef
mi1.add(AddAddressRefmenuitem)
local CleanupStructmenuitem = createMenuItem(mmenu)
CleanupStructmenuitem.Caption = sMenuItem44
CleanupStructmenuitem.OnClick = CleanupStruct
mi1.add(CleanupStructmenuitem)
local Sep2menuitem = createMenuItem(mmenu)
Sep2menuitem.Caption = '-'
mi1.add(Sep2menuitem)
local SwitchLuaGuimenuitem = createMenuItem(mmenu)
SwitchLuaGuimenuitem.Caption = sMenuItem45
SwitchLuaGuimenuitem.OnClick = SwitchLuaGui
mi1.add(SwitchLuaGuimenuitem)
mmenu_items.add(mi1)
--form.show()
end
function DissectStructRemove()
local nCount = getStructureCount()
local sText = 'Do you want to delete all Unnamed structures now...? \n' ..
'Note: [All] = Delete ALL structures !'
local nResult = messageDialog(sText, mtInformation, mbYes, mbAll, mbCancel)
if not (nResult == 6 or nResult == 8) then return end
-- LIFO deletion...
for i=nCount-1,0,-1 do
--local sName = nil
local oStruct = getStructure(i)
local sName = string.match(oStruct.name, "unnamed")
if (nResult == 8) then sName = oStruct.name end
if (sName ~= nil) then oStruct.removeFromGlobalStructureList() end
end
end
function CleanupStruct()
local nResult = 0
local nIdx = 0
local aStructInfo = {}
local aStructList = {}
local aStructElem = {}
function Split(s, sep)
local sep = sep or '%.'
local nPosSep = string.find(s,sep)
if (nPosSep == nil) then return end -- when explicit offsets are used...
local sStr1 = string.sub(s,1,nPosSep-1)
local sStr2 = string.sub(s,nPosSep+1)
aStructInfo[sStr1] = nIdx
aStructInfo[sStr2] = nIdx +1
aStructList[sStr1] = nIdx
local nOffset = 0
local nCount = getStructureCount()
for i=0,nCount-1 do
local oStruct = getStructure(i)
if (oStruct.Name == sStr1) then
local nElem = oStruct.Count
for j=0,nElem-1 do
local oElem = oStruct.Element[j]
if (oElem.Name == sStr2) then nOffset = oElem.Offset; break end
end
end
end
aStructElem[sStr1..'~'..sStr2..'~'..nOffset] = nIdx
end
function StructElemRemove()
local sText = 'Do you want to remove obsolete elements from all structures now...? \n\n'..
'Tip: Remove "Unnamed/Obsolete" structures first !'
nResult = messageDialog(sText, mtInformation, mbYes, mbCancel)
if not (nResult == 6 ) then return end
-- clears Lua Engine window
luaForm = getLuaEngine()
luaForm.MenuItem5.doClick()
print('\n\n')
print('Recreating "Structure.Elements" objects... Please, be patient... \n')
local nCount = getStructureCount()
-- perhaps: better to delete structs first and then add struct.elements...?!
for i=nCount-1,0,-1 do
local oStruct = getStructure(i)
local sName = string.match(oStruct.name, "unnamed")
if (sName == nil) then
oStruct.destroy()
end
end
local sPrevStruct = ''
local oCurStruct = nil
for k,v in ipairs(aStructElem) do
local aString = SplitStr(v, '~')
local sCurStruct = aString[1]
print('=> ['.. k .. ']: ' .. aString[1] .. ' + ' .. aString[2] .. ' + ' .. string.format('%X',tonumber(aString[3])))
if (sCurStruct ~= sPrevStruct) then
oCurStruct = createStructure(aString[1])
oCurStruct.addToGlobalStructureList()
end
local oElem = oCurStruct.addElement()
oElem.Name = aString[2]
oElem.Offset = tonumber(aString[3])
oElem.Vartype = 3
sPrevStruct = aString[1]
end
end
-- *********************************
-- *** looping through memrecords...
local al = getAddressList()
local nCount = al.Count
local sSep = '%.'
for i=0,nCount-1 do
local mr = al.getMemoryRecord(i)
local addrVal = tostring(tonumber(mr.Address) or -99)
if (addrVal == "-99") then addrVal = string.sub(mr.Address,1,1) end
local sDescr = string.match(mr.Description,"pointerscan")
if ( (mr.Type < 10 and mr.OffsetCount > 0 and sDescr == nil) or addrVal == "+") then
--print(string.format('[%03d/%03d~%03d]: %s => %02d - %03d | %s ~> %s {%s}',
-- i, mr.ID, mr.Index, mr.Description, mr.Type, mr.OffsetCount, mr.Address, addrVal, sDescr))
if (string.sub(mr.Address,1,1) == "+") then
Split(string.sub(mr.Address,2),sSep)
end
for j=0,mr.OffsetCount-1 do
local sOffset = tonumber(mr.OffsetText[j],16)
if (sOffset == nil) then
Split(mr.OffsetText[j],sSep)
end
end
end
end
local aTmp = {}
for n in pairs(aStructElem) do table.insert(aTmp, n) end
table.sort(aTmp)
aStructElem = aTmp
--[[
for i,n in ipairs(aStructElem) do
print(i .. ' - ' .. n .. ' [' .. aStructElem[i] .. ']')
end
local nCount = getStructureCount()
local sName = ''
for i=0,nCount-1 do
local oStruct = getStructure(i)
sName = oStruct.name
print(tostring(sName))
end
for k,v in pairs(aStructInfo) do
print(k)
end
print('\n')
for k,v in pairs(aStructList) do
print(k)
end
]]--
StructElemRemove()
if (nResult == 6 ) then
print('\n => Verify your structures and then [Save As] your table under new name...')
print('\n => Just close window when no longer needed...')
end
end
-- ***
-- source info: google "cheat engine a way to create a checkbox list?"
function DissectStructRemoveSelect()
function createScrollBox(Parent)
local scrbox = createComponentClass('TScrollBox', Parent)
scrbox.Parent = Parent
return scrbox
end
local function addImgButton(oPanel)
local btn1 = createButton(oPanel)
btn1.Width = 120
btn1.Height = 20
btn1.Top = oPanel.Height - btn1.Height - 10
btn1.Left = 10
btn1.Caption = 'Delete selected...'
btn1.onClick = bg_Toggle
btn1.ShowHint = true
btn1.Hint = " Click here to initiate deletion... "
end
function bg_Toggle(sender)
local sText = 'Do you want to delete these selected structures now...?'
local nResult = messageDialog(sText, mtInformation, mbYes, mbCancel)
if not (nResult == 6 ) then return end
local nCount = getStructureCount()
local i
for i=nCount-1,0,-1 do
--print(_G['cbx'..i].State)
local oStruct = getStructure(i)
if (_G['cbx'..i].State == 1) then
oStruct.destroy()
end
end
f.close()
end
function buildListbox()
local nCount = getStructureCount()
if (nCount == 0) then return end
f = createForm()
f.Top = 200
f.Left = 200
f.Width = 350
f.Height = 350
f.Caption = "Deleting structures..."
local oPanel = createPanel(f)
oPanel.width,oPanel.top,oPanel.left = 320,10,10
oPanel.Height = 300
addImgButton(f)
a = createScrollBox(oPanel)
a.Top = 0
a.Left = 10
a.Width = 300
a.Height = 290
a.Color = '0x00DFF7FF'
a.ScrollWidth = 10
a.VertScrollBar.Increment = 200
a.VertScrollBar.Page = 300
--a.VertScrollBar.Smooth = true
local nRange = nCount * 15 -- still gives good results with "full" structure list...
a.VertScrollBar.Range = nRange
local ctop=a.Top
local i
for i=0,nCount-1 do
local oStruct = getStructure(i)
sName = oStruct.name
local cbxname='cbx'..i
--print(cbxname .. ' : ' .. sName)
local cbx=createCheckBox(a)
_G[cbxname]=cbx
cbx.Left = 10
cbx.Top = ctop
ctop=ctop+20
cbx.caption = sName
end
end
buildListbox()
end
-- ***
-- source info: google "cheat engine Change description/value of a node in structure dissect"
function AddAddressByRef()
local bCreateStruct = true
local bReplaceBracket = '_'
local bReplaceSpace = false
local structForm = enumStructureForms()[1]
if (structForm == nil) then return end
-- gives base/startaddress of chain_Structs...
local sBaseAddr = structForm.Column[0].AddressText
local sBaseAddr2 = sBaseAddr:match("%[(.-)%]")
if (sBaseAddr2 ~= nil) then sBaseAddr = sBaseAddr2 end
--print(string.format("A) %X - %s",structForm.Column[0].Address, sBaseAddr))
local aStructList = {}
local nCount = getStructureCount()
local sName = ''
for i=0,nCount-1 do
local oStruct = getStructure(i)
sName = oStruct.name
if (sName ~= nil) then aStructList[sName] = i end
--print('{' .. i .. '}: ' .. tostring(sName))
end
--[[
for k,v in pairs(aStructList) do
print(k .. ' ~ ' .. v)
end
]]--
local entry = structForm.tvStructureView.Selected
local struct = integerToUserData(entry.Parent.Data)
local structelement = struct.Element[entry.Index]
local offsetlist={}
nCount = 0
while entry.Parent do
local sStruct = structelement.Name
-- replacing [] and 'spaces'...
local sStruct1 = string.gsub(sStruct,'[%[%]]',bReplaceBracket)
if (sStruct ~= sStruct1) then
if (bReplaceBracket ~= '') then
if (bReplaceSpace) then sStruct = string.gsub(sStruct,'%s',bReplaceBracket) end
sStruct = string.gsub(sStruct,'[%[%]]',bReplaceBracket)
else
sStruct = ''
end
end
local bUseOffset = 0
--print(string.format('[%X] = %s',structelement.Offset, sStruct))
table.insert(offsetlist,1,{structelement.Offset, sStruct, structelement.Vartype, bUseOffset})
entry = entry.Parent
if entry.Parent then
struct = integerToUserData(entry.Parent.Data)
structelement = struct.Element[entry.Index]
end
nCount = nCount + 1
end
-- add mainstruct name...
table.insert(offsetlist,1,{0,struct.Name,0,0})
-- create memrecord...
local al = getAddressList()
local mr = al.createMemoryRecord()
local sDescript = offsetlist[#offsetlist][2]
if (sDescript == '') then sDescript = '_no_Name_Descriptive' end
mr.Description = sDescript
mr.Address = sBaseAddr
mr.Type = offsetlist[#offsetlist][3]
mr.OffsetCount = #offsetlist-1
for i=2,#offsetlist do
local sCurStruct = offsetlist[i-1][2]
if (bCreateStruct and sCurStruct ~= '') then
local oStruct = getStructure(aStructList[sCurStruct])
if (aStructList[sCurStruct] == nil) then
oStruct = createStructure(sCurStruct)
oStruct.addToGlobalStructureList()
end
local oElem = oStruct.getElementByOffset(offsetlist[i][1])
if (oElem == nil) then oElem = oStruct.addElement() end
oElem.Offset = offsetlist[i][1]
oElem.Name = offsetlist[i][2]
end
local sAddr1 = offsetlist[i-1][2]
local sAddr2 = offsetlist[i][2]
sAddress = sAddr1 .. '.' .. sAddr2
if (sAddr1 == '' or sAddr2 == '') then mr.Offset[#offsetlist-i] = offsetlist[i][1]
else mr.OffsetText[#offsetlist-i] = sAddress end
--print(string.format('%X ~ %s => Type: %d | bUseOffset: %d',offsetlist[i][1], sAddress, offsetlist[i][3], offsetlist[i][4]))
end
end
local function OpenLuaEngine()
form = getLuaEngine() -- get Lua Engine form
form.MenuItem5.doClick() -- clear its window (using menu_item)
getMemoryViewForm().miLuaEngine.doClick()
form.Panel1.Visible = true
form.Splitter1.Visible = true
form.Menu = luaMenu
end
function SwitchLuaGui()
if (bHideLua == 0) then bHideLua = 1 else bHideLua = 0 end
form = getLuaEngine()
form.MenuItem5.doClick() -- clearing lua window
getMemoryViewForm().miLuaEngine.doClick() -- opening lua window
if (luaMenu == nil) then luaMenu = form.Menu end
if (bHideLua == 0) then
form.Panel1.Visible = true
form.Splitter1.Visible = true
form.Menu = luaMenu
form.Font.Name = 'default'
form.Font.Size = 10
--form.Panel2.Visible = false
--form.Panel3.Visible = false
else
form.Panel1.Visible = false
form.Splitter1.Visible = false
form.Menu = nil
end
end
-- END functions for [Design] submnenu...
-- **************************************
local function CheckCEinfo()
local myCEset = getSettings() -- or getSettings('')
local nDebugger1 = myCEset.Value['Use VEH Debugger']
local nDebugger2 = myCEset.Value['Use Windows Debugger']
local nDebugger3 = myCEset.Value['Use Kernel Debugger']
local sDebugger = 'VEH'
if ( nDebugger2 == '1') then sDebugger = 'Windows' end
if ( nDebugger3 == '1') then sDebugger = 'Kernel' end
local nBP1 = myCEset.Value['Hardware breakpoints']
local nBP2 = myCEset.Value['Software breakpoints']
local nBP3 = myCEset.Value['Exception breakpoints']
local sBP = 'Hardware'
if ( nBP2 == '1') then sBP = 'Software' end
if ( nBP3 == '1') then sBP = 'Page Exceptions' end
showMessage('Debugger : ' .. sDebugger .. "\n\z" .. 'Breakpoints: ' .. sBP)
--[[
print('Debugger : ' .. sDebugger .. '\n')
print('Breakpoints: ' .. sBP .. '\n')
myCEset = getSettings('VersionCheck')
print('VersionCheck:')
print('Check On Launch: \t' .. myCEset.Value['CheckOnLaunch'])
print('Check Interval: \t' .. myCEset.Value['CheckInterval'])
]]
end
function chkDirFile(sPath, bType)
-- directory can NOT end with a '\'... !
local sCheck = string.sub(sPath,-1)
if (sCheck == '\\') then sPath = string.gsub(sPath,'\\$','') end
--print(sPath)
local attr = lfs.attributes(sPath)
local sType = 'directory'
if (bType == 1) then sType = 'file' end
if attr then
-- file/folder exists or get filesize...
if (bType == 2) then
if (attr.size < 1000) then
return '(file seems invalid as being too small... ?!) \n'
else return '\n' end
end
if attr.mode == sType then
return true
else
return false
end
end
return false
end
function getPath(path, sMgs, sSection)
local path = path
if ( path == '<game>' ) then
local bExist = chkDirFile(myPath,0)
if bExist then path = myPath else path = 'undefined' end
end
if ( path == '<table>' ) then
local sTablename = getTable():match("(.*[/\\])")
local bExist = chkDirFile(sTablename,0)
if bExist then path = sTablename else path = 'undefined' end
end
local bExist = chkDirFile(path,0)
if not bExist then
showMessage('Your \'' .. sMgs .. '\' is incorrect ! \n' ..
'[' .. path .. '] \n\n' ..
'Check [' .. sSection .. '...] and correct accordingly...')
path = 'undefined'
end
return path
end
local function DissectCode(sender)
local path = getPath(pathSaveFiles,'Dissect Code location','Developer tools')
if ( path == 'undefined' ) then return end
-- for those rare occassions whereby myGame is not picked up...
if ( bDissectProc == '0' ) then
--if (process == nil or process == '') then return end
--if (myGame == nil or myGame == '') then return end
if not openProcess(myGame) then
if not openProcess(process) then
showMessage('You need to attach a game first... !')
return
else
myGame = process
end
end
else
-- manually attaching process can give problems for certain games...
if not openProcess(process) then
showMessage('You need to attach a game first... !')
return
else
myGame = process
end
end
local sCheck = string.sub(path,-1)
if (sCheck == '\\') then path = string.gsub(path,'\\$','') end
path = string.format(path .. '\\' .. myGame:match("(.+)%..+") .. '.disCode')
--print(path)
local bExist = chkDirFile(path,1)
local sFileExist = 'Following Dissect Code file already exists: \n'
local sFileInvalid = '\n'
if bExist then
local bSize = chkDirFile(path,2)
-- filesize in bytes...
if not (bSize) then
sFileInvalid = '(file seems invalid as being too small... ?!) \n'
end
end
local menufn = sender.Caption
if menufn == sMenuItem26 then
if bExist then
sFileInvalid = chkDirFile(path,2)
if (not ( sFileInvalid == '\n') ) then
local sText = sFileExist ..
'[' .. path .. '] \n' ..
sFileInvalid ..
'\n\n' ..
'Therefore this file will not be loaded...'
showMessage(sText)
return
end
local sText = sFileExist ..
'[' .. path .. '] \n\n\n' ..
'Do you want to load it now...? \n' ..
'> loading will take about 10~30 secs \n' ..
'> wait for it to finish...'
local nResult = messageDialog(sText, mtInformation, mbYes, mbCancel)
if not (nResult == 6 ) then return end
else
local sText = 'Following Dissect Code file could not be found:' ..
'\n' .. '[' .. path .. ']'
showMessage(sText)
return
end
local bOK = getDissectCode().loadFromFile(path)
if (bOK) then
sText = 'Dissect Code file loaded successfully...'
else
sText = 'Dissect Code file could not be loaded... ?!'
end
showMessage(sText)
end
if menufn == sMenuItem27 then
if ( getDissectCode().getReferencedStrings() == nil ) then
sText = 'No Dissect Code Analysis currently exits... \n' ..
'Either Load a Dissect Code file or Build one... !'
showMessage(sText)
return
end
if bExist then
local sText = 'Are your sure you want to overwrite it now...?! \n' ..
'> saving info will take about 10~30 secs \n' ..
'> wait for it to finish...'
sFileInvalid = chkDirFile(path,2)
sText = sFileExist ..
'[' .. path .. '] \n' ..
sFileInvalid .. '\n\n' ..
sText
local nResult = messageDialog(sText, mtWarning, mbYes, mbCancel)
if not (nResult == 6 ) then return end
else
sText = 'The Dissect Code file will be save as follows: \n' ..
'[' .. path .. '] \n\n\n' ..
'Do you want to save it now...? \n' ..
'> saving info will take about 10~30 secs \n' ..
'> wait for it to finish...'
local nResult = messageDialog(sText, mtWarning, mbYes, mbCancel)
if not (nResult == 6 ) then return end
end
local bOK = getDissectCode().saveToFile(path)
-- verify if filesize makes sense...
sFileInvalid = chkDirFile(path,2)
if (not ( sFileInvalid == '\n') ) then
local sText = 'Following Dissect Code file has been created: \n' ..
'[' .. path .. '] \n' ..
sFileInvalid .. '\n' ..
'Therefore you should try to resave and/or rebuild...'
showMessage(sText)
return
end
if (bOK) then
sText = 'Dissect Code file saved successfully...'
else
sText = 'Dissect Code file could not be saved... ?!'
end
showMessage(sText)
end
if menufn == sMenuItem28 then
local sText = 'The Dissect Code routine can run a very long time ! \n' ..
'Are you sure you want to start this process now ? \n' ..
'(close the analysis window when finished...) ?'
if bExist then
sFileInvalid = chkDirFile(path,2)
sText = sFileExist ..
'[' .. path .. '] \n' ..
sFileInvalid .. '\n\n' ..
sText
end
local nResult = messageDialog(sText,mtWarning, mbYes, mbCancel)
if not (nResult == 6 ) then return end
-- also possible to call: miReferencedFunctions
getMemoryViewForm().Dissectcode1.doClick()
end
if menufn == sMenuItem29 then
local sText = 'Are you sure you want to clear the current Dissect Code Analysis ?'
if bExist then
sFileInvalid = chkDirFile(path,2)
sText = sFileExist ..
'[' .. path .. '] \n' ..
sFileInvalid .. '\n\n' ..
sText
end
local nResult = messageDialog(sText,mtWarning, mbYes, mbCancel)
if not (nResult == 6 ) then return end
getDissectCode().clear()
end
end
-- section [Design] submnenu (main)...
-- ****************************
-- adding submenus...
-- ******************
-- 1 = menuTitle ~2 = functionName
aMenuEngine = { {'getName Anvil','getAnvil'},{'getName UE3','getUE3'},{'getName UE4','getUE4'},{'getName UE4.1x','getUE41'} }
local function addMenuItem()
local mmenu = mForm.Menu
local mmenu_items = menu_getItems(mmenu)
-- Design submenu...
if (bSysMenu == 1) then
local mi2 = createMenuItem(mmenu)
mi2.Caption = '[Design]'
local MemViewmenuitem = createMenuItem(mmenu)
MemViewmenuitem.Caption = sMenuItem21
MemViewmenuitem.OnClick = OpenMemViewer
mi2.add(MemViewmenuitem)
local DissectStructmenuitem = createMenuItem(mmenu)
DissectStructmenuitem.Caption = sMenuItem22
DissectStructmenuitem.OnClick = OpenDissectStruct
mi2.add(DissectStructmenuitem)
local LuaEnginemenuitem = createMenuItem(mmenu)
LuaEnginemenuitem.Caption = sMenuItem23
LuaEnginemenuitem.OnClick = OpenLuaEngine
mi2.add(LuaEnginemenuitem)
local Sepmenuitem = createMenuItem(mmenu)
Sepmenuitem.Caption = '-'
mi2.add(Sepmenuitem)
local CheckDebugmenuitem = createMenuItem(mmenu)
CheckDebugmenuitem.Caption = sMenuItem24
CheckDebugmenuitem.OnClick = CheckCEinfo
mi2.add(CheckDebugmenuitem)
local Dissect_mi = createMenuItem(mmenu)
Dissect_mi.Caption = sMenuItem25
--DissectLoadmenuitem.OnClick = DissectCode
mi2.add(Dissect_mi)
local DissectLoadmenuitem = createMenuItem(mmenu)
DissectLoadmenuitem.Caption = sMenuItem26
DissectLoadmenuitem.OnClick = DissectCode
Dissect_mi.add(DissectLoadmenuitem)
local DissectSavemenuitem = createMenuItem(mmenu)
DissectSavemenuitem.Caption = sMenuItem27
DissectSavemenuitem.OnClick = DissectCode
Dissect_mi.add(DissectSavemenuitem)
local DissectBuildmenuitem = createMenuItem(mmenu)
DissectBuildmenuitem.Caption = sMenuItem28
DissectBuildmenuitem.OnClick = DissectCode
Dissect_mi.add(DissectBuildmenuitem)
local DissectClearmenuitem = createMenuItem(mmenu)
DissectClearmenuitem.Caption = sMenuItem29
DissectClearmenuitem.OnClick = DissectCode
Dissect_mi.add(DissectClearmenuitem)
-- show Anvil option...
local gameOffsets = SplitStr(structParams, "~")
local bStructEnabled = tonumber(string.format('%d',gameOffsets[1]))
if aMenuEngine[bStructEnabled] then sMenuItem30 = aMenuEngine[bStructEnabled][1] end
if (bStructEnabled ~= 99) then
Getnamemenuitem = createMenuItem(mmenu)
Getnamemenuitem.Caption = sMenuItem30 .. sGetnameMark
Getnamemenuitem.OnClick = enableStructLookup
mi2.add(Getnamemenuitem)
end
local Sep2menuitem = createMenuItem(mmenu)
Sep2menuitem.Caption = '-'
mi2.add(Sep2menuitem)
SwitchLuamenuitem = createMenuItem(mmenu)
SwitchLuamenuitem.Caption = sMenuItem31
SwitchLuamenuitem.OnClick = SwitchLuaGui
mi2.add(SwitchLuamenuitem)
mmenu_items.add(mi2)
end
-- Tools submenu...
local mi = createMenuItem(mmenu)
mi.Caption = '[Tools]'
compactmenuitem = createMenuItem(mmenu)
compactmenuitem.Caption = sMenuItem1
compactmenuitem.OnClick = cycleFullCompact
mi.add(compactmenuitem)
if (bWindowMode == 1) then
WinModemenuitem = createMenuItem(mmenu)
WinModemenuitem.Caption = sMenuItem2 .. sWindowMark
WinModemenuitem.OnClick = cycleWinMode
mi.add(WinModemenuitem)
end
OpenFilemenuitem = createMenuItem(mmenu)
OpenFilemenuitem.Caption = sMenuItem4
OpenFilemenuitem.OnClick = OpenFileDialog
OpenFilemenuitem.Name = 'LaunchGame'
mi.add(OpenFilemenuitem)
local DisableCheatsmenuitem = createMenuItem(mmenu)
DisableCheatsmenuitem.Caption = sMenuItem6
DisableCheatsmenuitem.OnClick = DisableMainScript
mi.add(DisableCheatsmenuitem)
local Sepmenuitem = createMenuItem(mmenu)
Sepmenuitem.Caption = '-'
mi.add(Sepmenuitem)
local ShowTablemenuitem = createMenuItem(mmenu)
ShowTablemenuitem.Caption = sMenuItem5
ShowTablemenuitem.OnClick = ShowTableName
mi.add(ShowTablemenuitem)
Configmenuitem = createMenuItem(mmenu)
Configmenuitem.Caption = sMenuItem3 .. sConfigMark
Configmenuitem.OnClick = cycleConfig
mi.add(Configmenuitem)
mmenu_items.add(mi)
itemMenusalreadyexists = 'yes'
end
if not itemMenusalreadyexists then addMenuItem() end
if (bDefaultCompactGui == 1) then cycleFullCompact() end
-- adding image footer to gui...
-- google: "cheat engine Adding a background picture"
-- **************************************************
local sImgName = 'FearlessRev_Footer.png'
local function attachBackground(wc,tblFile)
local p = createPicture()
p.loadFromStream(findTableFile(tblFile).Stream)
wc.OnPaint = function(sender)
local c = sender.getCanvas()
local bitmap = p.getBitmap()
local width = wc.width
-- centering image...
width = (width /2) - (bitmap.Width /2) -- image width
c.draw(width,0,bitmap)
end
end
local function addImgFooter(oPanel,tblFile)
if ImgFooter then return end
--MPanelImg = createPanel(al)
local p = createPicture()
p.loadFromStream(findTableFile(tblFile).Stream)
local bitmap = p.getBitmap()
oPanel.width,oPanel.top,oPanel.left = 10,0,10
-- get panel height based on img_height...
oPanel.Height = bitmap.Height + 2
oPanel.Align = alBottom
oPanel.Caption = 'FearlessRevolution'
ImgFooter = 'yes'
-- additional settings...
oPanel.Anchors = '[akBottom]'
oPanel.Color = hColor -- use same color as addresslist
oPanel.setBevelOuter(0) -- hide surrounding "border"border
end
-- google "cheat engine edit box has two properties that do not work"
local function addImgButton(oPanel)
local btn1 = createButton(oPanel)
btn1.Width = 35
btn1.Height = 20
btn1.Top = oPanel.Height - btn1.Height - 5
btn1.Left = 5
btn1.Caption = 'Info'
btn1.onClick = bg_Toggle
btn1.ShowHint = true
btn1.Hint = " Click this button to open your browser, which will then show you this game\'s topic @ FRF... "
end
function bg_Toggle(sender)
os.execute([[start "" ]] .. sBrowser .. sSearch)
end
if not imgFooteralreadyexists then
local MPanelImg = createPanel(al)
addImgFooter(MPanelImg,sImgName)
attachBackground(MPanelImg,sImgName)
addImgButton(MPanelImg)
cycleConfig()
imgFooteralreadyexists = 'yes'
end
-- show info in Title bar...
-- *************************
function WinTitleTimer()
local tmer2 = createTimer(mForm, false)
tmer2.OnTimer = UpdateWinTitle
tmer2.Interval = nChkTimer
tmer2.Enabled = true
end
local sPID = 0
local bReset = 0
local bDisableRun = 0
function UpdateWinTitle()
-- scripts to run w/ every time_interval...
mrScriptToRun.Active = true
-- ***
local sGame = myGame
local myPID = getProcessIDFromProcessName(myGame)
if (myPID == sPID) then return end
sPID = getProcessIDFromProcessName(myGame)
if (sPID == nil) then sPID = 0 end
--print(string.format('%s -- %s -- %s',myGame, tostring(sPID), process))
if ( bCorrectProc == '0' or bCorrectProc == '1' or bCorrectProc == '2') then
if ( openProcess(myGame) ) then
-- x64 games can give "timely loading issues" here...
if not pcall(function() getAddress(myGame) end) then sPID = 0; return end
local startAddr = getAddress(myGame)
local endAddr = nCheckMemRange
if (endAddr <= 0 ) then endAddr = getModuleSize(process) end
endAddr = startAddr + endAddr
local addrProc = getStaticAddr(sCheckProc,0,"",3,startAddr,endAddr,sProtFlags)
if (addrProc == nil or addrProc == 0) then sPID = 0 else bReset = 1 end
--print(tostring(sGame) .. ' + ' .. tostring(process))
end
end
if (sPID == 0 or process == nil) then
sGame = '<no/incorrect Game process selected>'
-- in case of crashes, reset variable...
myGame = al.getMemoryRecordByID(myGameID).Description
if (bCorrectProc == '9') then myGame = '' end
OpenFilemenuitem.Enabled = true
bDisableRun = 0
end
--print("**" .. tostring(sPID) .. ' - ' .. tostring(process))
mForm.Caption="Cheat Engine v" .. getCEVersion() .. " ~ [" .. sGame .. "]"
if (tmer2 ~= nil and sPID ~= 0 and bCorrectProc == '0') then
tmer2.destroy()
tmer2 = nil
end
-- "reset" table for pre-v7 CEs...
if (bReset == 1) then
-- using hotkey to disable script will disable scripts AND locked values...
DisableMainScript(true)
bReset = 0
bDisableRun = 1
OpenFilemenuitem.Enabled = false
if (bWindowMode == 1) then addrD3D = 0; CheckWindowMode() end
end
if ( bCorrectProc == '2' and myPID ~= sPID) then CheckOnFilename() end
--print("***" .. tostring(myStartAddr) .. " -*")
end
-- checks processlist for "similar" name...
function CheckOnFilename()
-- remove extension...
local sFilename = myGame:match("(.+)%..+")
--print(myGame .. sFilename)
if (sFilename == '' or sFilename == nil) then return end
for pid,name in pairs(getProcessList()) do
local bHit = string.find(name, sFilename)
if ( bHit ~= nil ) then
--print(string.format("%x - %s", pid,name))
myGame = name
end
--print(string.format("%x - %s", pid,name))
end
end
-- see Settings page for details...
WinTitleTimer()
-- ensures that myGame is updated when [File ~ Open Process]-ing...
function onOpenProcess(processId)
myGame = getProcessList()[processId]
--print(string.format('ProcessID: %d & name: %s', processId,getProcessList()[processId] ))
getTable()
end
-- google "cheat engine REQ: access to CT table name - [Solved] ~ @CEF - Cheat Engine section"
function onTableLoad(before)
if ( before == false ) then
getTable()
end
end
-- collects [address] found in opcode...
-- see also 'getName' as alternative...!
function getStaticAddr(sAOB,nOffset,sBaseAddr,nEval,nStartMem,nEndMem,sFlags)
nEval = nEval or 0
nStartMem = nStartMem or 0
nEndMem = nEndMem or 0xffffffffffffffff
sFlags = sFlags or "+X-C-W"
--local scan1 = AOBScan(sAOB,"+X-C-W")
--print("* " .. scan1[0])
local scan = createMemScan(false)
scan.setOnlyOneResult(true)
scan.firstScan(soExactValue,vtByteArray,rtRounded,sAOB,nil,nStartMem,nEndMem,sFlags,
fsmNotAligned,nil,true,false,false,false)
scan.waitTillDone()
scan.getOnlyResult()
local bArch = targetIs64Bit()
local addrStruct = scan.Result
--print(string.format('+ %X +',scan.Result))
if (nEval == 0 or nEval == 2) then
local offsVal = scan.Result - nOffset
--print(string.format('- %X -',offsVal))
offsVal = string.format('%X',readInteger(offsVal,true))
--print(offsVal)
addrStruct = tonumber(offsVal,16)
if ( bArch ) then addrStruct = scan.Result + tonumber(offsVal,16) - nOffset + 4 end
--print(string.format('%X',addrStruct))
if (nEval == 2) then
addrStruct = readPointer(addrStruct)
end
end
scan.destroy()
if (nEval == 3) then return addrStruct end
local addrFound = getAddress(sBaseAddr)
if ( bArch ) then writeQword(addrFound,addrStruct) else writeInteger(addrFound,addrStruct) end
--print(string.format('* %X *',addrStruct))
end
-- see Settings ~ Maintenance scripts...
function Form_Actions(sender)
runFormScripts(sender)
end
-- run script at least once...
local mr = al.getMemoryRecordByID(26071)
mr.Active = true