local ffi=require("ffi")
local http=require("gamesense/http")
local vector=require("vector")

--local SystemAccName = ffi.string(vtable_bind("vgui2.dll", "VGUI_System010", 32, "const char*(__thiscall*)(void*)")()):match('\\Users\\(.+)\\Desktop')

local function vtable_bind(module, interface, index, type)
    local addr = ffi.cast("void***", client.create_interface(module, interface)) or error(interface .. " is nil.")
    return ffi.cast(ffi.typeof(type), addr[0][index]), addr
end

local function __thiscall(func, this) -- bind wrapper for __thiscall functions
    return function(...)
        return func(this, ...)
    end
end

local function vtable_thunk(index, typestring)
    local t = ffi.typeof(typestring)
    return function(instance, ...)
        assert(instance ~= nil)
        if instance then
            local addr=ffi.cast("void***", instance)
            return __thiscall(ffi.cast(t, (addr[0])[index]),addr)
        end
    end
end

ffi.cdef [[
    typedef struct
    {
        float x;
        float y;
        float z;
    } vec3_t;
    typedef struct
    {
        char pad[0x117D0];
        float pitch;
        float yaw;
        float roll;
    } player;
]]

local angles={

}

local nativeGetClientEntity=__thiscall(vtable_bind("client.dll","VClientEntityList003",3,"player*(__thiscall*)(void*, int)"))

local nativeEyeAngles=vtable_thunk(170,"vec3_t*(__thiscall*)(void*)")

local enabled_ref=ui.new_checkbox("RAGE","Other","Roll Resolver")
local enabled_key_ref=ui.new_hotkey("RAGE","Other","Roll Resolver key",true)
local freestand_ref=ui.new_checkbox("RAGE","Other","Resolve Freeestand")
local force_key_ref=ui.new_hotkey("RAGE","Other","Force resolve roll",false)
--local force_180_ref=ui.new_checkbox("RAGE","Other","Force 180 resolve")
local force_sideways_key_ref=ui.new_hotkey("RAGE","Other","Force sideways resolve",false)
local force_backwards_key_ref=ui.new_hotkey("RAGE","Other","Force backwards resolve",false)
local force_75_ref=ui.new_hotkey("RAGE","Other","Force 75 roll",false)
local force_moving_ref=ui.new_checkbox("RAGE","Other","Force resolve moving")
local indicator_ref=ui.new_checkbox("RAGE","Other","Roll Indicator")
local pitch_resolver=ui.new_checkbox("RAGE","Other","Pitch Resolver")
local force_resolver_pitch_ref=ui.new_hotkey("RAGE","Other","Force resolver pitch with low velocity",false)

local yaw_ref=ui.reference("PLAYERS","Adjustments","Force body yaw value")
ui.set_visible(yaw_ref,true)

function set_player_roll(player,angle)
    angles[player]=angle
end

function set_player_roll_by_index(index,angle)
    angles[index]=angle
end

function on_net_update_start()
    local players = entity.get_players(true)
    if not ui.get(enabled_ref) or not ui.get(enabled_key_ref) then
        for i, p in pairs(players) do
            local player=nativeGetClientEntity(p)
            player.roll=0
        end
        return 
    end

    for i, p in pairs(players) do
	if ui.get(pitch_resolver) then
               	 local velocity=get_velocity(entity.get_prop(p,"m_vecVelocity[0]"),entity.get_prop(p,"m_vecVelocity[1]"))
		local check = not ui.get(force_resolver_pitch_ref) or velocity < 50
		if check then
			player.pitch= 145 - ((velocity / 50) * 56)
		end
	end

        if angles[p]~=nil then
            local player=nativeGetClientEntity(p)
            player.roll=angles[p]
        end
    end
end

client.set_event_callback("net_update_start", on_net_update_start)

local resolve_state={
    ["example"]={
                    ["rolling"]=true,
                    ["backwards"]=true,
                    ["sideways"]=true,
                    ["missed_sideways"]=0,
                    ["missed_backwards"]=0
    }
}

function get_angle(vector)
    return math.atan2(vector.y,vector.x)*(180/math.pi)
end

function get_velocity(vec_velocity0,vec_velocity1)
    return math.sqrt(vec_velocity0*vec_velocity0+vec_velocity1*vec_velocity1)
end

function normalize(angle)   
    angle=(angle%360+360)%360
    return angle>180 and angle-360 or angle
end

local degree_to_radian = function(degree)
    return (math.pi/180)*degree
end

local angle_to_vector = function(angle)
    local pitch=degree_to_radian(angle.x)
    local yaw = degree_to_radian(angle.y)
    return vector(math.cos(pitch)*math.cos(yaw), math.cos(pitch)*math.sin(yaw), -math.sin(pitch))
end

local get_wall_fraction_with_origin = function(player,angle,origin)
    local vector=angle_to_vector(angle)*8192
    local impact=origin+vector
    return client.trace_line(player, origin.x, origin.y, origin.z, impact.x, impact.y, impact.z)
end

local get_distance_to_wall_with_origin = function(player,angle,origin)
    local fraction,index = get_wall_fraction_with_origin(player,angle,origin)
    return fraction*8192
