local ui_get, ui_set_visible = ui.get, ui.set_visible

local is_alive, localplayer = entity.is_alive, entity.get_local_player

local outlined_circle, skeet_indicator = renderer.circle_outline, renderer.indicator

local enabled = ui.new_checkbox("RAGE", "Aimbot", "[RAFETTO] Indicators")
local colorpicker = ui.new_color_picker("RAGE", "Aimbot", "[RAFETTO] Indicators", 150, 200, 60, 255)
local label = ui.new_label("RAGE", "Aimbot", "[RAFETTO] color")
local colorpicker2 = ui.new_color_picker("RAGE", "Aimbot", "[RAFETTO] color", 255, 0, 0, 255)
local indicators = ui.new_multiselect("RAGE", "Aimbot", "Extra indicators", "Local desync", "Fake lag", "", "", "", "", "Force body aim")
local showcircle = ui.new_checkbox("RAGE", "Aimbot", "Deync circle")
local showcircle2 = ui.new_checkbox("RAGE", "Aimbot", "Fake lag circle")

local get = {

	uiscale = ui.reference("misc", "Settings", "DPI scale"),

	angle = 0,
	aaenabled = ui.reference("aa", "Anti-aimbot angles", "Enabled"),
	yaw = ui.reference("aa", "Anti-aimbot angles", "Body yaw"),

	fakelag = {ui.reference("aa", "Fake lag", "Enabled")},
	fakelaglimit = ui.reference("aa", "Fake lag", "Limit"),
	chockedcmds = {0, 0, 0, 0, 0},

	hideshots = {ui.reference("aa", "Other", "On shot anti-aim")},
	fakepeek = {ui.reference("aa", "Other", "Fake peek")},
	resolveroverride = ui.reference("Rage", "Other", "Anti-aim correction override"),
	safe = ui.reference("Rage", "Aimbot", "Force safe point"),
	baim = ui.reference("Rage", "Other", "Force body aim")

}

local inds = {
	desync = false,
	fakelag = false,
	hideshots = false,
	fakepeek = false,
	resolver = false,
	safe = false,
	baim = false,

	uiscale = 1
}

local function Lerp(delta, from, to) -----ty t0ny for giving me these fire funcs 
	if (delta > 1) then
		return to
	end
	if (delta < 0) then
		return from
	end
	return from + ( to - from ) * delta
end

