· 5 years ago · Dec 02, 2020, 01:18 AM
1-- local variables for API functions. any changes to the line below will be lost on re-generation
2local client_camera_angles, client_color_log, client_delay_call, client_error_log, client_exec, client_eye_position, client_log, client_screen_size, client_set_event_callback, client_userid_to_entindex, entity_get_classname, entity_get_local_player, entity_get_player_weapon, entity_get_prop, globals_curtime, globals_realtime, globals_mapname, globals_tickinterval, math_abs, math_ceil, math_floor, math_max, math_min, math_sqrt, renderer_circle, renderer_circle_outline, renderer_line, renderer_measure_text, renderer_rectangle, renderer_text, renderer_triangle, string_format, table_concat, table_insert, table_remove, table_sort, ui_get, ui_new_button, ui_new_checkbox, ui_new_color_picker, ui_new_combobox, ui_new_hotkey, ui_new_multiselect, ui_new_slider, ui_new_textbox, ui_reference, ui_set, ui_set_callback, loadstring, tostring, assert, require, ui_set_visible, setmetatable, type, pairs, ipairs, pcall, error, tonumber, select, unpack = client.camera_angles, client.color_log, client.delay_call, client.error_log, client.exec, client.eye_position, client.log, client.screen_size, client.set_event_callback, client.userid_to_entindex, entity.get_classname, entity.get_local_player, entity.get_player_weapon, entity.get_prop, globals.curtime, globals.realtime, globals.mapname, globals.tickinterval, math.abs, math.ceil, math.floor, math.max, math.min, math.sqrt, renderer.circle, renderer.circle_outline, renderer.line, renderer.measure_text, renderer.rectangle, renderer.text, renderer.triangle, string.format, table.concat, table.insert, table.remove, table.sort, ui.get, ui.new_button, ui.new_checkbox, ui.new_color_picker, ui.new_combobox, ui.new_hotkey, ui.new_multiselect, ui.new_slider, ui.new_textbox, ui.reference, ui.set, ui.set_callback, loadstring, tostring, assert, require, ui.set_visible, setmetatable, type, pairs, ipairs, pcall, error, tonumber, select, unpack
3-- saving optimized by dev
4--[[Original Code by sapphyrus]]--
5-- enhanced by dev, baka
6-- update 11/9/2020
7-- super small json pretty print
8-- based on https://github.com/bungle/lua-resty-prettycjson/blob/master/lib/resty/prettycjson.lua and https://github.com/bungle/lua-resty-prettycjson/blob/master/lib/resty/prettycjson.lua
9local json_encode_pretty
10do local a,b,c,d,e=string.byte,string.find,string.format,string.gsub,string.match;local f,g,h=table.concat,string.sub,string.rep;local i,j=1/0,-1/0;local k='[^ -!#-[%]^-\255]'local l;do local n,o;local p,q;local function r(n)q[p]=tostring(n)p=p+1 end;local s=e(tostring(0.5),'[^0-9]')local t=e(tostring(12345.12345),'[^0-9'..s..']')if s=='.'then s=nil end;local u;if s or t then u=true;if s and b(s,'%W')then s='%'..s end;if t and b(t,'%W')then t='%'..t end end;local v=function(w)if j<w and w<i then local x=tostring(w)if u then if t then x=d(x,t,'')end;if s then x=d(x,s,'.')end end;q[p]=x;p=p+1;return end;error('invalid number')end;local y;local z={['"']='\\"',['\\']='\\\\',['\b']='\\b',['\f']='\\f',['\n']='\\n',['\r']='\\r',['\t']='\\t',__index=function(_,B)return c('\\u00%02X',a(B))end}setmetatable(z,z)local function C(x)q[p]='"'if b(x,k)then x=d(x,k,z)end;q[p+1]=x;q[p+2]='"'p=p+3 end;local function D(E)local F=E[0]if type(F)=='number'then q[p]='['p=p+1;for G=1,F do y(E[G])q[p]=','p=p+1 end;if F>0 then p=p-1 end;q[p]=']'else F=E[1]if F~=nil then q[p]='['p=p+1;local G=2;repeat y(F)F=E[G]if F==nil then break end;G=G+1;q[p]=','p=p+1 until false;q[p]=']'else q[p]='{'p=p+1;local F=p;for H,n in pairs(E)do C(H)q[p]=':'p=p+1;y(n)q[p]=','p=p+1 end;if p>F then p=p-1 end;q[p]='}'end end;p=p+1 end;local I={boolean=r,number=v,string=C,table=D}setmetatable(I,I)function y(n)if n==o then q[p]='null'p=p+1;return end;return I[type(n)](n)end;function l(J,K)n,o=J,K;p,q=1,{}y(n)return f(q)end;function json_encode_pretty(n,L,M,N)local x,O=l(n)if not x then return x,O end;L,M,N=L or"\n",M or"\t",N or" "local p,G,H,w,P,Q,R=1,0,0,#x,{},nil,nil;local S=g(N,-1)=="\n"for T=1,w do local B=g(x,T,T)if not R and(B=="{"or B=="[")then P[p]=Q==":"and f{B,L}or f{h(M,G),B,L}G=G+1 elseif not R and(B=="}"or B=="]")then G=G-1;if Q=="{"or Q=="["then p=p-1;P[p]=f{h(M,G),Q,B}else P[p]=f{L,h(M,G),B}end elseif not R and B==","then P[p]=f{B,L}H=-1 elseif not R and B==":"then P[p]=f{B,N}if S then p=p+1;P[p]=h(M,G)end else if B=='"'and Q~="\\"then R=not R and true or nil end;if G~=H then P[p]=h(M,G)p,H=p+1,G end;P[p]=B end;Q,p=B,p+1 end;return f(P)end end end
11
12local ordered_table = {}
13do local b={}local c={}function ordered_table.insert(d,e,f)if f==nil then ordered_table.remove(d,e)else if d[b][e]==nil then d[c][#d[c]+1]=e end;d[b][e]=f end end;local function g(d,f)for h,i in ipairs(d)do if f==i then return h end end end;function ordered_table.remove(d,e)local j=d[b]local f=j[e]if f~=nil then local k=d[c]table.remove(k,assert(g(k,e)))j[e]=nil end;return f end;function ordered_table.pairs(d)local h=0;return function()h=h+1;local l=d[c][h]if l~=nil then return l,d[b][l]end end end;ordered_table.__newindex=ordered_table.insert;ordered_table.__len=function(d)return#d[c]end;ordered_table.__pairs=ordered_table.pairs;ordered_table.__index=function(d,e)return d[b][e]end;function ordered_table:new(m)m=m or{}local n={}local o={}local d={[c]=n,[b]=o}local p=#m;if p%2~=0 then error("key: "..tostring(m[#m]).." is missing value",2)end;for h=1,p/2 do local e=m[h*2-1]local f=m[h*2]if o[e]~=nil then error("duplicated key:"..tostring(e),2)end;n[#n+1]=e;o[e]=f end;return setmetatable(d,self)end;setmetatable(ordered_table,{__call=ordered_table.new}) end
14
15local package_loaded = package.loaded
16
17local vector3, vector2
18do local vector = (function() local a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,pcall,t,u,v,w,error,type,tonumber,setmetatable=client.camera_angles,client.draw_debug_text,client.eye_position,client.trace_bullet,client.trace_line,entity.get_local_player,math.abs,math.acos,math.atan,math.atan2,math.cos,math.deg,math.fmod,math.max,math.min,math.rad,math.random,math.sin,math.sqrt,pcall,renderer.line,renderer.text,renderer.world_to_screen,string.char,error,type,tonumber,setmetatable;local x=require"ffi"local y,z=x.sizeof,x.istype;local A,B="vector3","vector2"while pcall(y,A)or pcall(y,B)do A,B=A..w(q(97,122)),B..w(q(97,122))end;x.cdef("typedef struct { double x, y, z; } "..A.."; typedef struct { double x, y; } "..B..";")local C=1/0;local function D(E,F)if not E then error(F,3)end end;local function G(H,I,J)return o(n(H,I),J)end;local function K(L)if L~=L or L==C then return 0 elseif L>=-180 and L<=180 then return L end;local M=m(m(L+360,360),360)return M>180 and M-360 or M end;local N={}local O={__index=N}local P={}local Q;local function R(E)return E~=nil and z(A,E)end;local function S(T)if R(T)then return T:unpack()elseif type(T)=="number"then return T,T,T else error("Invalid arguments",3)end end;local U={}local V={__index=U}local W;local function X(E)return E~=nil and z(B,E)end;local function Y(T)if X(T)then return T:unpack()elseif type(T)=="number"then return T,T else error("Invalid arguments")end end;function O:__eq(T)return R(T)and self.x==T.x and self.y==T.y and self.z==T.z end;function O:__unm()D(R(self),"Self has to be vector3")return Q(-self.x,-self.y,-self.z)end;function O:__add(T)D(R(self),"Self has to be vector3")local Z,_,a0=S(T)return Q(self.x+Z,self.y+_,self.z+a0)end;function O:__sub(T)D(R(self),"Self has to be vector3")local Z,_,a0=S(T)return Q(self.x-Z,self.y-_,self.z-a0)end;function O:__mul(T)D(R(self),"Self has to be vector3")local Z,_,a0=S(T)return Q(self.x*Z,self.y*_,self.z*a0)end;function O:__div(T)D(R(self),"Self has to be vector3")local Z,_,a0=S(T)return Q(self.x/Z,self.y/_,self.z/a0)end;function O:__tostring()D(R(self),"Self has to be vector3")return"("..self.x..", "..self.y..", "..self.z..")"end;function O.__call(a1,Z,_,a0)return Q(Z,_,a0)end;function O.__index(a2,a3)if N[a3]~=nil then return N[a3]elseif P[a2]~=nil then return P[a2][a3]end end;function O.__newindex(a2,a3,a4)if N[a3]==nil then P[a2]=P[a2]or{}P[a2][a3]=a4 end end;function N:clear()self.x,self.y,self.z=0,0,0 end;function N:unpack()return self.x,self.y,self.z end;function N:dup()return Q(self:unpack())end;N.clone=N.dup;function N:set(Z,_,a0)if R(Z)then Z,_,a0=Z:unpack()end;self.x=Z;self.y=_;self.z=a0 end;function N:scale(a5)self:set(self.x*a5,self.y*a5,self.z*a5)return self end;function N:length_sqr()return self.x*self.x+self.y*self.y+self.z*self.z end;function N:length_2d_sqr()return self.x*self.x+self.y*self.y end;function N:length()return s(self:length_sqr())end;function N:length_2d()return s(self:length_2d_sqr())end;function N:dot(T)return self.x*T.x+self.y*T.y+self.z*T.z end;function N:cross(T)return Q(self.y*T.z-self.z*T.y,self.z*T.x-self.x*T.z,self.x*T.y-self.y*T.x)end;function N:dist_to(T)return(T-self):length()end;function N:dist_to_2d(T)return(T-self):length_2d()end;function N:normalize()local a6=self:length()if a6==0 then return 0 else self:scale(1/a6)return a6 end end;function N:normalize_2d()local a6=self:length_2d()if a6==0 then return 0 else self:scale(1/a6)return a6 end end;function N:normalized()local a6=self:length()if a6==0 then return Q()end;return self/a6 end;function N:lerp(T,a7)return self+(T-self)*a7 end;function N:vector_angles(T)local a8,a9,aa;local ab,ac,ad;if T==nil then ab,ac,ad=self.x,self.y,self.z;a8,a9,aa=c()if a8==nil then return end else ab,ac,ad=T.x,T.y,T.z;a8,a9,aa=self.x,self.y,self.z end;local ae,af,ag=ab-a8,ac-a9,ad-aa;if ae==0 and af==0 then return W(ag>0 and 270 or 90,0)else local ah=l(j(af,ae))local ai=s(ae*ae+af*af)local aj=l(j(-ag,ai))return W(aj,ah)end end;function N:trace_line(T,ak)ak=ak or-1;local al,am,an=self:unpack()local ao,ap=e(ak,al,am,an,T:unpack())local aq=self:lerp(T,ao)return ao,ap,aq end;function N:trace_line_skip(T,ar,as)as=as or 10;local ao,ap=0,-1;local aq=self;local at=0;while as>=at and ao<1 and(ap>-1 and ar(ap)or aq==self)do ao,ap,aq=aq:trace_line(T,ap)at=at+1 end;local ao=self:dist_to(aq)/self:dist_to(T)return ao,ap,aq end;function N:trace_bullet(T,au)au=au or f()local al,am,an=self:unpack()return d(au,al,am,an,T:unpack())end;function N:get_fov(av,aw)if av==nil then av=N(c())end;if aw==nil then aw=U(a())end;local ax=av:vector_angles(self)return(aw-ax):length_2d()end;function N:in_fov(ay,av,aw)if ay==nil then error("Invalid arguments: FOV is required")end;return ay>self:get_fov(av,aw)end;function N:normalize_angles()self.x=n(-89,o(89,self.x))self.y=K(self.y)self.z=0 end;function N:to_screen()return v(self:unpack())end;function N:draw_text(az,aA,aB,aC,aD,...)local aE,aF=self:to_screen()if aE~=nil then u(aE,aF,az,aA,aB,aC,"c"..(aD or""),0,...)return true end;return false end;function N:draw_debug_text(aG,aH,az,aA,aB,aC,...)b(self.x,self.y,self.z,aG,aH,az,aA,aB,aC,...)end;function N:draw_line(T,az,aA,aB,aC,aI)aI=aI or 1;az,aA,aB,aC=az or 255,aA or 255,aB or 255,aC or 255;local aJ,aK=self:to_screen()local aL,aM=T:to_screen()if aJ~=nil and aL~=nil then for at=1,aI do local aN=at-1;t(aJ,aK-aN,aL,aM-aN,az,aA,aB,aC)t(aJ-aN,aK,aL-aN,aM,az,aA,aB,aC)end end;return aJ~=nil and aL~=nil end;function N:is_zero(aO)aO=aO or 0.001;return g(self.x)<aO and g(self.y)<aO and g(self.z)<aO end;function N.vector_to_angle(aP)local aj,ah;local a6=aP:length()if a6>0 then aj=l(i(-aP.z,a6))ah=l(i(aP.y,aP.x))else W(aP.x>0 and 270 or 90,0)end end;function N.angle_forward(L)if L==nil then error("angle cannot be nil",2)end;local aj,ah=p(L.x),p(L.y)local aQ,aR=r(aj),k(aj)local aS,aT=r(ah),k(ah)return Q(aR*aT,aR*aS,-aQ)end;function N.angle_right(L)local aj,ah,aU=p(L.x),p(L.y),R(L)and p(L.z)or 0;local aQ,aR=r(aj),k(aj)local aS,aT=r(ah),k(ah)local aV,aW=r(aU),k(aU)return Q(-1.0*aV*aQ*aT+-1.0*aW*-aS,-1.0*aV*aQ*aS+-1.0*aW*aT,-1.0*aV*aR)end;function N.angle_up(L)local aj,ah,aU=p(L.x),p(L.y),R(L)and p(L.z)or 0;local aQ,aR=r(aj),k(aj)local aS,aT=r(ah),k(ah)local aV,aW=r(aU),k(aU)return Q(aW*aQ*aT+-aV*-aS,aW*aQ*aS+-aV*aT,aW*aR)end;function N.angle_to_vectors(L)return N.angle_forward(L),N.angle_right(L),N.angle_up(L)end;function N.angle_diff(aX,aY)local aZ=m(aX-aY,360)if aX>aY then if aZ>=180 then aZ=aZ-360 end else if aZ<=-180 then aZ=aZ+360 end end;return aZ end;function N.angle_approach(a_,E,b0)a_=K(a_)E=K(E)local aZ=a_-E;if b0<0 then b0=-b0 end;if aZ<-180 then aZ=aZ+360 elseif aZ>180 then aZ=aZ-360 end;if aZ>b0 then E=E+b0 elseif aZ<-b0 then E=E-b0 else E=a_ end;return E end;function N.get_FOV(b1,av,b2)local b3=N.angle_forward(b1)local aZ=(b2-av):normalized()local ay=h(b3:dot(aZ)/aZ:length())return n(0,l(ay))end;Q=x.metatype(A,O)function V:__eq(T)return X(T)and self.x==T.x and self.y==T.y end;function V:__unm(T)return W(-self.x,-self.y)end;function V:__add(T)local Z,_=Y(T)return W(self.x+Z,self.y+_)end;function V:__sub(T)local Z,_=Y(T)return W(self.x-Z,self.y-_)end;function V:__mul(T)local Z,_=Y(T)return W(self.x*Z,self.y*_)end;function V:__div(T)local Z,_=Y(T)return W(self.x/Z,self.y/_)end;function V:__tostring()return"("..self.x..", "..self.y..")"end;function V.__call(a1,Z,_)return W(Z,_)end;function U:clear()self.x,self.y=0,0 end;function U:unpack()return self.x,self.y end;function U:dup()return W(self:unpack())end;U.clone=U.dup;function U:set(Z,_,a0)if X(Z)then Z,_=Z:unpack()end;self.x=Z;self.y=_ end;function U:scale(a5)self:set(self.x*a5,self.y*a5)return self end;function U:length_sqr()return self.x*self.x+self.y*self.y end;function U:rad()return W(p(self.x),p(self.y))end;function U:deg()return W(l(self.x),l(self.y))end;U.length_2d_sqr=U.length_sqr;function U:length()return s(self:length_sqr())end;U.length_2d=U.length;function U:dist_to(T)return(T-self):length()end;U.dist_to_2d=U.dist_to;function U:normalize()local a6=self:length()if a6==0 then return 0 else self:scale(1/a6)return a6 end end;function U:dot(T)return self.x*T.x+self.y*T.y end;function U:perp()return W(-self.y,self.x)end;function U:normalize_angles()self.x=n(-89,o(89,self.x))self.y=K(self.y)end;W=x.metatype(B,V)setmetatable(N,{__call=function(a1,Z,_,a0)if R(Z)or X(Z)then Z,_,a0=Z:unpack()a0=a0 or 0 end;Z,_,a0=tonumber(Z),tonumber(_),tonumber(a0)if Z==nil or _==nil or a0==nil then return end;return Q(Z,_,a0)end})setmetatable(U,{__call=function(a1,Z,_)if R(Z)or X(Z)then Z,_=Z:unpack()end;Z,_=tonumber(Z),tonumber(_)if Z==nil or _==nil then return end;return W(Z,_)end})return setmetatable({vector3=N,vector2=U,normalize_angle=K,clamp=G},{__call=function()return N,U end,__index=function(a2,a3)if type(a3)=="string"then return a2[a3:lower()]end end}) end)() vector3, vector2 = vector.vector3, vector.vector2 end
19
20local json = { _version = "0.1.2" }
21local ffi = require "ffi"
22
23local ffi_cast = ffi.cast
24local new_charbuffer = ffi.typeof("char[?]")
25local new_intptr = ffi.typeof("int[1]")
26local new_widebuffer = ffi.typeof("wchar_t[?]")
27ffi.cdef [[
28typedef int(__thiscall* get_clipboard_text_count)(void*);
29typedef void(__thiscall* set_clipboard_text)(void*, const char*, int);
30typedef void(__thiscall* get_clipboard_text)(void*, int, const char*, int);
31]]
32local function vmt_entry(instance, index, type)
33 return ffi.cast(type, (ffi.cast("void***", instance)[0])[index])
34end
35
36-- instance is bound to the callback as an upvalue
37local function vmt_bind(module, interface, index, typestring)
38 local instance = client.create_interface(module, interface) or error("invalid interface")
39 local success, typeof = pcall(ffi.typeof, typestring)
40 if not success then
41 error(typeof, 2)
42 end
43 local fnptr = vmt_entry(instance, index, typeof) or error("invalid vtable")
44 return function(...)
45 return fnptr(instance, ...)
46 end
47end
48-- localize
49local native_Localize_ConvertAnsiToUnicode = vmt_bind("localize.dll", "Localize_001", 15, "int(__thiscall*)(void*, const char*, wchar_t*, int)")
50local native_Localize_ConvertUnicodeToAnsi = vmt_bind("localize.dll", "Localize_001", 16, "int(__thiscall*)(void*, wchar_t*, char*, int)")
51local native_Localize_FindSafe = vmt_bind("localize.dll", "Localize_001", 12, "wchar_t*(__thiscall*)(void*, const char*)")
52local function localize_string(str, buf_size)
53 local res = native_Localize_FindSafe(str)
54 local charbuffer = new_charbuffer(buf_size or 1024)
55 native_Localize_ConvertUnicodeToAnsi(res, charbuffer, buf_size or 1024)
56 if charbuffer then
57 if ffi.string(charbuffer) == "#FIXME_LOCALIZATION_FAIL_MISSING_STRING" then
58 charbuffer = false
59 end
60 end
61 return charbuffer and ffi.string(charbuffer) or str
62end
63M = {}
64surface_native = {
65 native_Surface_DrawSetColor = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 15, "void(__thiscall*)(void*, int, int, int, int)"),
66 native_Surface_DrawFilledRect = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 16, "void(__thiscall*)(void*, int, int, int, int)"),
67 native_Surface_DrawOutlinedRect = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 18, "void(__thiscall*)(void*, int, int, int, int)"),
68 native_Surface_DrawLine = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 19, "void(__thiscall*)(void*, int, int, int, int)"),
69 native_Surface_DrawPolyLine = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 20, "void(__thiscall*)(void*, int*, int*, int)"),
70 native_Surface_DrawSetTextFont = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 23, "void(__thiscall*)(void*, unsigned long)"),
71 native_Surface_DrawSetTextColor = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 25, "void(__thiscall*)(void*, int, int, int, int)"),
72 native_Surface_DrawSetTextPos = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 26, "void(__thiscall*)(void*, int, int)"),
73 native_Surface_DrawPrintText = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 28, "void(__thiscall*)(void*, const wchar_t*, int, int)"),
74 native_Surface_DrawGetTextureId = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 34, "int(__thiscall*)(void*, const char*)"),
75 native_Surface_DrawGetTextureFile = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 35, "bool(__thiscall*)(void*, int, char*, int)"),
76 native_Surface_DrawSetTextureFile = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 36, "void(__thiscall*)(void*, int, const char*, int, bool)"),
77 native_Surface_DrawSetTextureRGBA = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 37, "void(__thiscall*)(void*, int, const wchar_t*, int, int)"),
78 native_Surface_DrawSetTexture = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 38, "void(__thiscall*)(void*, int)"),
79 native_Surface_DeleteTextureByID = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 39, "void(__thiscall*)(void*, int)"),
80 native_Surface_DrawGetTextureSize = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 40, "void(__thiscall*)(void*, int, int&, int&)"),
81 native_Surface_DrawTexturedRect = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 41, "void(__thiscall*)(void*, int, int, int, int)"),
82 native_Surface_IsTextureIDValid = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 42, "bool(__thiscall*)(void*, int)"),
83 native_Surface_CreateNewTextureID = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 43, "int(__thiscall*)(void*, bool)"),
84 native_Surface_UnlockCursor = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 66, "void(__thiscall*)(void*)"),
85 native_Surface_LockCursor = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 67, "void(__thiscall*)(void*)"),
86 native_Surface_CreateFont = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 71, "unsigned int(__thiscall*)(void*)"),
87 native_Surface_SetFontGlyph = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 72, "void(__thiscall*)(void*, unsigned long, const char*, int, int, int, int, unsigned long, int, int)"),
88 native_Surface_GetTextSize = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 79, "void(__thiscall*)(void*, unsigned long, const wchar_t*, int&, int&)"),
89 native_Surface_GetCursorPos = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 100, "unsigned int(__thiscall*)(void*, int*, int*)"),
90 native_Surface_SetCursorPos = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 101, "unsigned int(__thiscall*)(void*, int, int)"),
91 native_Surface_DrawOutlinedCircle = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 103, "void(__thiscall*)(void*, int, int, int, int)"),
92 native_Surface_DrawFilledRectFade = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 123, "void(__thiscall*)(void*, int, int, int, int, unsigned int, unsigned int, bool)"),
93}
94font_cache = {}
95function draw_print_text(text, localized)
96 if localized then
97 local cb_size = 1024
98 local char_buffer = new_charbuffer(cb_size)
99 native_Localize_ConvertUnicodeToAnsi(text, char_buffer, cb_size)
100
101 local test = ffi.string(char_buffer)
102 return surface_native.native_Surface_DrawPrintText(text, test:len(), 0)
103 else
104 local wb_size = 1024
105 local wide_buffer = new_widebuffer(wb_size)
106
107 native_Localize_ConvertAnsiToUnicode(text, wide_buffer, wb_size)
108 return surface_native.native_Surface_DrawPrintText(wide_buffer, text:len(), 0)
109 end
110end
111function get_text_size(font, text)
112 local wide_buffer = new_widebuffer(1024)
113 local w_ptr = new_intptr()
114 local h_ptr = new_intptr()
115
116 native_Localize_ConvertAnsiToUnicode(text, wide_buffer, 1024)
117 surface_native.native_Surface_GetTextSize(font, wide_buffer, w_ptr, h_ptr)
118
119 local w = tonumber(w_ptr[0])
120 local h = tonumber(h_ptr[0])
121
122 return w, h
123end
124function M.create_font(windows_font_name, tall, weight, flags)
125 local flags_i = 0
126 local t = type(flags)
127 if t == "number" then
128 flags_i = flags
129 elseif t == "table" then
130 for i=1, #flags do
131 flags_i = flags_i + flags[i]
132 end
133 else
134 error("invalid flags type, has to be number or table")
135 end
136
137 local cache_key = string.format("%s\0%d\0%d\0%d", windows_font_name, tall, weight, flags_i)
138 if font_cache[cache_key] == nil then
139 font_cache[cache_key] = surface_native.native_Surface_CreateFont()
140 surface_native.native_Surface_SetFontGlyph(font_cache[cache_key], windows_font_name, tall, weight, 0, 0, bit.bor(flags_i), 0, 0)
141 end
142
143 return font_cache[cache_key]
144end
145function M.draw_text(x, y, r, g, b, a, font, text)
146 surface_native.native_Surface_DrawSetTextPos(x, y)
147 surface_native.native_Surface_DrawSetTextFont(font)
148 surface_native.native_Surface_DrawSetTextColor(r, g, b, a)
149 return draw_print_text(text, false)
150end
151function M.draw_filled_rect(x, y, w, h, r, g, b, a)
152 surface_native.native_Surface_DrawSetColor(r, g, b, a)
153 return surface_native.native_Surface_DrawFilledRect(x, y, x + w, y + h)
154end
155function M.get_text_size(font, text)
156 return get_text_size(font, text)
157end
158SFont = M.create_font("Verdana", 13, 300, {0x010})
159--[ VGUI_System ]--
160local VGUI_System010 = client.create_interface("vgui2.dll", "VGUI_System010") or print( "Error finding VGUI_System010")
161local VGUI_System = ffi_cast( ffi.typeof( "void***" ), VGUI_System010 )
162function draw_circle_3d(x, y, z, radius, r, g, b, a, accuracy, width, outline, start_degrees, percentage)
163 local accuracy = accuracy ~= nil and accuracy or 3
164 local width = width ~= nil and width or 1
165 local outline = outline ~= nil and outline or false
166 local start_degrees = start_degrees ~= nil and start_degrees or 0
167 local percentage = percentage ~= nil and percentage or 1
168
169 local screen_x_line_old, screen_y_line_old
170 for rot=start_degrees, percentage*360, accuracy do
171 local rot_temp = math.rad(rot)
172 local lineX, lineY, lineZ = radius * math.cos(rot_temp) + x, radius * math.sin(rot_temp) + y, z
173 local screen_x_line, screen_y_line = renderer.world_to_screen(lineX, lineY, lineZ)
174 if screen_x_line ~=nil and screen_x_line_old ~= nil then
175 for i=1, width do
176 local i=i-1
177 renderer.line(screen_x_line, screen_y_line-i, screen_x_line_old, screen_y_line_old-i, r, g, b, a)
178 end
179 if outline then
180 local outline_a = a/255*160
181 renderer.line(screen_x_line, screen_y_line-width, screen_x_line_old, screen_y_line_old-width, 16, 16, 16, outline_a)
182 renderer.line(screen_x_line, screen_y_line+1, screen_x_line_old, screen_y_line_old+1, 16, 16, 16, outline_a)
183 end
184 end
185 screen_x_line_old, screen_y_line_old = screen_x_line, screen_y_line
186 end
187end
188local get_clipboard_text_count = ffi_cast( "get_clipboard_text_count", VGUI_System[ 0 ][ 7 ] ) or print( "get_clipboard_text_count Invalid")
189local set_clipboard_text = ffi_cast( "set_clipboard_text", VGUI_System[ 0 ][ 9 ] ) or print( "set_clipboard_text Invalid")
190local get_clipboard_text = ffi_cast( "get_clipboard_text", VGUI_System[ 0 ][ 11 ] ) or print( "get_clipboard_text Invalid")
191function text_split(szFullString, szSeparator)
192 local nFindStartIndex = 1
193 local nSplitIndex = 1
194 local nSplitArray = {}
195 while true do
196 local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex)
197 if not nFindLastIndex then
198 nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
199 break
200 end
201 nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1)
202 nFindStartIndex = nFindLastIndex + string.len(szSeparator)
203 nSplitIndex = nSplitIndex + 1
204 end
205 return nSplitArray
206 end
207function split_localize(text)
208 local args = text_split(text, " ")
209 local ret = ""
210 for key, value in pairs(args) do
211 local cache_value = value
212 if string.find(value, "%(") then
213 value = string.sub(value, 2, -2)
214 local res = localize_string(value)
215 if res == value then
216 value = cache_value
217 end
218 end
219 ret = ret..localize_string(value)
220 end
221 return ret
222end
223-------------------------------------------------------------------------------
224-- Encode
225-------------------------------------------------------------------------------
226
227local encode
228
229local escape_char_map = {
230 [ "\\" ] = "\\",
231 [ "\"" ] = "\"",
232 [ "\b" ] = "b",
233 [ "\f" ] = "f",
234 [ "\n" ] = "n",
235 [ "\r" ] = "r",
236 [ "\t" ] = "t",
237}
238
239local escape_char_map_inv = { [ "/" ] = "/" }
240for k, v in pairs(escape_char_map) do
241 escape_char_map_inv[v] = k
242end
243
244
245local function escape_char(c)
246 return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
247end
248
249
250function encode_nil(val)
251 return "null"
252end
253
254
255local function encode_table(val, stack)
256 local res = {}
257 stack = stack or {}
258
259 -- Circular reference?
260 if stack[val] then error("circular reference") end
261
262 stack[val] = true
263
264 if rawget(val, 1) ~= nil or next(val) == nil then
265 -- Treat as array -- check keys are valid and it is not sparse
266 local n = 0
267 for k in pairs(val) do
268 if type(k) ~= "number" then
269 error("invalid table: mixed or invalid key types")
270 end
271 n = n + 1
272 end
273 if n ~= #val then
274 error("invalid table: sparse array")
275 end
276 -- Encode
277 for i, v in ipairs(val) do
278 table.insert(res, encode(v, stack))
279 end
280 stack[val] = nil
281 return "[" .. table.concat(res, ",") .. "]"
282
283 else
284 -- Treat as an object
285 for k, v in pairs(val) do
286 if type(k) ~= "string" then
287 error("invalid table: mixed or invalid key types")
288 end
289 table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
290 end
291 stack[val] = nil
292 return "{" .. table.concat(res, ",") .. "}"
293 end
294end
295
296
297local function encode_string(val)
298 return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
299end
300
301
302local function encode_number(val)
303 -- Check for NaN, -inf and inf
304 if val ~= val or val <= -math.huge or val >= math.huge then
305 error("unexpected number value '" .. tostring(val) .. "'")
306 end
307 return string.format("%.14g", val)
308end
309
310
311type_func_map = {
312 [ "nil" ] = encode_nil,
313 [ "table" ] = encode_table,
314 [ "string" ] = encode_string,
315 [ "number" ] = encode_number,
316 [ "boolean" ] = tostring,
317}
318
319
320encode = function(val, stack)
321 local t = type(val)
322 local f = type_func_map[t]
323 if f then
324 return f(val, stack)
325 end
326 error("unexpected type '" .. t .. "'")
327end
328
329
330function json.encode(val)
331 return ( encode(val) )
332end
333
334
335-------------------------------------------------------------------------------
336-- Decode
337-------------------------------------------------------------------------------
338
339local parse
340
341local function create_set(...)
342 local res = {}
343 for i = 1, select("#", ...) do
344 res[ select(i, ...) ] = true
345 end
346 return res
347end
348
349local space_chars = create_set(" ", "\t", "\r", "\n")
350local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
351local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
352local literals = create_set("true", "false", "null")
353
354local literal_map = {
355 [ "true" ] = true,
356 [ "false" ] = false,
357 [ "null" ] = nil,
358}
359
360
361local function next_char(str, idx, set, negate)
362 for i = idx, #str do
363 if set[str:sub(i, i)] ~= negate then
364 return i
365 end
366 end
367 return #str + 1
368end
369
370
371local function decode_error(str, idx, msg)
372 local line_count = 1
373 local col_count = 1
374 for i = 1, idx - 1 do
375 col_count = col_count + 1
376 if str:sub(i, i) == "\n" then
377 line_count = line_count + 1
378 col_count = 1
379 end
380 end
381 error( string.format("%s at line %d col %d", msg, line_count, col_count) )
382end
383
384
385local function codepoint_to_utf8(n)
386 -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
387 local f = math.floor
388 if n <= 0x7f then
389 return string.char(n)
390 elseif n <= 0x7ff then
391 return string.char(f(n / 64) + 192, n % 64 + 128)
392 elseif n <= 0xffff then
393 return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
394 elseif n <= 0x10ffff then
395 return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
396 f(n % 4096 / 64) + 128, n % 64 + 128)
397 end
398 error( string.format("invalid unicode codepoint '%x'", n) )
399end
400
401
402local function parse_unicode_escape(s)
403 local n1 = tonumber( s:sub(1, 4), 16 )
404 local n2 = tonumber( s:sub(7, 10), 16 )
405 -- Surrogate pair?
406 if n2 then
407 return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
408 else
409 return codepoint_to_utf8(n1)
410 end
411end
412
413
414local function parse_string(str, i)
415 local res = ""
416 local j = i + 1
417 local k = j
418
419 while j <= #str do
420 local x = str:byte(j)
421
422 if x < 32 then
423 decode_error(str, j, "control character in string")
424
425 elseif x == 92 then -- `\`: Escape
426 res = res .. str:sub(k, j - 1)
427 j = j + 1
428 local c = str:sub(j, j)
429 if c == "u" then
430 local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
431 or str:match("^%x%x%x%x", j + 1)
432 or decode_error(str, j - 1, "invalid unicode escape in string")
433 res = res .. parse_unicode_escape(hex)
434 j = j + #hex
435 else
436 if not escape_chars[c] then
437 decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
438 end
439 res = res .. escape_char_map_inv[c]
440 end
441 k = j + 1
442
443 elseif x == 34 then -- `"`: End of string
444 res = res .. str:sub(k, j - 1)
445 return res, j + 1
446 end
447
448 j = j + 1
449 end
450
451 decode_error(str, i, "expected closing quote for string")
452end
453
454
455local function parse_number(str, i)
456 local x = next_char(str, i, delim_chars)
457 local s = str:sub(i, x - 1)
458 local n = tonumber(s)
459 if not n then
460 decode_error(str, i, "invalid number '" .. s .. "'")
461 end
462 return n, x
463end
464
465
466local function parse_literal(str, i)
467 local x = next_char(str, i, delim_chars)
468 local word = str:sub(i, x - 1)
469 if not literals[word] then
470 decode_error(str, i, "invalid literal '" .. word .. "'")
471 end
472 return literal_map[word], x
473end
474
475
476local function parse_array(str, i)
477 local res = {}
478 local n = 1
479 i = i + 1
480 while 1 do
481 local x
482 i = next_char(str, i, space_chars, true)
483 -- Empty / end of array?
484 if str:sub(i, i) == "]" then
485 i = i + 1
486 break
487 end
488 -- Read token
489 x, i = parse(str, i)
490 res[n] = x
491 n = n + 1
492 -- Next token
493 i = next_char(str, i, space_chars, true)
494 local chr = str:sub(i, i)
495 i = i + 1
496 if chr == "]" then break end
497 if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
498 end
499 return res, i
500end
501
502
503local function parse_object(str, i)
504 local res = {}
505 i = i + 1
506 while 1 do
507 local key, val
508 i = next_char(str, i, space_chars, true)
509 -- Empty / end of object?
510 if str:sub(i, i) == "}" then
511 i = i + 1
512 break
513 end
514 -- Read key
515 if str:sub(i, i) ~= '"' then
516 decode_error(str, i, "expected string for key")
517 end
518 key, i = parse(str, i)
519 -- Read ':' delimiter
520 i = next_char(str, i, space_chars, true)
521 if str:sub(i, i) ~= ":" then
522 decode_error(str, i, "expected ':' after key")
523 end
524 i = next_char(str, i + 1, space_chars, true)
525 -- Read value
526 val, i = parse(str, i)
527 -- Set
528 res[key] = val
529 -- Next token
530 i = next_char(str, i, space_chars, true)
531 local chr = str:sub(i, i)
532 i = i + 1
533 if chr == "}" then break end
534 if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
535 end
536 return res, i
537end
538
539
540local char_func_map = {
541 [ '"' ] = parse_string,
542 [ "0" ] = parse_number,
543 [ "1" ] = parse_number,
544 [ "2" ] = parse_number,
545 [ "3" ] = parse_number,
546 [ "4" ] = parse_number,
547 [ "5" ] = parse_number,
548 [ "6" ] = parse_number,
549 [ "7" ] = parse_number,
550 [ "8" ] = parse_number,
551 [ "9" ] = parse_number,
552 [ "-" ] = parse_number,
553 [ "t" ] = parse_literal,
554 [ "f" ] = parse_literal,
555 [ "n" ] = parse_literal,
556 [ "[" ] = parse_array,
557 [ "{" ] = parse_object,
558}
559
560
561parse = function(str, idx)
562 local chr = str:sub(idx, idx)
563 local f = char_func_map[chr]
564 if f then
565 return f(str, idx)
566 end
567 decode_error(str, idx, "unexpected character '" .. chr .. "'")
568end
569
570
571function json.decode(str)
572 if type(str) ~= "string" then
573 error("expected argument of type string, got " .. type(str))
574 end
575 local res, idx = parse(str, next_char(str, 1, space_chars, true))
576 idx = next_char(str, idx, space_chars, true)
577 if idx <= #str then
578 decode_error(str, idx, "trailing garbage")
579 end
580 return res
581end
582
583local function get(data)
584 local creation_time = data.created_at()
585 local retn_value = data.get(creation_time)
586
587 local addition_content = readfile("mydata.json")
588 if addition_content ~= nil then
589 addition_content = json.decode(addition_content)
590 for key, value in pairs(addition_content) do
591 if value.map == nil then
592 error("mydata.json parse failed")
593 end
594 if retn_value[value.map] == nil then
595 retn_value[value.map] = {}
596 end
597 table.insert(retn_value[value.map], value)
598 end
599 end
600
601 return retn_value, creation_time
602end
603
604local data_weapon, weapon_prev, reload_data, last_weapon_switch, data_map = {}
605
606local function reset_cvar(cvar)
607 local val = tonumber(cvar:get_string())
608 cvar:set_raw_int(val)
609 cvar:set_raw_float(val)
610end
611local function lerp(a, b, percentage)
612 return a + (b - a) * percentage
613end
614local function table_contains(tbl, val)
615 for i = 1, #tbl do
616 if tbl[i] == val then
617 return true
618 end
619 end
620 return false
621end
622
623local MOVETYPE_NOCLIP = 8
624local dist_max = 1100
625local dist_max_sqr = dist_max^2
626local wx_offset_vec = vector3(0, 0, 20)
627local land_offsets_vec = {
628 vector3(0, 0, 12),
629 vector3(0, 12, 0),
630 vector3(12, 0, 0)
631}
632
633local helper_recreate_dynamic = {
634 active=false
635}
636local helper_debug = false
637local cvar_sensitivity = cvar.sensitivity
638local MOVE_PREPARE, MOVE_THROW, MOVE_DONE = 1, 2, 3
639local airstrafe_reference = ui.reference("MISC", "Movement", "Air strafe")
640local quick_peek_assist_reference = ui.reference("MISC", "Movement", "Easy strafe")
641local brightness_adjustment_reference = ui.reference("VISUALS", "Effects", "Brightness adjustment")
642ui.new_label("LUA", "B", "--------------------------------------------------")
643local enabled_reference = ui.new_checkbox("LUA", "B", "Helper")
644local hotkey_reference = ui.new_hotkey("LUA", "B", "Helper hotkey", true)
645local types_reference = ui.new_multiselect("LUA", "B", "\nHelper types", {
646 "Grenade: Smoke",
647 "Grenade: Flashbang",
648 "Grenade: High Explosive",
649 "Grenade: Molotov",
650 "Wallbang: Legit",
651 "Wallbang: HvH",
652 "Movement"
653})
654local color_reference = ui.new_color_picker("LUA", "B", "Helper color ", 39, 175, 131, 255)
655local ignore_visibility_reference = ui.new_checkbox("LUA", "B", "Show locations behind walls")
656local silent_enabled_reference = ui.new_combobox("LUA", "B", "Automatic release", "Legit (Silent)", "Legit (Smooth)", "Rage")
657local silent_dist = ui.new_slider("LUA", "B", "Silent Distance", 0, 25, 15, true)
658local legit_smooth_dist = ui.new_slider("LUA", "B", "Smooth Distance", 0, 15, 5, true)
659local legit_smooth_fact = ui.new_slider("LUA", "B", "Smooth Factor", 10, 50, 25, true)
660ui.set_callback(silent_enabled_reference, function(c)
661 ui_set_visible(silent_dist, (ui_get(c) == "Rage"))
662 ui_set_visible(legit_smooth_dist, (ui_get(c) == "Legit (Smooth)"))
663 ui_set_visible(legit_smooth_fact, (ui_get(c) == "Legit (Smooth)"))
664end)
665local saving_enabled_reference = ui.new_checkbox("LUA", "B", "Helper saving")
666local saving_hotkey_reference = ui.new_hotkey("LUA", "B", "Helper saving hotkey", true)
667local saving_from_reference = ui.new_textbox("LUA", "B", "From")
668local saving_to_reference = ui.new_textbox("LUA", "B", "To")
669local saving_type_reference = ui.new_combobox("LUA", "B", "Type", {
670 "Grenade",
671 "Wallbang: Legit",
672 "Wallbang: HvH",
673 "Movement"
674})
675local saving_properties_reference = ui.new_multiselect("LUA", "B", "Properties", {
676 "Jump",
677 "Run",
678 "Tickrate"
679})
680local saving_run_direction_reference = ui.new_combobox("LUA", "B", "Run duration / direction", {"Forward", "Left", "Right", "Back"})
681local saving_run_duration_reference = ui.new_slider("LUA", "B", "\nRun duration", 1, 256, 20, true, "t")
682ui.new_label("LUA", "B", "--------------------------------------------------")
683local data_all, data_loaded_at
684do
685 local success, result = pcall(require, "helper_data")
686 if not success then
687 print(result)
688 local line1 = "Helper data file not found!"
689 local line2 = "Make sure to copy 'helper.lua' and 'helper_data.ljbc' into the CS:GO folder"
690 client_delay_call(0, function()
691 client_error_log(line1, " ", line2)
692 end)
693 client_set_event_callback("paint", function()
694 if ui_get(enabled_reference) then
695 local screen_width, screen_height = client_screen_size()
696 local width = 375
697 renderer_rectangle(screen_width/2 - width/2, 56, width+2, 26, 16, 16, 16, 150)
698 renderer_text(screen_width/2, 64, 255, 16, 16, 255, "bc", 0, line1)
699 renderer_text(screen_width/2, 64+10, 215, 215, 215, 255, "c", 0, line2)
700 end
701 end)
702 return
703 end
704 package_loaded["helper_data"] = nil
705 data_all, data_loaded_at = get((result))
706end
707
708local console_names = {
709 ["CSmokeGrenade"] = "weapon_smokegrenade",
710 ["CSensorGrenade"] = "weapon_smokegrenade",
711 ["CFlashbang"] = "weapon_flashbang",
712 ["CDecoyGrenade"] = "weapon_flashbang",
713 ["CIncendiaryGrenade"] = "weapon_molotov",
714 ["CMolotovGrenade"] = "weapon_molotov",
715 ["CHEGrenade"] = "weapon_hegrenade",
716 ["CWeaponAWP"] = "weapon_wallbang",
717 ["CWeaponSCAR20"] = "weapon_wallbang",
718 ["CWeaponG3SG1"] = "weapon_wallbang",
719 ["CWeaponSSG08"] = "weapon_wallbang",
720 ["CDEagle"] = "weapon_wallbang",
721 ["CAK47"] = "weapon_wallbang_light",
722 ["CWeaponSG556"] = "weapon_wallbang_light",
723 ["CWeaponGalilAR"] = "weapon_wallbang_light",
724 ["CWeaponM4A1"] = "weapon_wallbang_light",
725 ["CWeaponM4A4"] = "weapon_wallbang_light",
726 ["CWeaponAug"] = "weapon_wallbang_light",
727 ["CWeaponFamas"] = "weapon_wallbang_light",
728 ["CWeaponTec9"] = "weapon_wallbang_light",
729 ["CKnife"] = "weapon_knife",
730}
731local movement_buttons_chars = {
732 ["in_attack"] = "A",
733 ["in_jump"] = "J",
734 ["in_duck"] = "D",
735 ["in_forward"] = "F",
736 ["in_back"] = "B",
737 ["in_use"] = "U",
738 ["in_moveleft"] = "L",
739 ["in_moveright"] = "R",
740 ["in_attack2"] = "Z",
741 ["in_speed"] = "S"
742}
743local names_to_type = {
744 ["Grenade: Smoke"] = "grenade",
745 ["Grenade: Flashbang"] = "grenade",
746 ["Grenade: High Explosive"] = "grenade",
747 ["Grenade: Molotov"] = "grenade",
748 ["Grenade"] = "grenade",
749 ["Wallbang: Legit"] = "wallbang",
750 ["Wallbang: HvH"] = "wallbang_hvh",
751 ["Movement"] = "movement"
752}
753local console_names_to_name = {
754 ["weapon_smokegrenade"] = "Grenade: Smoke",
755 ["weapon_flashbang"] = "Grenade: Flashbang",
756 ["weapon_hegrenade"] = "Grenade: High Explosive",
757 ["weapon_molotov"] = "Grenade: Molotov",
758}
759local throwtype_description = {
760 ["RUN"] = "Runthrow",
761 ["JUMP"] = "Jumpthrow",
762 ["RUNJUMP"] = "Run + Jumpthrow"
763}
764local run_direction_yaw = {
765 ["Forward"] = 0,
766 ["Back"] = 180,
767 ["Left"] = 90,
768 ["Right"] = -90,
769}
770local map_aliases = {
771 ["workshop/141243798/aim_ag_texture2"] = "aim_ag_texture2",
772 ["workshop/1855851320/de_cache_new"] = "de_cache"
773}
774local map_patterns = {
775 ["_scrimmagemap$"] = ""
776}
777
778local on_saving_enabled_changed
779local function on_enabled_changed()
780 reload_data = true
781 local enabled = ui_get(enabled_reference)
782 ui_set_visible(types_reference, enabled)
783 ui_set_visible(color_reference, enabled)
784 ui_set_visible(ignore_visibility_reference, enabled)
785 ui_set_visible(saving_enabled_reference, enabled)
786 ui_set_visible(silent_enabled_reference, enabled)
787 ui_set_visible(silent_dist, enabled and (ui_get(silent_enabled_reference) == "Rage"))
788 ui_set_visible(legit_smooth_dist, enabled and (ui_get(silent_enabled_reference) == "Legit (Smooth)"))
789 ui_set_visible(legit_smooth_fact, enabled and (ui_get(silent_enabled_reference) == "Legit (Smooth)"))
790 if not enabled and ui_get(saving_enabled_reference) then
791 ui_set(saving_enabled_reference, false)
792 if on_saving_enabled_changed ~= nil then
793 on_saving_enabled_changed()
794 end
795 end
796end
797ui.set_callback(enabled_reference, on_enabled_changed)
798ui.set_callback(types_reference, on_enabled_changed)
799on_enabled_changed()
800
801local function setup_debug()
802 local table_gen = require "lib/table_gen"
803 ui.new_button("LUA", "B", "Grenade helper generate statistics", function()
804 local maps = {}
805 for map, map_spots in pairs(data_all) do
806 table_insert(maps, map)
807 end
808 table_sort(maps)
809 local rows = {}
810 local headings = {"MAP", "Smokes", "Flashes", "Molotovs", "Grenades", "Wallbangs", "One-ways", "Other"}
811 local total_row = {"TOTAL", 0, 0, 0, 0, 0, 0, 0}
812
813 for i=1, #maps do
814 local row = {maps[i], 0, 0, 0, 0, 0, 0, 0}
815 local map_locations = data_all[maps[i]]
816 for i=1, #map_locations do
817 local index = 8
818 if map_locations[i].type == "grenade" then
819 if map_locations[i].weapon == "weapon_smokegrenade" then
820 index = 2
821 elseif map_locations[i].weapon == "weapon_flashbang" then
822 index = 3
823 elseif map_locations[i].weapon == "weapon_molotov" then
824 index = 4
825 elseif map_locations[i].weapon == "weapon_hegrenade" then
826 index = 5
827 end
828 elseif map_locations[i].type == "wallbang" then
829 index = 6
830 elseif map_locations[i].type == "wallbang_hvh" then
831 index = 7
832 end
833
834 if not map_locations[i].temporary then
835 row[index] = row[index] + 1
836 total_row[index] = total_row[index] + 1
837 end
838 end
839
840 table_insert(rows, row)
841 end
842
843 table_insert(rows, {"", "", "", "", "", "", "", ""})
844 table_insert(rows, total_row)
845
846 local tbl_result = table_gen(rows, headings, {style="Unicode (Single Line)"})
847 client_log("Locations loaded:")
848 for s in tbl_result:gmatch("[^\r\n]+") do
849 client_color_log(210, 210, 210, s)
850 end
851 end)
852
853 ui.new_button("LUA", "B", "Clear dynamic data", function()
854 if data_map ~= nil then
855 for i=1, #data_map do
856 data_map[i].landX = nil
857 data_map[i].landY = nil
858 data_map[i].landZ = nil
859 data_map[i].flyDuration = nil
860 end
861 end
862 end)
863
864 ui.new_button("LUA", "B", "Create missing dynamic data", function()
865 if data_map ~= nil then
866 helper_recreate_dynamic.active = true
867 end
868 end)
869end
870
871local function get_mapname()
872 local mapname = globals_mapname()
873 if map_aliases[mapname] ~= nil then
874 mapname = map_aliases[mapname]
875 end
876
877 if data_all ~= nil and data_all[mapname] == nil then
878 for pattern, replacement in pairs(map_patterns) do
879 local mapname_temp = mapname:gsub(pattern, replacement)
880 if data_all[mapname_temp] ~= nil then
881 mapname = mapname_temp
882 break
883 end
884 end
885 end
886
887 return mapname
888end
889
890local movement_saving_hotkey_prev, movement_play_location, movement_play_prev, movement_play_index, movement_play_frame_progress
891local saving_location, grenade_thrown_at, grenade_entindex
892local function on_saving_teleport()
893 if saving_location ~= nil then
894 client_exec("setpos_exact ", saving_location.x, " ", saving_location.y, " ", saving_location.z, "; setang ", saving_location.pitch, " ", saving_location.yaw, " 0")
895 end
896end
897local saving_teleport_reference = ui.new_button("LUA", "B", " Teleport to current location ", on_saving_teleport)
898
899local function on_saving_export(c)
900 local props_saved = {"map", "from", "to", "type", "weapon", "tickrate", "x", "y", "z", "pitch", "yaw", "throwType", "throwStrength", "viewAnglesDistanceMax", "runDuration", "runYaw", "duck", "flyDuration", "landX", "landY", "landZ", "data"}
901 local location_export = ordered_table({})
902 if saving_location ~= nil then
903 for i=1, #props_saved do
904 if saving_location[props_saved[i]] ~= nil then
905 location_export[props_saved[i]] = saving_location[props_saved[i]]
906 end
907 end
908 if location_export.tickrate == "" then
909 location_export.tickrate = nil
910 end
911 if not location_export.duck then
912 location_export.duck = nil
913 end
914 if location_export.throwStrength == 1 then
915 location_export.throwStrength = nil
916 end
917 if location_export.viewAnglesDistanceMax == 0.22 then
918 location_export.viewAnglesDistanceMax = nil
919 end
920 if location_export.runDuration == 20 then
921 location_export.runDuration = nil
922 end
923 if location_export.runYaw == 0 then
924 location_export.runYaw = nil
925 end
926
927 local json_str = json_encode_pretty(location_export, "\n", " ")
928 if location_export.data ~= nil then
929 local data_escaped = json_encode_pretty({location_export.data}, "", "", ""):sub(2, -2)
930 local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
931
932 json_str = json_str:gsub((data_escaped:gsub(quotepattern, "%%%1")), location_export.data)
933 end
934 if ui.name(c) == " Save " then
935 --Append file
936 local mydata = readfile('mydata.json')
937 writefile('mydata.json', mydata ~= nil and (string.sub(mydata, 1, -2)..","..json_str..']') or '['..json_str..']')
938 client_log("Saved spot to mydata.json")
939 package_loaded["helper_data"] = nil
940 local new_data_all, new_data_loaded_at = get((require("helper_data")))
941 data_all, data_loaded_at = new_data_all, new_data_loaded_at
942 reload_data = true
943 client_log("Helper spots were reloaded")
944 package_loaded["helper_data"] = nil
945 else
946 client_log("Export Message:\n", json_str)
947 end
948 end
949end
950
951local saving_update_file_reference = ui.new_button("LUA", "B", " Save ", on_saving_export)
952local saving_import_reference = ui.new_button("LUA", "B", " Import ", function()
953 local clipboard_text_length = get_clipboard_text_count( VGUI_System )
954 if clipboard_text_length > 0 then
955 local buffer = ffi.new("char[?]", clipboard_text_length)
956 local size = clipboard_text_length * ffi.sizeof("char[?]", clipboard_text_length)
957 get_clipboard_text( VGUI_System, 0, buffer, size )
958 local clipboard_data = ffi.string( buffer, clipboard_text_length-1 )
959 local ifSucc, ret = pcall(json.decode, '['..clipboard_data..']')
960 if ifSucc then
961 local mydata = readfile('mydata.json')
962 writefile('mydata.json', mydata ~= nil and (string.sub(mydata, 1, -2)..","..clipboard_data..']') or '['..clipboard_data..']')
963 end
964 end
965end)
966local saving_export_reference = ui.new_button("LUA", "B", " Export ", on_saving_export)
967local function on_saving_properties_changed(reference)
968 local saving_properties = ui_get(saving_properties_reference)
969 if reference ~= nil then
970 local saving_enabled = ui_get(saving_enabled_reference)
971 ui_set_visible(saving_run_duration_reference, saving_enabled and table_contains(saving_properties, "Run"))
972 ui_set_visible(saving_run_direction_reference, saving_enabled and table_contains(saving_properties, "Run"))
973 end
974end
975ui.set_callback(saving_properties_reference, on_saving_properties_changed)
976ui.set_callback(saving_run_duration_reference, on_saving_properties_changed)
977
978local console_input_registered = false
979local function on_saving_console_input(text)
980 if not ui_get(saving_enabled_reference) then
981 return
982 end
983
984 if text == "helper_debug" or text == "helper_debug " then
985 helper_debug = true
986 client_log("Helper debug: on")
987 setup_debug()
988 return true
989 elseif text:sub(1, 14) == "helper_search " then
990 local search_str = text:sub(15, -1):lower()
991 local eyepos = vector3(client.eye_position())
992 print("Locations matching \"", search_str, "\":")
993 for i=1, #data_weapon do
994 local location = data_weapon[i]
995 if location.name:lower():match(search_str) then
996 print("- ", location.from, " to ", location.to, " (", location.id, ", ", string_format("dist: %.1d", location.pos:dist_to(eyepos)), ")")
997 end
998 end
999 return true
1000 elseif text:sub(1, 16) == "helper_teleport " then
1001 local search_str = text:sub(17, -1):lower():gsub(" ", "")
1002 for i=1, #data_weapon do
1003 local location = data_weapon[i]
1004 if location.id:lower() == search_str then
1005 print("Teleported to ", location.name, " (", location.id, ")")
1006 client.exec("setpos ", location.x, " ", location.y, " ", location.z, "; setang ", location.pitch, " ", location.yaw)
1007 return true
1008 end
1009 end
1010 print("Location \"", search_str, "\" not found.")
1011 return true
1012 end
1013end
1014
1015function on_saving_enabled_changed()
1016 reload_data = true
1017 local saving_enabled = ui_get(enabled_reference) and ui_get(saving_enabled_reference)
1018 ui_set_visible(saving_hotkey_reference, saving_enabled)
1019 ui_set_visible(saving_from_reference, saving_enabled)
1020 ui_set_visible(saving_to_reference, saving_enabled)
1021 ui_set_visible(saving_type_reference, saving_enabled)
1022 ui_set_visible(saving_properties_reference, saving_enabled)
1023 ui_set_visible(saving_teleport_reference, saving_enabled)
1024 ui_set_visible(saving_update_file_reference, saving_enabled)
1025 ui_set_visible(saving_import_reference, saving_enabled)
1026 ui_set_visible(saving_export_reference, saving_enabled)
1027 if not saving_enabled then
1028 saving_location = nil
1029 end
1030 ui_set(saving_properties_reference, {})
1031 ui_set(saving_run_duration_reference, 20)
1032 ui_set(saving_run_direction_reference, "Forward")
1033 on_saving_properties_changed(saving_properties_reference)
1034
1035 if saving_enabled and not console_input_registered then
1036 client_set_event_callback("console_input", on_saving_console_input)
1037 console_input_registered = true
1038 end
1039end
1040ui.set_callback(saving_enabled_reference, on_saving_enabled_changed)
1041on_saving_enabled_changed()
1042
1043local function on_run_command(e)
1044 local local_player = entity_get_local_player()
1045 local weapon = console_names[entity_get_classname(entity_get_player_weapon(local_player))]
1046
1047 if ui_get(saving_enabled_reference) then
1048 if e.command_number % 32 == 0 then
1049 package_loaded["helper_data"] = nil
1050 local new_data_all, new_data_loaded_at = get((require("helper_data")))
1051 if new_data_loaded_at ~= data_loaded_at then
1052 data_all, data_loaded_at = new_data_all, new_data_loaded_at
1053 reload_data = true
1054 client_log("Helper spots were reloaded")
1055 end
1056 package_loaded["helper_data"] = nil
1057 end
1058 end
1059
1060 if weapon ~= weapon_prev or reload_data then
1061 if weapon ~= weapon_prev then
1062 last_weapon_switch = globals_realtime()
1063 end
1064 weapon_prev = weapon
1065 reload_data = nil
1066 data_weapon = {}
1067
1068 local offset_z = 20
1069 local player_radius = 16
1070 local accurate_move_offset_table_start = {
1071 vector3(player_radius*0.7, 0, offset_z),
1072 vector3(-player_radius*0.7, 0, offset_z),
1073 vector3(0, player_radius*0.7, offset_z),
1074 vector3(0, -player_radius*0.7, offset_z),
1075 }
1076 local accurate_move_offset_table_end = {
1077 vector3(player_radius*2, 0, 0),
1078 vector3(0, player_radius*2, 0),
1079 vector3(-player_radius*2, 0, 0),
1080 vector3(0, -player_radius*2, 0),
1081 }
1082 local inaccurate_check_offset_table = {
1083 vector3(0, 0, 0),
1084 vector3(8, 0, 0),
1085 vector3(-8, 0, 0),
1086 vector3(0, 8, 0),
1087 vector3(0, -8, 0),
1088 }
1089 local inaccurate_check_top, inaccurate_check_bottom = vector3(0, 0, 6), -vector3(0, 0, 6)
1090
1091 if weapon ~= nil and ui_get(enabled_reference) then
1092 local types = ui_get(types_reference)
1093
1094 if #types > 0 then
1095 local mapname = get_mapname()
1096 data_map = data_all[mapname]
1097
1098 if data_map ~= nil then
1099 local saving_enabled = ui_get(saving_enabled_reference)
1100 local types_enabled = {}
1101 local position_cache = {}
1102 for i=1, #types do
1103 local type_enabled = names_to_type[types[i]]
1104 if type_enabled ~= "grenade" or table_contains(types, console_names_to_name[weapon]) then
1105 table_insert(types_enabled, type_enabled)
1106 end
1107 end
1108
1109 local tickrate = 1/globals_tickinterval()
1110 for i=1, #data_map do
1111 local location = data_map[i]
1112 if (weapon == location.weapon or (weapon == "weapon_wallbang" and location.weapon == "weapon_wallbang_light")) and table_contains(types_enabled, location.type) and (location.tickrate == nil or location.tickrate == tickrate or true) and (not location.temporary or saving_enabled) then
1113 if location.name == nil then
1114 local shorten_name, show_source = true, false
1115 location.name = shorten_name and split_localize(location.to) or (split_localize(location.from) .. " to " .. split_localize(location.to))
1116 end
1117
1118 if location.runDuration == nil then
1119 location.runDuration = 20
1120 end
1121 if location.duck == nil then
1122 location.duck = false
1123 end
1124 if location.throwStrength == nil then
1125 location.throwStrength = 1
1126 end
1127 if location.viewAnglesDistanceMax == nil then
1128 location.viewAnglesDistanceMax = 0.12
1129 end
1130 if location.runYaw == nil then
1131 location.runYaw = 0
1132 end
1133 if location.flyDuration ~= nil and location.runDuration ~= nil and (location.type == "RUN" or location.type == "RUNJUMP") then
1134 -- location.flyDuration = location.flyDuration + location.runDuration
1135 end
1136
1137 if location.pos_inaccurate == 1 then
1138 location.pos = nil
1139 end
1140
1141 if location.pos == nil then
1142 local id = table_concat({location.x, location.y, location.z}, " ")
1143 if position_cache[id] == nil then
1144 local pos = vector3(location.x, location.y, location.z)
1145 for id2, pos2 in pairs(position_cache) do
1146 if pos2:dist_to(pos) < 1 then
1147 id = id2
1148 end
1149 end
1150
1151 if position_cache[id] == nil then
1152 -- bad position
1153 if location.pos_inaccurate == nil then
1154 local min = 1
1155 for i=1, #inaccurate_check_offset_table do
1156 local frac = (pos+inaccurate_check_offset_table[i]+inaccurate_check_top):trace_line(pos+inaccurate_check_offset_table[i]+inaccurate_check_bottom, local_player)
1157 min = math_min(min, frac)
1158 end
1159
1160 if min == 1 then
1161 -- client.log("position of ", location.id, " inaccurate, waiting for pos with same x y")
1162
1163 -- pos:draw_debug_text(0, 25, 255, 255, 255, 255, min)
1164 location.pos_inaccurate = 1
1165 local pos_new = pos - vector3(0, 0, 16)
1166 local frac = (pos_new-vector3(0, 0, -1)):trace_line(pos_new+vector3(0, 0, -1), local_player)
1167 if frac > 0.4 and frac < 0.6 then
1168 pos = pos_new
1169 end
1170 location.pos = pos
1171 reload_data = true
1172 else
1173 -- good position, cache it
1174 position_cache[id] = pos
1175 end
1176 elseif location.pos_inaccurate == 1 then
1177 -- client.log("checking for accurate position of ", location.id)
1178 location.pos = vector3(location.x, location.y, location.z)
1179 location.pos_inaccurate = 2
1180
1181 for i=1, #data_weapon do
1182 local pos2 = data_weapon[i].pos
1183 if pos2 ~= location.pos and pos2:dist_to_2d(location.pos) < 1 and pos2:dist_to(location.pos) < 50 then
1184 -- client.log(pos2:dist_to(location.pos))
1185 location.pos = pos2
1186 location.pos_inaccurate = nil
1187 -- client.log("found accurate position for", location.id, ".")
1188 break
1189 end
1190 end
1191
1192 if location.pos_inaccurate == 2 then
1193 local frac, entindex_hit, pos_hit = (pos+vector3(0, 0, 32)):trace_line(pos-vector3(0, 0, 32), local_player)
1194 if frac ~= 1 then
1195 -- client.log("found no accurate position for ", location.id, ", guessing")
1196 location.pos = pos_hit
1197 location.pos.inaccurate = true
1198 location.pos.accurate_move = false
1199
1200 end
1201 location.pos_inaccurate = nil
1202 end
1203 end
1204 end
1205 end
1206 location.pos = position_cache[id] or location.pos
1207 end
1208 if location.fwd == nil then
1209 if location.pitch == nil or location.yaw == nil and helper_debug then
1210 client.error_log("Invalid location, pitch or yaw missing: ", location.id)
1211 end
1212 location.fwd = vector3.angle_forward(vector3(location.pitch or 0, location.yaw or 0, 0))
1213 location.view_offset = location.duck and 46 or 64
1214
1215 -- determine target in world
1216 local eye_pos = location.pos + vector3(0, 0, location.view_offset)
1217 location.eye_pos = eye_pos
1218 local target = eye_pos+(location.fwd*2048)
1219 local fraction, entindex_hit, target_hit = eye_pos:trace_line(target, local_player)
1220 location.target = target_hit
1221 end
1222 if location.viewangles == nil then
1223 location.viewangles = vector2(location.pitch, location.yaw)
1224 end
1225 if location.data_parsed == nil and location.data ~= nil then
1226 local recording_compressed = location.data
1227 local frames = {}
1228
1229 -- set up stuff
1230 local real = {
1231 pitch = location.pitch,
1232 yaw = location.yaw
1233 }
1234 for key, char in pairs(movement_buttons_chars) do
1235 real[key] = 0
1236 end
1237
1238 local recording_compressed_new = {}
1239 for i=1, #recording_compressed do
1240 if type(recording_compressed[i]) == "number" then
1241 for i=1, recording_compressed[i] do
1242 table.insert(recording_compressed_new, {})
1243 end
1244 else
1245 table.insert(recording_compressed_new, recording_compressed[i])
1246 end
1247 end
1248
1249 for i=1, #recording_compressed_new do
1250 local frame_compressed = recording_compressed_new[i]
1251 real.pitch = real.pitch + (frame_compressed[1] or 0)
1252 real.yaw = real.yaw + (frame_compressed[2] or 0)
1253
1254 if frame_compressed[3] ~= nil then
1255 local keys_down = {}
1256 for char in frame_compressed[3]:gmatch(".") do
1257 keys_down[char] = true
1258 end
1259
1260 for key, char in pairs(movement_buttons_chars) do
1261 if keys_down[char] then
1262 real[key] = 1
1263 end
1264 end
1265
1266 if frame_compressed[4] ~= nil then
1267 local keys_up = {}
1268 for char in frame_compressed[4]:gmatch(".") do
1269 keys_up[char] = true
1270 end
1271
1272 for key, char in pairs(movement_buttons_chars) do
1273 if keys_up[char] then
1274 real[key] = 0
1275 end
1276 end
1277 end
1278 end
1279
1280 real.forwardmove = real["in_forward"] == 1 and 450 or (real["in_back"] == 1 and -450 or 0)
1281 if frame_compressed[5] ~= nil then
1282 real.forwardmove = frame_compressed[5]
1283 end
1284
1285 real.sidemove = real["in_moveright"] == 1 and 450 or (real["in_moveleft"] == 1 and -450 or 0)
1286 if frame_compressed[6] ~= nil then
1287 real.sidemove = frame_compressed[6]
1288 end
1289
1290 local frame = {}
1291 for key, value in pairs(real) do
1292 frame[key] = value
1293 end
1294
1295 table.insert(frames, frame)
1296 end
1297 location.data_parsed = frames
1298 end
1299
1300 if location.destroyX ~= nil and location.destroyY ~= nil and location.destroyZ ~= nil then
1301 if location.destroyText == nil then
1302 location.destroyText = "Break the Glass"
1303 end
1304 local destroy = vector3(location.destroyX, location.destroyY, location.destroyZ)
1305
1306 if location.destroyStartX ~= nil and location.destroyStartY ~= nil and location.destroyStartZ ~= nil then
1307 location.destroy_start = vector3(location.destroyStartX, location.destroyStartY, location.destroyStartZ)
1308 else
1309 location.destroy_start = location.eye_pos
1310 end
1311
1312 local delta = destroy - location.destroy_start
1313 local destroy_new = location.destroy_start + delta*1.2
1314
1315 location.destroy = destroy_new
1316 end
1317 if location.land == nil and location.landX ~= nil then
1318 location.land = vector3(location.landX, location.landY, location.landZ)
1319 end
1320
1321 if location.pos.accurate_move == nil and location.accurateMove ~= nil then
1322 location.pos.accurate_move = location.accurateMove
1323 end
1324 if location.pos.visibility_location == nil then
1325 location.pos.visibility_location = location.pos+vector3(location.visX or 0, location.visY or 0, location.visZ or 40)
1326 -- location.pos.visibility_location:draw_debug_text(0, 5, 255, 255, 255, 100, "HI")
1327 end
1328 if location.pos.accurate_move == nil then
1329 local count_accurate_move = 0
1330
1331 -- go through all directions
1332 for i=1, #accurate_move_offset_table_end do
1333 if count_accurate_move > 1 then
1334 break
1335 end
1336
1337 -- set offset added to start for this direction
1338 local end_offset = accurate_move_offset_table_end[i]
1339
1340 -- loop through all start points
1341 for i=1, #accurate_move_offset_table_start do
1342 local start = location.pos + accurate_move_offset_table_start[i]
1343 -- client.draw_debug_text(start.x, start.y, start.z, 0, 5, 255, 255, 255, 255, "S", i)
1344
1345 local fraction, entindex_hit = start:trace_line(start + end_offset, entity_get_local_player())
1346 local end_pos = start + end_offset
1347 -- client.draw_debug_text(end_pos.x, end_pos.y, end_pos.z, 0, 5, 255, 255, 255, 255, "E", i)
1348
1349 if entindex_hit == 0 and fraction > 0.45 and fraction < 0.7 then
1350 count_accurate_move = count_accurate_move + 1
1351 -- client.draw_debug_text(end_pos.x, end_pos.y, end_pos.z, 1, 5, 0, 255, 0, 100, "HIT ", fraction)
1352 break
1353 end
1354 end
1355 end
1356
1357 -- client.draw_debug_text(location.pos.x, location.pos.y, location.pos.z, 0, 5, 255, 255, 255, 255, "hit ", count_accurate_move, " times")
1358 location.pos.accurate_move = count_accurate_move > 1
1359 end
1360 table_insert(data_weapon, location)
1361 end
1362 end
1363 end
1364 end
1365 end
1366 end
1367
1368 if not e.from_paint and movement_saving_hotkey_prev and saving_location ~= nil and saving_location.data_parsed ~= nil then
1369 local buttons_indices = {
1370 ["in_attack"] = 1,
1371 ["in_jump"] = 2,
1372 ["in_duck"] = 4,
1373 ["in_forward"] = 8,
1374 ["in_back"] = 16,
1375 ["in_use"] = 32,
1376 ["in_moveleft"] = 512,
1377 ["in_moveright"] = 1024,
1378 ["in_attack2"] = 2048,
1379 ["in_speed"] = 131072
1380 }
1381
1382 for i=1, #saving_location.data_parsed-1 do
1383 local frame = saving_location.data_parsed[i]
1384 if not frame.did_run then
1385 frame.did_run = true
1386
1387 local local_player = entity.get_local_player()
1388 local buttons = entity.get_prop(local_player, "m_nButtons")
1389
1390 for key, value in pairs(frame) do
1391 if buttons_indices[key] ~= nil then
1392 local value_btns = bit.band(buttons, buttons_indices[key]) == buttons_indices[key]
1393 local value_sc = value ~= 0
1394 if value_btns ~= value_sc then
1395 -- client.log(key, " differs: ", value_sc, " -> ", value_btns)
1396 frame[key] = value_btns and 1 or 0
1397 end
1398 end
1399 end
1400
1401 break
1402 end
1403 end
1404 end
1405end
1406client.set_event_callback("run_command", on_run_command)
1407
1408local function is_grenade_being_thrown(weapon, cmd)
1409 local pin_pulled = entity_get_prop(weapon, "m_bPinPulled")
1410 if pin_pulled ~= nil then
1411 if pin_pulled == 0 or cmd.in_attack == 1 or cmd.in_attack2 == 1 then
1412 local throw_time = entity_get_prop(weapon, "m_fThrowTime")
1413 if throw_time ~= nil and throw_time > 0 and throw_time < globals_curtime() then
1414 return true
1415 end
1416 end
1417 end
1418 return false
1419end
1420
1421local function grenade_apply_movement(cmd, active_move_location)
1422 if active_move_location.type == "grenade" then
1423 cmd["in_forward"] = 0
1424 cmd["in_back"] = 0
1425 cmd["in_moveleft"] = 0
1426 cmd["in_moveright"] = 0
1427
1428 cmd["forwardmove"] = 0
1429 cmd["sidemove"] = 0
1430
1431 cmd["in_jump"] = 0
1432 cmd["in_speed"] = 0
1433
1434 if (active_move_location.throwType == "RUN" or active_move_location.throwType == "RUNJUMP") then
1435 cmd["in_forward"] = 1
1436 cmd["forwardmove"] = 450
1437 end
1438
1439 cmd.move_yaw = active_move_location.yaw + (active_move_location.runYaw or 0)
1440 end
1441 cmd.in_duck = active_move_location.duck and 1 or 0
1442end
1443
1444local locations_on, location_targeted, position_closest
1445local active_move, active_move_start, active_move_location, airstrafe_disabled, quick_peek_assist_disabled, active_move_weapon
1446local saving_hotkey_prev = false
1447local has_to_release_hotkey = false
1448
1449local function on_setup_command(cmd)
1450 if not ui_get(enabled_reference) then
1451 return
1452 end
1453
1454 local types = ui_get(types_reference)
1455 if #types == 0 then
1456 return
1457 end
1458
1459 local local_player = entity_get_local_player()
1460 local weapon = entity_get_player_weapon(local_player)
1461 if weapon == nil then
1462 return
1463 end
1464
1465 local tickrate = 1/globals_tickinterval()
1466 local tickrate_mp = tickrate/64
1467
1468 local movement_setup_command_values = {"pitch", "yaw", "forwardmove", "sidemove", "in_forward", "in_back", "in_moveleft", "in_moveright", "in_jump", "in_duck", "in_speed", "in_attack", "in_attack2", "in_use"}
1469
1470 local set_forwardmove = false
1471 local hotkey, hotkey_mode = ui_get(hotkey_reference)
1472 if hotkey or helper_recreate_dynamic.active then
1473 local silent_enabled = ui_get(silent_enabled_reference) ~= "Legit (Smooth)" or helper_recreate_dynamic.active
1474
1475 if helper_recreate_dynamic.active and helper_recreate_dynamic.location == nil then
1476 if active_move == nil then
1477 for i=1, #data_map do
1478 local location = data_map[i]
1479 if location.landX == nil and not location.dynamic_skip and location.type == "grenade" then
1480 client_log("[", i, "/", #data_map, "] Creating dynamic data for ", location.id, " / ", location.name)
1481 helper_recreate_dynamic.location = location
1482 local command = "setpos_exact " .. location.x .. " " .. location.y .. " " .. location.z .. "; setang " .. location.pitch .. " " .. location.yaw .. " " .. 0
1483 client_exec("use ", location.weapon)
1484 client_exec(command)
1485 client_delay_call(0.1, function()
1486 client_exec(command)
1487 client_exec("use ", location.weapon)
1488 client_delay_call(0.15, function()
1489 client_exec("noclip off")
1490 client_exec("use ", location.weapon)
1491 location_targeted = location
1492 helper_recreate_dynamic.thrown = false
1493
1494 client_delay_call(2, function()
1495 if helper_recreate_dynamic.location == location and helper_recreate_dynamic.thrown == false and active_move == nil then
1496 client_log("[", i, "/", #data_map, "] Timed out. Skipping")
1497 client_exec("use weapon_knife")
1498 location.dynamic_skip = true
1499 helper_recreate_dynamic.location = nil
1500 end
1501 end)
1502 end)
1503 end)
1504 break
1505 end
1506 end
1507 if helper_recreate_dynamic.location == nil then
1508 client_log("Done creating dynamic data")
1509 local out = ordered_table({
1510 "format", 2,
1511 "helper_spots", {}
1512 })
1513 for i=1, #data_weapon do
1514 local location = data_weapon[i]
1515 location.dynamic_skip = false
1516 if location.id ~= nil and location.landX ~= nil then
1517 table_insert(out, ordered_table({
1518 "id", location.id,
1519 "landX", location.landX,
1520 "landY", location.landY,
1521 "landZ", location.landZ,
1522 "flyDuration", location.flyDuration,
1523 }))
1524 end
1525 end
1526
1527 local out_json = json_encode_pretty(out, "\n", " ")
1528 for s in out_json:gmatch("[^\r\n]+") do
1529 client_color_log(210, 210, 210, s)
1530 end
1531
1532 helper_recreate_dynamic = {
1533 active=false
1534 }
1535 end
1536 end
1537 end
1538
1539 if helper_recreate_dynamic.active and helper_recreate_dynamic.location ~= nil and helper_recreate_dynamic.thrown == false and active_move == nil then
1540 cmd.in_attack = 1
1541 if helper_recreate_dynamic.location.duck then
1542 cmd.in_duck = 1
1543 end
1544 end
1545
1546 if (location_targeted ~= nil and location_targeted.type == "grenade") or (active_move ~= nil and active_move_location ~= nil) then
1547 if silent_enabled or (active_move ~= nil and active_move_location ~= nil) or vector2(client_camera_angles()):dist_to(vector2(location_targeted.pitch, location_targeted.yaw)) <= location_targeted.viewAnglesDistanceMax then
1548 -- aiming at the location and pin pulled
1549 if active_move == nil then
1550 local speed = vector3(entity_get_prop(local_player, "m_vecVelocity")):length()
1551 if (cmd.in_attack == 1 or cmd.in_attack2 == 1) and entity_get_prop(weapon, "m_bPinPulled") == 1 and speed < 2 then
1552 if entity_get_prop(local_player, "m_flDuckAmount") == (location_targeted.duck and 1 or 0) then
1553 if location_targeted.targeted then
1554 local throw_strength = entity_get_prop(weapon, "m_flThrowStrength")
1555 if throw_strength == location_targeted.throwStrength then
1556 active_move = MOVE_PREPARE
1557 active_move_weapon = weapon
1558 active_move_start = cmd.command_number
1559 active_move_location = location_targeted
1560 else
1561 if location_targeted.throwStrength == 1 then
1562 cmd.in_attack = 1
1563 cmd.in_attack2 = 0
1564 elseif location_targeted.throwStrength == 0.5 then
1565 cmd.in_attack = 1
1566 cmd.in_attack2 = 1
1567 elseif location_targeted.throwStrength == 0 then
1568 cmd.in_attack = 0
1569 cmd.in_attack2 = 1
1570 end
1571 end
1572 end
1573 end
1574 end
1575 end
1576 if active_move ~= nil and active_move_weapon ~= weapon then
1577 active_move = nil
1578 end
1579 if active_move == MOVE_PREPARE or active_move == MOVE_THROW then
1580 if not silent_enabled then
1581 cvar_sensitivity:set_raw_float(0)
1582 end
1583 if active_move_location.throwType == "RUN" or active_move_location.throwType == "RUNJUMP" then
1584 local step = math.floor((cmd.command_number-active_move_start) / tickrate_mp)
1585
1586 if active_move_location.runDuration > step or active_move == MOVE_THROW then
1587 grenade_apply_movement(cmd, active_move_location)
1588 elseif active_move == MOVE_PREPARE then
1589 active_move = MOVE_THROW
1590 end
1591 else
1592 active_move = MOVE_THROW
1593 end
1594 end
1595
1596 if active_move == MOVE_PREPARE then
1597 if active_move_location.throwStrength == 1 then
1598 cmd.in_attack = 1
1599 cmd.in_attack2 = 0
1600 elseif active_move_location.throwStrength == 0.5 then
1601 cmd.in_attack = 1
1602 cmd.in_attack2 = 1
1603 elseif active_move_location.throwStrength == 0 then
1604 cmd.in_attack = 0
1605 cmd.in_attack2 = 1
1606 end
1607 end
1608
1609 if active_move == MOVE_THROW then
1610 local throw_type = active_move_location.throwType
1611 cmd.in_attack = 0
1612 cmd.in_attack2 = 0
1613
1614 grenade_apply_movement(cmd, active_move_location)
1615 if throw_type == "JUMP" or throw_type == "RUNJUMP" then
1616 cmd.in_jump = 1
1617 end
1618 active_move = MOVE_DONE
1619
1620 if not silent_enabled then
1621 client_delay_call(0.2, function()
1622 reset_cvar(cvar_sensitivity)
1623 end)
1624 end
1625 if ui_get(airstrafe_reference) then
1626 airstrafe_disabled = true
1627 ui_set(airstrafe_reference, false)
1628 end
1629
1630 if helper_recreate_dynamic.active then
1631 helper_recreate_dynamic.thrown = true
1632 end
1633
1634 client_delay_call(0.8, function()
1635 active_move = nil
1636 active_move_location = nil
1637 has_to_release_hotkey = false
1638
1639 if airstrafe_disabled then
1640 airstrafe_disabled = nil
1641 ui_set(airstrafe_reference, true)
1642 end
1643 end)
1644 has_to_release_hotkey = true
1645 elseif active_move == MOVE_DONE then
1646 cmd.in_attack = 0
1647 cmd.in_attack2 = 0
1648 if ui_get(airstrafe_reference) then
1649 airstrafe_disabled = true
1650 ui_set(airstrafe_reference, false)
1651 end
1652
1653 grenade_apply_movement(cmd, active_move_location)
1654
1655 if is_grenade_being_thrown(weapon, cmd) then
1656 if silent_enabled then
1657 cmd.pitch = active_move_location.pitch
1658 cmd.yaw = active_move_location.yaw
1659 cmd.allow_send_packet = false
1660 end
1661 active_move = nil
1662 end
1663 end
1664 end
1665 if (cmd.in_attack == 1 or cmd.in_attack2 == 1) and location_targeted ~= nil and location_targeted.type == "grenade" then
1666 cmd.in_duck = location_targeted.duck and 1 or 0
1667 end
1668 elseif movement_play_location ~= nil and (cmd.in_forward == 1 or cmd.in_back == 1 or cmd.in_moveleft == 1 or cmd.in_moveright == 1 or true) then
1669 if ui_get(airstrafe_reference) then
1670 airstrafe_disabled = true
1671 ui_set(airstrafe_reference, false)
1672 end
1673
1674 movement_play_frame_progress = 0
1675 if movement_play_location.data_parsed[math.floor(movement_play_index)] ~= nil then
1676 local frame = movement_play_location.data_parsed[math.floor(movement_play_index)]
1677 client_camera_angles(frame.pitch, frame.yaw)
1678
1679 for i=1, #movement_setup_command_values do
1680 local name = movement_setup_command_values[i]
1681 local value = frame[name]
1682 if value == 1 or (name ~= "in_attack" and name ~= "in_attack2") then
1683 cmd[name] = value
1684 end
1685 end
1686 cmd.move_yaw = cmd.yaw
1687
1688 movement_play_index = movement_play_index + 1/tickrate_mp
1689 elseif movement_play_index ~= nil then
1690 -- client.log("playback finished after ", #movement_play_location.data_parsed, " frames")
1691 movement_play_index = nil
1692 movement_play_location = nil
1693 end
1694 movement_play_prev = true
1695 elseif location_targeted ~= nil then
1696 if location_targeted.type == "movement" and location_targeted.data_parsed ~= nil and vector2(client_camera_angles()):dist_to(vector2(location_targeted.pitch, location_targeted.yaw)) <= location_targeted.viewAnglesDistanceMax then
1697 movement_play_location = location_targeted
1698 movement_play_prev = false
1699 movement_play_index = 1
1700
1701 client_delay_call((#location_targeted.data_parsed)*(1/64)+0.2, function()
1702 if airstrafe_disabled then
1703 airstrafe_disabled = false
1704 ui_set(airstrafe_reference, true)
1705 end
1706 end)
1707 end
1708 elseif not has_to_release_hotkey then
1709 -- move to closest location
1710 if cmd.forwardmove == 0 and cmd.sidemove == 0 and cmd.in_forward == 0 and cmd.in_back == 0 and cmd.in_moveleft == 0 and cmd.in_moveright == 0 then
1711 if position_closest ~= nil then
1712 local origin = vector3(entity_get_prop(local_player, "m_vecAbsOrigin"))
1713 local distance, distance_2d = origin:dist_to(position_closest), origin:dist_to_2d(position_closest)
1714 if (distance_2d < 0.08 and distance > 0.08 and distance < 4) or (position_closest.inaccurate and distance < 40) then
1715 distance = distance_2d
1716 end
1717 if distance < 32 and distance > 0.08 then
1718 local yaw = origin:vector_angles(position_closest).y
1719 cmd.move_yaw = yaw
1720 if position_closest.accurate_move then
1721 cmd.forwardmove = 450
1722 else
1723 if distance > 10 then
1724 cmd.forwardmove = 450
1725 else
1726 cmd.forwardmove = math_min(450, math_max(1.01, distance * 6))
1727 end
1728 set_forwardmove = true
1729 end
1730
1731 cmd.in_forward = 1
1732 -- cmd.in_speed = 1
1733 end
1734 end
1735 end
1736 end
1737 else
1738 active_move = nil
1739 active_move_location = nil
1740 has_to_release_hotkey = false
1741 movement_play_location = nil
1742
1743
1744 if airstrafe_disabled then
1745 airstrafe_disabled = false
1746 ui_set(airstrafe_reference, true)
1747 end
1748 end
1749 if set_forwardmove then
1750 if ui_get(quick_peek_assist_reference) then
1751 quick_peek_assist_disabled = true
1752 ui_set(quick_peek_assist_reference, false)
1753 end
1754 elseif quick_peek_assist_disabled then
1755 ui_set(quick_peek_assist_reference, true)
1756 quick_peek_assist_disabled = false
1757 end
1758 location_targeted = nil
1759
1760 if ui_get(saving_enabled_reference) and ui_get(saving_hotkey_reference) and names_to_type[ui_get(saving_type_reference)] == "movement" and saving_location ~= nil then
1761 -- initialize data if first frame
1762 if not movement_saving_hotkey_prev then
1763 saving_location.data_parsed = {}
1764 end
1765
1766 local frame = {}
1767 for i=1, #movement_setup_command_values do
1768 frame[movement_setup_command_values[i]] = cmd[movement_setup_command_values[i]]
1769 end
1770 table_insert(saving_location.data_parsed, frame)
1771
1772 -- only start recording if something changes
1773 movement_saving_hotkey_prev = movement_saving_hotkey_prev or (cmd.forwardmove ~= 0 or cmd.sidemove ~= 0 or cmd.in_duck ~= 0 or cmd.in_jump ~= 0 or cmd.in_attack ~= 0 or cmd.in_attack2 ~= 0)
1774 elseif movement_saving_hotkey_prev then
1775 movement_saving_hotkey_prev = false
1776 -- recording finished
1777
1778 local recording = saving_location.data_parsed
1779 local recording_compressed = {}
1780
1781 local real = {}
1782 for key, char in pairs(movement_buttons_chars) do
1783 real[key] = 0
1784 end
1785 real.pitch = recording[1].pitch
1786 real.yaw = recording[1].yaw
1787
1788 for i=1, #recording do
1789 local frame = recording[i]
1790
1791 -- determine key flags
1792 local keys_down, keys_up = "", ""
1793 for key, char in pairs(movement_buttons_chars) do
1794 if frame[key] == 1 and real[key] == 0 then
1795 keys_down = keys_down .. char
1796 elseif frame[key] == 0 and real[key] == 1 then
1797 keys_up = keys_up .. char
1798 end
1799 real[key] = frame[key]
1800 end
1801
1802 local frame_compressed = {frame.pitch-real.pitch, frame.yaw-real.yaw, keys_down, keys_up, frame.forwardmove, frame.sidemove}
1803
1804 -- check if sidemove is what we expect it to be
1805 if (frame.sidemove == 0 and frame.in_moveright == 0 and frame.in_moveleft == 0)
1806 or (frame.sidemove == 450 and frame.in_moveright == 1 and frame.in_moveleft == 0)
1807 or (frame.sidemove == -450 and frame.in_moveright == 0 and frame.in_moveleft == 1) then
1808 frame_compressed[6] = nil
1809
1810 -- check if forwardmove is what we expect it to be
1811 if (frame.forwardmove == 0 and frame.in_forward == 0 and frame.in_back == 0)
1812 or (frame.forwardmove == 450 and frame.in_forward == 1 and frame.in_back == 0)
1813 or (frame.forwardmove == -450 and frame.in_forward == 0 and frame.in_back == 1) then
1814 frame_compressed[5] = nil
1815
1816 -- check if no key is lifted
1817 if keys_up == "" then
1818 frame_compressed[4] = nil
1819
1820 -- check if no key is pressed
1821 if keys_down == "" then
1822 frame_compressed[3] = nil
1823
1824 -- check if yaw is unchanged
1825 if frame_compressed[2] == 0 then
1826 frame_compressed[2] = nil
1827
1828 -- check if pitch is unchanged
1829 if frame_compressed[1] == 0 then
1830 frame_compressed[1] = nil
1831 end
1832 end
1833 end
1834 end
1835 end
1836 end
1837
1838 table_insert(recording_compressed, frame_compressed)
1839
1840 -- update real pitch and yaw
1841 real.pitch = frame.pitch
1842 real.yaw = frame.yaw
1843 end
1844
1845 local recording_compressed_new = {}
1846
1847 local amt = 0
1848 for i=1, #recording_compressed do
1849 if #recording_compressed[i] == 0 then
1850 amt = amt + 1
1851 else
1852 if amt > 0 then
1853 table.insert(recording_compressed_new, amt)
1854 amt = 0
1855 end
1856 table.insert(recording_compressed_new, recording_compressed[i])
1857 end
1858 end
1859 if amt > 0 then
1860 table.insert(recording_compressed_new, amt)
1861 amt = 0
1862 end
1863
1864 saving_location.pitch = recording[1].pitch
1865 saving_location.yaw = recording[1].yaw
1866
1867 -- json_encode_pretty(dt, [lf = "\n", [id = "\t", [ac = " ", [ec = function]]]])
1868 saving_location.data = json_encode_pretty(recording_compressed_new, "", "", "")
1869 end
1870end
1871client.set_event_callback("setup_command", on_setup_command)
1872
1873local function on_paint_saving(local_player, weapon, screen_width, screen_height, locations_on, on_correct)
1874 local location_type = names_to_type[ui_get(saving_type_reference)]
1875 local create_location = false
1876
1877 local saving_hotkey = ui_get(saving_hotkey_reference)
1878
1879 if saving_hotkey and not saving_hotkey_prev then
1880 if location_type == "grenade" then
1881 if entity_get_prop(weapon, "m_bPinPulled") == 1 or true then
1882 create_location = true
1883 end
1884 elseif location_type ~= "movement" or not movement_saving_hotkey_prev then
1885 create_location = true
1886 end
1887 end
1888
1889 if create_location then
1890 for map, map_spots in pairs(data_all) do
1891 for i=1, #map_spots do
1892 if map_spots[i].temporary then
1893 table_remove(map_spots, i)
1894 break
1895 end
1896 end
1897 end
1898
1899 local weapon_name = console_names[entity_get_classname(entity_get_player_weapon(entity_get_local_player()))]
1900 if weapon_name ~= nil then
1901 local mapname = get_mapname()
1902 saving_location = ordered_table({
1903 "temporary", true,
1904 "map", mapname,
1905 "from", "",
1906 "to", "",
1907 "type", location_type,
1908 "weapon", weapon_name,
1909 "x", "",
1910 "y", "",
1911 "z", "",
1912 "pitch", "",
1913 "yaw", ""
1914 })
1915
1916 saving_location.x, saving_location.y, saving_location.z = entity_get_prop(local_player, "m_vecAbsOrigin")
1917 saving_location.pitch, saving_location.yaw = client_camera_angles()
1918 saving_location.duck = entity_get_prop(local_player, "m_flDuckAmount") > 0 and true or nil
1919
1920 if location_type == "grenade" then
1921 local throw_strength = entity_get_prop(weapon, "m_flThrowStrength")
1922 if throw_strength ~= nil and throw_strength ~= 1 then
1923 saving_location.throwStrength = throw_strength
1924 end
1925 end
1926
1927 if data_all[mapname] == nil then
1928 data_all[mapname] = {}
1929 end
1930
1931 table_insert(data_all[mapname], saving_location)
1932 reload_data = true
1933 end
1934 end
1935
1936
1937 if saving_location ~= nil then
1938 if saving_location.type == "grenade" then
1939 local saving_properties = ui_get(saving_properties_reference)
1940 if table_contains(saving_properties, "Jump") and table_contains(saving_properties, "Run") then
1941 saving_location.throwType = "RUNJUMP"
1942 elseif table_contains(saving_properties, "Jump") then
1943 saving_location.throwType = "JUMP"
1944 elseif table_contains(saving_properties, "Run") then
1945 saving_location.throwType = "RUN"
1946 else
1947 saving_location.throwType = "NORMAL"
1948 end
1949
1950 if table_contains(saving_properties, "Run") then
1951 local run_duration = ui_get(saving_run_duration_reference)
1952 saving_location.runDuration = run_duration
1953 local run_direction = ui_get(saving_run_direction_reference)
1954 saving_location.runYaw = run_direction_yaw[run_direction]
1955 else
1956 saving_location.runDuration = nil
1957 saving_location.runYaw = nil
1958 end
1959
1960 saving_location.tickrate = table_contains(saving_properties, "Tickrate") and 1/globals_tickinterval() or nil
1961 end
1962
1963 local from = ui_get(saving_from_reference)
1964
1965 saving_location.to = ui_get(saving_to_reference)
1966 if saving_location.to == "" then
1967 saving_location.to = "Unnamed"
1968 end
1969 if create_location and on_correct and not locations_on[1].temporary then
1970 saving_location.from = locations_on[1].from
1971 saving_location.pos = locations_on[1].pos
1972 saving_location.x, saving_location.y, saving_location.z = saving_location.pos:unpack()
1973 else
1974 saving_location.from = from
1975 end
1976 if saving_location.from == "" then
1977 saving_location.from = "Unnamed"
1978 end
1979 saving_location.name = saving_location.to
1980 end
1981
1982 saving_hotkey_prev = saving_hotkey
1983
1984 local lines = {}
1985 local from, to = ui_get(saving_from_reference), ui_get(saving_to_reference)
1986 if from == "" or to == "" then
1987 table_insert(lines, {255, 255, 255, 255, "b", "Saving new location"})
1988 if from == "" then
1989 table_insert(lines, {255, 16, 16, 255, "", "Warning: from not set"})
1990 end
1991 if to == "" then
1992 table_insert(lines, {255, 16, 16, 255, "", "Warning: to not set"})
1993 end
1994 else
1995 table_insert(lines, {255, 255, 255, 255, "b", "Saving '", from, "' to '", to, "'"})
1996 end
1997
1998 if grenade_thrown_at ~= nil and saving_location ~= nil and saving_location.type == "grenade" then
1999 table_insert(lines, {27, 162, 248, 255, "", "Grenade flying for ", string_format("%.2fs", globals_curtime()-grenade_thrown_at)})
2000 elseif saving_location ~= nil and saving_location.flyDuration ~= nil then
2001 table_insert(lines, {27, 162, 248, 255, "", "Grenade took ", string_format("%.2fs", saving_location.flyDuration)})
2002 elseif location_type == "movement" then
2003 local saving_cvars = {
2004 {"sv_airaccelerate", "float", 12},
2005 {"sv_enablebunnyhopping", "int", 0},
2006 {"sv_autobunnyhopping", "int", 0},
2007 }
2008
2009 if ui_get(airstrafe_reference) then
2010 table_insert(lines, {255, 16, 16, 255, "", "Warning: Air strafe is enabled"})
2011 end
2012
2013 for i=1, #saving_cvars do
2014 local cvar_name, cvar_type, value_correct = unpack(saving_cvars[i])
2015 local cvar_obj = cvar[cvar_name]
2016
2017 local value
2018 if cvar_type == "float" then
2019 value = cvar_obj:get_float()
2020 elseif cvar_type == "int" then
2021 value = cvar_obj:get_int()
2022 elseif cvar_type == "string" then
2023 value = cvar_obj:get_string()
2024 end
2025
2026 if value ~= nil and value ~= value_correct then
2027 table_insert(lines, {255, 16, 16, 255, "", "Warning: cvar " .. cvar_name .. " is wrong (correct=" .. value_correct .. ")"})
2028 end
2029 end
2030
2031 table_insert(lines, {})
2032
2033 if saving_location ~= nil and saving_location.data_parsed ~= nil then
2034 local tickinterval = globals_tickinterval()
2035 if saving_hotkey then
2036 table_insert(lines, {230, 84, 84, 255, "", "Recording for ", string_format("%.2fs", tickinterval*(#saving_location.data_parsed-1))})
2037 elseif saving_location.data ~= nil then
2038 table_insert(lines, {84, 230, 94, 255, "", "Recorded for ", string_format("%.2fs", tickinterval*(#saving_location.data_parsed))})
2039 end
2040 end
2041 end
2042
2043 if location_type == "grenade" then
2044 local saving_properties = ui_get(saving_properties_reference)
2045 if #saving_properties > 0 then
2046 table_insert(lines, {230, 230, 230, 255, "", "Properties: ", table_concat(saving_properties, ", ")})
2047 end
2048
2049 if table_contains(saving_properties, "Run") then
2050 local run_direction = ui_get(saving_run_direction_reference)
2051 table_insert(lines, {230, 230, 230, 255, "", "Run duration: ", run_direction == "Forward" and "" or " ", ui_get(saving_run_duration_reference), " ticks"})
2052 if run_direction ~= "Forward" then
2053 table_insert(lines, {230, 230, 230, 255, "", "Run direction: ", run_direction})
2054 end
2055 end
2056 end
2057
2058 if #lines[#lines] == 0 then
2059 lines[#lines] = nil
2060 end
2061
2062 local line_width, line_height = {}, {}
2063 for i=1, #lines do
2064 line_width[i], line_height[i] = renderer_measure_text(select(5, unpack(lines[i])))
2065 end
2066 local width = math_max(0, unpack(line_width))
2067
2068 local x = screen_width/2-width/2
2069 local y = 60
2070
2071 --draw background
2072 renderer_rectangle(x-5, y-4, width+10, #lines*10+10, 16, 16, 16, 150)
2073
2074 for i=1, #lines do
2075 table_insert(lines[i], 6, 0)
2076 local flag_offset = i == -1 and (width/2 - line_width[i]/2) or 0
2077
2078 if lines[i][5] == "b" then flag_offset = flag_offset + 1 end
2079 renderer_text(x + flag_offset, y+i*10-10, unpack(lines[i]))
2080 end
2081end
2082
2083local function on_paint()
2084 location_targeted = nil
2085 position_closest = nil
2086 if not ui_get(enabled_reference) then
2087 return
2088 end
2089 local types = ui_get(types_reference)
2090 if #types == 0 then
2091 return
2092 end
2093
2094 local local_player = entity_get_local_player()
2095 local weapon = entity_get_player_weapon(local_player)
2096 if weapon == nil then
2097 return
2098 end
2099
2100 local is_running_commands = not (entity_get_prop(local_player, "m_MoveType") == MOVETYPE_NOCLIP)
2101
2102 if not is_running_commands then
2103 on_run_command({command_number=globals.tickcount(), from_paint=true})
2104 end
2105
2106 if is_running_commands and ui_get(hotkey_reference) and movement_play_index ~= nil and movement_play_location ~= nil and movement_play_index % 1 == 0 then
2107 local recording = movement_play_location.data_parsed
2108 if recording ~= nil and recording[movement_play_index] ~= nil and recording[movement_play_index-1] ~= nil then
2109 local progress = movement_play_frame_progress / globals_tickinterval()
2110 movement_play_frame_progress = movement_play_frame_progress + globals.frametime()
2111
2112 if progress >= 0 and progress <= 1 then
2113 local pitch = lerp(recording[movement_play_index-1].pitch, recording[movement_play_index].pitch, progress)
2114 local yaw = lerp(recording[movement_play_index-1].yaw, recording[movement_play_index].yaw, progress)
2115
2116 client_camera_angles(pitch, yaw)
2117 end
2118 end
2119 end
2120
2121 local dist_max_targets = 20
2122 local full_world_alpha_distance = 200
2123 local flags_world = "c"
2124 local flags_target = ""
2125 local flags_target_sub = "-"
2126 local background_r, background_g, background_b, background_a = 19, 19, 19, 130
2127 local locations_world_visible_only = not ui_get(ignore_visibility_reference)
2128 local r, g, b, a = ui_get(color_reference)
2129 local a_mp = a/255
2130 local realtime = globals_realtime()
2131
2132 if last_weapon_switch ~= nil then
2133 local delta = realtime - last_weapon_switch
2134 if 0.45 > delta then
2135 a_mp = a_mp * delta / 0.45
2136 end
2137 end
2138
2139 local origin = vector3(entity_get_prop(local_player, "m_vecAbsOrigin"))
2140 local eye_pos = vector3(client_eye_position())
2141 local camera_pos = vector3(client.camera_position())
2142 local screen_width, screen_height = client_screen_size()
2143
2144 -- find locations close that we need to draw (close and on)
2145 local locations_close, locations_close_unchecked = {}, {}
2146 locations_on = {}
2147
2148 local dist_closest = 1/0
2149
2150 for i=1, #data_weapon do
2151 local location = data_weapon[i]
2152 local location_pos = location.pos
2153 if location_pos.distance_sqr == nil then
2154 location_pos.distance_sqr = (origin-location_pos):length_sqr()
2155 end
2156
2157 if dist_max_sqr > location_pos.distance_sqr then
2158 if location_pos.distance == nil then
2159 location_pos.distance = math_sqrt(location_pos.distance_sqr)
2160 location_pos.wx, location_pos.wy = (location_pos+wx_offset_vec):to_screen()
2161 if location_pos.wx ~= nil and (location_pos.wx > screen_width or location_pos.wx < 0 or location_pos.wy > screen_height or location_pos.wy < 0) then
2162 location_pos.wx = nil
2163 end
2164 if location_pos.wx ~= nil then
2165 location_pos.wx_bottom, location_pos.wy_bottom = location_pos:to_screen()
2166 end
2167
2168 location_pos.distance_2d = origin:dist_to_2d(location_pos)
2169 if (location_pos.distance_2d < 0.08 and location_pos.distance > 0.08 and location_pos.distance < 4) or (location_pos.inaccurate and location_pos.distance < 32) then
2170 location_pos.distance = location_pos.distance_2d
2171 end
2172 end
2173
2174 table_insert(locations_close_unchecked, location)
2175
2176 if location_pos.wx ~= nil then
2177 if location_pos.distance_2d < 80 or location.temporary then
2178 location_pos.visible = true
2179 end
2180 if locations_world_visible_only and location_pos.visible == nil then
2181 local fraction = camera_pos:trace_line(location_pos.visibility_location, local_player)
2182 location_pos.visible = fraction > 0.97
2183 end
2184 if not locations_world_visible_only or location_pos.visible or helper_debug or (location_pos.last_visible ~= nil and realtime - location_pos.last_visible < 0.15) then
2185 table_insert(locations_close, location)
2186 end
2187 end
2188
2189 if location_pos.visible == nil then
2190 location_pos.visible = false
2191 end
2192
2193 if location_pos.visible ~= (location_pos.visible_prev or false) then
2194 if location_pos.visible then
2195 location_pos.last_invisible = realtime
2196 else
2197 location_pos.last_visible = realtime
2198 end
2199 end
2200
2201 if dist_closest > location_pos.distance then
2202 position_closest = location_pos
2203 dist_closest = location_pos.distance
2204 end
2205 end
2206 end
2207
2208 for i=1, #locations_close_unchecked do
2209 if locations_close_unchecked[i].pos == position_closest and locations_close_unchecked[i].pos.distance < dist_max_targets then
2210 table_insert(locations_on, locations_close_unchecked[i])
2211 end
2212 end
2213
2214 local on_correct = locations_on[1] ~= nil and locations_on[1].pos.distance < 0.08
2215 local a_mp_target = on_correct and 1 or (locations_on[1] == nil and 0 or (1-locations_on[1].pos.distance/dist_max_targets))
2216
2217 if ui_get(saving_enabled_reference) then
2218 on_paint_saving(local_player, weapon, screen_width, screen_height, locations_on, on_correct)
2219 end
2220
2221 -- determine position offset for all locations based on locations with the same position
2222 local pos_offsets = {}
2223 for i=1, #locations_close do
2224 local pos = locations_close[i].pos
2225 if pos_offsets[pos] == nil then
2226 pos_offsets[pos] = -1
2227 pos.world_alpha_multiplier = math_min(1, 1 - (pos.distance-full_world_alpha_distance) / (dist_max-full_world_alpha_distance))
2228 if pos.visible and pos.last_invisible ~= nil and realtime - pos.last_invisible < 0.35 then
2229 pos.world_alpha_multiplier = pos.world_alpha_multiplier * (realtime - pos.last_invisible) / 0.35
2230 elseif not pos.visible and pos.last_visible ~= nil and realtime - pos.last_visible < 0.15 then
2231 pos.world_alpha_multiplier = pos.world_alpha_multiplier * (1 - (realtime - pos.last_visible) / 0.15)
2232 end
2233 if #locations_on > 0 then
2234 pos.world_alpha_multiplier = table_contains(locations_on, locations_close[i]) and 1 or pos.world_alpha_multiplier*0.15
2235 elseif active_move_location ~= nil then
2236 pos.world_alpha_multiplier = active_move_location == pos and 1 or 0
2237 end
2238 end
2239 pos_offsets[pos] = pos_offsets[pos] + 1
2240 locations_close[i].offset = pos_offsets[pos]
2241 end
2242
2243 -- determine text for all positions that are on screen
2244 for i=1, #locations_close do
2245 local location = locations_close[i]
2246 location.text_world = location.name -- .. " (" .. tostring(location.pos.accurate_move) .. ")"
2247 if helper_debug then
2248 location.text_world = location.name .. " (" .. string_format("%.1f", location.pos.distance) .. ", " .. (location.id or "no id") .. ", " .. string_format("%.2f", location.pos.world_alpha_multiplier) .. ")"
2249 end
2250 end
2251
2252 -- determine text width for a position by first finding the longest string, then doing measure_text
2253 local pos_width = {}
2254 for i=1, #locations_close do
2255 local location = locations_close[i]
2256 if location.text_world ~= nil then
2257 if pos_width[locations_close[i].pos] == nil or pos_width[locations_close[i].pos]:len() < location.text_world:len() then
2258 pos_width[locations_close[i].pos] = location.text_world
2259 end
2260 end
2261 end
2262 for pos, text in pairs(pos_width) do
2263 pos_width[pos] = M.get_text_size(SFont, text)
2264
2265 local width = math_ceil(pos_width[pos]/2)*2+6
2266 local height = (pos_offsets[pos]+1)*10+4
2267 local color_ref = {ui.get(color_reference)}
2268 M.draw_filled_rect(pos.wx-width/2, pos.wy-height+7, width, height, background_r, background_g, background_b, background_a*pos.world_alpha_multiplier*a_mp)
2269
2270 if pos.wx_bottom ~= nil then
2271 renderer_line(pos.wx-1, pos.wy+7, pos.wx_bottom-1, pos.wy_bottom, background_r, background_g, background_b, background_a*0.3*pos.world_alpha_multiplier*a_mp)
2272 renderer_line(pos.wx, pos.wy+7, pos.wx_bottom, pos.wy_bottom, background_r, background_g, background_b, background_a*pos.world_alpha_multiplier*a_mp)
2273 renderer_line(pos.wx+1, pos.wy+7, pos.wx_bottom+1, pos.wy_bottom, background_r, background_g, background_b, background_a*0.3*pos.world_alpha_multiplier*a_mp)
2274 draw_circle_3d(pos.x, pos.y, pos.z, 8, color_ref[1], color_ref[2], color_ref[3], background_a*0.3*pos.world_alpha_multiplier*a_mp, 3, 3)
2275 end
2276 end
2277
2278 -- draw world text
2279 for i=1, #locations_close do
2280 local location = locations_close[i]
2281 if location.text_world ~= nil then
2282 local r, g, b, a = r, g, b, a
2283 if location.temporary then
2284 r, g, b = 255, 0, 0
2285 end
2286 local textw, texth = M.get_text_size(SFont, location.text_world)
2287 M.draw_text(location.pos.wx - textw/2, location.pos.wy-10*location.offset - texth/2, r, g, b, a*location.pos.world_alpha_multiplier*a_mp, SFont, location.text_world)
2288 end
2289 end
2290
2291 local screen_center = vector2(screen_width, screen_height)/2
2292
2293 local dist_closest, location_closest = 1/0
2294 for i=1, #locations_on do
2295 local location = locations_on[i]
2296 -- renderer_text(15, 5+i*10, 255, 255, 255, 255, nil, 0, "", location.name, " ", location.offset, " ", location.id, " ", location.description)
2297 local target = location.target
2298 target.wx, target.wy = location.target:to_screen()
2299 if target.wx ~= nil then
2300 local dist = screen_center:dist_to_2d(vector2(target.wx, target.wy))
2301 if dist < dist_closest then
2302 location_closest, dist_closest = location, dist
2303 end
2304 end
2305 end
2306 location_targeted = location_closest
2307
2308 if location_closest ~= nil and location_closest.target.wx ~= nil then
2309 -- location_targeted.crosshair_dist = vector2(client_camera_angles()):dist_to_2d(vector2(location_closest.pitch, location_closest.yaw))
2310 local delta = vector2(client_camera_angles()) - location_targeted.viewangles
2311 delta:normalize_angles()
2312 location_targeted.crosshair_dist = delta:length_2d()
2313 location_targeted.viewangles_correct = (location_targeted.crosshair_dist <= location_closest.viewAnglesDistanceMax)
2314 location_targeted.center_dist = dist_closest
2315 local closest_targeted = ((ui_get(silent_enabled_reference) == "Legit (Silent)" and location_closest.type == "grenade") and (location_targeted.crosshair_dist <= location_closest.viewAnglesDistanceMax) or location_targeted.viewangles_correct) and entity_get_prop(local_player, "m_flDuckAmount") == (location_closest.duck and 1 or 0)
2316 if ui_get(silent_enabled_reference) == "Rage" then
2317 closest_targeted = ((ui_get(silent_enabled_reference) == "Rage" and location_closest.type == "grenade") and (location_targeted.crosshair_dist < ui_get(silent_dist)) or location_targeted.viewangles_correct) and entity_get_prop(local_player, "m_flDuckAmount") == (location_closest.duck and 1 or 0)
2318 end
2319 local line_drawn = location_targeted.center_dist < 230
2320
2321 local can_target = true
2322 if location_targeted.destroy ~= nil then
2323 local fraction, entindex_hit = location_targeted.destroy_start:trace_line(location_targeted.destroy, local_player)
2324 can_target = fraction > 0.84
2325 -- location_targeted.destroy_start:draw_line(location_targeted.destroy, 255, can_target and 0 or 255, can_target and 0 or 255, 255)
2326 end
2327 if ui_get(silent_enabled_reference) == "Legit (Smooth)" then
2328 closest_targeted = ((ui_get(silent_enabled_reference) == "Legit (Smooth)" and location_closest.type == "grenade") and (location_targeted.crosshair_dist <= location_closest.viewAnglesDistanceMax) or location_targeted.viewangles_correct) and entity_get_prop(local_player, "m_flDuckAmount") == (location_closest.duck and 1 or 0)
2329 local clamp_angles = function(angle)
2330 angle = angle % 360
2331 angle = (angle + 360) % 360
2332 if angle > 180 then
2333 angle = angle - 360
2334 end
2335 return angle
2336 end
2337 if not closest_targeted and ui_get(hotkey_reference) and location_targeted.crosshair_dist < ui_get(legit_smooth_dist) then
2338 local pitch, yaw = client_camera_angles()
2339 client_camera_angles(pitch + clamp_angles(location_closest.pitch - pitch) / ui_get(legit_smooth_fact), yaw + clamp_angles(location_closest.yaw - yaw) / ui_get(legit_smooth_fact))
2340 end
2341 end
2342 location_closest.targeted = closest_targeted and can_target
2343
2344 -- determine all texts + subtexts
2345 for i=1, #locations_on do
2346 local location = locations_on[i]
2347 location.target_text = location.name
2348 location.target_text_2 = nil
2349 location.target_subtext = nil
2350 if location == location_closest then
2351 local info = {}
2352 if location.duck then
2353 table_insert(info, "DUCK")
2354 end
2355 if location.throwStrength ~= 1 then
2356 local strength_text = tostring(location.throwStrength) .. " STRENGTH"
2357 if location.throwStrength == 0 then
2358 strength_text = "RIGHTCLICK"
2359 elseif location.throwStrength == 0.5 then
2360 strength_text = "RIGHT+LEFTCLICK"
2361 end
2362 table_insert(info, strength_text)
2363 end
2364
2365 -- if location.flyDuration ~= nil then
2366 -- table_insert(info, round(location.flyDuration, 1) .. " S")
2367 -- end
2368 if can_target then
2369 local subtext = table_concat(info, ", ")
2370 if subtext ~= "" then
2371 location.target_subtext = subtext
2372 end
2373 else
2374 location.target_subtext = location.destroyText:upper()
2375 end
2376
2377 local target_text_2_elements = {}
2378
2379 if throwtype_description[location.throwType] ~= nil then
2380 table_insert(target_text_2_elements, throwtype_description[location.throwType])
2381 end
2382 if location.temporary then
2383 table_insert(target_text_2_elements, "temporary")
2384 end
2385
2386 if #target_text_2_elements > 0 then
2387 location.target_text_2 = " - " .. table_concat(target_text_2_elements, ", ")
2388 end
2389 end
2390 end
2391
2392 -- draw all backgrounds
2393 for i=1, #locations_on do
2394 local location = locations_on[i]
2395 if location.target.wx ~= nil then
2396 local text_width_2 = 0
2397 if location.target_text_2 ~= nil then
2398 text_width_2 = M.get_text_size(SFont, location.target_text_2)
2399 end
2400 local text_width = M.get_text_size(SFont, location.target_text)
2401 local subtext_width = location.target_subtext ~= nil and renderer_measure_text(flags_target_sub, location.target_subtext) or 0
2402 local width = math_max(text_width+text_width_2, subtext_width)
2403 local height = 10
2404 if location.target_subtext ~= nil then
2405 height = height + 6
2406 end
2407 location.target_text_width = text_width
2408
2409 M.draw_filled_rect(location.target.wx-7, location.target.wy-6, width+16, height+3, background_r, background_g, background_b, background_a*a_mp*a_mp_target)
2410
2411 if location ~= location_closest then
2412 renderer_circle(location.target.wx, location.target.wy, 8, 8, 8, 120*a_mp*a_mp_target, 4, 0, 1)
2413 end
2414 end
2415 end
2416
2417 if location_closest.type ~= "wallbang_hvh" then
2418 if closest_targeted and on_correct then
2419 if can_target then
2420 local r, g, b = 0, 255, 0
2421 if location_closest.type == "wallbang" then
2422 local max_distance = 8192
2423
2424 local pitch, yaw = client_camera_angles()
2425
2426 local fwd = vector3.angle_forward(vector2(pitch, yaw, 0))
2427 local end_pos = eye_pos + (fwd * max_distance)
2428 local damage, entindex_hit = eye_pos:trace_bullet(end_pos, local_player)
2429
2430 if entindex_hit > 0 then
2431 r, g, b = 10, 96, 255
2432 end
2433 end
2434 renderer_circle(location_closest.target.wx, location_closest.target.wy, r, g, b, 150*a_mp*a_mp_target, 3, 0, 1)
2435 else
2436 renderer_circle(location_closest.target.wx, location_closest.target.wy, 255, 150, 0, 150*a_mp*a_mp_target, 3, 0, 1)
2437 end
2438 else
2439 local a_mp_circles = a_mp_target
2440 if not on_correct then
2441 a_mp_circles = a_mp_target / 4
2442 end
2443 if line_drawn then
2444 renderer_circle(location_closest.target.wx, location_closest.target.wy, 255, 32, 32, 80*a_mp*a_mp_circles, 3, 0, 1)
2445 else
2446 renderer_circle(location_closest.target.wx, location_closest.target.wy, 255, 32, 32, 20*a_mp*a_mp_circles, 3, 0, 1)
2447 end
2448 end
2449 end
2450
2451 if location_targeted.center_dist > 4 then
2452 local mp = ui_get(brightness_adjustment_reference) == "Night mode" and 0.4 or 0.8
2453 renderer_line(location_closest.target.wx, location_closest.target.wy, screen_width/2, screen_height/2, r, g, b, a*mp*a_mp*a_mp_target)
2454 end
2455 if location_targeted.land ~= nil then
2456 local wx, wy = location_targeted.land:to_screen()
2457
2458 if wx ~= nil then
2459 if not true then
2460 local wx_top, wy_top = (location_targeted.land+land_offsets_vec[1]):to_screen()
2461 if wx_top ~= nil then
2462 renderer_line(wx, wy, wx_top, wy_top, 255, 0, 0, a*a_mp*a_mp_target)
2463 end
2464
2465 local wx_fwd, wy_fwd = (location_targeted.land+land_offsets_vec[2]):to_screen()
2466 if wx_fwd ~= nil then
2467 renderer_line(wx, wy, wx_fwd, wy_fwd, 255, 0, 0, a*a_mp*a_mp_target)
2468 end
2469
2470 local wx_back, wy_back = (location_targeted.land-land_offsets_vec[2]):to_screen()
2471 if wx_back ~= nil then
2472 renderer_line(wx, wy, wx_back, wy_back, 255, 0, 0, a*a_mp*a_mp_target)
2473 end
2474
2475 local wx_left, wy_left = (location_targeted.land+land_offsets_vec[3]):to_screen()
2476 if wx_left ~= nil then
2477 renderer_line(wx, wy, wx_left, wy_left, 255, 0, 0, a*a_mp*a_mp_target)
2478 end
2479
2480 local wx_right, wy_right = (location_targeted.land-land_offsets_vec[3]):to_screen()
2481 if wx_right ~= nil then
2482 renderer_line(wx, wy, wx_right, wy_right, 255, 0, 0, a*a_mp*a_mp_target)
2483 end
2484 else
2485 if wx ~= nil then
2486 local wx_top, wy_top = (location_targeted.land+land_offsets_vec[1]):to_screen()
2487 if wx_top ~= nil then
2488 local size = math_max(5, math_min(22, math.abs(wy_top-wy)*0.8))
2489
2490 renderer_triangle(wx-size-2, wy-size-1, wx+size+2, wy-size-1, wx, wy+2, background_r, background_g, background_b, background_a*a_mp*a_mp_target*0.6)
2491 renderer_triangle(wx-size, wy-size, wx+size, wy-size, wx, wy, r, g, b, a*a_mp*a_mp_target*0.6)
2492 end
2493 end
2494 end
2495 end
2496 end
2497
2498 for i=1, #locations_on do
2499 local location = locations_on[i]
2500 if location.target.wx ~= nil then
2501 local a_multiplier = 0.35
2502 if location == location_closest then
2503 a_multiplier = line_drawn and 1 or 0.65
2504 end
2505
2506 renderer_circle_outline(location.target.wx, location.target.wy, 255, 255, 255, 255*a_multiplier*a_mp*a_mp_target, 4, 0, 1, 1)
2507
2508 local r, g, b, a = r, g, b, a
2509 if location.temporary then
2510 r, g, b = 255, 0, 0
2511 end
2512 M.draw_text(location.target.wx+6, location.target.wy-6, r, g, b, a*a_multiplier*a_mp*a_mp_target, SFont, location.target_text)
2513
2514 if location.target_text_2 ~= nil then
2515 M.draw_text(location.target.wx+6+location.target_text_width, location.target.wy-6, 200, 200, 200, 255*a_multiplier*0.8*a_mp*a_mp_target, SFont, location.target_text_2)
2516 end
2517
2518 if location.target_subtext ~= nil then
2519 if can_target then
2520 renderer_text(location.target.wx+6, location.target.wy-6+10, 255, 255, 255, 160*a_multiplier*a_mp*a_mp_target, flags_target_sub, 0, location.target_subtext)
2521 else
2522 renderer_text(location.target.wx+6, location.target.wy-6+10, 255, 150, 32, 160*a_multiplier*a_mp*a_mp_target, flags_target_sub, 0, location.target_subtext)
2523 end
2524 end
2525 end
2526 end
2527 end
2528
2529 -- reset
2530 for i=1, #data_weapon do
2531 data_weapon[i].pos.distance = nil
2532 data_weapon[i].pos.distance_sqr = nil
2533 data_weapon[i].pos.wx = nil
2534 data_weapon[i].pos.wx_bottom = nil
2535
2536 if data_weapon[i].pos.visible ~= nil then
2537 data_weapon[i].pos.visible_prev = data_weapon[i].pos.visible
2538 data_weapon[i].pos.visible = nil
2539 end
2540 end
2541 if not on_correct then
2542 location_targeted = nil
2543 locations_on = {}
2544 end
2545end
2546client.set_event_callback("paint", on_paint)
2547
2548local function on_grenade_detonate(e, grenade_type)
2549 if grenade_type ~= "molotov" and client_userid_to_entindex(e.userid) ~= entity_get_local_player() then
2550 return
2551 end
2552
2553 if ui_get(saving_enabled_reference) then
2554 if helper_recreate_dynamic.active then
2555 helper_recreate_dynamic.location.flyDuration = globals_curtime()-grenade_thrown_at
2556 helper_recreate_dynamic.location.landX = e.x
2557 helper_recreate_dynamic.location.landY = e.y
2558 helper_recreate_dynamic.location.landZ = e.z
2559 client_log("Landed after ", globals_curtime()-grenade_thrown_at)
2560 client_delay_call(0.4, function()
2561 helper_recreate_dynamic.location = nil
2562 end)
2563 client_exec("host_timescale 1")
2564 else
2565 if saving_location ~= nil and grenade_thrown_at ~= nil then
2566 -- saving_location.flyDuration = globals_curtime()-grenade_thrown_at
2567 saving_location.landX = e.x
2568 saving_location.landY = e.y
2569 saving_location.landZ = e.z
2570 reload_data = true
2571 end
2572 end
2573 end
2574 grenade_thrown_at = nil
2575end
2576client.set_event_callback("smokegrenade_detonate", function(e) on_grenade_detonate(e, "smokegrenade") end)
2577client.set_event_callback("hegrenade_detonate", function(e) on_grenade_detonate(e, "hegrenade") end)
2578client.set_event_callback("inferno_startburn", function(e) on_grenade_detonate(e, "molotov") end)
2579client.set_event_callback("flashbang_detonate", function(e) on_grenade_detonate(e, "flashbang") end)
2580client.set_event_callback("decoy_started", function(e) on_grenade_detonate(e, "decoy") end)
2581
2582client.set_event_callback("molotov_detonate", function()
2583 if helper_recreate_dynamic.active then
2584 local location = helper_recreate_dynamic.location
2585 client_delay_call(0.5, function()
2586 if helper_recreate_dynamic.location == location then
2587 client_log("Exploded in air. Skipping")
2588 helper_recreate_dynamic.location.dynamic_skip = true
2589 helper_recreate_dynamic.location = nil
2590 client_exec("host_timescale 1")
2591 end
2592 end)
2593 end
2594end)
2595
2596local function on_grenade_thrown(e)
2597 if client_userid_to_entindex(e.userid) ~= entity_get_local_player() then
2598 return
2599 end
2600
2601 if saving_location ~= nil then
2602 saving_location.flyDuration = nil
2603 saving_location.landX = nil
2604 saving_location.landY = nil
2605 saving_location.landZ = nil
2606 end
2607
2608 if helper_recreate_dynamic.active then
2609 client_exec("host_timescale 6")
2610 end
2611
2612 grenade_thrown_at = globals_curtime()
2613 grenade_entindex = entity_get_player_weapon(entity_get_local_player())
2614end
2615client.set_event_callback("grenade_thrown", on_grenade_thrown)
2616
2617local function on_shutdown()
2618 if airstrafe_disabled then
2619 ui_set(airstrafe_reference, true)
2620 end
2621 if quick_peek_assist_disabled then
2622 ui_set(quick_peek_assist_reference, true)
2623 end
2624 reset_cvar(cvar_sensitivity)
2625end
2626client.set_event_callback("shutdown", on_shutdown)
2627
2628local function on_player_connect_full(e)
2629 if ui_get(saving_enabled_reference) and client_userid_to_entindex(e.userid) == entity_get_local_player() and not helper_recreate_dynamic.active then
2630 ui_set(saving_enabled_reference, false)
2631 on_saving_enabled_changed()
2632 end
2633end
2634client.set_event_callback("player_connect_full", on_player_connect_full)