end

function get_angle_to_local(player)
    local local_player = entity.get_local_player()
    local lo=vector(entity.get_origin(local_player))
    local eo=vector(entity.get_origin(player))
    local no=get_angle(vector(eo.x-lo.x,eo.y-lo.y,eo.z-lo.z))
    local ea=entity.get_prop(player,"m_angEyeAngles[1]")
    local d=normalize(ea-no)
    return d
end

function get_angle_to_local_opposite(player)
    local local_player = entity.get_local_player()
    local eo=vector(entity.get_origin(local_player))
    local lo=vector(entity.get_origin(player))
    local no=get_angle(vector(eo.x-lo.x,eo.y-lo.y,eo.z-lo.z))
    return normalize(no)
end


function is_sideways(player)
    local d=get_angle_to_local(player)
    return ((d >= 45 and d <= 135) or (d<=-45 and d >= -135))
end

local desyncs={

}

function resolve_freestand(p)
    local force_angle=ui.get(force_75_ref) and 75 or 50
    local enemy_eye_pos=vector(entity.get_origin(p))
    enemy_eye_pos.z=enemy_eye_pos.z+64
    local ang_to_local=get_angle_to_local_opposite(p)
    local enemy_eye_angle=vector(0,normalize(ang_to_local),0)
    local eye_left=vector(0,normalize(ang_to_local+60),0)
    local eye_right=vector(0,normalize(ang_to_local-60),0)
    local distance_middle=get_distance_to_wall_with_origin(p,enemy_eye_angle,enemy_eye_pos)
    local distance_left=get_distance_to_wall_with_origin(p,eye_left,enemy_eye_pos)
    local distance_right=get_distance_to_wall_with_origin(p,eye_right,enemy_eye_pos)
    --print(distance_middle," ",distance_left," ",distance_right)
    if distance_middle>100 and distance_left>75 and distance_right>75 then return 0 end
    local ang=get_angle_to_local(p)
    local retval=distance_left>distance_right and -force_angle or force_angle
    if math.abs(ang)>90 then
        retval=-retval
    end
    return retval
end

function on_prediction(cmd)
    if not ui.get(enabled_ref) or not ui.get(enabled_key_ref) then return end
    local players = entity.get_players(true)

    local force_angle=ui.get(force_75_ref) and 75 or 50

    for i, p in pairs(players) do
            if resolve_state[p]==nil then 
                resolve_state[p]={
                    ["rolling"]=false,
                    ["backwards"]=true,
                    ["sideways"]=true,
                    ["missed_sideways"]=0,
                    ["missed_backwards"]=0
                }
            end
            if ui.get(force_sideways_key_ref) then
                plist.set(p,"Force body yaw value",-58)
                plist.set(p,"Force body yaw",true)
                set_player_roll(p,force_angle)
            elseif ui.get(force_backwards_key_ref) then
                plist.set(p,"Force body yaw value",58)
                plist.set(p,"Force body yaw",true)
                set_player_roll(p,force_angle)
            elseif resolve_state[p].rolling or ui.get(force_key_ref) then
                plist.set(p,"Force body yaw",false)
                local velocity=get_velocity(entity.get_prop(p,"m_vecVelocity[0]"),entity.get_prop(p,"m_vecVelocity[1]"))
                local desync=0
                local desync1=(entity.get_prop(p,"m_flPoseParameter",11)-0.5)*120
                if math.abs(desync1)>0.4 then
                    desyncs[p]=desync1
                end
                if desyncs[p]~=nil then
                    desync=desyncs[p]
                end
                local is_desyncing=true
                local roll_amount=0
                --if math.abs(desync)<1 then is_desyncing=false end
                if (ui.get(force_moving_ref) or velocity<125) then
                    local sideways=is_sideways(p)
                    if sideways and entity.get_prop(p,"m_angEyeAngles[0]")>70 then
                        roll_amount=resolve_state[p].sideways and force_angle or -force_angle
                    elseif is_desyncing then
                        if ui.get(freestand_ref) and velocity<5 then
                            roll_amount=resolve_freestand(p)
                            if not resolve_state[p].backwards then roll_amount=-roll_amount end
                            if roll_amount==0 then
                                local right_desync=desync>0
                                if resolve_state[p].backwards then
                                    roll_amount=right_desync and force_angle or -force_angle
                                else
                                    roll_amount=right_desync and -force_angle or force_angle
                                end
                            end
                        else
                            local right_desync=desync>0
                            if resolve_state[p].backwards then
                                roll_amount=right_desync and force_angle or -force_angle
                            else
                                roll_amount=right_desync and -force_angle or force_angle
                            end
                        end
                    end
                end
                set_player_roll(p,roll_amount)
            else
                plist.set(p,"Force body yaw",false)
                set_player_roll(p,0)
            end
    end
end

client.set_event_callback("setup_command", on_prediction)