local function ColorLerp(value, ranges)
	if value <= ranges[1].start then return ranges[1].color end
	if value >= ranges[#ranges].start then return ranges[#ranges].color end

	local selected = #ranges
	for i = 1, #ranges - 1 do
		if value < ranges[i + 1].start then
			selected = i
			break
		end
	end
	local minColor = ranges[selected]
	local maxColor = ranges[selected + 1]
	local lerpValue = (value - minColor.start) / (maxColor.start - minColor.start)
	return {r = Lerp( lerpValue, minColor.color.r, maxColor.color.r ), g = Lerp( lerpValue, minColor.color.g, maxColor.color.g ), b = Lerp( lerpValue, minColor.color.b, maxColor.color.b )}
end

local function table_contains(table, element)
	for _, value in pairs(table) do
		if value == element then
			return true
		end
	end
	return false
end

local function setvis()
	local indz = ui_get(indicators)
	local on = ui_get(enabled)

	ui_set_visible(colorpicker, on)
	ui_set_visible(indicators, on)

	ui_set_visible(label, on)
	ui_set_visible(colorpicker2, on)

	ui_set_visible(showcircle, on and table_contains(indz, "Local desync") )
	ui_set_visible(showcircle2, on and table_contains(indz, "Fake lag") )

	if on then -- put this beat in here cuz i would assume that my table contains function would cause a lil lag and this reduces it
		inds.desync = table_contains(indz, "Local desync")
		inds.fakelag = table_contains(indz, "Fake lag")
		inds.hideshots = table_contains(indz, "Hide shots")
		inds.fakepeek = table_contains(indz, "Fake peek")
		inds.resolver = table_contains(indz, "Resolver override")
		inds.safe = table_contains(indz, "Force safe point")
		inds.baim = table_contains(indz, "Force body aim")
	end

	local uiscale = ui_get(get.uiscale)

	if uiscale == "100%" then -- i also assume that this would probz reduce lag
		inds.uiscale = 1
	elseif uiscale == "125%" then
		inds.uiscale = 2
	elseif uiscale == "150%" then
		inds.uiscale = 3
	elseif uiscale == "175%" then
		inds.uiscale = 4
	else
		inds.uiscale = 5
	end
end

ui.set_callback(enabled, setvis)
ui.set_callback(indicators, setvis)
ui.set_callback(get.uiscale, setvis)
setvis()

client.set_event_callback("setup_command", function(c) --stolen from rave1337 lmao
	if ui_get(enabled) then
		if inds.desync and ui_get(get.aaenabled) and ui_get(get.yaw) ~= "Off" then
			if c.chokedcommands == 0 then
				if c.in_use == 1 then
					get.angle = 0
				else
					get.angle = math.min(57, math.abs(entity.get_prop(entity.get_local_player(), "m_flPoseParameter", 11)*120-60))
				end
			end
		end

		table.insert(get.chockedcmds, 1, c.chokedcommands)
		table.remove(get.chockedcmds, 6)
	end
end)

client.set_event_callback("paint", function()
	if ui_get(enabled) and is_alive(localplayer()) then
		local r, g, b, a = ui_get(colorpicker)
		local r2, g2, b2, a2 = ui_get(colorpicker2)

		if inds.desync and ui_get(get.aaenabled) and ui_get(get.yaw) ~= "Off" then
			
			local percent = get.angle/57
			local color = ColorLerp(percent, {[1] = {start = 0, color = {r = r2, g = g2, b = b2}}, [2] = {start = 1, color = {r = r, g = g, b = b}}})

			local ind_y = skeet_indicator(color.r, color.g, color.b, 255, "FAKE")

			if ui_get(showcircle) then
				ind_y = ind_y + 20 + ((inds.uiscale - 1) * 3.5)
				local ind_x = 86 + ((inds.uiscale - 1) * 20)
				local size = 10 + ((inds.uiscale - 1) * 4)
				local thickness = 6 + ((inds.uiscale - 1) * 2)
				outlined_circle(ind_x, ind_y, 0, 0, 0, 155, size, 0, 1, thickness)
				if percent >= 0.99 then percent = percent + 0.01 end -- i do the little + 0.01 to make the circle full even if it isnt at 100% desync, it looks way nicer then without it 
				outlined_circle(ind_x, ind_y, color.r, color.g, color.b, 255, size - 1, 0, percent, thickness - 2) 
			end
		end

		if inds.fakelag and ui_get(get.fakelag[1]) and ui_get(get.fakelag[2]) then -- this part is horrible cuz i wanted to get it done
			local percent = get.chockedcmds[1]/ui_get(get.fakelaglimit)
			local color = ColorLerp(percent, {[1] = {start = 0, color = {r = r2, g = g2, b = b2}}, [2] = {start = 1, color = {r = r, g = g, b = b}}})
			if ui_get(showcircle2) then
				local ind_y = skeet_indicator(color.r, color.g, color.b, 255, "FL")
				ind_y = ind_y + 20 + ((inds.uiscale - 1) * 3.5)
				local ind_x = 60 + ((inds.uiscale - 1) * 10)
				local size = 10 + ((inds.uiscale - 1) * 4)
				local thickness = 6 + ((inds.uiscale - 1) * 2)
				outlined_circle(ind_x, ind_y, 0, 0, 0, 155, size, 0, 1, thickness)
				outlined_circle(ind_x, ind_y, color.r, color.g, color.b, 255, size - 1, 0, percent, thickness - 2)  
			else
				local str = "FL "
				for i, v in ipairs(get.chockedcmds) do
					if i ~= 5 then
						str = str.. tostring(v).. " - "
					else
						str = str.. tostring(v)
					end
				end
				skeet_indicator(color.r, color.g, color.b, 255, str)
			end
		end

		if inds.hideshots and ui_get(get.hideshots[1]) and ui_get(get.hideshots[2]) then
			skeet_indicator(r, g, b, 255, "")
		end

		if inds.fakepeek and ui_get(get.fakepeek[1]) and ui_get(get.fakepeek[2]) then
			skeet_indicator(r, g, b, 255, "")
		end

		if inds.resolver and ui_get(get.resolveroverride) then
			skeet_indicator(r, g, b, 255, "RAFETTO RESOLVER")
		end

		if inds.safe and ui_get(get.safe) then
			skeet_indicator(r, g, b, 255, "")
		end

		if inds.baim and ui_get(get.baim) then
			skeet_indicator(r, g, b, 255, "BAIM")
		end
	end
end)
--------------------------------------------------------------------------------
-- Caching common functions
--------------------------------------------------------------------------------
local uix, vector = require 'gamesense/uix', require 'vector'
local client_camera_angles, entity_get_local_player, entity_get_players, entity_get_prop, math_floor, math_max, math_min, renderer_indicator, ui_get, ui_new_color_picker, ui_new_slider, ui_reference, ui_set, ui_set_visible = client.camera_angles, entity.get_local_player, entity.get_players, entity.get_prop, math.floor, math.max, math.min, renderer.indicator, ui.get, ui.new_color_picker, ui.new_slider, ui.reference, ui.set, ui.set_visible

--------------------------------------------------------------------------------
-- Constants and variables
--------------------------------------------------------------------------------
local enable_ref
local color_ref
local min_fov_ref
local max_fov_ref
local scale_ref
local builtin_fov_ref

local scaled_fov
local BASE_DISTANCE = 1000.0

--------------------------------------------------------------------------------
-- Utility functions
--------------------------------------------------------------------------------
local function clamp(val, min, max)
    val = math_min(max, val)
    val = math_max(min, val)
    return val
end

local function lerp(min, max, factor)
    factor = clamp(factor, 0.0, 1.0)
    local lerp_result = (1-factor)*min+factor*max
    return clamp(lerp_result, min, max)
end

local function distance_to_ray(pos, ray_start, ray_direction)
    return ray_direction:cross(pos-ray_start):length()
end

local function find_closest_ent(local_origin)
    local players = entity_get_players(true)
    local forward_vector = vector():init_from_angles(client_camera_angles())

    local closest_ent
    local shortest_distance = math.huge

    for i=1, #players do
        local ent = players[i]
        local enemy_origin = vector(entity_get_prop(ent, "m_vecOrigin"))
        local distance = distance_to_ray(enemy_origin, local_origin, forward_vector)
        if distance <= shortest_distance then
            closest_ent = ent
            shortest_distance = distance
        end
    end

    return closest_ent, shortest_distance
end

--------------------------------------------------------------------------------
-- Callback functions
--------------------------------------------------------------------------------
local function on_setup_command()
    local local_player = entity_get_local_player()
    local local_origin = vector(entity_get_prop(local_player, "m_vecOrigin"))

    local min_fov = ui_get(min_fov_ref)
    local max_fov = ui_get(max_fov_ref)
    local nearest_player = find_closest_ent(local_origin)

    if nearest_player ~= nil then
        local enemy_origin = vector(entity_get_prop(nearest_player, "m_vecOrigin"))
        local distance_to_enemy = local_origin:dist(enemy_origin)

        local max_distance = BASE_DISTANCE*ui_get(scale_ref)*0.01
        scaled_fov = lerp(min_fov, max_fov, (max_distance-distance_to_enemy)/max_distance)
        scaled_fov = math_floor(scaled_fov)
    else
        scaled_fov = min_fov
    end

    ui_set(builtin_fov_ref, scaled_fov)
end

local function on_paint()
    local r, g, b, a = ui_get(color_ref)
    renderer_indicator(r, g, b, a, "FOV: ", scaled_fov, "\u{00B0}")
end

local function on_dynamic_fov_toggle(ref, value)
    ui_set_visible(min_fov_ref, value)
    ui_set_visible(max_fov_ref, value)
    ui_set_visible(scale_ref, value)
end
--------------------------------------------------------------------------------
-- Initilization code
--------------------------------------------------------------------------------
do
    enable_ref      = uix.new_checkbox("RAGE", "Aimbot", "[RAFETTO] Dynamic FOV")
    color_ref       = ui_new_color_picker("RAGE", "Aimbot", "\nIndicator color", 255, 255, 255, 255)
    min_fov_ref     = ui_new_slider("RAGE", "Aimbot", "\nMinimum FOV", 1, 180, 5, true, "\u{00B0}")
    max_fov_ref     = ui_new_slider("RAGE", "Aimbot", "\nMaximum FOV", 1, 180, 23, true, "\u{00B0}")
    scale_ref       = ui_new_slider("RAGE", "Aimbot", "Distance scale", 0, 350, 82, true, "x", 0.01)
    builtin_fov_ref = ui_reference("RAGE", "Aimbot", "Maximum FOV")

    enable_ref:on("change", on_dynamic_fov_toggle)
    enable_ref:on("paint", on_paint)
    enable_ref:on("setup_command", on_setup_command)

    scaled_fov = ui_get(builtin_fov_ref)
end
local client_set_event_callback = client.set_event_callback
local ui_get, ui_set, ui_new_hotkey = ui.get, ui.set, ui.new_hotkey
local client_draw_indicator = client.draw_indicator

local client_set_event_callback = client.set_event_callback
local ui_get, ui_set, ui_new_hotkey = ui.get, ui.set, ui.new_hotkey
local client_draw_indicator = client.draw_indicator

local aimbot = ui.reference("RAGE", "Aimbot", "Automatic Penetration")

local aimbottoggle = ui_new_hotkey("RAGE", "Aimbot", "[RAFETTO] AutoWall Toggle Key")

local function on_paint(ctx)

	if ui_get(aimbottoggle) then
		if not ui_get(aimbot) then 
			ui_set(aimbot, true)
		end
		client_draw_indicator(ctx, 255, 255, 255, 200, "AW")
	else 
		if ui_get(aimbot) then
			ui_set(aimbot, false)
		end
		client_draw_indicator(ctx, 255, 0, 0, 255, "")
	end
end

client_set_event_callback("paint", on_paint)
local aimbot = ui.reference("RAGE", "Aimbot", "Automatic fire")

local aimbottoggle = ui_new_hotkey("RAGE", "Aimbot", "[RAFETTO] Automatic Fire Key")

local function on_paint(ctx)

	if ui_get(aimbottoggle) then
		if not ui_get(aimbot) then 
			ui_set(aimbot, true)
		end
		client_draw_indicator(ctx, 255, 255, 255, 200, "TM")
	else 
		if ui_get(aimbot) then
			ui_set(aimbot, false)
		end
		client_draw_indicator(ctx, 255, 0, 0, 255, "")
	end
end

client_set_event_callback("paint", on_paint)
client_draw_text, client_draw_indicator, client_set_event_callback, client_screen_size, ui_new_slider, ui_new_combobox, ui_reference, ui_set_visible, ui_is_menu_open, ui_new_color_picker, ui_set_callback, ui_set, ui_new_checkbox, ui_new_hotkey, ui_new_button, ui_new_multiselect, ui_get = client.draw_text, client.draw_indicator, client.set_event_callback, client.screen_size, ui.new_slider, ui.new_combobox, ui.reference, ui.set_visible, ui.is_menu_open, ui.new_color_picker, ui.set_callback, ui.set, ui.new_checkbox, ui.new_hotkey, ui.new_button, ui.new_multiselect, ui.get

--menu *****
override = ui.new_checkbox("RAGE", "Aimbot", "[RAFETTO] Resolver override")
override_color = ui.new_color_picker("RAGE", "Other", "\n flag")
override_key = ui.new_hotkey("RAGE", "Aimbot", "[RAFETTO] Resolver Override Key")
override_indicator = ui.new_combobox("RAGE", "Aimbot", "[RAFETTO] Select Indicator", "", "", "Crosshair")

local function update_menu(visible)
	if ui.get(override, true) then
		ui.set_visible(override_color, true)
		ui.set_visible(override_key, true)
		ui.set_visible(override_indicator, true)
	else
		ui.set_visible(override_color, false)
		ui.set_visible(override_key, false)
		ui.set_visible(override_indicator, false)
	end
end
client.set_event_callback("paint", update_menu)

--references men
selectedplayer = ui.reference("PLAYERS", "Players", "Player list")
forcebody = ui.reference("PLAYERS", "Adjustments", "Force body yaw")
resetlist = ui.reference("PLAYERS", "Players", "Reset all")
correction_active = ui.reference("PLAYERS", "Adjustments", "Correction active")
applyall = ui.reference("players", "adjustments", "Apply to all")
body_slider = ui.reference("PLAYERS", "Adjustments", "Force body yaw value")

--override key

function setbodyyaw()
	if ui.get(override, true) then
	else
		return
	end
	if ui.get(body_slider) == 0 and canManual == true then
		ui.set(forcebody, true)
		ui.set(body_slider, 60)
		ui.set(applyall, true)
		canManual = false
	end
	if ui.get(body_slider) == 60 and canManual == true then
		ui.set(forcebody, true)
		ui.set(body_slider, -60)
		ui.set(applyall, true)
		canManual = false
	end
    if ui.get(body_slider) == -60 and canManual == true then
		ui.set(forcebody, false)
		ui.set(body_slider, 0)
		ui.set(applyall, true)
		canManual = false
    end
end

function on_paint()
	if ui.get(override, true) then
	else
		return
	end
	if ui.get(override_key) then
		if canManual == true then
			setbodyyaw()
			canManual = false
		end
	else
		canManual = true
	end
end
client.set_event_callback("paint", on_paint)

--overide flag

local r, g, b = ui.get(override_color) --this doesn't work cus flags are really weird so I'm just setting a static color instead, if anyone knows how to make this work then please let me know

client.register_esp_flag("LEFT", 255, 0, 255, function(c)
	if ui.get(body_slider) == 60 then return true end
end)
client.register_esp_flag("RIGHT", 255, 0, 255, function(c)
	if ui.get(body_slider) == -60 then return true end
end)

--override indicators

client.set_event_callback("paint", function()

	local r, g, b, a = ui.get(override_color)
	local w, h = client_screen_size()
	local center = { w/2, h/2 }
	local y = (center[2])
	
	if ui.get(override, true) and ui.get(override_indicator) == "Default" then
		if ui.get(body_slider) == -60 then
			renderer.indicator(r, g, b, a, "RIGHT")
		elseif ui.get(body_slider) == 60 then
			renderer.indicator(r, g, b, a, "LEFT")
		elseif ui.get(forcebody) == false then
			renderer.indicator(r, g, b, a, "DEFAULT")
		end
	end
	if ui.get(override, true) and ui.get(override_indicator) == "Crosshair" then
		if ui.get(body_slider) == -60 then
			renderer.text(center[1] + 7, y + 25, r, g, b, a, "c", 0, "RIGHT ⮞")
		elseif ui.get(body_slider) == 60 then
			renderer.text(center[1] - 7, y + 25, r, g, b, a, "c", 0, "⮜ LEFT")
		elseif ui.get(forcebody) == false then
			renderer.text(center[1], y + 25, 255, 255, 255, a, "c", 0, "RAFETTOHOOK")
		end
	end
end)

--reset override on round start
client.set_event_callback("round_start", function()
	ui.set(body_slider, 0)
	ui.set(forcebody, false)
	ui.set(applyall, true)
end)
-- local variables for API functions. any changes to the line below will be lost on re-generation
local client_latency, client_screen_size, client_set_event_callback, client_system_time, entity_get_local_player, entity_get_player_resource, entity_get_prop, globals_absoluteframetime, globals_tickinterval, math_ceil, math_floor, math_min, math_sqrt, renderer_measure_text, ui_reference, pcall, renderer_gradient, renderer_rectangle, renderer_text, string_format, table_insert, ui_get, ui_new_checkbox, ui_new_color_picker, ui_new_multiselect, ui_new_textbox, ui_set, ui_set_callback, ui_set_visible = client.latency, client.screen_size, client.set_event_callback, client.system_time, entity.get_local_player, entity.get_player_resource, entity.get_prop, globals.absoluteframetime, globals.tickinterval, math.ceil, math.floor, math.min, math.sqrt, renderer.measure_text, ui.reference, pcall, renderer.gradient, renderer.rectangle, renderer.text, string.format, table.insert, ui.get, ui.new_checkbox, ui.new_color_picker, ui.new_multiselect, ui.new_textbox, ui.set, ui.set_callback, ui.set_visible

local flag, old_renderer_text, old_renderer_measure_text = "d", renderer_text, renderer_measure_text
function renderer_text(x, y, r, g, b, a, flags, max_width, ...)
	return old_renderer_text(x, y, r, g, b, a, flags == nil and flag or flag .. flags, max_width, ...)
end
function renderer_measure_text(flags, ...)
	return old_renderer_measure_text(flags == nil and flag or flag .. flags, ...)
end

local allow_unsafe_scripts = pcall(client.create_interface)

local FLOW_OUTGOING, FLOW_INCOMING = 0, 1
local native_GetNetChannelInfo, GetRemoteFramerate, native_GetTimeSinceLastReceived, native_GetAvgChoke, native_GetAvgLoss, native_IsLoopback, GetAddress

if allow_unsafe_scripts then
	local ffi = require "ffi"

	local function vmt_entry(instance, index, type)
		return ffi.cast(type, (ffi.cast("void***", instance)[0])[index])
	end

	local function vmt_thunk(index, typestring)
		local t = ffi.typeof(typestring)
		return function(instance, ...)
			assert(instance ~= nil)
			if instance then
				return vmt_entry(instance, index, t)(instance, ...)
			end
		end
	end

	local function vmt_bind(module, interface, index, typestring)
		local instance = client.create_interface(module, interface) or error("invalid interface")
		local fnptr = vmt_entry(instance, index, ffi.typeof(typestring)) or error("invalid vtable")
		return function(...)
			return fnptr(instance, ...)
		end
	end

	native_GetNetChannelInfo = vmt_bind("engine.dll", "VEngineClient014", 78, "void*(__thiscall*)(void*)")
	local native_GetName = vmt_thunk(0, "const char*(__thiscall*)(void*)")
	local native_GetAddress = vmt_thunk(1, "const char*(__thiscall*)(void*)")
	native_IsLoopback = vmt_thunk(6, "bool(__thiscall*)(void*)")
	local native_IsTimingOut = vmt_thunk(7, "bool(__thiscall*)(void*)")
	native_GetAvgLoss = vmt_thunk(11, "float(__thiscall*)(void*, int)")
	native_GetAvgChoke = vmt_thunk(12, "float(__thiscall*)(void*, int)")
	native_GetTimeSinceLastReceived = vmt_thunk(22, "float(__thiscall*)(void*)")
	local native_GetRemoteFramerate = vmt_thunk(25, "void(__thiscall*)(void*, float*, float*, float*)")
	local native_GetTimeoutSeconds = vmt_thunk(26, "float(__thiscall*)(void*)")

	local pflFrameTime = ffi.new("float[1]")
	local pflFrameTimeStdDeviation = ffi.new("float[1]")
	local pflFrameStartTimeStdDeviation = ffi.new("float[1]")

	function GetRemoteFramerate(netchannelinfo)
		native_GetRemoteFramerate(netchannelinfo, pflFrameTime, pflFrameTimeStdDeviation, pflFrameStartTimeStdDeviation)
		if pflFrameTime ~= nil and pflFrameTimeStdDeviation ~= nil and pflFrameStartTimeStdDeviation ~= nil then
			return pflFrameTime[0], pflFrameTimeStdDeviation[0], pflFrameStartTimeStdDeviation[0]
		end
	end

	function GetAddress(netchannelinfo)
		local addr = native_GetAddress(netchannelinfo)
		if addr ~= nil then
			return ffi.string(addr)
		end
	end

	local function GetName(netchannelinfo)
		local name = native_GetName(netchannelinfo)
		if name ~= nil then
			return ffi.string(name)
		end
	end
end

local cvar_game_mode, cvar_game_type, cvar_fps_max, cvar_fps_max_menu = cvar.game_mode, cvar.game_type, cvar.fps_max, cvar.fps_max_menu
local table_clear = require "table.clear"

-- initialize window
local window = ((function() local a={}local b,c,d,e,f=renderer.rectangle,renderer.gradient,renderer.texture,math.floor,math.ceil;local function g(h,i,j,k,l,m,n,o,p)p=p or 1;b(h,i,j,p,l,m,n,o)b(h,i+k-p,j,p,l,m,n,o)b(h,i+p,p,k-p*2,l,m,n,o)b(h+j-p,i+p,p,k-p*2,l,m,n,o)end;local function q(h,i,j,k,r,s,t,u,v,w,x,y,z,p)p=p or 1;if z then b(h,i,p,k,r,s,t,u)b(h+j-p,i,p,k,v,w,x,y)c(h+p,i,j-p*2,p,r,s,t,u,v,w,x,u,true)c(h+p,i+k-p,j-p*2,p,r,s,t,u,v,w,x,u,true)else b(h,i,j,p,r,s,t,u)b(h,i+k-p,j,p,v,w,x,y)c(h,i+p,p,k-p*2,r,s,t,u,v,w,x,y,false)c(h+j-p,i+p,p,k-p*2,r,s,t,u,v,w,x,y,false)end end;local A;do local B="\x14\x14\x14\xFF"local C="\x0c\x0c\x0c\xFF"A=renderer.load_rgba(table.concat({B,B,B,C,B,C,B,C,B,C,B,B,B,C,B,C}),4,4)end;local function D(E,F)if F~=nil and type(E)=="string"and E:sub(-1,-1)=="%"then E=math.floor(tonumber(E:sub(1,-2))/100*F)end;return E end;local function G(H)if H.position=="fixed"then local I,J=client.screen_size()if H.left~=nil then H.x=D(H.left,I)elseif H.right~=nil then H.x=I-(H.w or 0)-D(H.right,I)end;if H.top~=nil then H.y=D(H.top,J)elseif H.bottom~=nil then H.y=J-(H.h or 0)-D(H.bottom,J)end end;local h,i,j,k,o=H.x,H.y,H.w,H.h,H.a or 255;local K=1;if h==nil or i==nil or j==nil or o==nil then return end;H.i_x,H.i_y,H.i_w,H.i_h=H.x,H.y,H.w,H.h;if H.title_bar then K=(H.title~=nil and select(2,renderer.measure_text(H.title_text_size,H.title))or 13)+2;H.t_x,H.t_y,H.t_w,H.t_h=H.x,H.y,H.w,K end;if H.border then g(h,i,j,k,18,18,18,o)g(h+1,i+1,j-2,k-2,62,62,62,o)g(h+2,i+K+1,j-4,k-K-3,44,44,44,o,H.border_width)g(h+H.border_width+2,i+K+H.border_width+1,j-H.border_width*2-4,k-K-H.border_width*2-3,62,62,62,o)H.i_x=H.i_x+H.border_width+3;H.i_y=H.i_y+H.border_width+3;H.i_w=H.i_w-(H.border_width+3)*2;H.i_h=H.i_h-(H.border_width+3)*2;H.t_x,H.t_y,H.t_w=H.x+2,H.y+2,H.w-4;K=K-1 end;if K>1 then c(H.t_x,H.t_y,H.t_w,K,56,56,56,o,44,44,44,o,false)if H.title~=nil then local l,m,n,o=unpack(H.title_text_color)o=o*H.a/255;renderer.text(H.t_x+3,H.t_y+2,l or 255,m or 255,n or 255,o or 255,(H.title_text_size or"")..(H.title_text_flags or""),0,tostring(H.title))end;H.i_y=H.i_y+K;H.i_h=H.i_h-K end;if H.gradient_bar then local L=0;if H.background then L=1;local M,N=16,25;b(H.i_x+1,H.i_y,H.i_w-2,1,M,M,M,o)b(H.i_x+1,H.i_y+3,H.i_w-2,1,N,N,N,o)for O=0,1 do c(H.i_x+(H.i_w-1)*O,H.i_y,1,4,M,M,M,o,N,N,N,o,false)end end;do local h,i,P=H.i_x+L,H.i_y+L,1;local Q,R=e((H.i_w-L*2)/2),f((H.i_w-L*2)/2)for O=1,2 do c(h,i,Q,1,59*P,175*P,222*P,o,202*P,70*P,205*P,o,true)c(h+Q,i,R,1,202*P,70*P,205*P,o,201*P,227*P,58*P,o,true)i,P=i+1,P*0.5 end end;H.i_y=H.i_y+2+L*2;H.i_h=H.i_h-2-L*2 end;if H.background then d(A,H.i_x,H.i_y,H.i_w,H.i_h,255,255,255,255,"t")end;if H.draggable then local p=7;renderer.triangle(h+j-1,i+k-p,h+j-1,i+k-1,h+j-p,i+k-1,62,62,62,o)end;H.i_x=H.i_x+H.margin_left;H.i_w=H.i_w-H.margin_left-H.margin_right;H.i_y=H.i_y+H.margin_top;H.i_h=H.i_h-H.margin_top-H.margin_bottom end;local S={}local T={}local U={}local V={__index=U}function U:set_active(W)if W then S[self.id]=self;table.insert(T,1,self.id)else S[self.id]=nil end end;function U:set_z_index(X)self.z_index=X;self.z_index_reset=true end;function U:is_in_window(h,i)return h>=self.x and h<=self.x+self.w and i>=self.y and i<=self.y+self.h end;function U:set_inner_width(Y)if self.border then Y=Y+(self.border_width+3)*2 end;Y=Y+self.margin_left+self.margin_right;self.w=Y end;function U:set_inner_height(Z)local K=1;if self.title_bar then K=(self.title~=nil and select(2,renderer.measure_text(self.title_text_size,self.title))or 13)+2 end;if self.border then Z=Z+(self.border_width+3)*2;K=K-1 end;if K>1 then Z=Z+K end;if self.gradient_bar then local L=0;if self.background then L=1 end;Z=Z+2+L*2 end;Z=Z+self.margin_top+self.margin_bottom;self.h=Z end;function a.new(_,h,i,j,k,a0)local H=setmetatable({id=_,top=h,left=i,w=j,h=k,a=255,paint_callback=a0,title_bar=true,title_bar_in_menu=false,title_text_color={255,255,255,255},title_text_size=nil,gradient_bar=true,border=true,border_width=3,background=true,first=true,visible=true,margin_top=0,margin_bottom=0,margin_left=0,margin_right=0,position="fixed",draggable=false,draggable_save=false,in_menu=false},V)H:set_active(true)return H end;local a1,a2,a3;local function a4(a5)local a6={"bottom","unset","top"}local a7={}for O=#T,1,-1 do local H=S[T[O]]if H~=nil then local a8=H.z_index or"unset"if H.z_index_reset then H.z_index=nil;H.z_index_reset=nil end;a7[a8]=a7[a8]or{}if H.first then table.insert(a7[a8],1,H.id)H.first=nil else table.insert(a7[a8],H.id)end end end;T={}for O=1,#a6 do local a9=a7[a6[O]]if a9~=nil then for O=#a9,1,-1 do table.insert(T,a9[O])end end end;local aa=ui.is_menu_open()local ab={}for O=1,#T do local H=S[T[O]]if H~=nil and H.in_menu==a5 then if H.title_bar_in_menu then H.title_bar=aa end;if H.pre_paint_callback~=nil then H:pre_paint_callback()end;if S[H.id]~=nil then table.insert(ab,S[H.id])end end end;if aa then local ac,ad=ui.mouse_position()local ae=client.key_state(0x01)if ae then for O=#ab,1,-1 do local H=ab[O]if H.visible and H:is_in_window(a1,a2)then H.first=true;if a3 then local af,ag=ac-a1,ad-a2;if H.position=="fixed"then local ah=H.left==nil and"right"or"left"local ai=H.top==nil and"bottom"or"top"local aj={{ah,(ah=="right"and-1 or 1)*af},{ai,(ai=="bottom"and-1 or 1)*ag}}for O=1,#aj do local ak,al=unpack(aj[O])local am=type(H[ak])if am=="string"and H[ak]:sub(-1,-1)=="%"then elseif am=="number"then H[ak]=H[ak]+al end end else H.x=H.x+af;H.y=H.y+ag end end;break end end end;a1,a2=ac,ad;a3=ae end;for O=1,#ab do local H=ab[O]if H.visible and H.in_menu==a5 then G(H)if H.paint_callback~=nil then H:paint_callback()end end end end;local a1,a2,a3;client.delay_call(0,client.set_event_callback,"paint",function()a4(false)end)client.delay_call(0,client.set_event_callback,"paint_ui",function()a4(true)end)return a end)()).new("watermark")
window.title = "[RAFETTO] Watermark"
window.title_bar = false
window.margin_bottom = 2
window.margin_left = 3
window.margin_right = 3
window.border_width = 2
window.top = 15
window.right = 15
window.in_menu = true

-- custom name
local db = database.read("sapphyrus_watermark") or {}

--local pingspike_reference = ui_reference("MISC", "Miscellaneous", "Ping spike")
local antiut_reference = ui_reference("MISC", "Settings", "Anti-untrusted")
local is_beta = pcall(ui_reference, "MISC", "Settings", "Crash logs")

local names = {"Logo", "", "FPS", "Ping", "", "", "", "", "", "", "", "", "Time + seconds"}

local watermark_reference = ui_new_multiselect("RAGE", "Aimbot", "[RAFETTO] Watermark ", names)
local color_reference = ui_new_color_picker("RAGE", "Aimbot", "[RAFETTO] Watermark", 149, 184, 6, 255)
local custom_name_reference = ui_new_textbox("RAGE", "Aimbot", "Watermark name")
local rainbow_header_reference = ui_new_checkbox("RAGE", "Aimbot", "[RAFETTO] Rainbow Watermark")

local fps_prev = 0
local value_prev = {}
local last_update_time = 0

local offset_x, offset_y = -15, 15
--local offset_x, offset_y = 525, 915 --debug, show above net_graph

local function clamp(cur_val, min_val, max_val)
	return math_min(math.max(cur_val, min_val), max_val)
end

local function lerp(a, b, percentage)
	return a + (b - a) * percentage
end

local function table_contains(tbl, val)
	for i=1, #tbl do
		if tbl[i] == val then
			return true
		end
	end
	return false
end

local function table_remove_element(tbl, val)
	local tbl_new = {}
	for i=1, #tbl do
		if tbl[i] ~= val then
			table_insert(tbl_new, tbl[i])
		end
	end
	return tbl_new
end

local function table_lerp(a, b, percentage)
	local result = {}
	for i=1, #a do
		result[i] = lerp(a[i], b[i], percentage)
	end
	return result
end

local function on_watermark_changed()
	local value = ui_get(watermark_reference)

	if #value > 0 then
		--Make Time / Time + seconds act as a kind of "switch", only allow one to be selected at a time.
		if table_contains(value, "Time") and table_contains(value, "Time + seconds") then
			local value_new = value
			if not table_contains(value_prev, "Time") then
				value_new = table_remove_element(value_new, "Time + seconds")
			elseif not table_contains(value_prev, "Time + seconds") then
				value_new = table_remove_element(value_new, "Time")
			end

			--this shouldn't happen, but why not add a failsafe
			if table_contains(value_new, "Time") and table_contains(value_new, "Time + seconds") then
				value_new = table_remove_element(value_new, "Time")
			end

			ui_set(watermark_reference, value_new)
			on_watermark_changed()
			return
		end
	end
	ui_set_visible(custom_name_reference, table_contains(value, "Custom text"))
	ui_set_visible(rainbow_header_reference, #value > 0)

	value_prev = value
end
ui_set_callback(watermark_reference, on_watermark_changed)
on_watermark_changed()

local function round(num, numDecimalPlaces)
	local mult = 10^(numDecimalPlaces or 0)
	return math_floor(num * mult + 0.5) / mult
end

local ft_prev = 0
local function get_fps()
	ft_prev = ft_prev * 0.9 + globals_absoluteframetime() * 0.1
	return round(1 / ft_prev)
end

local function lerp_color_yellow_red(val, max_normal, max_yellow, max_red, default, yellow, red)
	default = default or {255, 255, 255}
	yellow = yellow or {230, 210, 40}
	red = red or {255, 32, 32}
	if val > max_yellow then
		return unpack(table_lerp(yellow, red, clamp((val-max_yellow)/(max_red-max_yellow), 0, 1)))
	else
		return unpack(table_lerp(default, yellow, clamp((val-max_normal)/(max_yellow-max_normal), 0, 1)))
	end
end

local watermark_items = {
	{
		--gamesense logo
		name = "Logo",
		get_width = function(self, frame_data)
			self.game_width = renderer_measure_text(nil, "rafettohook")
			self.sense_width = renderer_measure_text(nil, "")
			self.beta_width = (is_beta and (renderer_measure_text(nil, " [beta]")) or 0)
			return self.game_width + self.sense_width + self.beta_width
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			local r_sense, g_sense, b_sense = ui_get(color_reference)

			renderer_text(x, y, 255, 255, 255, a, nil, 0, "rafettohook")
			renderer_text(x+self.game_width, y, r_sense, g_sense, b_sense, a, nil, 0, "")
			if is_beta then
				renderer_text(x+self.game_width+self.sense_width, y, 255, 255, 255, a*0.9, nil, 0, " [beta]")
			end
		end
	},
	{
		name = "Custom text",
		get_width = function(self, frame_data)
			local edit = ui_get(custom_name_reference)
			if edit ~= self.edit_prev and self.edit_prev ~= nil then
				db.custom_name = edit
			elseif edit == "" and db.custom_name ~= nil then
				ui_set(custom_name_reference, db.custom_name)
			end
			self.edit_prev = edit

			local text = db.custom_name
			if text ~= nil and text:gsub(" ", "") ~= "" then
				self.text = text
				return renderer_measure_text(nil, text)
			else
				self.text = nil
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			-- local r_sense, g_sense, b_sense = ui_get(color_reference)
			renderer_text(x, y, r, g, b, a, nil, 0, self.text)
		end
	},
	{
		name = "FPS",
		get_width = function(self, frame_data)
			self.fps = get_fps()
			self.text = tostring(self.fps or 0) .. " fps"

			local fps_max, fps_max_menu = cvar_fps_max:get_float(), cvar_fps_max_menu:get_float()
			local fps_max = globals.mapname() == nil and math.min(fps_max == 0 and 999 or fps_max, fps_max_menu == 0 and 999 or fps_max) or fps_max == 0 and 999 or fps_max

			self.width = math.max(renderer_measure_text(nil, self.text), renderer_measure_text(nil, fps_max .. " fps"))
			return self.width
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			--fps
			local fps_r, fps_g, fps_b = r, g, b
			if self.fps < (1 / globals_tickinterval()) then
				-- fps_r, fps_g, fps_b = 255, 0, 0
			end

			renderer_text(x+self.width, y, fps_r, fps_g, fps_b, a, "r", 0, self.text)
		end
	},
	{
		name = "Ping",
		get_width = function(self, frame_data)
			local ping = client_latency()
			if ping > 0 then
				self.ping = ping
				self.text = round(self.ping*1000, 0) .. "ms"
				self.width = math.max(renderer_measure_text(nil, "999ms"), renderer_measure_text(nil, self.text))
				return self.width
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			if self.ping > 0.15 then
				r, g, b = 255, 0, 0
			end
			renderer_text(x+self.width, y, r, g, b, a, "r", 0, self.text)
		end
	},
	{
		name = "KDR",
		get_width = function(self, frame_data)
			frame_data.local_player = frame_data.local_player or entity.get_local_player()
			if frame_data.local_player == nil then return end

			local player_resource = entity_get_player_resource()
			if player_resource == nil then return end

			self.kills = entity_get_prop(player_resource, "m_iKills", frame_data.local_player)
			self.deaths = math.max(entity_get_prop(player_resource, "m_iDeaths", frame_data.local_player), 1)

			self.kdr = self.kills/self.deaths

			if self.kdr ~= 0 then
				self.text = string.format("%1.1f", round(self.kdr, 1))
				self.text_width = math.max(renderer_measure_text(nil, "10.0"), renderer_measure_text(nil, self.text))
				self.unit_width = renderer_measure_text("-", "kdr")
				return self.text_width+self.unit_width
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			renderer_text(x+self.text_width, y, r, g, b, a, "r", 0, self.text)
			renderer_text(x+self.text_width+self.unit_width, y+2, 255, 255, 255, a*0.75, "r-", 0, "kdr")
		end
	},
	{
		name = "Velocity",
		get_width = function(self, frame_data)
			frame_data.local_player = frame_data.local_player or entity.get_local_player()
			if frame_data.local_player == nil then return end

			local vel_x, vel_y = entity_get_prop(frame_data.local_player, "m_vecVelocity")
			if vel_x ~= nil then
				self.velocity = math_sqrt(vel_x*vel_x + vel_y*vel_y)

				self.vel_width = renderer_measure_text(nil, "9999")
				self.unit_width = renderer_measure_text("-", "vel")
				return self.vel_width+self.unit_width
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			local velocity = self.velocity
			-- velocity = string.rep(round(globals.realtime() % 9, 0), 4)
			velocity = math_min(9999, velocity) + 0.4
			velocity = round(velocity, 0)

			renderer_text(x+self.vel_width, y, 255, 255, 255, a, "r", 0, velocity)
			renderer_text(x+self.vel_width+self.unit_width, y+3, 255, 255, 255, a*0.75, "r-", 0, "vel")
		end
	},
	{
		name = "Server framerate",
		get_width = function(self, frame_data)
			if not allow_unsafe_scripts then return end

			frame_data.local_player = frame_data.local_player or entity.get_local_player()
			if frame_data.local_player == nil then return end

			frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
			if frame_data.net_channel_info == nil then return end

			local frame_time, frame_time_std_dev, frame_time_start_time_std_dev = GetRemoteFramerate(frame_data.net_channel_info)
			if frame_time ~= nil then
				self.framerate = frame_time * 1000
				self.var = frame_time_std_dev * 1000

				self.text1 = "sv:"
				self.text2 = string.format("%.1f", self.framerate)
				self.text3 = " +-"
				self.text4 = string.format("%.1f", self.var)

				self.width1 = renderer_measure_text(nil, self.text1)
				self.width2 = math.max(renderer_measure_text(nil, self.text2), renderer_measure_text(nil, "99.9"))
				self.width3 = renderer_measure_text(nil, self.text3)
				self.width4 = math.max(renderer_measure_text(nil, self.text4), renderer_measure_text(nil, "9.9"))

				return self.width1 + self.width2 + self.width3 + self.width4
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			local fr_r, fr_g, fr_b = lerp_color_yellow_red(self.framerate, 8, 14, 20, {r, g, b})
			local vr_r, vr_g, vr_b = lerp_color_yellow_red(self.var, 5, 10, 18, {r, g, b})

			renderer_text(x, y, r, g, b, a, nil, 0, self.text1)
			renderer_text(x+self.width1+self.width2, y, fr_r, fr_g, fr_b, a, "r", 0, self.text2)
			renderer_text(x+self.width1+self.width2, y, r, g, b, a, nil, 0, self.text3)
			renderer_text(x+self.width1+self.width2+self.width3, y, vr_r, vr_g, vr_b, a, nil, 0, self.text4)
		end
	},
	{
		name = "Network lag",
		get_width = function(self, frame_data)
			if not allow_unsafe_scripts then return end

			frame_data.local_player = frame_data.local_player or entity.get_local_player()
			if frame_data.local_player == nil then return end

			frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
			if frame_data.net_channel_info == nil then return end

			local reasons = {}

			-- timeout
			local time_since_last_received = native_GetTimeSinceLastReceived(frame_data.net_channel_info)
			if time_since_last_received ~= nil and time_since_last_received > 0.1 then
				table_insert(reasons, string_format("%.1fs timeout", time_since_last_received))
			end

			-- loss
			local avg_loss = native_GetAvgLoss(frame_data.net_channel_info, FLOW_INCOMING)
			if avg_loss ~= nil and avg_loss > 0 then
				table_insert(reasons, string_format("%d%% loss", math.ceil(avg_loss*100)))
			end

			-- choke
			local avg_choke = native_GetAvgChoke(frame_data.net_channel_info, FLOW_INCOMING)
			if avg_choke > 0 then
				table_insert(reasons, string_format("%d%% choke", math.ceil(avg_choke*100)))
			end

			if #reasons > 0 then
				self.text = table.concat(reasons, ", ")
				return renderer_measure_text(nil, self.text)
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			renderer_text(x, y, 255, 32, 32, a, nil, 0, self.text)
		end
	},
	{
		name = "Server info",
		get_width = function(self, frame_data)
			if not allow_unsafe_scripts then return end

			frame_data.local_player = frame_data.local_player or entity.get_local_player()
			if frame_data.local_player == nil then return end

			frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
			if frame_data.net_channel_info == nil then return end
			frame_data.is_loopback = frame_data.is_loopback == nil and native_IsLoopback(frame_data.net_channel_info) or frame_data.is_loopback

			local game_rules = entity.get_game_rules()
			frame_data.is_valve_ds = frame_data.is_valve_ds == nil and entity.get_prop(game_rules, "m_bIsValveDS") == 1 or frame_data.is_valve_ds

			local text
			if frame_data.is_loopback then
				text = "Local server"
			elseif frame_data.is_valve_ds then
				local game_mode_name
				local game_mode, game_type = cvar_game_mode:get_int(), cvar_game_type:get_int()

				local is_queued_matchmaking = entity.get_prop(game_rules, "m_bIsQueuedMatchmaking") == 1

				if is_queued_matchmaking then
					if game_type == 0 and game_mode == 1 then
						game_mode_name = "MM"
					elseif game_type == 0 and game_mode == 2 then
						game_mode_name = "Wingman"
					elseif game_type == 3 then
						game_mode_name = "Custom"
					elseif game_type == 4 and game_mode == 0 then
						game_mode_name = "Guardian"
					elseif game_type == 4 and game_mode == 1 then
						game_mode_name = "Co-op Strike"
					elseif game_type == 6 and game_mode == 0 then
						game_mode_name = "Danger Zone"
					end
				else
					if game_type == 0 and game_mode == 0 then
						game_mode_name = "Casual"
					elseif game_type == 1 and game_mode == 0 then
						game_mode_name = "Arms Race"
					elseif game_type == 1 and game_mode == 1 then
						game_mode_name = "Demolition"
					elseif game_type == 1 and game_mode == 2 then
						game_mode_name = "Deathmatch"
					end
				end

				if game_mode_name ~= nil then
					text = "Valve (" .. game_mode_name .. ")"
				else
					text = "Valve"
				end
			end

			if text ~= nil then
				self.text = text
				return renderer_measure_text(nil, text)
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			renderer_text(x, y, 255, 255, 255, a, nil, 0, self.text)
		end
	},
	{
		name = "Server IP",
		get_width = function(self, frame_data)
			if not allow_unsafe_scripts then return end

			frame_data.net_channel_info = frame_data.net_channel_info or native_GetNetChannelInfo()
			if frame_data.net_channel_info == nil then return end

			frame_data.is_loopback = frame_data.is_loopback == nil and native_IsLoopback(frame_data.net_channel_info) or frame_data.is_loopback
			if frame_data.is_loopback then return end

			frame_data.is_valve_ds = frame_data.is_valve_ds == nil and entity.get_prop(entity.get_game_rules(), "m_bIsValveDS") == 1 or frame_data.is_valve_ds
			if frame_data.is_valve_ds then return end

			frame_data.server_address = frame_data.server_address or GetAddress(frame_data.net_channel_info)
			if frame_data.server_address ~= nil and frame_data.server_address ~= "" then
				self.text = frame_data.server_address
				return renderer_measure_text(nil, self.text)
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			renderer_text(x, y, 255, 255, 255, a, nil, 0, self.text)
		end
	},
	{
		name = "Tickrate",
		get_width = function(self, frame_data)
			if globals.mapname() == nil then return end

			local tickinterval = globals_tickinterval()
			if tickinterval ~= nil then
				local text = 1/globals_tickinterval() .. " tick"
				self.text = text
				return renderer_measure_text(nil, text)
			end
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			renderer_text(x, y, 255, 255, 255, a, nil, 0, self.text)
		end
	},
	{
		name = "Time",
		get_width = function(self, frame_data)
			self.time_width = renderer_measure_text(nil, "00")
			self.sep_width = renderer_measure_text(nil, ":")
			return self.time_width + self.sep_width + self.time_width + (self.seconds and (self.sep_width + self.time_width) or 0)
		end,
		draw = function(self, x, y, w, h, r, g, b, a)
			-- local time_center = x + 16

			local hours, minutes, seconds, milliseconds = client_system_time()
			hours, minutes = string_format("%02d", hours), string_format("%02d", minutes)
			-- renderer_text(time_center, y, 255, 255, 255, a, "r", 0, hours)
			-- renderer_text(time_center, y, 255, 255, 255, a, "", 0, ":")
			-- renderer_text(time_center+4, y, 255, 255, 255, a, "", 0, minutes)

			-- time_center = time_center + 18

			-- if self.seconds then
			-- 	seconds = string_format("%02d", seconds)
			-- 	renderer_text(time_center, y, 255, 255, 255, a, "", 0, ":")
			-- 	renderer_text(time_center+4, y, 255, 255, 255, a, "", 0, seconds)
			-- end

			renderer_text(x, y, 255, 255, 255, a, "", 0, hours)
			renderer_text(x+self.time_width, y, 255, 255, 255, a, "", 0, ":")
			renderer_text(x+self.time_width+self.sep_width, y, 255, 255, 255, a, "", 0, minutes)

			if self.seconds then
				seconds = string_format("%02d", seconds)
				renderer_text(x+self.time_width*2+self.sep_width, y, 255, 255, 255, a, "", 0, ":")
				renderer_text(x+self.time_width*2+self.sep_width*2, y, 255, 255, 255, a, "", 0, seconds)
			end

		end,
		seconds = false
	},
}

local items_drawn = {}
window.pre_paint_callback = function()
	table_clear(items_drawn)
	local value = ui_get(watermark_reference)

	if table_contains(value, "Custom text") then
		value = table_remove_element(value, "Custom text")
		if table_contains(value, "Logo") then
			table_insert(value, 2, "Custom text")
		else
			table_insert(value, 1, "Custom text")
		end
	end

	local screen_width, screen_height = client_screen_size()
	local x = offset_x >= 0 and offset_x or screen_width + offset_x
	local y = offset_y >= 0 and offset_y or screen_height + offset_y

	for i=1, #watermark_items do
		local item = watermark_items[i]
		if item.name == "Time" then
			item.seconds = table_contains(value, "Time + seconds")

			if item.seconds then
				table_insert(value, "Time")
			end
		end
	end

	--calculate width and draw container
	local item_margin = 9
	local width = 0

	local frame_data = {}

	for i=1, #watermark_items do
		local item = watermark_items[i]
		if table_contains(value, item.name) then
			local item_width = item:get_width(frame_data)
			if item_width ~= nil and item_width > 0 then
				table.insert(items_drawn, {
					item = item,
					item_width = item_width,
					x = width
				})
				width = width + item_width + item_margin
			end
		end
	end

	local _, height = renderer_measure_text(nil, "A")

	window.gradient_bar = ui_get(rainbow_header_reference)

	window:set_inner_width(width-item_margin)
	window:set_inner_height(height)

	window.visible = #items_drawn > 0
end

window.paint_callback = function()
	local r, g, b = 255, 255, 255
	local a_text = 230
	for i=1, #items_drawn do
		local item = items_drawn[i]

		-- bounding box
		-- renderer_rectangle(x_text+item.x, y_text, item.item_width, 14, 255, 0, 0, 100)

		-- draw item
		item.item:draw(window.i_x+item.x, window.i_y, item.item_width, 30, r, g, b, a_text)

		-- draw seperator
		if #items_drawn > i then
			renderer.rectangle(window.i_x+item.x+item.item_width+4, window.i_y+1, 1, window.i_h-1, 210, 210, 210, 255)
		end
	end
end

client.set_event_callback("shutdown", function()
	database.write("sapphyrus_watermark", db)
end)
local globals_frametime = globals.frametime
local globals_tickinterval = globals.tickinterval
local entity_is_enemy = entity.is_enemy
local entity_get_prop = entity.get_prop
local entity_is_dormant = entity.is_dormant
local entity_is_alive = entity.is_alive
local entity_get_origin = entity.get_origin
local entity_get_local_player = entity.get_local_player
local entity_get_player_resource = entity.get_player_resource
local table_insert = table.insert
local math_floor = math.floor

local vector = require 'vector'

local master_switch = ui.new_checkbox('RAGE', 'Aimbot', '[RAFETTO] Aimbot Log')
local master_switch_hitboxes = ui.new_checkbox('RAGE', 'Aimbot', '[RAFETTO] Aimbot Shot Hitbox')
local hitboxes_color = ui.new_color_picker('RAGE', 'Aimbot', '[RAFETTO] Aimbot Shot Hitbox Color', 255, 0, 0, 65)
local hitboxes_time = ui.new_slider('RAGE', 'Aimbot', '\n Shots hitboxes time', 5, 200, 20, true, 's', 0.1)
local force_safe_point = ui.reference('RAGE', 'Aimbot', 'Force safe point')

local time_to_ticks = function(t) return math_floor(0.5 + (t / globals_tickinterval())) end
local vec_substract = function(a, b) return { a[1] - b[1], a[2] - b[2], a[3] - b[3] } end
local vec_lenght = function(x, y) return (x * x + y * y) end

local g_impact = { }
local g_aimbot_data = { }
local g_sim_ticks, g_net_data = { }, { }

local cl_data = {
    tick_shifted = false,
    tick_base = 0
}

local float_to_int = function(n) 
	return n >= 0 and math.floor(n+.5) or math.ceil(n-.5)
end

local get_entities = function(enemy_only, alive_only)
    local enemy_only = enemy_only ~= nil and enemy_only or false
    local alive_only = alive_only ~= nil and alive_only or true
    
    local result = {}
    local player_resource = entity_get_player_resource()
    
    for player = 1, globals.maxplayers() do
        local is_enemy, is_alive = true, true
        
        if enemy_only and not entity_is_enemy(player) then is_enemy = false end
        if is_enemy then
            if alive_only and entity_get_prop(player_resource, 'm_bAlive', player) ~= 1 then is_alive = false end
            if is_alive then table_insert(result, player) end
        end
    end

    return result
end

local generate_flags = function(e, on_fire_data)
    return {
		e.refined and 'R' or '',
		e.expired and 'X' or '',
		e.noaccept and 'N' or '',
		cl_data.tick_shifted and 'S' or '',
		on_fire_data.teleported and 'T' or '',
		on_fire_data.interpolated and 'I' or '',
		on_fire_data.extrapolated and 'E' or '',
		on_fire_data.boosted and 'B' or '',
		on_fire_data.high_priority and 'H' or ''
    }
end

local hitgroup_names = { 'generic', 'head', 'chest', 'stomach', 'left arm', 'right arm', 'left leg', 'right leg', 'neck', '?', 'gear' }
local weapon_to_verb = { knife = 'Knifed', hegrenade = 'Naded', inferno = 'Burned' }

--region net_update
local function g_net_update()
	local me = entity_get_local_player()
    local players = get_entities(true, true)
	local m_tick_base = entity_get_prop(me, 'm_nTickBase')
	
    cl_data.tick_shifted = false
    
	if m_tick_base ~= nil then
		if cl_data.tick_base ~= 0 and m_tick_base < cl_data.tick_base then
			cl_data.tick_shifted = true
		end
	
		cl_data.tick_base = m_tick_base
    end

	for i=1, #players do
		local idx = players[i]
        local prev_tick = g_sim_ticks[idx]
        
        if entity_is_dormant(idx) or not entity_is_alive(idx) then
            g_sim_ticks[idx] = nil
            g_net_data[idx] = nil
        else
            local player_origin = { entity_get_origin(idx) }
            local simulation_time = time_to_ticks(entity_get_prop(idx, 'm_flSimulationTime'))
    
            if prev_tick ~= nil then
                local delta = simulation_time - prev_tick.tick

                if delta < 0 or delta > 0 and delta <= 64 then
                    local m_fFlags = entity_get_prop(idx, 'm_fFlags')

                    local diff_origin = vec_substract(player_origin, prev_tick.origin)
                    local teleport_distance = vec_lenght(diff_origin[1], diff_origin[2])

                    g_net_data[idx] = {
                        tick = delta-1,

                        origin = player_origin,
                        tickbase = delta < 0,
                        lagcomp = teleport_distance > 4096,
                    }
                end
            end

            g_sim_ticks[idx] = {
                tick = simulation_time,
                origin = player_origin,
            }
        end
    end
end
--endregion

local function g_aim_fire(e)
    local data = e

    if ui.get(master_switch_hitboxes) then
        local r, g, b, a = ui.get(hitboxes_color)

        client.draw_hitboxes(e.target, ui.get(hitboxes_time)/10, 19, r, g, b, a, e.tick)
    end

    local plist_sp = plist.get(e.target, 'Override safe point')
    local plist_fa = plist.get(e.target, 'Correction active')
    local checkbox = ui.get(force_safe_point)

    if g_net_data[e.target] == nil then
        g_net_data[e.target] = { }
    end

    data.tick = e.tick

    data.eye = vector(client.eye_position)
    data.shot = vector(e.x, e.y, e.z)

    data.teleported = g_net_data[e.target].lagcomp or false
    data.choke = g_net_data[e.target].tick or '?'
    data.self_choke = globals.chokedcommands()
    data.correction = plist_fa and 1 or 0
    data.safe_point = ({
        ['Off'] = 'off',
        ['On'] = true,
        ['-'] = checkbox
    })[plist_sp]

    g_aimbot_data[e.id] = data
end

local function g_aim_hit(e)
    if not ui.get(master_switch) or g_aimbot_data[e.id] == nil then
        return
    end

    local on_fire_data = g_aimbot_data[e.id]
	local name = string.lower(entity.get_player_name(e.target))
	local hgroup = hitgroup_names[e.hitgroup + 1] or '?'
    local aimed_hgroup = hitgroup_names[on_fire_data.hitgroup + 1] or '?'
    
    local hitchance = math_floor(on_fire_data.hit_chance + 0.5) .. '%'
    local health = entity_get_prop(e.target, 'm_iHealth')

    local flags = generate_flags(e, on_fire_data)

    print(string.format(
        '[%d] [%d/%d] Hit %s\'s %s for %i(%d) (%i remaining) aimed=%s(%s) sp=%s (%s) LC=%s TC=%s', 
        e.id, on_fire_data.tick%1000, globals.tickcount()%1000, name, hgroup, e.damage, on_fire_data.damage, health, aimed_hgroup, hitchance, on_fire_data.safe_point,
        table.concat(flags), on_fire_data.self_choke, on_fire_data.choke
    ))
end

local function g_aim_miss(e)
    if not ui.get(master_switch) or g_aimbot_data[e.id] == nil then
        return
    end

    local on_fire_data = g_aimbot_data[e.id]
    local name = string.lower(entity.get_player_name(e.target))

	local hgroup = hitgroup_names[e.hitgroup + 1] or '?'
    local hitchance = math_floor(on_fire_data.hit_chance + 0.5) .. '%'

    local flags = generate_flags(e, on_fire_data)
    local reason = e.reason == '?' and 'unknown' or e.reason

    local inaccuracy = 0
    for i=#g_impact, 1, -1 do
        local impact = g_impact[i]

        if impact and impact.tick == globals.tickcount() then
            local aim, shot = 
                (impact.origin-on_fire_data.shot):angles(),
                (impact.origin-impact.shot):angles()

            inaccuracy = vector(aim-shot):length2d()
            break
        end
    end

    print(string.format(
        '[%d] [%d/%d] Missed %s\'s %s(%i)(%s) due to %s:%.2f°, sp=%s (%s) LC=%s TC=%s', 
        e.id, on_fire_data.tick%1000, globals.tickcount()%1000, name, hgroup, on_fire_data.damage, hitchance, reason, inaccuracy, on_fire_data.safe_point, 
        table.concat(flags), on_fire_data.self_choke, on_fire_data.choke
    ))
end

local function g_player_hurt(e)
    local attacker_id = client.userid_to_entindex(e.attacker)
	
    if not ui.get(master_switch) or attacker_id == nil or attacker_id ~= entity.get_local_player() then
        return
    end

    local group = hitgroup_names[e.hitgroup + 1] or "?"
	
    if group == "generic" and weapon_to_verb[e.weapon] ~= nil then
        local target_id = client.userid_to_entindex(e.userid)
		local target_name = entity.get_player_name(target_id)

		print(string.format("%s %s for %i damage (%i remaining)", weapon_to_verb[e.weapon], string.lower(target_name), e.dmg_health, e.health))
	end
end

local function g_bullet_impact(e)
    local tick = globals.tickcount()
    local me = entity.get_local_player()
    local user = client.userid_to_entindex(e.userid)
    
    if user ~= me then
        return
    end

    if #g_impact > 150 and g_impact[#g_impact].tick ~= tick then
        g_impact = { }
    end

    g_impact[#g_impact+1] = 
    {
        tick = tick,
        origin = vector(client.eye_position()), 
        shot = vector(e.x, e.y, e.z)
    }
end

client.set_event_callback('aim_fire', g_aim_fire)
client.set_event_callback('aim_hit', g_aim_hit)
client.set_event_callback('aim_miss', g_aim_miss)
client.set_event_callback('net_update_end', g_net_update)

client.set_event_callback('player_hurt', g_player_hurt)
client.set_event_callback('bullet_impact', g_bullet_impact)


 
by

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