--author cosmo forked by nightaiga local ffi = require "ffi" local imgui = require "mimgui" local se = require "samp.events" local inicfg = require "inicfg" local cfg = inicfg.load({ settings = { x = 0, y = 0, } }, '..\\config\\key_sync.ini') local target = -1 local keys = { ["onfoot"] = {}, ["vehicle"] = {} } function main() if not isSampLoaded() then return end repeat wait(0) until isSampAvailable() wait(-1) end function se.onSendSpawn() target = -1 end function se.onSpectatePlayer(playerid, camType) target = select(2, sampGetCharHandleBySampPlayerId(playerid)) end function se.onPlayerSync(playerId, data) local result, id = sampGetPlayerIdByCharHandle(target) if result and id == playerId then keys["onfoot"] = {} keys["onfoot"]["W"] = (data.upDownKeys == 65408) or nil keys["onfoot"]["A"] = (data.leftRightKeys == 65408) or nil keys["onfoot"]["S"] = (data.upDownKeys == 00128) or nil keys["onfoot"]["D"] = (data.leftRightKeys == 00128) or nil keys["onfoot"]["Alt"] = (bit.band(data.keysData, 1024) == 1024) or nil keys["onfoot"]["Shift"] = (bit.band(data.keysData, 8) == 8) or nil keys["onfoot"]["Space"] = (bit.band(data.keysData, 32) == 32) or nil keys["onfoot"]["F"] = (bit.band(data.keysData, 16) == 16) or nil keys["onfoot"]["C"] = (bit.band(data.keysData, 2) == 2) or nil keys["onfoot"]["RKM"] = (bit.band(data.keysData, 4) == 4) or nil keys["onfoot"]["LKM"] = (bit.band(data.keysData, 128) == 128) or nil end end function se.onVehicleSync(playerId, vehicleId, data) local result, id = sampGetPlayerIdByCharHandle(target) if result and id == playerId then keys["vehicle"] = {} keys["vehicle"]["W"] = (bit.band(data.keysData, 8) == 8) or nil keys["vehicle"]["A"] = (data.leftRightKeys == 65408) or nil keys["vehicle"]["S"] = (bit.band(data.keysData, 32) == 32) or nil keys["vehicle"]["D"] = (data.leftRightKeys == 00128) or nil keys["vehicle"]["H"] = (bit.band(data.keysData, 2) == 2) or nil keys["vehicle"]["Space"] = (bit.band(data.keysData, 128) == 128) or nil keys["vehicle"]["Ctrl"] = (bit.band(data.keysData, 1) == 1) or nil keys["vehicle"]["Alt"] = (bit.band(data.keysData, 4) == 4) or nil keys["vehicle"]["Q"] = (bit.band(data.keysData, 256) == 256) or nil keys["vehicle"]["E"] = (bit.band(data.keysData, 64) == 64) or nil keys["vehicle"]["F"] = (bit.band(data.keysData, 16) == 16) or nil keys["vehicle"]["Up"] = (data.upDownKeys == 65408) or nil keys["vehicle"]["Down"] = (data.upDownKeys == 00128) or nil end end imgui.OnInitialize(function() sW, sH = getScreenResolution() u32 = imgui.ColorConvertFloat4ToU32 imgui.SwitchContext() imgui.GetStyle().WindowPadding = imgui.ImVec2(10, 10) imgui.GetStyle().ItemSpacing = imgui.ImVec2(5, 5) imgui.GetStyle().WindowRounding = 5.0 imgui.GetStyle().Colors[imgui.Col.WindowBg] = imgui.ImVec4(0.16, 0.16, 0.22, 0.50) end) imgui.OnFrame( function() return target ~= -1 end, function(self) self.HideCursor = true imgui.SetNextWindowPos(imgui.ImVec2(cfg.settings.x, cfg.settings.y), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5)) -- sW / 2, sH - 100 imgui.Begin("##KEYS", nil, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.AlwaysAutoResize) local pos = imgui.GetWindowPos() if doesCharExist(target) then local plState = (isCharOnFoot(target) and "onfoot" or "vehicle") imgui.BeginGroup() imgui.SetCursorPosX(10 + 30 + 5) KeyCap("W", (keys[plState]["W"] ~= nil), imgui.ImVec2(30, 30)) KeyCap("A", (keys[plState]["A"] ~= nil), imgui.ImVec2(30, 30)); imgui.SameLine() KeyCap("S", (keys[plState]["S"] ~= nil), imgui.ImVec2(30, 30)); imgui.SameLine() KeyCap("D", (keys[plState]["D"] ~= nil), imgui.ImVec2(30, 30)) imgui.EndGroup() imgui.SameLine(nil, 20) if plState == "onfoot" then imgui.BeginGroup() KeyCap("Shift", (keys[plState]["Shift"] ~= nil), imgui.ImVec2(75, 30)); imgui.SameLine() KeyCap("Alt", (keys[plState]["Alt"] ~= nil), imgui.ImVec2(55, 30)) KeyCap("Space", (keys[plState]["Space"] ~= nil), imgui.ImVec2(135, 30)) imgui.EndGroup() imgui.SameLine() imgui.BeginGroup() KeyCap("C", (keys[plState]["C"] ~= nil), imgui.ImVec2(30, 30)); imgui.SameLine() KeyCap("F", (keys[plState]["F"] ~= nil), imgui.ImVec2(30, 30)) KeyCap("RM", (keys[plState]["RKM"] ~= nil), imgui.ImVec2(30, 30)); imgui.SameLine() KeyCap("LM", (keys[plState]["LKM"] ~= nil), imgui.ImVec2(30, 30)) imgui.EndGroup() else imgui.BeginGroup() KeyCap("Ctrl", (keys[plState]["Ctrl"] ~= nil), imgui.ImVec2(65, 30)); imgui.SameLine() KeyCap("Alt", (keys[plState]["Alt"] ~= nil), imgui.ImVec2(65, 30)) KeyCap("Space", (keys[plState]["Space"] ~= nil), imgui.ImVec2(135, 30)) imgui.EndGroup() imgui.SameLine() imgui.BeginGroup() KeyCap("Up", (keys[plState]["Up"] ~= nil), imgui.ImVec2(40, 30)) KeyCap("Down", (keys[plState]["Down"] ~= nil), imgui.ImVec2(40, 30)) imgui.EndGroup() imgui.SameLine() imgui.BeginGroup() KeyCap("H", (keys[plState]["H"] ~= nil), imgui.ImVec2(30, 30)); imgui.SameLine() KeyCap("F", (keys[plState]["F"] ~= nil), imgui.ImVec2(30, 30)) KeyCap("Q", (keys[plState]["Q"] ~= nil), imgui.ImVec2(30, 30)); imgui.SameLine() KeyCap("E", (keys[plState]["E"] ~= nil), imgui.ImVec2(30, 30)) imgui.EndGroup() end else imgui.Text("The player has left the stream zone!") end if (cfg.settings.x ~= pos.x) or (cfg.settings.y ~= pos.y) then cfg.settings.x = pos.x cfg.settings.y = pos.y inicfg.save(cfg, '..\\config\\key_sync.ini') end imgui.End() end ) function KeyCap(keyName, isPressed, size) local DL = imgui.GetWindowDrawList() local p = imgui.GetCursorScreenPos() local colors = { [true] = imgui.ImVec4(0.60, 0.60, 1.00, 1.00), [false] = imgui.ImVec4(0.60, 0.60, 1.00, 0.10) } if KEYCAP == nil then KEYCAP = {} end if KEYCAP[keyName] == nil then KEYCAP[keyName] = { status = isPressed, color = colors[isPressed], timer = nil } end local K = KEYCAP[keyName] if isPressed ~= K.status then K.status = isPressed K.timer = os.clock() end local rounding = 3.0 local A = imgui.ImVec2(p.x, p.y) local B = imgui.ImVec2(p.x + size.x, p.y + size.y) if K.timer ~= nil then K.color = bringVec4To(colors[not isPressed], colors[isPressed], K.timer, 0.1) end local ts = imgui.CalcTextSize(keyName) local text_pos = imgui.ImVec2(p.x + (size.x / 2) - (ts.x / 2), p.y + (size.y / 2) - (ts.y / 2)) imgui.Dummy(size) DL:AddRectFilled(A, B, u32(K.color), rounding) DL:AddRect(A, B, u32(colors[true]), rounding, _, 1) DL:AddText(text_pos, 0xFFFFFFFF, keyName) end function cyrillic(text) local convtbl = { [230] = 155, [231] = 159, [247] = 164, [234] = 107, [250] = 144, [251] = 168, [254] = 171, [253] = 170, [255] = 172, [224] = 097, [240] = 112, [241] = 099, [226] = 162, [228] = 154, [225] = 151, [227] = 153, [248] = 165, [243] = 121, [184] = 101, [235] = 158, [238] = 111, [245] = 120, [233] = 157, [242] = 166, [239] = 163, [244] = 063, [237] = 174, [229] = 101, [246] = 036, [236] = 175, [232] = 156, [249] = 161, [252] = 169, [215] = 141, [202] = 075, [204] = 077, [220] = 146, [221] = 147, [222] = 148, [192] = 065, [193] = 128, [209] = 067, [194] = 139, [195] = 130, [197] = 069, [206] = 079, [213] = 088, [168] = 069, [223] = 149, [207] = 140, [203] = 135, [201] = 133, [199] = 136, [196] = 131, [208] = 080, [200] = 133, [198] = 132, [210] = 143, [211] = 089, [216] = 142, [212] = 129, [214] = 137, [205] = 072, [217] = 138, [218] = 167, [219] = 145 } local result = {} for i = 1, string.len(text) do local c = text:byte(i) result[i] = string.char(convtbl[c] or c) end return table.concat(result) end function bringVec4To(from, dest, start_time, duration) local timer = os.clock() - start_time if timer >= 0.00 and timer <= duration then local count = timer / (duration / 100) return imgui.ImVec4( from.x + (count * (dest.x - from.x) / 100), from.y + (count * (dest.y - from.y) / 100), from.z + (count * (dest.z - from.z) / 100), from.w + (count * (dest.w - from.w) / 100) ), true end return (timer > duration) and dest or from, false end function onScriptTerminate(script, quitGame) if script == thisScript() then os.remove(getWorkingDirectory().."\\config\\key_sync.ini") if not inicfg.save(cfg, '..\\config\\key_sync.ini') then print("DATA SAVING ERROR") end end end