function on_aim_miss(shot)
    if not ui.get(enabled_ref) or not ui.get(enabled_key_ref) or shot.reason~="?" then return end   
    local velocity=get_velocity(entity.get_prop(shot.target,"m_vecVelocity[0]"),entity.get_prop(shot.target,"m_vecVelocity[1]"))
    if velocity >=125 and not ui.get(force_moving_ref) then return end
    print("[Roll Resolver] ","Missed player ",entity.get_player_name(shot.target)," sw:",tostring(is_sideways(shot.target) and 1 or 0)," states:",tostring(resolve_state[shot.target].backwards and 1 or 0).." "..tostring(resolve_state[shot.target].sideways and 1 or 0).." "..resolve_state[shot.target].missed_backwards.." "..resolve_state[shot.target].missed_sideways)
    if resolve_state[shot.target].rolling==false then
        resolve_state[shot.target].rolling=true
        if is_sideways(shot.target) then
            resolve_state[shot.target].sideways=true
        else
            resolve_state[shot.target].backwards=true
        end
    else
        if is_sideways(shot.target) then
            resolve_state[shot.target].missed_sideways=resolve_state[shot.target].missed_sideways+1
            if resolve_state[shot.target].missed_sideways>1 then
                resolve_state[shot.target].sideways=not resolve_state[shot.target].sideways
            end
        else
            resolve_state[shot.target].missed_backwards=resolve_state[shot.target].missed_backwards+1
            if resolve_state[shot.target].missed_backwards>3 then
                resolve_state[shot.target].rolling=false
            end
            if resolve_state[shot.target].missed_backwards>1 then
                resolve_state[shot.target].backwards=not resolve_state[shot.target].backwards
            end
        end
    end
end

client.set_event_callback("aim_miss", on_aim_miss)

function on_aim_hit(shot)
    if not ui.get(enabled_ref) or not ui.get(enabled_key_ref) then return end
    local velocity=get_velocity(entity.get_prop(shot.target,"m_vecVelocity[0]"),entity.get_prop(shot.target,"m_vecVelocity[1]"))
    if velocity >=125 and not ui.get(force_moving_ref) then return end
    resolve_state[shot.target].missed_backwards=0
    resolve_state[shot.target].missed_sideways=0
end

client.set_event_callback("aim_hit", on_aim_hit)

client.set_event_callback("paint", function()
    if ui.get(force_sideways_key_ref) then
        renderer.indicator(50, 50, 255, 255, "Slideway")
    elseif ui.get(force_backwards_key_ref) then
        renderer.indicator(50, 50, 255, 255, "Backwards")
    elseif ui.get(force_key_ref) then
        renderer.indicator(50, 255, 50, 255, "Force resolve roll")
    end
    if not ui.get(indicator_ref) then return end
    local y=300
    for i,v in pairs(angles) do
        if entity.get_player_name(i)~="unknown" then
            renderer.text(300,y,255,50,50,255,255,"d+",entity.get_player_name(i)..": "..v.."°".."| sw:"..tostring(is_sideways(i) and 1 or 0).." | states: "..tostring(resolve_state[i].backwards and 1 or 0).." "..tostring(resolve_state[i].sideways and 1 or 0).." "..resolve_state[i].missed_backwards.." "..resolve_state[i].missed_sideways)
            y=y+20
        end
    end
end)

client.set_event_callback("client_disconnect", function(event)
    resolve_state={
        ["example"]={
                    ["rolling"]=false,
                    ["backwards"]=true,
                    ["sideways"]=true,
                    ["missed_sideways"]=0,
                    ["missed_backwards"]=0
                }
    }
end) 

Lua online compiler

Write, Run & Share Lua code online using OneCompiler's Lua online compiler for free. It's one of the robust, feature-rich online compilers for Lua language, running the latest Lua version 5.4. Getting started with the OneCompiler's Lua editor is easy and fast. The editor shows sample boilerplate code when you choose language as Lua and start coding.

Taking inputs (stdin)

OneCompiler's Lua online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample Lua program which takes name as input and prints hello message with your name.

name = io.read("*a")
print ("Hello ", name)

About Lua

Lua is a light weight embeddable scripting language which is built on top of C. It is used in almost all kind of applications like games, web applications, mobile applications, image processing etc. It's a very powerful, fast, easy to learn, open-source scripting language.

Syntax help

Variables

  • By default all the variables declared are global variables
  • If the variables are explicitly mentioned as local then they are local variables.
  • Lua is a dynamically typed language and hence only the values will have types not the variables.

Examples

-- global variables
a = 10

-- local variables

local x = 30
Value TypeDescription
numberRepresents numbers
stringRepresents text
nilDifferentiates values whether it has data or not
booleanValue can be either true or false
functionRepresents a sub-routine
userdataRepresents arbitary C data
threadRepresents independent threads of execution.
tableCan hold any value except nil

Loops

1. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while(condition)
do
--code
end

2. Repeat-Until:

Repeat-Until is also used to iterate a set of statements based on a condition. It is very similar to Do-While, it is mostly used when you need to execute the statements atleast once.

repeat
   --code
until( condition )

3. For:

For loop is used to iterate a set of statements based on a condition.

for init,max/min value, increment
do
   --code
end

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increase re-usuability and modularity.

optional_function_scope function function_name( argument1, argument2, argument3........, argumentn)
--code
return params with comma seperated
end