script_name('Mine Tools') script_author('Victor Strand') script_description('special edition - MonetLoader Android') script_version('1.0-monet') script_properties('work-in-pause') require('lib.samp.events') local imgui = require('mimgui') local ffi = require('ffi') local enc = require('encoding') enc.default = 'CP1251' local u8 = enc.UTF8 local inicfg = require('inicfg') local jsoncfg do local ok, lib = pcall(require, 'jsoncfg') jsoncfg = (ok and lib) or { load = function(def) return def end, save = function() return false end } end local requests= require('requests') local lfs = require('lfs') local sampev = require('lib.samp.events') local MDS = MONET_DPI_SCALE local new = imgui.new local MT = { bg = imgui.ImVec4(0.055, 0.047, 0.039, 0.975), bg2 = imgui.ImVec4(0.086, 0.071, 0.055, 1.00), panel = imgui.ImVec4(0.110, 0.090, 0.067, 1.00), panelH = imgui.ImVec4(0.165, 0.133, 0.094, 1.00), amber = imgui.ImVec4(0.949, 0.686, 0.180, 1.00), amberD = imgui.ImVec4(0.545, 0.376, 0.086, 1.00), amberH = imgui.ImVec4(1.000, 0.804, 0.322, 1.00), ember = imgui.ImVec4(0.902, 0.361, 0.086, 1.00), emberD = imgui.ImVec4(0.482, 0.169, 0.039, 1.00), copper = imgui.ImVec4(0.760, 0.451, 0.208, 1.00), steel = imgui.ImVec4(0.667, 0.702, 0.741, 1.00), gem = imgui.ImVec4(0.451, 0.780, 0.839, 1.00), good = imgui.ImVec4(0.478, 0.788, 0.353, 1.00), bad = imgui.ImVec4(0.878, 0.298, 0.208, 1.00), text = imgui.ImVec4(0.949, 0.914, 0.839, 1.00), textDim = imgui.ImVec4(0.729, 0.678, 0.588, 0.75), border = imgui.ImVec4(0.702, 0.510, 0.243, 0.32), } local ORE_COL = { imgui.ImVec4(0.780, 0.769, 0.741, 1.00), imgui.ImVec4(0.667, 0.702, 0.741, 1.00), imgui.ImVec4(0.847, 0.886, 0.937, 1.00), imgui.ImVec4(0.804, 0.498, 0.196, 1.00), imgui.ImVec4(1.000, 0.843, 0.000, 1.00), imgui.ImVec4(0.361, 0.353, 0.373, 1.00), } local u32, u32v do local floor = math.floor local function c8(v) if v <= 0 then return 0 end if v >= 1 then return 255 end return floor(v * 255 + 0.5) end u32 = function(r, g, b, a) return c8(r) + c8(g) * 0x100 + c8(b) * 0x10000 + c8(a or 1) * 0x1000000 end u32v = function(c, a) return c8(c.x) + c8(c.y) * 0x100 + c8(c.z) * 0x10000 + c8(a ~= nil and a or c.w) * 0x1000000 end end local V do local pool, idx = {}, 0 for i = 1, 16 do pool[i] = imgui.ImVec2(0, 0) end V = function(x, y) idx = idx % 16 + 1 local v = pool[idx] v.x = x; v.y = y return v end end local TRANSPARENT = imgui.ImVec4(0, 0, 0, 0) local updMouse, mouseXY do local mx, my = 0, 0 updMouse = function() local mp = imgui.GetMousePos() mx, my = mp.x, mp.y end mouseXY = function() return mx, my end end local animT0 = os.clock() local function animTime() return os.clock() - animT0 end local function pulseWave(period, phase) return 0.5 + 0.5 * math.sin(animTime() / (period or 1) * 6.2832 + (phase or 0)) end local function approach(cur, target, dt, speed) return cur + (target - cur) * (1 - math.exp(-(speed or 8) * dt)) end local function lerp(a, b, t) return a + (b - a) * t end local function capsule(DL, x, y, w, h, col) local r = h * 0.5 if w <= h then DL:AddCircleFilled(V(x + w*0.5, y + r), math.min(r, w*0.5), col, 20) return end DL:AddRectFilled(V(x + r, y), V(x + w - r, y + h), col, 0) DL:AddCircleFilled(V(x + r, y + r), r, col, 20) DL:AddCircleFilled(V(x + w - r, y + r), r, col, 20) end local pushClip, popClip do local ok0 = nil pushClip = function(DL, x0, y0, x1, y1) if ok0 then DL:PushClipRect(V(x0,y0), V(x1,y1), true); return true elseif ok0 == false then return false end local ok = pcall(DL.PushClipRect, DL, V(x0,y0), V(x1,y1), true) ok0 = ok return ok end popClip = function(DL) DL:PopClipRect() end end local faR, faS do local ok1, m1 = pcall(require, 'fAwesome6'); faR = ok1 and m1 or nil local ok2, m2 = pcall(require, 'fAwesome6_solid'); faS = ok2 and m2 or nil end local function faIco(name, fallback) if not faS then return '' end local ok, v = pcall(function() return faS[name] end) if ok and type(v) == 'string' and #v > 0 then return v end if fallback then local ok2, v2 = pcall(function() return faS[fallback] end) if ok2 and type(v2) == 'string' and #v2 > 0 then return v2 end end return '' end local IC = {} local IC_NAMES = { HELMET = {'HELMET_SAFETY','HARD_HAT'}, GEM = {'GEM','DIAMOND'}, MOUNT = {'MOUNTAIN','MOUND'}, HAMMER = {'HAMMER','GAVEL'}, FIRE = {'FIRE','FIRE_FLAME_CURVED'}, BOLT = {'BOLT','BOLT_LIGHTNING'}, COINS = {'COINS','SACK_DOLLAR'}, CHART = {'CHART_SIMPLE','CHART_BAR'}, GEAR = {'GEAR','SLIDERS'}, SLIDERS = {'SLIDERS','GEAR'}, STORE = {'STORE','BAG_SHOPPING'}, SEARCH = {'MAGNIFYING_GLASS','SEARCH'}, EYE = {'EYE','EYE_SLASH'}, ROUTE = {'ROUTE','ARROWS_LEFT_RIGHT'}, CLOCK = {'CLOCK','HOURGLASS'}, VOLUME = {'VOLUME_HIGH','VOLUME_UP'}, PIN = {'LOCATION_DOT','MAP_PIN'}, RUN = {'PERSON_RUNNING','PERSON'}, CUBE = {'CUBE','BOX'}, LAYERS = {'LAYER_GROUP','CLONE'}, STAR = {'STAR','CERTIFICATE'}, CROWN = {'CROWN','STAR'}, DOWN = {'DOWNLOAD','ARROW_DOWN'}, PLANE = {'PAPER_PLANE','SHARE'}, USER = {'USER','CIRCLE_USER'}, XMARK = {'XMARK','X'}, RESET = {'ARROW_ROTATE_LEFT','ROTATE_LEFT'}, WARN = {'TRIANGLE_EXCLAMATION','CIRCLE_EXCLAMATION'}, CHECK = {'CIRCLE_CHECK','CHECK'}, SHIELD = {'SHIELD_HALVED','SHIELD'}, TRUCK = {'TRUCK_FAST','TRUCK'}, BRUSH = {'PALETTE','BRUSH'}, LIGHT = {'LIGHTBULB','SUN'}, WEIGHT = {'WEIGHT_HANGING','WEIGHT_SCALE'}, TERMINAL= {'TERMINAL','KEYBOARD'}, PLAY = {'PLAY','CIRCLE_PLAY'}, LINK = {'LINK','UP_RIGHT_FROM_SQUARE'}, } for k, v in pairs(IC_NAMES) do IC[k] = faIco(v[1], v[2]) end local ORE_IC = { IC.CUBE, IC.LAYERS, IC.GEM, IC.SHIELD, IC.CROWN, IC.FIRE } local drawDust do local pool, lastT = {}, os.clock() local function spawn(p, fromBottom) p.x = math.random() p.y = fromBottom and (1.05 + math.random()*0.2) or math.random() p.sp = 0.035 + math.random() * 0.075 p.am = 0.008 + math.random() * 0.030 p.fr = 0.4 + math.random() * 1.3 p.ph = math.random() * 6.283 p.r = 0.7 + math.random() * 1.7 p.a = 0.08 + math.random() * 0.22 p.hot= math.random() < 0.35 end for i = 1, 26 do pool[i] = {}; spawn(pool[i], false) end drawDust = function(DL, x, y, w, h, count) if not DL or w <= 0 or h <= 0 then return end local now = os.clock() local dt = now - lastT lastT = now if dt < 0 or dt > 0.25 then dt = 0.016 end count = math.min(count or #pool, #pool) for i = 1, #pool do local p = pool[i] p.y = p.y - p.sp * dt p.ph = p.ph + p.fr * dt if p.y < -0.1 then spawn(p, true) end end local ok = pushClip(DL, x, y, x + w, y + h) for i = 1, count do local p = pool[i] local gx = x + (p.x + math.sin(p.ph) * p.am) * w local gy = y + p.y * h if gy >= y - 2 and gy <= y + h + 2 then local col = p.hot and u32(0.95, 0.45 + 0.25*math.sin(p.ph*2), 0.12, p.a) or u32(0.62, 0.56, 0.48, p.a * 0.75) DL:AddCircleFilled(V(gx, gy), p.r * MDS, col, 8) end end if ok then popClip(DL) end end end local SOUND_URL = 'https://raw.githubusercontent.com/victorstrand250-cpu/Photo-Katalog/b4d2477ff14db881184baa85def75fa6a9fa146c/faaah.mp3' local SOUND_DIR = getWorkingDirectory()..'/MineTools' local SOUND_FILE = SOUND_DIR..'/ore_pickup.mp3' local bass = nil local oreStream = 0 local oreSoundEnabled = new.bool(true) pcall(function() bass = ffi.load('libbass.so') ffi.cdef[[ int BASS_Init(int device, unsigned long freq, unsigned long flags, void* win, void* clsid); unsigned long BASS_StreamCreateFile(int mem, const char* file, unsigned long long offset, unsigned long long length, unsigned long flags); unsigned long BASS_StreamCreateURL(const char* url, unsigned long offset, unsigned long flags, void* proc, void* user); int BASS_ChannelPlay(unsigned long handle, int restart); int BASS_ChannelStop(unsigned long handle); int BASS_ChannelSetAttribute(unsigned long handle, unsigned long attrib, float value); int BASS_StreamFree(unsigned long handle); ]] pcall(function() bass.BASS_Init(-1, 44100, 0, nil, nil) end) end) local effil = nil pcall(function() effil = require('effil') end) local function asyncDownloadFile(url, path, onDone) local function finish(ok) if onDone then pcall(onDone, ok) end end if not (url and url ~= '' and path and path ~= '') then finish(false); return end if effil then local runner = effil.thread(function(u) local ok_h, https = pcall(require, 'ssl.https') if not ok_h or not https then return {false} end local ok_r, body, code = pcall(https.request, u) if ok_r and type(body) == 'string' then return {body, code} end return {false} end) local ok_run, handle = pcall(runner, url) if not ok_run or not handle then finish(false); return end lua_thread.create(function() local startT = os.clock() local r = handle:get(0) while not r do local st = handle:status() if st == 'failed' or st == 'cancelled' or st == 'canceled' then break end if os.clock() - startT > 60 then break end wait(50) r = handle:get(0) end pcall(function() handle:cancel(0) end) local body = r and r[1] if type(body) == 'string' and #body > 100 then local f = io.open(path, 'wb') if f then f:write(body); f:close(); finish(true); return end end finish(false) end) else lua_thread.create(function() local ok, resp = pcall(requests.get, url) if ok and resp and resp.status_code == 200 and resp.text and #resp.text > 100 then local f = io.open(path, 'wb') if f then f:write(resp.text); f:close(); finish(true); return end end finish(false) end) end end local function playOreSound() if not bass or not oreSoundEnabled[0] then return end lua_thread.create(function() if not doesFileExist(SOUND_FILE) then return end pcall(function() if oreStream ~= 0 then bass.BASS_ChannelStop(oreStream) bass.BASS_StreamFree(oreStream) oreStream = 0 end oreStream = bass.BASS_StreamCreateFile(0, SOUND_FILE, 0, 0, 0) if oreStream ~= 0 then bass.BASS_ChannelSetAttribute(oreStream, 2, 0.8) bass.BASS_ChannelPlay(oreStream, 1) end end) end) end local function downloadOreSound() lua_thread.create(function() while not isSampAvailable() do wait(500) end pcall(function() if not doesDirectoryExist(SOUND_DIR) then createDirectory(SOUND_DIR) end end) if doesFileExist(SOUND_FILE) then return end asyncDownloadFile(SOUND_URL, SOUND_FILE) end) end local AUTHOR_TG = 'https://t.me/victor_st0' local CHANNEL_TG = 'https://t.me/strand_scripts' local CAT_CFG = 'catalog_scripts' local CAT_FOLDER = getWorkingDirectory()..'/MineTools' local CAT_IMAGES = CAT_FOLDER..'/images' local DEFAULT_SCRIPTS = { { name = u8('\xc1\xee\xf2 \xed\xe0 \xd8\xe0\xf5\xf2\xf3'), short = u8('\xd1\xf2\xe0\xe1\xe8\xeb\xfc\xed\xfb\xe9 \xe8 \xe1\xe5\xe7\xee\xef\xe0\xf1\xed\xfb\xe9 \xe1\xee\xf2 \xe4\xeb\xff \xf8\xe0\xf5\xf2\xfb. \xc1\xe5\xe7\xee\xef\xe0\xf1\xed\xee\xf1\xf2\xfc \xef\xee\xeb\xed\xee\xf1\xf2\xfc\xfe \xe0\xe2\xf2\xee\xec\xe0\xf2\xe8\xe7\xe8\xf0\xee\xe2\xe0\xed\xe0!'), vip = true, featured = true, price_text = u8('\xd6\xe5\xed\xe0: 400 \xf0\xf3\xe1 / 200 \xe3\xf0\xed \xe2 \xec\xe5\xf1\xff\xf6'), tg_link = 'https://t.me/strand_scripts/265', img_url = 'https://raw.githubusercontent.com/victorstrand250-cpu/Photo-Katalog/refs/heads/main/file_00000000be8c720a8804ceec0c4c3957.png', img_file = 'mine_bot_v2.png', img_ratio = 9/16, }, { name = u8('\xc1\xee\xf2 \xd4\xe5\xf0\xec\xe0 \xd5\xeb\xee\xef\xea\xe0/\xcb\xfc\xed\xe0'), short = u8('\xc0\xe2\xf2\xee\xec\xe0\xf2\xe8\xf7\xe5\xf1\xea\xe8\xe9 \xe1\xee\xf2 \xe4\xeb\xff \xf1\xe1\xee\xf0\xe0 \xf5\xeb\xee\xef\xea\xe0 \xe8 \xeb\xfc\xed\xe0 \xed\xe0 \xf1\xe5\xf0\xe2\xe5\xf0\xe5 Arizona RP.'), vip = true, price_month = '3$', price_year = '28$', tg_link = AUTHOR_TG, img_url = 'https://raw.githubusercontent.com/victorstrand250-cpu/Photo-Katalog/refs/heads/main/file_0000000036a0720abc49af32cb501c9a.png', img_file = 'farm_bot.png', }, { name = u8('\xc1\xee\xf2 \xd2\xd0\xc0\xcc\xc2\xc0\xc9'), short = u8('\xc0\xe2\xf2\xee\xec\xe0\xf2\xe8\xf7\xe5\xf1\xea\xe8\xe9 \xe1\xee\xf2 \xe2\xee\xe4\xe8\xf2\xe5\xeb\xff \xf2\xf0\xe0\xec\xe2\xe0\xff. \xc1\xe5\xf1\xef\xeb\xe0\xf2\xed\xee \xe4\xeb\xff \xea\xe0\xe6\xe4\xee\xe3\xee!'), vip = false, price_month = nil, price_year = nil, tg_link = CHANNEL_TG, img_url = 'https://raw.githubusercontent.com/victorstrand250-cpu/Photo-Katalog/refs/heads/main/1775526101667.png', img_file = 'tram_bot.png', }, { name = u8('Track Helper'), short = u8('\xd5\xe5\xeb\xef\xe5\xf0 \xe4\xeb\xff \xf0\xe0\xe1\xee\xf2\xfb \xe4\xe0\xeb\xfc\xed\xee\xe1\xee\xe9\xf9\xe8\xea\xe0 \xed\xe0 Arizona RP. \xd3\xef\xf0\xee\xf9\xe0\xe5\xf2 \xe4\xee\xf1\xf2\xe0\xe2\xea\xf3 \xe3\xf0\xf3\xe7\xee\xe2.'), vip = false, price_month = nil, price_year = nil, tg_link = CHANNEL_TG, img_url = 'https://raw.githubusercontent.com/victorstrand250-cpu/Photo-Katalog/refs/heads/main/1776333245763.png', img_file = 'track_helper.png', }, { name = u8('Object Menu'), short = u8('\xcc\xe5\xed\xfe \xe4\xeb\xff \xf1\xee\xe7\xe4\xe0\xed\xe8\xff \xe2\xe8\xe7\xf3\xe0\xeb\xfc\xed\xfb\xf5 \xee\xe1\xfa\xe5\xea\xf2\xee\xe2 \xe8 \xf0\xe5\xe4\xe0\xea\xf2\xe8\xf0\xee\xe2\xe0\xed\xe8\xff \xef\xee\xe7\xe8\xf6\xe8\xe9.'), vip = false, price_month = nil, price_year = nil, tg_link = CHANNEL_TG, img_url = 'https://raw.githubusercontent.com/victorstrand250-cpu/Photo-Katalog/refs/heads/main/file_00000000041c71f48308c9fdf10ef1f0.png', img_file = 'object_menu.png', }, } local catScripts = {} local catTextures = {} local catPending = {} local function safeNum(v) return tonumber(v) or 0 end local function safeDist3d(x1,y1,z1,x2,y2,z2) x1=tonumber(x1) or 0; y1=tonumber(y1) or 0; z1=tonumber(z1) or 0 x2=tonumber(x2) or 0; y2=tonumber(y2) or 0; z2=tonumber(z2) or 0 local dx,dy,dz = x1-x2, y1-y2, z1-z2 return math.sqrt(dx*dx+dy*dy+dz*dz) end local function openLink(url) pcall(function() local gta = ffi.load('GTASA') pcall(ffi.cdef, [[ void _Z12AND_OpenLinkPKc(const char* link); ]]) gta._Z12AND_OpenLinkPKc(url) end) end local function catEnsureDirs() pcall(function() lfs.mkdir(CAT_FOLDER) end) pcall(function() lfs.mkdir(CAT_IMAGES) end) end local function catLoadScripts() local saved = jsoncfg.load({scripts={}}, CAT_CFG) local result = {} for _,s in ipairs(DEFAULT_SCRIPTS) do table.insert(result,s) end if saved and saved.scripts then for _,s in ipairs(saved.scripts) do table.insert(result,s) end end return result end local function catScheduleDownload(imgFile, imgUrl) if not imgFile or imgFile == '' or not imgUrl or imgUrl == '' then return end if catTextures[imgFile] then return end catTextures[imgFile] = 'loading' local path = CAT_IMAGES..'/'..imgFile if doesFileExist(path) then local f = io.open(path,'rb') if f then local hdr = f:read(8); f:close() local valid = false if hdr then if hdr:byte(1)==0x89 and hdr:byte(2)==0x50 then valid=true end if hdr:byte(1)==0xFF and hdr:byte(2)==0xD8 then valid=true end end if not valid then os.remove(path) end else os.remove(path) end end if doesFileExist(path) then table.insert(catPending, {file=imgFile, path=path}) return end asyncDownloadFile(imgUrl, path, function(ok) if ok then table.insert(catPending, {file=imgFile, path=path}) else catTextures[imgFile] = 'failed' end end) end local CFG_FILE = 'minetools.ini' local cfgDir = getWorkingDirectory()..'/config' if not doesDirectoryExist(cfgDir) then createDirectory(cfgDir) end local settings = inicfg.load({ main = { renderOre = false, renderStone = false, renderMetal = false, renderSilver = false, renderBronze = false, renderGold = false, showOreLine = false, showOreDistance = false, autoDig = false, fastRun = false, statisticsWindow = false, statisticsStone = false, statisticsMetal = false, statisticsSilver = false, statisticsBronze = false, statisticsGold = false, statisticsCoal = false, totalPrice = false, oreTimer = false, oreTimerDistance = false, oreTimerLine = false, colorStone = 0xFFC7C4BD, colorMetal = 0xFFAAB3BD, colorSilver = 0xFFD8E2EF, colorBronze = 0xFFCD7F32, colorGold = 0xFFFFD700, colorOreTimer = 0xFFF2AF2E, selectedPage = 2, renderRadius = 100, renderSize = 21, renderOreTimerSize = 21, statisticsPosX = 300, statisticsPosY = 300, priceStone = 20000, priceMetal = 45000, priceSilver = 25000, priceBronze = 70000, priceGold = 50000, priceCoal = 15000, countStone = 0, countMetal = 0, countSilver = 0, countBronze = 0, countGold = 0, countCoal = 0, commandOpenMenu = 'mt', oreSoundEnabled = true, subscribed = false, }, }, CFG_FILE) inicfg.load(settings, CFG_FILE) do local FIX = { colorStone=0xFFC7C4BD, colorMetal=0xFFAAB3BD, colorSilver=0xFFD8E2EF, colorBronze=0xFFCD7F32, colorGold=0xFFFFD700, colorOreTimer=0xFFF2AF2E } local dirty = false for key, def in pairs(FIX) do local v = tonumber(settings.main[key]) if not v or bit.band(bit.rshift(v, 24), 0xFF) == 0 then settings.main[key] = def dirty = true end end if dirty then inicfg.save(settings, CFG_FILE) end end if not doesFileExist(getWorkingDirectory()..'/config/'..CFG_FILE) then inicfg.save(settings, CFG_FILE) end local prefix = '{696969}[{DCDCDC}MineTools{696969}]{696969}: ' local str = ffi.string local oreTextures = { ['cs_rockdetail2'] = 1, ['ab_flakeywall'] = 2, ['metalic128'] = 3, ['Strip_Gold'] = 4, ['gold128'] = 5 } local resources = {} local textsTable = {} local a = 0 local oreTimerList = {} local oreObjCache = {} local ore3dCache = {} local oreColorCache = {} local function cachedColor(argb) argb = tonumber(argb) or 0xFFFFFFFF if not oreColorCache[argb] then local aa = bit.band(bit.rshift(argb,24),0xFF)/255 local rr = bit.band(bit.rshift(argb,16),0xFF)/255 local gg = bit.band(bit.rshift(argb, 8),0xFF)/255 local bb = bit.band(argb,0xFF)/255 oreColorCache[argb] = imgui.GetColorU32Vec4(imgui.ImVec4(rr,gg,bb,aa)) end return oreColorCache[argb] end local function argbToVec4(argb) argb = tonumber(argb) or 0xFFFFFFFF return imgui.ImVec4( bit.band(bit.rshift(argb,16),0xFF)/255, bit.band(bit.rshift(argb, 8),0xFF)/255, bit.band(argb,0xFF)/255, bit.band(bit.rshift(argb,24),0xFF)/255) end local font = {} local pages = { u8('\xcf\xee\xe8\xf1\xea \xf0\xf3\xe4\xfb'), u8('\xd1\xf2\xe0\xf2\xe8\xf1\xf2\xe8\xea\xe0'), u8('\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8'), u8('\xca\xe0\xf2\xe0\xeb\xee\xe3'), } local ORE_LABEL = u8('\xd0\xf3\xe4\xe0') local ORE_REMAIN = u8('\xce\xf1\xf2\xe0\xeb\xee\xf1\xfc ') local STAT_TITLE = u8('\xd1\xf2\xe0\xf2\xe8\xf1\xf2\xe8\xea\xe0') local STAT_PROFIT = u8('\xcf\xf0\xe8\xe1\xfb\xeb\xfc: ') local STAT_NAMES = { u8('\xca\xe0\xec\xe5\xed\xfc'), u8('\xcc\xe5\xf2\xe0\xeb\xeb'), u8('\xd1\xe5\xf0\xe5\xe1\xf0\xee'), u8('\xc1\xf0\xee\xed\xe7\xe0'), u8('\xc7\xee\xeb\xee\xf2\xee'), u8('\xd3\xe3\xee\xeb\xfc'), } local BANNER_NEW = u8('\xcd\xce\xc2\xc8\xcd\xca\xc0! \xc1\xce\xd2 \xcd\xc0 \xd8\xc0\xd5\xd2\xd3') local BANNER_NEW_URL = 'https://t.me/strand_scripts/265' local mainWindow = new.bool(false) local subscribeWindow = new.bool(false) local subYtClicked = false local subTgClicked = false local render = new.bool(true) local renderOre = new.bool(settings.main.renderOre) local renderStone = new.bool(settings.main.renderStone) local renderMetal = new.bool(settings.main.renderMetal) local renderSilver = new.bool(settings.main.renderSilver) local renderBronze = new.bool(settings.main.renderBronze) local renderGold = new.bool(settings.main.renderGold) local showOreLine = new.bool(settings.main.showOreLine) local showOreDistance = new.bool(settings.main.showOreDistance) local autoDig = new.bool(settings.main.autoDig) local fastRun = new.bool(settings.main.fastRun) local statisticsWindow = new.bool(settings.main.statisticsWindow) local statisticsStone = new.bool(settings.main.statisticsStone) local statisticsMetal = new.bool(settings.main.statisticsMetal) local statisticsSilver = new.bool(settings.main.statisticsSilver) local statisticsBronze = new.bool(settings.main.statisticsBronze) local statisticsGold = new.bool(settings.main.statisticsGold) local statisticsCoal = new.bool(settings.main.statisticsCoal) local totalPrice = new.bool(settings.main.totalPrice) local oreTimer = new.bool(settings.main.oreTimer) local oreTimerDistance = new.bool(settings.main.oreTimerDistance) local oreTimerLine = new.bool(settings.main.oreTimerLine) local renderRadius = new.int(settings.main.renderRadius) local renderSize = new.int(settings.main.renderSize) local priceStone = new.int(settings.main.priceStone) local priceMetal = new.int(settings.main.priceMetal) local priceSilver = new.int(settings.main.priceSilver) local priceBronze = new.int(settings.main.priceBronze) local priceGold = new.int(settings.main.priceGold) local priceCoal = new.int(settings.main.priceCoal) local renderOreTimerSize= new.int(settings.main.renderOreTimerSize) local commandOpenMenu = new.char[256](u8(settings.main.commandOpenMenu)) local UI = { renderOre = renderOre, renderStone = renderStone, renderMetal = renderMetal, renderSilver = renderSilver, renderBronze = renderBronze, renderGold = renderGold, showOreLine = showOreLine, showOreDistance = showOreDistance, autoDig = autoDig, fastRun = fastRun, statisticsWindow = statisticsWindow, statisticsStone = statisticsStone, statisticsMetal = statisticsMetal, statisticsSilver = statisticsSilver, statisticsBronze = statisticsBronze, statisticsGold = statisticsGold, statisticsCoal = statisticsCoal, totalPrice = totalPrice, oreTimer = oreTimer, oreTimerDistance = oreTimerDistance, oreTimerLine = oreTimerLine, renderRadius = renderRadius, renderSize = renderSize, renderOreTimerSize = renderOreTimerSize, priceStone = priceStone, priceMetal = priceMetal, priceSilver = priceSilver, priceBronze = priceBronze, priceGold = priceGold, priceCoal = priceCoal, commandOpenMenu = commandOpenMenu, oreSoundEnabled = oreSoundEnabled, } local sessionStart = os.clock() local cfgDirty, cfgLastSave = false, 0 local function saveSettingsSoon() cfgDirty = true if os.clock() - cfgLastSave >= 5 then cfgLastSave = os.clock() cfgDirty = false inicfg.save(settings, CFG_FILE) end end local function saveSettingsNow() cfgDirty = false cfgLastSave = os.clock() inicfg.save(settings, CFG_FILE) end local function isSubscribed() return settings.main.subscribed == true or settings.main.subscribed == 'true' end local function toggleMainMenu() if not isSubscribed() then subscribeWindow[0] = true return end mainWindow[0] = not mainWindow[0] end local faKeep = {} local function utf8cp(str) if type(str) ~= 'string' then return nil end local b1 = str:byte(1); if not b1 then return nil end if b1 < 0x80 then return b1 end local b2 = str:byte(2); if not b2 then return nil end if b1 < 0xE0 then return (b1-0xC0)*0x40 + (b2-0x80) end local b3 = str:byte(3); if not b3 then return nil end if b1 < 0xF0 then return (b1-0xE0)*0x1000 + (b2-0x80)*0x40 + (b3-0x80) end local b4 = str:byte(4); if not b4 then return nil end return (b1-0xF0)*0x40000 + (b2-0x80)*0x1000 + (b3-0x80)*0x40 + (b4-0x80) end local function buildIconRange() local seen, cps = {}, {} for _, glyph in pairs(IC) do local cp = utf8cp(glyph) if cp and cp > 0 and not seen[cp] then seen[cp] = true; cps[#cps+1] = cp end end if #cps == 0 then return nil end table.sort(cps) local arr = imgui.new.ImWchar[#cps * 2 + 1]() for i, cp in ipairs(cps) do arr[(i-1)*2] = cp; arr[(i-1)*2+1] = cp end arr[#cps*2] = 0 return arr end imgui.OnInitialize(function() imgui.SwitchContext() local io = imgui.GetIO() io.IniFilename = nil imgui.GetStyle():ScaleAllSizes(MDS) local ranges = io.Fonts:GetGlyphRangesCyrillic() local ttf = getWorkingDirectory()..'/lib/mimgui/trebucbd.ttf' if not doesFileExist(ttf) then ttf = getWorkingDirectory()..'/../trebucbd.ttf' end local iconRange if faR and faS then local ok, rng = pcall(buildIconRange) iconRange = ok and rng or nil faKeep[#faKeep+1] = iconRange end local function mergeFA(px) if not (faR and faS and iconRange) then return end local cfg = imgui.ImFontConfig() cfg.MergeMode = true cfg.PixelSnapH = true faKeep[#faKeep+1] = cfg pcall(function() io.Fonts:AddFontFromMemoryCompressedBase85TTF( faR.get_font_data_base85('solid'), px, cfg, iconRange) end) end io.Fonts:AddFontFromFileTTF(ttf, 14*MDS, nil, ranges) mergeFA(14*MDS) for size = 10, 27 do font[size] = io.Fonts:AddFontFromFileTTF(ttf, size*MDS, nil, ranges) mergeFA(size*MDS) end pcall(function() io.FontDefault = font[14] end) minetools_theme() end) function join_argb(a, r, g, b) local argb = b argb = bit.bor(argb, bit.lshift(g, 8)) argb = bit.bor(argb, bit.lshift(r, 16)) argb = bit.bor(argb, bit.lshift(a, 24)) return argb end function convertToPriceFormat(num) num = tostring(num) if num ~= nil and #num > 3 then local b, e = ('%d'):format(num):gsub('^%-', '') local c = b:reverse():gsub('%d%d%d', '%1.') local d = c:reverse():gsub('^%.', '') return '$'..(e == 1 and '-' or '')..d end return '$'..num end function main() while not isSampAvailable() do wait(100) end while not sampIsLocalPlayerSpawned() do wait(200) end local function cbool(v) return v == true or v == 'true' end sessionStart = os.clock() oreSoundEnabled[0] = cbool(settings.main.oreSoundEnabled) downloadOreSound() catEnsureDirs() catScripts = catLoadScripts() lua_thread.create(function() wait(500) for _, sc in ipairs(catScripts) do if sc.img_url and sc.img_url ~= '' and sc.img_file and sc.img_file ~= '' then catScheduleDownload(sc.img_file, sc.img_url) wait(200) end end end) sampRegisterChatCommand(settings.main.commandOpenMenu, toggleMainMenu) sampRegisterChatCommand('mtore', function() renderOre[0] = not renderOre[0] settings.main.renderOre = renderOre[0] inicfg.save(settings, CFG_FILE) sampAddChatMessage(prefix..('\xd0\xf3\xe4\xe0: '..(renderOre[0] and '{00FF00}\xc2\xca\xcb' or '{FF4444}\xc2\xdb\xca\xcb')), -1) end) sampRegisterChatCommand('mttimer', function() oreTimer[0] = not oreTimer[0] settings.main.oreTimer = oreTimer[0] inicfg.save(settings, CFG_FILE) sampAddChatMessage(prefix..('\xd2\xe0\xe9\xec\xe5\xf0: '..(oreTimer[0] and '{00FF00}\xc2\xca\xcb' or '{FF4444}\xc2\xdb\xca\xcb')), -1) end) lua_thread.create(function() while true do wait(5000) if cfgDirty then saveSettingsNow() end end end) lua_thread.create(function() while true do wait(1500) if not renderOre[0] and not autoDig[0] then ore3dCache = {} else local tmp = {} for tid = 0, 2048 do if tid % 256 == 0 then wait(0) end local ok_t, defined = pcall(sampIs3dTextDefined, tid) if ok_t and defined then local ok_i, ttext, _, ox, oy, oz = pcall(function() local t,c,x,y,z = sampGet3dTextInfoById(tid) return t,c,x,y,z end) if ok_i and ttext and ttext:find('\xcc\xe5\xf1\xf2\xee\xf0\xee\xe6\xe4\xe5\xed\xe8\xe5') then local nx2,ny2,nz2 = tonumber(ox),tonumber(oy),tonumber(oz) if nx2 and ny2 and nz2 then table.insert(tmp, {nx2, ny2, nz2}) end end end end ore3dCache = tmp end end end) wait(99) sampAddChatMessage('{FF8C00}> {FFCC00}Mine Tools {FF8C00}| {FFFFFF}\xc0\xe2\xf2\xee\xf0: {FFD700}Victor Strand', -1) sampAddChatMessage('{FF8C00}> {AAAAAA}\xcc\xe5\xed\xfe: {FFFFFF}/'..settings.main.commandOpenMenu..'{AAAAAA} | \xd0\xf3\xe4\xe0: {FFFFFF}/mtore{AAAAAA} | \xd2\xe0\xe9\xec\xe5\xf0: {FFFFFF}/mttimer', -1) sampAddChatMessage('{FF8C00}> {00CC66}\xd8\xe0\xf5\xf2\xb8\xf0\xf1\xea\xe8\xe9 \xea\xe0\xf0\xfc\xe5\xf0 \xed\xe0\xf7\xe8\xed\xe0\xe5\xf2\xf1\xff. \xd3\xe4\xe0\xf7\xe8!', -1) while true do wait(0) if fastRun[0] then local ok, onFoot = pcall(isCharOnFoot, PLAYER_PED) if ok and onFoot then setGameKeyState(16, 1) wait(10) setGameKeyState(16, 0) end end end end function minetools_theme() local s = imgui.GetStyle() local c = s.Colors local C = imgui.Col local IV4 = imgui.ImVec4 local IV2 = imgui.ImVec2 s.WindowTitleAlign = IV2(0.5, 0.5) s.ButtonTextAlign = IV2(0.5, 0.5) s.WindowPadding = IV2(10*MDS, 10*MDS) s.FramePadding = IV2(8*MDS, 6*MDS) s.ItemSpacing = IV2(8*MDS, 7*MDS) s.ItemInnerSpacing = IV2(5*MDS, 5*MDS) s.TouchExtraPadding = IV2(5*MDS, 5*MDS) s.IndentSpacing = 14*MDS s.WindowBorderSize = 0 s.ChildBorderSize = 0 s.PopupBorderSize = 1 s.FrameBorderSize = 0 s.TabBorderSize = 0 s.ScrollbarSize = 9*MDS s.GrabMinSize = 12*MDS s.WindowRounding = 10*MDS s.ChildRounding = 8*MDS s.FrameRounding = 6*MDS s.PopupRounding = 8*MDS s.ScrollbarRounding = 6*MDS s.GrabRounding = 6*MDS s.TabRounding = 6*MDS c[C.Text] = MT.text c[C.TextDisabled] = MT.textDim c[C.WindowBg] = MT.bg c[C.ChildBg] = IV4(0.078, 0.063, 0.047, 0.60) c[C.PopupBg] = IV4(0.071, 0.059, 0.043, 0.98) c[C.Border] = MT.border c[C.BorderShadow] = IV4(0, 0, 0, 0.35) c[C.FrameBg] = IV4(0.129, 0.106, 0.078, 1.00) c[C.FrameBgHovered] = IV4(0.196, 0.157, 0.106, 1.00) c[C.FrameBgActive] = IV4(0.259, 0.196, 0.118, 1.00) c[C.TitleBg] = MT.bg2 c[C.TitleBgActive] = MT.amberD c[C.TitleBgCollapsed] = MT.bg c[C.MenuBarBg] = MT.bg2 c[C.ScrollbarBg] = IV4(0.071, 0.059, 0.043, 0.60) c[C.ScrollbarGrab] = IV4(0.353, 0.259, 0.129, 1.00) c[C.ScrollbarGrabHovered]= IV4(0.510, 0.373, 0.169, 1.00) c[C.ScrollbarGrabActive] = MT.amber c[C.CheckMark] = MT.amber c[C.SliderGrab] = MT.copper c[C.SliderGrabActive] = MT.amber c[C.Button] = IV4(0.161, 0.129, 0.090, 1.00) c[C.ButtonHovered] = IV4(0.286, 0.196, 0.098, 1.00) c[C.ButtonActive] = IV4(0.420, 0.263, 0.106, 1.00) c[C.Header] = IV4(0.235, 0.169, 0.086, 0.85) c[C.HeaderHovered] = IV4(0.353, 0.235, 0.106, 0.95) c[C.HeaderActive] = IV4(0.451, 0.290, 0.118, 1.00) c[C.Tab] = IV4(0.110, 0.090, 0.067, 1.00) c[C.TabHovered] = IV4(0.353, 0.235, 0.106, 1.00) c[C.TabActive] = IV4(0.451, 0.290, 0.118, 1.00) c[C.Separator] = MT.border c[C.SeparatorHovered] = IV4(0.902, 0.361, 0.086, 0.75) c[C.SeparatorActive] = MT.ember c[C.ResizeGrip] = IV4(0.420, 0.302, 0.129, 0.50) c[C.ResizeGripHovered] = IV4(0.600, 0.412, 0.153, 0.80) c[C.ResizeGripActive] = MT.amber c[C.PlotLines] = MT.amber c[C.PlotHistogram] = MT.copper c[C.TextSelectedBg] = IV4(0.545, 0.376, 0.086, 0.45) c[C.NavHighlight] = MT.amber end local function pushInvisBtn() imgui.PushStyleColor(imgui.Col.Button, TRANSPARENT) imgui.PushStyleColor(imgui.Col.ButtonHovered, TRANSPARENT) imgui.PushStyleColor(imgui.Col.ButtonActive, TRANSPARENT) end local function pF(f) if f then imgui.PushFont(f); return true end return false end local function pFpop(v) if v then imgui.PopFont() end end local function mtSection(icon, label) local DL = imgui.GetWindowDrawList() local p = imgui.GetCursorScreenPos() local w = imgui.GetContentRegionAvail().x local h = 20*MDS local pf = pF(font[14]) local ix = p.x if icon ~= '' then local isz = imgui.CalcTextSize(icon) DL:AddText(V(ix, p.y + (h-isz.y)*0.5), u32v(MT.amber), icon) ix = ix + isz.x + 6*MDS end local tsz = imgui.CalcTextSize(label) DL:AddText(V(ix, p.y + (h-tsz.y)*0.5), u32v(MT.text), label) local lx = ix + tsz.x + 8*MDS local ly = p.y + h*0.5 if lx < p.x + w then DL:AddRectFilledMultiColor( V(lx, ly-0.6*MDS), V(p.x + w, ly+0.6*MDS), u32v(MT.amber, 0.55), u32v(MT.amber, 0.00), u32v(MT.amber, 0.00), u32v(MT.amber, 0.55)) end pFpop(pf) imgui.Dummy(V(w, h)) end local mtToggleAnim = {} local function mtToggle(key, icon, label, ptr, hint) local DL = imgui.GetWindowDrawList() local p = imgui.GetCursorScreenPos() local w = imgui.GetContentRegionAvail().x local h = 34*MDS local st = mtToggleAnim[key] if not st then st = { t = ptr[0] and 1 or 0, hov = 0, last = os.clock() }; mtToggleAnim[key] = st end local now = os.clock() local dt = now - st.last; st.last = now if dt < 0 or dt > 0.25 then dt = 0.016 end imgui.SetCursorScreenPos(V(p.x, p.y)) pushInvisBtn() local pressed = imgui.Button('##tg'..key, V(w, h)) imgui.PopStyleColor(3) local hovered = imgui.IsItemHovered() if pressed then ptr[0] = not ptr[0] end st.t = approach(st.t, ptr[0] and 1 or 0, dt, 14) st.hov = approach(st.hov, hovered and 1 or 0, dt, 12) local t = st.t DL:AddRectFilled(V(p.x, p.y), V(p.x+w, p.y+h), u32(0.85, 0.62, 0.32, 0.04 + 0.05*st.hov + 0.04*t), 6*MDS) capsule(DL, p.x, p.y + 5*MDS, 3*MDS, h - 10*MDS, u32v(MT.amber, 0.20 + 0.65*t)) local ix = p.x + 12*MDS local pf = pF(font[14]) if icon ~= '' then local isz = imgui.CalcTextSize(icon) DL:AddText(V(ix, p.y + (h-isz.y)*0.5), u32v(t > 0.5 and MT.amber or MT.textDim, lerp(0.65, 1.0, t)), icon) ix = ix + isz.x + 8*MDS end local tsz = imgui.CalcTextSize(label) DL:AddText(V(ix, p.y + (h-tsz.y)*0.5), u32(lerp(MT.textDim.x, MT.text.x, t), lerp(MT.textDim.y, MT.text.y, t), lerp(MT.textDim.z, MT.text.z, t), lerp(0.75, 1.0, t)), label) pFpop(pf) local tw, th = 42*MDS, 20*MDS local tx = p.x + w - tw - 8*MDS local ty = p.y + (h - th) * 0.5 local r = th * 0.5 if t > 0.02 then capsule(DL, tx-4*MDS, ty-4*MDS, tw+8*MDS, th+8*MDS, u32v(MT.amber, (0.06 + 0.07*pulseWave(1.8)) * t)) end capsule(DL, tx-1.4*MDS, ty-1.4*MDS, tw+2.8*MDS, th+2.8*MDS, u32v(t > 0.5 and MT.amber or MT.border, lerp(0.30, 0.85, t))) capsule(DL, tx, ty, tw, th, u32(lerp(0.153, 0.545, t), lerp(0.122, 0.318, t), lerp(0.086, 0.086, t), 1)) local knobX = tx + r + (tw - th) * t DL:AddCircleFilled(V(knobX, ty + r + 0.8*MDS), r - 2.5*MDS, u32(0,0,0,0.35), 16) DL:AddCircleFilled(V(knobX, ty + r), r - 2.5*MDS, u32(lerp(0.66, 1.00, t), lerp(0.60, 0.86, t), lerp(0.52, 0.42, t), 1), 16) if hint and hovered then imgui.SetTooltip(hint) end imgui.SetCursorScreenPos(V(p.x, p.y)) imgui.Dummy(V(w, h)) return pressed end local function mtButton(id, icon, label, wpx, hpx, colA, colB, txtCol) local DL = imgui.GetWindowDrawList() local p = imgui.GetCursorScreenPos() local w = (wpx and wpx > 0) and wpx or imgui.GetContentRegionAvail().x local h = hpx or 36*MDS imgui.SetCursorScreenPos(V(p.x, p.y)) pushInvisBtn() local pressed = imgui.Button('##b'..id, V(w, h)) imgui.PopStyleColor(3) local hov = imgui.IsItemHovered() local down = imgui.IsItemActive() local sq = down and 1.5*MDS or 0 local x, y, ww, hh = p.x+sq, p.y+sq, w-sq*2, h-sq*2 local r = hh * 0.5 capsule(DL, x+1.5*MDS, y+3*MDS, ww, hh, u32(0,0,0, down and 0.25 or 0.45)) capsule(DL, x-1.4*MDS, y-1.4*MDS, ww+2.8*MDS, hh+2.8*MDS, u32v(colB or MT.amber, hov and 0.95 or 0.55)) local cl, cr = u32v(colA or MT.amberD, 1), u32v(colB or MT.copper, 1) if ww > hh then DL:AddCircleFilled(V(x+r, y+r), r, cl, 20) DL:AddCircleFilled(V(x+ww-r, y+r), r, cr, 20) DL:AddRectFilledMultiColor(V(x+r, y), V(x+ww-r, y+hh), cl, cr, cr, cl) else capsule(DL, x, y, ww, hh, cl) end do local per = 3.2 local pp = (animTime() % per) / per local hw = math.max(14*MDS, ww * 0.22) local sc = x - hw + pp * (ww + hw*2) local TXc, TYc, TZc = 1, 0.97, 0.90 local aMax = hov and 0.24 or 0.14 local sxA, sxB = x + r, x + ww - r if sxB > sxA then local ok = pushClip(DL, sxA, y, sxB, y+hh) DL:AddRectFilledMultiColor(V(sc-hw, y), V(sc, y+hh), u32(TXc,TYc,TZc,0), u32(TXc,TYc,TZc,aMax), u32(TXc,TYc,TZc,aMax), u32(TXc,TYc,TZc,0)) DL:AddRectFilledMultiColor(V(sc, y), V(sc+hw, y+hh), u32(TXc,TYc,TZc,aMax), u32(TXc,TYc,TZc,0), u32(TXc,TYc,TZc,0), u32(TXc,TYc,TZc,aMax)) DL:AddRectFilledMultiColor(V(sxA, y), V(sxB, y+hh*0.46), u32(TXc,TYc,TZc,0.12), u32(TXc,TYc,TZc,0.12), u32(TXc,TYc,TZc,0), u32(TXc,TYc,TZc,0)) if ok then popClip(DL) end end for side = 0, 1 do local ccx = (side == 0) and (x + r) or (x + ww - r) local x0 = (side == 0) and x or (x + ww - r) local ok = pushClip(DL, x0, y, x0 + r, y + hh) local d = math.abs(x0 + r*0.5 - sc) if d < hw then DL:AddCircleFilled(V(ccx, y+r), r, u32(TXc,TYc,TZc,(1-d/hw)*aMax), 20) end DL:AddCircleFilled(V(ccx, y+r), r, u32(TXc,TYc,TZc,0.05), 20) if ok then popClip(DL) end end end local lbl = (icon ~= '' and icon..' ' or '')..label local pf = pF(font[15]) local tsz = imgui.CalcTextSize(lbl) DL:AddText(V(x + (ww-tsz.x)*0.5 + 1, y + (hh-tsz.y)*0.5 + 1), u32(0,0,0,0.45), lbl) DL:AddText(V(x + (ww-tsz.x)*0.5, y + (hh-tsz.y)*0.5), u32v(txtCol or MT.text), lbl) pFpop(pf) imgui.SetCursorScreenPos(V(p.x, p.y)) imgui.Dummy(V(w, h)) return pressed end local function mtOreCard(x, y, w, h, icon, name, value, share, col) local DL = imgui.GetWindowDrawList() DL:AddRectFilled(V(x, y), V(x+w, y+h), u32v(MT.panel), 7*MDS) DL:AddRectFilledMultiColor(V(x+1, y+1), V(x+w-1, y+h-1), u32v(col, 0.16), u32v(col, 0.03), u32v(col, 0.03), u32v(col, 0.16)) DL:AddRect(V(x, y), V(x+w, y+h), u32v(col, 0.35), 7*MDS, 0, 1) capsule(DL, x, y+6*MDS, 3*MDS, h-12*MDS, u32v(col)) local pf = pF(font[12]) local ix = x + 10*MDS if icon ~= '' then local isz = imgui.CalcTextSize(icon) DL:AddText(V(ix, y + 6*MDS), u32v(col, 0.9), icon) ix = ix + isz.x + 5*MDS end DL:AddText(V(ix, y + 6*MDS), u32v(MT.textDim), name) pFpop(pf) local pv = pF(font[16]) local vs = imgui.CalcTextSize(value) DL:AddText(V(x + 10*MDS, y + h - vs.y - 7*MDS), u32v(col), value) pFpop(pv) if share and share > 0 then local bx, by = x + 10*MDS, y + h - 4*MDS local bw = w - 20*MDS capsule(DL, bx, by, bw, 3*MDS, u32(0.3,0.25,0.2,0.6)) capsule(DL, bx, by, math.max(3*MDS, bw*share), 3*MDS, u32v(col, 0.9)) end end imgui.OnFrame( function() return subscribeWindow[0] end, function(self) self.HideCursor = false updMouse() local sw, sh = getScreenResolution() local winW = math.min(sw * 0.78, 520 * MDS) local winH = 300 * MDS imgui.SetNextWindowPos(V(sw*0.5, sh*0.5), imgui.Cond.Always, V(0.5, 0.5)) imgui.SetNextWindowSize(V(winW, winH), imgui.Cond.Always) imgui.PushStyleColor(imgui.Col.WindowBg, TRANSPARENT) imgui.Begin('##subscribe', subscribeWindow, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse + imgui.WindowFlags.NoMove + imgui.WindowFlags.NoBackground) local DL = imgui.GetWindowDrawList() local wp = imgui.GetWindowPos() local thH = 56 * MDS DL:AddRectFilled(V(wp.x, wp.y), V(wp.x+winW, wp.y+winH), u32v(MT.bg), 10*MDS) DL:AddRectFilledMultiColor(V(wp.x, wp.y), V(wp.x+winW, wp.y+winH*0.5), u32v(MT.ember, 0.10), u32v(MT.ember, 0.10), u32v(MT.ember, 0.00), u32v(MT.ember, 0.00)) drawDust(DL, wp.x, wp.y, winW, winH, 14) DL:AddRect(V(wp.x, wp.y), V(wp.x+winW, wp.y+winH), u32v(MT.border), 10*MDS, 0, 1.2) DL:AddRectFilledMultiColor(V(wp.x, wp.y), V(wp.x+winW, wp.y+thH), u32v(MT.emberD), u32v(MT.amberD), u32v(MT.amberD), u32v(MT.emberD)) DL:AddRectFilledMultiColor( V(wp.x, wp.y+thH-1.5*MDS), V(wp.x+winW, wp.y+thH), u32v(MT.amber, 0.20), u32v(MT.amber, 0.95), u32v(MT.amber, 0.95), u32v(MT.amber, 0.20)) local pf = pF(font[18]) local hd = IC.HELMET..' Mine Tools' local hs = imgui.CalcTextSize(hd) local bob = math.sin(animTime() * 2.2) * 2 * MDS DL:AddText(V(wp.x + (winW-hs.x)*0.5, wp.y + (thH-hs.y)*0.5 + bob), u32v(MT.text), hd) pFpop(pf) imgui.SetCursorPos(V(14*MDS, thH + 14*MDS)) local pf2 = pF(font[14]) imgui.PushStyleColor(imgui.Col.Text, MT.textDim) imgui.PushTextWrapPos(winW - 14*MDS) imgui.TextUnformatted(u8('\xcf\xee\xe4\xef\xe8\xf8\xe8\xf1\xfc, \xf7\xf2\xee\xe1\xfb \xed\xe5 \xef\xf0\xee\xef\xf3\xf1\xf2\xe8\xf2\xfc \xed\xee\xe2\xfb\xe5 \xf1\xea\xf0\xe8\xef\xf2\xfb \xe8 \xee\xe1\xed\xee\xe2\xeb\xe5\xed\xe8\xff. \xdd\xf2\xee \xe7\xe0\xe9\xec\xb8\xf2 \xef\xee\xeb\xec\xe8\xed\xf3\xf2\xfb.')) imgui.PopTextWrapPos() imgui.PopStyleColor() pFpop(pf2) imgui.SetCursorPos(V(14*MDS, thH + 74*MDS)) local bw = (winW - 14*MDS*2 - 10*MDS) * 0.5 if mtButton('yt', subYtClicked and IC.CHECK or IC.PLAY, 'YouTube', bw, 46*MDS, subYtClicked and imgui.ImVec4(0.16,0.35,0.14,1) or imgui.ImVec4(0.45,0.08,0.08,1), subYtClicked and MT.good or imgui.ImVec4(0.85,0.18,0.14,1)) then openLink('https://youtube.com/@strand_samp?si=A291kCAs1SM2yoZm') subYtClicked = true end imgui.SetCursorPos(V(14*MDS + bw + 10*MDS, thH + 74*MDS)) if mtButton('tg', subTgClicked and IC.CHECK or IC.PLANE, 'Telegram', bw, 46*MDS, subTgClicked and imgui.ImVec4(0.16,0.35,0.14,1) or imgui.ImVec4(0.09,0.25,0.42,1), subTgClicked and MT.good or imgui.ImVec4(0.18,0.52,0.82,1)) then openLink('https://t.me/strand_scripts') subTgClicked = true end local both = subYtClicked and subTgClicked imgui.SetCursorPos(V(14*MDS, thH + 134*MDS)) if mtButton('subok', both and IC.CHECK or IC.WARN, u8('\xcf\xee\xe4\xef\xe8\xf1\xe0\xeb\xf1\xff \xe8 \xe3\xee\xf2\xee\xe2!'), winW - 28*MDS, 46*MDS, both and imgui.ImVec4(0.20,0.40,0.12,1) or imgui.ImVec4(0.14,0.12,0.09,1), both and MT.good or MT.border, both and MT.text or MT.textDim) then if both then settings.main.subscribed = true inicfg.save(settings, CFG_FILE) subscribeWindow[0] = false mainWindow[0] = true end end if not both then local pf3 = pF(font[13]) local warn = IC.WARN..u8(' \xd1\xed\xe0\xf7\xe0\xeb\xe0 \xed\xe0\xe6\xec\xe8 \xee\xe1\xe5 \xea\xed\xee\xef\xea\xe8') local ws = imgui.CalcTextSize(warn) DL:AddText(V(wp.x + (winW-ws.x)*0.5, wp.y + thH + 190*MDS), u32v(MT.amber, 0.65 + 0.35*pulseWave(1.4)), warn) pFpop(pf3) end imgui.End() imgui.PopStyleColor() end ) local curPage = math.max(1, math.min(4, tonumber(settings.main.selectedPage) or 1)) local tabAnim = { x = nil, w = 0, last = os.clock() } local TAB_DEF = { { IC.SEARCH, u8('\xd0\xf3\xe4\xe0') }, { IC.CHART, u8('\xd1\xf2\xe0\xf2\xe8\xf1\xf2\xe8\xea\xe0') }, { IC.GEAR, u8('\xce\xef\xf6\xe8\xe8') }, { IC.STORE, u8('\xca\xe0\xf2\xe0\xeb\xee\xe3')}, } local function oreColorEdit(id, key, icon) local argb = tonumber(settings.main[key]) or 0xFFFFFFFF local ct = new.float[4]( bit.band(bit.rshift(argb,16),0xFF)/255, bit.band(bit.rshift(argb, 8),0xFF)/255, bit.band(argb,0xFF)/255, bit.band(bit.rshift(argb,24),0xFF)/255) local pfc = pF(font[14]) local changed = imgui.ColorEdit4((icon or '')..'##col'..id, ct, imgui.ColorEditFlags.NoInputs) pFpop(pfc) if changed then settings.main[key] = '0x'..bit.tohex(join_argb( math.floor(ct[3]*255), math.floor(ct[0]*255), math.floor(ct[1]*255), math.floor(ct[2]*255))) inicfg.save(settings, CFG_FILE) oreColorCache = {} end end imgui.OnFrame( function() return mainWindow[0] end, function(self) self.HideCursor = false updMouse() local sw, sh = getScreenResolution() local winW = math.min(sw * 0.80, 660 * MDS) local winH = math.min(sh * 0.80, 560 * MDS) imgui.SetNextWindowPos(V(sw*0.5, sh*0.5), imgui.Cond.FirstUseEver, V(0.5, 0.5)) imgui.SetNextWindowSize(V(winW, winH), imgui.Cond.Always) imgui.PushStyleColor(imgui.Col.WindowBg, TRANSPARENT) imgui.Begin('##mine_tools_main', mainWindow, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse + imgui.WindowFlags.NoBackground) local DL = imgui.GetWindowDrawList() local wp = imgui.GetWindowPos() DL:AddRectFilled(V(wp.x, wp.y), V(wp.x+winW, wp.y+winH), u32v(MT.bg), 10*MDS) DL:AddRectFilledMultiColor(V(wp.x, wp.y+winH*0.55), V(wp.x+winW, wp.y+winH), u32v(MT.ember, 0.00), u32v(MT.ember, 0.00), u32v(MT.ember, 0.13), u32v(MT.ember, 0.13)) drawDust(DL, wp.x, wp.y, winW, winH, 26) DL:AddRect(V(wp.x, wp.y), V(wp.x+winW, wp.y+winH), u32v(MT.border), 10*MDS, 0, 1.2) local hdrH = 54*MDS DL:AddRectFilledMultiColor(V(wp.x, wp.y), V(wp.x+winW*0.55, wp.y+hdrH), u32v(MT.emberD, 0.95), u32v(MT.emberD, 0.00), u32v(MT.emberD, 0.00), u32v(MT.emberD, 0.95)) DL:AddRectFilledMultiColor(V(wp.x+winW*0.45, wp.y), V(wp.x+winW, wp.y+hdrH), u32v(MT.amberD, 0.00), u32v(MT.amberD, 0.90), u32v(MT.amberD, 0.90), u32v(MT.amberD, 0.00)) DL:AddRectFilledMultiColor(V(wp.x, wp.y+hdrH-1.5*MDS), V(wp.x+winW, wp.y+hdrH), u32v(MT.amber, 0.15), u32v(MT.amber, 0.90), u32v(MT.amber, 0.90), u32v(MT.amber, 0.15)) local hx = wp.x + 18*MDS local hy = wp.y + hdrH*0.5 local glow = 0.18 + 0.16 * pulseWave(2.0) DL:AddCircleFilled(V(hx + 8*MDS, hy), 20*MDS, u32v(MT.amber, glow*0.35), 20) DL:AddCircleFilled(V(hx + 8*MDS, hy), 13*MDS, u32v(MT.amber, glow*0.55), 20) local pfh = pF(font[22]) local hsz = imgui.CalcTextSize(IC.HELMET) DL:AddText(V(hx + 8*MDS - hsz.x*0.5, hy - hsz.y*0.5 + math.sin(animTime()*2.4)*2*MDS), u32v(MT.amberH), IC.HELMET) pFpop(pfh) local tx = hx + 34*MDS local pft = pF(font[20]) local t1, t2 = 'MINE', ' TOOLS' local s1 = imgui.CalcTextSize(t1) local s2 = imgui.CalcTextSize(t2) local ty = wp.y + hdrH*0.5 - s1.y*0.5 - 5*MDS DL:AddText(V(tx+1.2*MDS, ty+1.2*MDS), u32(0,0,0,0.5), t1..t2) DL:AddText(V(tx, ty), u32v(MT.amber), t1) DL:AddText(V(tx+s1.x, ty), u32v(MT.text), t2) do local per = 4.5 local pp = (animTime() % per) / per local hw = 26*MDS local sc = tx - hw + pp * (s1.x + s2.x + hw*2) local ok = pushClip(DL, sc-hw*0.5, ty-4*MDS, sc+hw*0.5, ty+s1.y+4*MDS) DL:AddText(V(tx, ty), u32(1.0, 0.95, 0.78, 0.9), t1..t2) if ok then popClip(DL) end end pFpop(pft) local pfs = pF(font[11]) local sub = u8('\xd8\xe0\xf5\xf2\xb8\xf0\xf1\xea\xe8\xe9 \xea\xee\xec\xe1\xe0\xe9\xed') DL:AddText(V(tx, wp.y + hdrH*0.5 + 5*MDS), u32v(MT.textDim), sub) pFpop(pfs) local clS = 28*MDS local clX = wp.x + winW - clS - 12*MDS local clY = wp.y + (hdrH - clS)*0.5 imgui.SetCursorScreenPos(V(clX, clY)) pushInvisBtn() local clPressed = imgui.Button('##mtclose', V(clS, clS)) imgui.PopStyleColor(3) local clHov = imgui.IsItemHovered() DL:AddRectFilled(V(clX, clY), V(clX+clS, clY+clS), u32v(clHov and MT.bad or MT.amber, clHov and 0.90 or 0.16), 6*MDS) local pfc = pF(font[14]) local xs = imgui.CalcTextSize(IC.XMARK) DL:AddText(V(clX + (clS-xs.x)*0.5, clY + (clS-xs.y)*0.5), u32v(clHov and MT.text or MT.textDim), IC.XMARK) pFpop(pfc) if clPressed then mainWindow[0] = false end local tabsY = wp.y + hdrH + 8*MDS local tabsH = 40*MDS local padX = 10*MDS local tabW = (winW - padX*2) / #TAB_DEF DL:AddRectFilled(V(wp.x+padX, tabsY), V(wp.x+winW-padX, tabsY+tabsH), u32(0, 0, 0, 0.30), 8*MDS) local now = os.clock() local dtT = now - tabAnim.last; tabAnim.last = now if dtT < 0 or dtT > 0.25 then dtT = 0.016 end local targetX = wp.x + padX + (curPage-1)*tabW if not tabAnim.x then tabAnim.x = targetX end tabAnim.x = approach(tabAnim.x, targetX, dtT, 16) do local ix, iy = tabAnim.x + 3*MDS, tabsY + 3*MDS local iw, ih = tabW - 6*MDS, tabsH - 6*MDS capsule(DL, ix-2*MDS, iy-2*MDS, iw+4*MDS, ih+4*MDS, u32v(MT.amber, 0.10 + 0.08*pulseWave(1.8))) local r = ih*0.5 if iw > ih then DL:AddCircleFilled(V(ix+r, iy+r), r, u32v(MT.emberD), 20) DL:AddCircleFilled(V(ix+iw-r, iy+r), r, u32v(MT.amberD), 20) DL:AddRectFilledMultiColor(V(ix+r, iy), V(ix+iw-r, iy+ih), u32v(MT.emberD), u32v(MT.amberD), u32v(MT.amberD), u32v(MT.emberD)) else capsule(DL, ix, iy, iw, ih, u32v(MT.amberD)) end capsule(DL, ix+4*MDS, iy+ih-3*MDS, iw-8*MDS, 2.5*MDS, u32v(MT.amber, 0.9)) end for i, td in ipairs(TAB_DEF) do local bx = wp.x + padX + (i-1)*tabW imgui.SetCursorScreenPos(V(bx, tabsY)) pushInvisBtn() local pressed = imgui.Button('##tab'..i, V(tabW, tabsH)) imgui.PopStyleColor(3) local hov = imgui.IsItemHovered() local act = (curPage == i) local lbl = (td[1] ~= '' and td[1]..' ' or '')..td[2] local pfb = pF(font[13]) local ls = imgui.CalcTextSize(lbl) local lx = bx + (tabW - ls.x)*0.5 local ly = tabsY + (tabsH - ls.y)*0.5 if act then DL:AddText(V(lx+1, ly+1), u32(0,0,0,0.45), lbl) end DL:AddText(V(lx, ly), u32v(act and MT.text or MT.textDim, act and 1.0 or (hov and 0.95 or 0.7)), lbl) pFpop(pfb) if pressed then curPage = i settings.main.selectedPage = i inicfg.save(settings, CFG_FILE) end end local bodyY = tabsY + tabsH + 8*MDS local bodyH = winH - (bodyY - wp.y) - 10*MDS imgui.SetCursorScreenPos(V(wp.x + padX, bodyY)) imgui.PushStyleColor(imgui.Col.ChildBg, TRANSPARENT) imgui.BeginChild('##mt_body', V(winW - padX*2, bodyH), false) local DL = imgui.GetWindowDrawList() local bodyClip = pushClip(DL, wp.x + padX, bodyY, wp.x + winW - padX, bodyY + bodyH) if curPage == 1 then if mtButton('banner', IC.STAR, BANNER_NEW, -1, 42*MDS, imgui.ImVec4(0.62,0.30,0.03,1), MT.amber, imgui.ImVec4(1.0,0.96,0.86,1)) then openLink(BANNER_NEW_URL) end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.SEARCH, u8('\xcf\xce\xc8\xd1\xca \xd0\xd3\xc4\xdb')) if mtToggle('ore', IC.GEM, u8('\xcf\xee\xe8\xf1\xea \xf0\xf3\xe4\xfb'), UI.renderOre, u8('\xd2\xe0\xea\xe6\xe5 \xea\xee\xec\xe0\xed\xe4\xee\xe9 /mtore')) then settings.main.renderOre = UI.renderOre[0]; inicfg.save(settings, CFG_FILE) end if mtToggle('dig', IC.HAMMER, u8('\xc0\xe2\xf2\xee-\xe2\xfb\xea\xe0\xef\xfb\xe2\xe0\xed\xe8\xe5'), UI.autoDig) then settings.main.autoDig = UI.autoDig[0]; inicfg.save(settings, CFG_FILE) end if mtToggle('line', IC.ROUTE, u8('\xcb\xe8\xed\xe8\xff \xe4\xee \xf0\xf3\xe4\xe5'), UI.showOreLine) then settings.main.showOreLine = UI.showOreLine[0]; inicfg.save(settings, CFG_FILE) end if mtToggle('dist', IC.PIN, u8('\xc4\xe8\xf1\xf2\xe0\xed\xf6\xe8\xff \xe4\xee \xf0\xf3\xe4\xfb'), UI.showOreDistance) then settings.main.showOreDistance = UI.showOreDistance[0]; inicfg.save(settings, CFG_FILE) end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.LAYERS, u8('\xd2\xc8\xcf\xdb \xd0\xd3\xc4\xdb')) local oreDefs = { {'st', ORE_IC[1], STAT_NAMES[1], UI.renderStone, 'UI.renderStone', 'colorStone'}, {'mt', ORE_IC[2], STAT_NAMES[2], UI.renderMetal, 'UI.renderMetal', 'colorMetal'}, {'sv', ORE_IC[3], STAT_NAMES[3], UI.renderSilver, 'UI.renderSilver', 'colorSilver'}, {'bz', ORE_IC[4], STAT_NAMES[4], UI.renderBronze, 'UI.renderBronze', 'colorBronze'}, {'gd', ORE_IC[5], STAT_NAMES[5], UI.renderGold, 'UI.renderGold', 'colorGold'}, } for _, od in ipairs(oreDefs) do if mtToggle(od[1], od[2], od[3], od[4]) then settings.main[od[5]] = od[4][0]; inicfg.save(settings, CFG_FILE) end end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.BRUSH, u8('\xd6\xc2\xc5\xd2\xc0 \xcf\xce\xc4\xcf\xc8\xd1\xc5\xc9')) for k, od in ipairs(oreDefs) do if k > 1 and (k-1) % 3 ~= 0 then imgui.SameLine(0, 10*MDS) end oreColorEdit(od[1], od[6], od[2]) end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.SLIDERS, u8('\xcf\xc0\xd0\xc0\xcc\xc5\xd2\xd0\xdb')) local pfSl = pF(font[14]) imgui.PushItemWidth(imgui.GetContentRegionAvail().x - 16*MDS) if imgui.SliderInt(u8('##rad'), UI.renderRadius, 1, 600, IC.PIN..u8(' \xd0\xe0\xe4\xe8\xf3\xf1: %d \xec')) then settings.main.renderRadius = UI.renderRadius[0]; inicfg.save(settings, CFG_FILE) end if imgui.SliderInt(u8('##fsz'), UI.renderSize, 10, 27, IC.BRUSH..u8(' \xd0\xe0\xe7\xec\xe5\xf0 \xf8\xf0\xe8\xf4\xf2\xe0: %d')) then settings.main.renderSize = UI.renderSize[0]; inicfg.save(settings, CFG_FILE) end imgui.PopItemWidth() pFpop(pfSl) imgui.Dummy(V(1, 4*MDS)) mtSection(IC.CLOCK, u8('\xd2\xc0\xc9\xcc\xc5\xd0 \xd0\xd3\xc4\xdb')) if mtToggle('tmr', IC.CLOCK, u8('\xd2\xe0\xe9\xec\xe5\xf0 \xf0\xe5\xf1\xef\xe0\xe2\xed\xe0'), UI.oreTimer, u8('\xd2\xe0\xea\xe6\xe5 \xea\xee\xec\xe0\xed\xe4\xee\xe9 /mttimer')) then settings.main.oreTimer = UI.oreTimer[0]; inicfg.save(settings, CFG_FILE) end do local pfc2 = pF(font[13]) imgui.PushStyleColor(imgui.Col.Text, MT.textDim) imgui.Text(IC.BRUSH..u8(' \xd6\xe2\xe5\xf2 \xf2\xe0\xe9\xec\xe5\xf0\xe0')) imgui.PopStyleColor() pFpop(pfc2) imgui.SameLine(0, 10*MDS) oreColorEdit('tm', 'colorOreTimer', nil) end if mtToggle('tmrd', IC.PIN, u8('\xc4\xe8\xf1\xf2\xe0\xed\xf6\xe8\xff \xe4\xee \xf2\xe0\xe9\xec\xe5\xf0\xe0'), UI.oreTimerDistance) then settings.main.oreTimerDistance = UI.oreTimerDistance[0]; inicfg.save(settings, CFG_FILE) end if mtToggle('tmrl', IC.ROUTE, u8('\xcb\xe8\xed\xe8\xff \xe4\xee \xf2\xe0\xe9\xec\xe5\xf0\xe0'), UI.oreTimerLine) then settings.main.oreTimerLine = UI.oreTimerLine[0]; inicfg.save(settings, CFG_FILE) end local pfSl2 = pF(font[14]) imgui.PushItemWidth(imgui.GetContentRegionAvail().x - 16*MDS) if imgui.SliderInt(u8('##tsz'), UI.renderOreTimerSize, 10, 27, IC.BRUSH..u8(' \xd0\xe0\xe7\xec\xe5\xf0 \xf2\xe0\xe9\xec\xe5\xf0\xe0: %d')) then settings.main.renderOreTimerSize = UI.renderOreTimerSize[0]; inicfg.save(settings, CFG_FILE) end imgui.PopItemWidth() pFpop(pfSl2) imgui.Dummy(V(1, 10*MDS)) elseif curPage == 2 then mtSection(IC.CHART, u8('\xc4\xce\xc1\xdb\xd7\xc0')) local counts = { tonumber(settings.main.countStone) or 0, tonumber(settings.main.countMetal) or 0, tonumber(settings.main.countSilver) or 0, tonumber(settings.main.countBronze) or 0, tonumber(settings.main.countGold) or 0, tonumber(settings.main.countCoal) or 0, } local prices = { tonumber(settings.main.priceStone) or 0, tonumber(settings.main.priceMetal) or 0, tonumber(settings.main.priceSilver) or 0, tonumber(settings.main.priceBronze) or 0, tonumber(settings.main.priceGold) or 0, tonumber(settings.main.priceCoal) or 0, } local totalCnt, totalSum = 0, 0 for k = 1, 6 do totalCnt = totalCnt + counts[k] totalSum = totalSum + counts[k] * prices[k] end local avail = imgui.GetContentRegionAvail().x local gap = 6*MDS local cw = (avail - gap*2) / 3 local ch = 58*MDS local base = imgui.GetCursorScreenPos() for k = 1, 6 do local col = (k-1) % 3 local row = math.floor((k-1) / 3) mtOreCard(base.x + col*(cw+gap), base.y + row*(ch+gap), cw, ch, ORE_IC[k], STAT_NAMES[k], tostring(counts[k]), totalCnt > 0 and counts[k]/totalCnt or 0, ORE_COL[k]) end imgui.Dummy(V(avail, ch*2 + gap + 6*MDS)) do local p = imgui.GetCursorScreenPos() local h = 42*MDS DL:AddRectFilled(V(p.x, p.y), V(p.x+avail, p.y+h), u32v(MT.panel), 8*MDS) DL:AddRectFilledMultiColor(V(p.x+1, p.y+1), V(p.x+avail-1, p.y+h-1), u32v(MT.amber, 0.16), u32v(MT.amber, 0.03), u32v(MT.amber, 0.03), u32v(MT.amber, 0.16)) DL:AddRect(V(p.x, p.y), V(p.x+avail, p.y+h), u32v(MT.amber, 0.40), 8*MDS, 0, 1) local pf1 = pF(font[13]) local l1 = IC.WEIGHT..u8(' \xc2\xf1\xe5\xe3\xee \xf0\xf3\xe4\xfb: ')..totalCnt DL:AddText(V(p.x+12*MDS, p.y+h*0.5-imgui.CalcTextSize(l1).y*0.5), u32v(MT.textDim), l1) pFpop(pf1) local pf2 = pF(font[16]) local l2 = IC.COINS..' '..convertToPriceFormat(totalSum) local s2b = imgui.CalcTextSize(l2) DL:AddText(V(p.x+avail-s2b.x-12*MDS, p.y+h*0.5-s2b.y*0.5), u32v(MT.amber), l2) pFpop(pf2) imgui.Dummy(V(avail, h + 8*MDS)) end mtSection(IC.EYE, u8('\xd7\xd2\xce \xcf\xce\xca\xc0\xc7\xdb\xc2\xc0\xd2\xdc \xc2 HUD')) if mtToggle('hud', IC.CHART, u8('\xd1\xf2\xe0\xf2\xe8\xf1\xf2\xe8\xea\xe0 \xed\xe0 \xfd\xea\xf0\xe0\xed\xe5'), UI.statisticsWindow) then settings.main.statisticsWindow = UI.statisticsWindow[0]; inicfg.save(settings, CFG_FILE) end local hudDefs = { {'hst', ORE_IC[1], STAT_NAMES[1], UI.statisticsStone, 'UI.statisticsStone'}, {'hmt', ORE_IC[2], STAT_NAMES[2], UI.statisticsMetal, 'UI.statisticsMetal'}, {'hsv', ORE_IC[3], STAT_NAMES[3], UI.statisticsSilver, 'UI.statisticsSilver'}, {'hbz', ORE_IC[4], STAT_NAMES[4], UI.statisticsBronze, 'UI.statisticsBronze'}, {'hgd', ORE_IC[5], STAT_NAMES[5], UI.statisticsGold, 'UI.statisticsGold'}, {'hcl', ORE_IC[6], STAT_NAMES[6], UI.statisticsCoal, 'UI.statisticsCoal'}, } for _, hd2 in ipairs(hudDefs) do if mtToggle(hd2[1], hd2[2], hd2[3], hd2[4]) then settings.main[hd2[5]] = hd2[4][0]; inicfg.save(settings, CFG_FILE) end end if mtToggle('tot', IC.COINS, u8('\xce\xe1\xf9\xe0\xff \xf6\xe5\xed\xe0'), UI.totalPrice) then settings.main.totalPrice = UI.totalPrice[0]; inicfg.save(settings, CFG_FILE) end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.COINS, u8('\xd6\xc5\xcd\xdb \xc7\xc0 \xd8\xd2\xd3\xca\xd3')) local priceFields = { {STAT_NAMES[1], UI.priceStone, 'UI.priceStone'}, {STAT_NAMES[2], UI.priceMetal, 'UI.priceMetal'}, {STAT_NAMES[3], UI.priceSilver, 'UI.priceSilver'}, {STAT_NAMES[4], UI.priceBronze, 'UI.priceBronze'}, {STAT_NAMES[5], UI.priceGold, 'UI.priceGold'}, {STAT_NAMES[6], UI.priceCoal, 'UI.priceCoal'}, } local pfPr = pF(font[14]) imgui.PushItemWidth(imgui.GetContentRegionAvail().x * 0.55) for k, pf3 in ipairs(priceFields) do if imgui.InputInt(ORE_IC[k]..' '..pf3[1]..'##p'..k, pf3[2], 1000, 10000) then if pf3[2][0] < 0 then pf3[2][0] = 0 end settings.main[pf3[3]] = pf3[2][0]; inicfg.save(settings, CFG_FILE) end end imgui.PopItemWidth() pFpop(pfPr) imgui.Dummy(V(1, 6*MDS)) if mtButton('resetstat', IC.RESET, u8('\xd1\xe1\xf0\xee\xf1\xe8\xf2\xfc \xf1\xf7\xb8\xf2\xf7\xe8\xea\xe8'), -1, 38*MDS, imgui.ImVec4(0.34,0.10,0.06,1), MT.bad) then settings.main.countStone=0; settings.main.countMetal=0 settings.main.countSilver=0; settings.main.countBronze=0 settings.main.countGold=0; settings.main.countCoal=0 inicfg.save(settings, CFG_FILE) end imgui.Dummy(V(1, 10*MDS)) elseif curPage == 3 then mtSection(IC.BOLT, u8('\xd8\xc0\xd5\xd2\xc0')) if mtToggle('run', IC.RUN, u8('\xc1\xfb\xf1\xf2\xf0\xfb\xe9 \xe1\xe5\xe3'), UI.fastRun, u8('\xc1\xe5\xf1\xea\xee\xed\xe5\xf7\xed\xfb\xe9 \xf1\xef\xf0\xe8\xed\xf2 \xef\xe5\xf8\xea\xee\xec')) then settings.main.fastRun = UI.fastRun[0]; inicfg.save(settings, CFG_FILE) end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.VOLUME, u8('\xc7\xc2\xd3\xca')) if mtToggle('snd', IC.VOLUME, u8('\xc7\xe2\xf3\xea \xef\xf0\xe8 \xe4\xee\xe1\xfb\xf7\xe5 \xf0\xf3\xe4\xfb'), UI.oreSoundEnabled) then settings.main.oreSoundEnabled = UI.oreSoundEnabled[0]; inicfg.save(settings, CFG_FILE) end if not doesFileExist(SOUND_FILE) then local pfd = pF(font[12]) imgui.TextColored(MT.textDim, IC.DOWN..u8(' \xc7\xe2\xf3\xea \xef\xee\xe4\xea\xe0\xf7\xe8\xe2\xe0\xe5\xf2\xf1\xff...')) pFpop(pfd) end imgui.Dummy(V(1, 4*MDS)) mtSection(IC.TERMINAL, u8('\xca\xce\xcc\xc0\xcd\xc4\xdb')) local pfCmd = pF(font[14]) imgui.PushItemWidth(imgui.GetContentRegionAvail().x * 0.6) if imgui.InputTextWithHint('##cmd', u8('\xca\xee\xec\xe0\xed\xe4\xe0 \xec\xe5\xed\xfe'), UI.commandOpenMenu, 256) then local decoded = u8:decode(ffi.string(UI.commandOpenMenu)) if decoded and decoded ~= '' then local clean = decoded:gsub('%A', '') if clean ~= '' then sampUnregisterChatCommand(settings.main.commandOpenMenu) settings.main.commandOpenMenu = clean inicfg.save(settings, CFG_FILE) sampRegisterChatCommand(clean, toggleMainMenu) end end end imgui.PopItemWidth() pFpop(pfCmd) local pfl = pF(font[12]) imgui.PushStyleColor(imgui.Col.Text, MT.textDim) imgui.Text(IC.TERMINAL..' /'..tostring(settings.main.commandOpenMenu)..u8(' \x97 \xec\xe5\xed\xfe')) imgui.Text(IC.GEM..u8(' /mtore \x97 \xef\xee\xe8\xf1\xea \xf0\xf3\xe4\xfb')) imgui.Text(IC.CLOCK..u8(' /mttimer \x97 \xf2\xe0\xe9\xec\xe5\xf0')) imgui.PopStyleColor() pFpop(pfl) imgui.Dummy(V(1, 6*MDS)) mtSection(IC.USER, u8('\xc0\xc2\xd2\xce\xd0')) local aw = (imgui.GetContentRegionAvail().x - 8*MDS) * 0.5 local ay = imgui.GetCursorPosY() if mtButton('chan', IC.PLANE, '@strand_scripts', aw, 36*MDS, imgui.ImVec4(0.09,0.25,0.42,1), imgui.ImVec4(0.18,0.52,0.82,1)) then openLink(CHANNEL_TG) end imgui.SetCursorPosY(ay) imgui.SetCursorPosX(aw + 8*MDS) if mtButton('auth', IC.USER, '@victor_st0', aw, 36*MDS, imgui.ImVec4(0.30,0.19,0.05,1), MT.copper) then openLink(AUTHOR_TG) end imgui.Dummy(V(1, 10*MDS)) elseif curPage == 4 then local availW = imgui.GetContentRegionAvail().x for i, sc in ipairs(catScripts) do local portrait = sc.img_ratio and sc.img_ratio < 1 local IMG_W, IMG_H if portrait then IMG_H = 118*MDS; IMG_W = IMG_H * sc.img_ratio else IMG_W = 96*MDS; IMG_H = 64*MDS end local CARD_H = IMG_H + 16*MDS local sp = imgui.GetCursorScreenPos() if sp.y + CARD_H < bodyY or sp.y > bodyY + bodyH then imgui.SetCursorScreenPos(V(sp.x, sp.y + CARD_H + 8*MDS)) imgui.Dummy(V(availW, 0)) goto cat_next end if sc.featured then local pl = 0.55 + 0.45 * pulseWave(1.6) DL:AddRectFilled(V(sp.x, sp.y), V(sp.x+availW, sp.y+CARD_H), u32v(MT.panel), 8*MDS) DL:AddRectFilledMultiColor(V(sp.x+1, sp.y+1), V(sp.x+availW-1, sp.y+CARD_H-1), u32v(MT.amber, 0.18), u32v(MT.ember, 0.06), u32v(MT.ember, 0.06), u32v(MT.amber, 0.18)) DL:AddRect(V(sp.x, sp.y), V(sp.x+availW, sp.y+CARD_H), u32v(MT.amber, 0.35 + 0.5*pl), 8*MDS, 0, 1.5) else DL:AddRectFilled(V(sp.x, sp.y), V(sp.x+availW, sp.y+CARD_H), u32v(MT.panel), 8*MDS) DL:AddRect(V(sp.x, sp.y), V(sp.x+availW, sp.y+CARD_H), u32v(MT.border), 8*MDS, 0, 1) end local imgX = sp.x + 8*MDS local imgY = sp.y + (CARD_H-IMG_H)*0.5 DL:AddRectFilled(V(imgX, imgY), V(imgX+IMG_W, imgY+IMG_H), u32(0.05,0.045,0.035,1), 5*MDS) local tex = sc.img_file and sc.img_file ~= '' and catTextures[sc.img_file] or nil if tex and type(tex) ~= 'string' then local ratio = sc.img_ratio or (IMG_W / IMG_H) local boxR = IMG_W / IMG_H local dw, dh if ratio > boxR then dw = IMG_W; dh = IMG_W / ratio else dh = IMG_H; dw = IMG_H * ratio end imgui.SetCursorScreenPos(V(imgX + (IMG_W-dw)*0.5, imgY + (IMG_H-dh)*0.5)) imgui.Image(tex, V(dw, dh)) else local ph = (tex=='loading') and (IC.DOWN..u8(' \xc7\xe0\xe3\xf0\xf3\xe7\xea\xe0')) or u8('\xcd\xe5\xf2 \xf4\xee\xf2\xee') local pfp = pF(font[11]) local ts = imgui.CalcTextSize(ph) DL:AddText(V(imgX+IMG_W*0.5-ts.x*0.5, imgY+IMG_H*0.5-ts.y*0.5), u32v(MT.textDim, 0.7), ph) pFpop(pfp) end local BTN_W, BTN_H = 92*MDS, 32*MDS local textX = imgX + IMG_W + 12*MDS local textW = availW - IMG_W - BTN_W - 34*MDS local pfn = pF(font[14]) local nm = sc.name or '?' DL:AddText(V(textX, sp.y + 10*MDS), u32v(MT.text), nm) local nmw = imgui.CalcTextSize(nm).x pFpop(pfn) do local pfb2 = pF(font[10]) local blbl = sc.vip and 'VIP' or 'FREE' local bs = imgui.CalcTextSize(blbl) local bw2 = bs.x + 12*MDS local bx2 = textX + nmw + 8*MDS local by2 = sp.y + 10*MDS capsule(DL, bx2, by2, bw2, 15*MDS, u32v(sc.vip and MT.amber or MT.good)) DL:AddText(V(bx2 + (bw2-bs.x)*0.5, by2 + (15*MDS-bs.y)*0.5), u32(0.06,0.05,0.03,1), blbl) pFpop(pfb2) end imgui.SetCursorScreenPos(V(textX, sp.y + 30*MDS)) imgui.BeginGroup() local pfd2 = pF(font[12]) imgui.PushStyleColor(imgui.Col.Text, MT.textDim) imgui.PushTextWrapPos(imgui.GetCursorPosX() + math.max(60*MDS, textW)) imgui.TextUnformatted(sc.short or '') imgui.PopTextWrapPos() imgui.PopStyleColor() pFpop(pfd2) if sc.vip and (sc.price_text or sc.price_month) then local pfp2 = pF(font[11]) local pl2 = sc.price_text or (u8('\xd6\xe5\xed\xe0: ')..tostring(sc.price_month).. u8('/\xec\xe5\xf1 \xe8\xeb\xe8 ')..tostring(sc.price_year or '?')..u8('/\xe3\xee\xe4')) imgui.TextColored(MT.amber, IC.COINS..' '..pl2) pFpop(pfp2) end imgui.EndGroup() imgui.SetCursorScreenPos(V(sp.x + availW - BTN_W - 10*MDS, sp.y + (CARD_H-BTN_H)*0.5)) local isFree = not sc.vip if mtButton('cat'..i, isFree and IC.DOWN or IC.CROWN, isFree and u8('\xc2\xe7\xff\xf2\xfc') or u8('\xca\xf3\xef\xe8\xf2\xfc'), BTN_W, BTN_H, isFree and imgui.ImVec4(0.10,0.30,0.12,1) or imgui.ImVec4(0.42,0.26,0.04,1), isFree and MT.good or MT.amber, imgui.ImVec4(1,0.97,0.90,1)) then if sc.tg_link then openLink(sc.tg_link) end end imgui.SetCursorScreenPos(V(sp.x, sp.y + CARD_H + 8*MDS)) imgui.Dummy(V(availW, 0)) ::cat_next:: end imgui.Dummy(V(1, 10*MDS)) end if bodyClip then popClip(DL) end imgui.EndChild() imgui.PopStyleColor() imgui.End() imgui.PopStyleColor() end ) imgui.OnFrame( function() return render[0] end, function(self) self.HideCursor = true local DL = imgui.GetBackgroundDrawList() if renderOre[0] and (renderStone[0] or renderMetal[0] or renderSilver[0] or renderBronze[0] or renderGold[0]) then local oreNameAndColor = { {STAT_NAMES[1], settings.main.colorStone, renderStone[0], ORE_IC[1]}, {STAT_NAMES[2], settings.main.colorMetal, renderMetal[0], ORE_IC[2]}, {STAT_NAMES[3], settings.main.colorSilver, renderSilver[0], ORE_IC[3]}, {STAT_NAMES[4], settings.main.colorBronze, renderBronze[0], ORE_IC[4]}, {STAT_NAMES[5], settings.main.colorGold, renderGold[0], ORE_IC[5]}, } local ok_p, mx, my, mz = pcall(getCharCoordinates, PLAYER_PED) local okc, cx, cy = false, nil, nil if ok_p and tonumber(mx) then okc, cx, cy = pcall(convert3DCoordsToScreen, mx, my, mz) okc = okc and tonumber(cx) ~= nil and tonumber(cy) ~= nil end if ok_p and tonumber(mx) then local radius = renderRadius[0] for k, entry in pairs(oreObjCache) do local ox,oy,oz,v = entry[1],entry[2],entry[3],entry[4] local nc = oreNameAndColor[v] if nc and nc[3] then local dist = safeDist3d(ox,oy,oz,mx,my,mz) if dist <= radius and isPointOnScreen(ox, oy, oz, 0) then local ok3, tx, ty = pcall(convert3DCoordsToScreen, ox, oy, oz) if ok3 and tx and ty then local col = cachedColor(nc[2]) if showOreLine[0] and okc then DL:AddLine(V(tx,ty), V(cx,cy), u32(0,0,0,0.35), 3.5*MDS) DL:AddLine(V(tx,ty), V(cx,cy), col, 1.8*MDS) end local text = (nc[4] or IC.GEM)..' '..ORE_LABEL if showOreDistance[0] then text = text..' ['..math.floor(dist)..']' end local fnt = font[renderSize[0]] local fsz = renderSize[0] * MDS local tsz = imgui.CalcTextSize(text) local tx2 = tx - tsz.x*.5 local ty2 = ty - fsz - 2*MDS if fnt then DL:AddTextFontPtr(fnt, fsz, V(tx2,ty2), col, text) else DL:AddText(V(tx2,ty2), col, text) end end end end end end end if renderOre[0] then local ok_p, px, py, pz = pcall(getCharCoordinates, PLAYER_PED) if ok_p and tonumber(px) and #ore3dCache > 0 then local okc2, cx, cy = pcall(convert3DCoordsToScreen, px, py, pz) okc2 = okc2 and tonumber(cx) ~= nil and tonumber(cy) ~= nil local radius = renderRadius[0] local col3d = cachedColor(settings.main.colorStone) local lineCol = u32v(MT.good, 0.90) local lineShadow = u32(0,0,0,0.35) for _, entry in ipairs(ore3dCache) do local ox,oy,oz = entry[1],entry[2],entry[3] local dist = safeDist3d(ox,oy,oz,px,py,pz) if dist <= radius and isPointOnScreen(ox, oy, oz, 0) then local ok_s, sx, sy = pcall(convert3DCoordsToScreen, ox, oy, oz) if ok_s and sx and sy then if showOreLine[0] and okc2 then DL:AddLine(V(cx,cy), V(sx,sy), lineShadow, 3.5*MDS) DL:AddLine(V(cx,cy), V(sx,sy), lineCol, 1.8*MDS) end local lbl = IC.MOUNT..' '..ORE_LABEL if showOreDistance[0] then lbl = lbl..' ['..math.floor(dist)..']' end local fnt = font[renderSize[0]] local fsz = renderSize[0] * MDS local tsz = imgui.CalcTextSize(lbl) local lx = sx - tsz.x*.5 local ly = sy - fsz - 2*MDS if fnt then DL:AddTextFontPtr(fnt, fsz, V(lx,ly), col3d, lbl) else DL:AddText(V(lx,ly), col3d, lbl) end end end end end end if oreTimer[0] then local ok0, mx, my, mz = pcall(getCharCoordinates, PLAYER_PED) if ok0 and tonumber(mx) then local okc, cx, cy = pcall(convert3DCoordsToScreen, mx, my, mz) local tmCol = cachedColor(settings.main.colorOreTimer) local tmFnt = font[renderOreTimerSize[0]] local tmPx = renderOreTimerSize[0] * MDS for k = #oreTimerList, 1, -1 do local v = oreTimerList[k] local diff = v[4] - os.time() if diff < 0 then table.remove(oreTimerList, k) elseif isPointOnScreen(v[1], v[2], v[3], 0) then local ok_s, tx, ty = pcall(convert3DCoordsToScreen, v[1], v[2], v[3]) if ok_s and tonumber(tx) and tonumber(ty) then local dist = math.floor(safeDist3d(v[1],v[2],v[3],mx,my,mz)) local timeStr = os.date('%M:%S', diff) local hot = diff < 60 local text = (hot and (IC.FIRE..' '..ORE_REMAIN) or (IC.CLOCK..' ')) ..timeStr..(oreTimerDistance[0] and (' ['..dist..']') or '') local tsz = tmFnt and imgui.CalcTextSize(text) or V(60*MDS, tmPx) local bw2 = tsz.x + 14*MDS local bh2 = tmPx + 8*MDS local bx2 = tx - bw2*0.5 local by2 = ty - bh2 - 4*MDS capsule(DL, bx2, by2, bw2, bh2, u32(0.04,0.035,0.03,0.72)) capsule(DL, bx2-1.2*MDS, by2-1.2*MDS, bw2+2.4*MDS, bh2+2.4*MDS, u32v(hot and MT.ember or MT.amber, hot and (0.35 + 0.45*pulseWave(0.6)) or 0.35)) capsule(DL, bx2, by2, bw2, bh2, u32(0.04,0.035,0.03,0.88)) if tmFnt then DL:AddTextFontPtr(tmFnt, tmPx, V(bx2 + (bw2-tsz.x)*0.5, by2 + (bh2-tsz.y)*0.5), tmCol, text) else DL:AddText(V(bx2 + 7*MDS, by2 + 4*MDS), tmCol, text) end if oreTimerLine[0] and okc and tonumber(cx) and tonumber(cy) then DL:AddLine(V(tx, ty), V(cx, cy), u32(0,0,0,0.35), 3*MDS) DL:AddLine(V(tx, ty), V(cx, cy), tmCol, 1.6*MDS) end end end end end end if #catPending > 0 then local item = table.remove(catPending, 1) if doesFileExist(item.path) then local ok_tex, tex = pcall(imgui.CreateTextureFromFile, item.path) catTextures[item.file] = (ok_tex and tex) or 'failed' else catTextures[item.file] = 'failed' end end end ) local hudAnim = { share = {0,0,0,0,0,0}, flash = {0,0,0,0,0,0}, prev = nil, pops = {}, total = 0, last = os.clock(), } local hudOpen = new.bool(true) imgui.OnFrame( function() return statisticsWindow[0] and (statisticsStone[0] or statisticsMetal[0] or statisticsSilver[0] or statisticsBronze[0] or statisticsGold[0] or statisticsCoal[0] or totalPrice[0]) end, function(self) self.HideCursor = false updMouse() local counts = { tonumber(settings.main.countStone) or 0, tonumber(settings.main.countMetal) or 0, tonumber(settings.main.countSilver) or 0, tonumber(settings.main.countBronze) or 0, tonumber(settings.main.countGold) or 0, tonumber(settings.main.countCoal) or 0, } local prices = { tonumber(settings.main.priceStone) or 0, tonumber(settings.main.priceMetal) or 0, tonumber(settings.main.priceSilver) or 0, tonumber(settings.main.priceBronze) or 0, tonumber(settings.main.priceGold) or 0, tonumber(settings.main.priceCoal) or 0, } local vis = { statisticsStone[0], statisticsMetal[0], statisticsSilver[0], statisticsBronze[0], statisticsGold[0], statisticsCoal[0], } local rows, maxCnt, earned, totalCnt = {}, 0, 0, 0 for k = 1, 6 do if vis[k] then rows[#rows+1] = k if counts[k] > maxCnt then maxCnt = counts[k] end earned = earned + counts[k] * prices[k] totalCnt = totalCnt + counts[k] end end local now = os.clock() local dt = now - hudAnim.last; hudAnim.last = now if dt < 0 or dt > 0.25 then dt = 0.016 end if not hudAnim.prev then hudAnim.prev = {counts[1],counts[2],counts[3],counts[4],counts[5],counts[6]} end for k = 1, 6 do local d = counts[k] - hudAnim.prev[k] if d > 0 then hudAnim.flash[k] = 1.0 hudAnim.pops[#hudAnim.pops+1] = { k = k, n = d, t = 0 } end hudAnim.prev[k] = counts[k] hudAnim.flash[k] = math.max(0, hudAnim.flash[k] - dt * 1.6) local target = maxCnt > 0 and (counts[k] / maxCnt) or 0 hudAnim.share[k] = approach(hudAnim.share[k], target, dt, 6) end for i = #hudAnim.pops, 1, -1 do local pp = hudAnim.pops[i] pp.t = pp.t + dt if pp.t > 1.4 then table.remove(hudAnim.pops, i) end end hudAnim.total = approach(hudAnim.total, earned, dt, 6) if math.abs(hudAnim.total - earned) < 1 then hudAnim.total = earned end local elapsed = math.max(1, os.clock() - sessionStart) local perHour = totalCnt / (elapsed / 3600) local rowH = 28*MDS local padX = 12*MDS local hdrH = 42*MDS local footH = totalPrice[0] and 46*MDS or 10*MDS local hudW = 224*MDS local hudH = hdrH + #rows * rowH + footH + 6*MDS imgui.SetNextWindowPos( V(tonumber(settings.main.statisticsPosX) or 300, tonumber(settings.main.statisticsPosY) or 300), imgui.Cond.FirstUseEver) imgui.SetNextWindowSize(V(hudW, hudH), imgui.Cond.Always) imgui.PushStyleColor(imgui.Col.WindowBg, TRANSPARENT) hudOpen[0] = true imgui.Begin('##mt_stats_hud', hudOpen, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse + imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoSavedSettings + imgui.WindowFlags.NoBackground) local sp = imgui.GetWindowPos() if tonumber(settings.main.statisticsPosX) ~= sp.x or tonumber(settings.main.statisticsPosY) ~= sp.y then settings.main.statisticsPosX = sp.x settings.main.statisticsPosY = sp.y end local DL = imgui.GetWindowDrawList() local wx, wy = sp.x, sp.y DL:AddRectFilled(V(wx, wy), V(wx+hudW, wy+hudH), u32(0.043,0.035,0.027,0.94), 10*MDS) DL:AddRectFilledMultiColor(V(wx, wy+hudH*0.45), V(wx+hudW, wy+hudH), u32v(MT.ember, 0.00), u32v(MT.ember, 0.00), u32v(MT.ember, 0.13), u32v(MT.ember, 0.13)) drawDust(DL, wx, wy, hudW, hudH, 12) DL:AddRect(V(wx, wy), V(wx+hudW, wy+hudH), u32v(MT.border), 10*MDS, 0, 1.2) DL:AddRectFilledMultiColor(V(wx, wy), V(wx+hudW, wy+hdrH), u32v(MT.emberD, 0.95), u32v(MT.amberD, 0.95), u32v(MT.amberD, 0.95), u32v(MT.emberD, 0.95)) DL:AddRectFilledMultiColor(V(wx, wy+hdrH-1.2*MDS), V(wx+hudW, wy+hdrH), u32v(MT.amber, 0.15), u32v(MT.amber, 0.90), u32v(MT.amber, 0.90), u32v(MT.amber, 0.15)) local lampG = 0.16 + 0.14 * pulseWave(2.0) DL:AddCircleFilled(V(wx + 20*MDS, wy + hdrH*0.5), 15*MDS, u32v(MT.amber, lampG*0.5), 18) local pfh = pF(font[16]) local hi = imgui.CalcTextSize(IC.HELMET) DL:AddText(V(wx + 20*MDS - hi.x*0.5, wy + hdrH*0.5 - hi.y*0.5 + math.sin(animTime()*2.4)*1.5*MDS), u32v(MT.amberH), IC.HELMET) pFpop(pfh) local pft = pF(font[14]) local ts = imgui.CalcTextSize(STAT_TITLE) DL:AddText(V(wx + 36*MDS, wy + hdrH*0.5 - ts.y*0.5), u32v(MT.text), STAT_TITLE) pFpop(pft) local pfe = pF(font[11]) local el = string.format('%02d:%02d', math.floor(elapsed/3600), math.floor(elapsed/60)%60) local es = imgui.CalcTextSize(IC.CLOCK..' '..el) DL:AddText(V(wx + hudW - es.x - padX, wy + hdrH*0.5 - es.y*0.5), u32(1, 0.92, 0.78, 0.80), IC.CLOCK..' '..el) pFpop(pfe) local pfr = pF(font[13]) for i, k in ipairs(rows) do local ry = wy + hdrH + (i-1)*rowH local col = ORE_COL[k] local fl = hudAnim.flash[k] if fl > 0 then DL:AddRectFilled(V(wx+4*MDS, ry+1*MDS), V(wx+hudW-4*MDS, ry+rowH-2*MDS), u32v(col, 0.20 * fl), 5*MDS) end local bw = (hudW - padX*2) * hudAnim.share[k] if bw > 1 then DL:AddRectFilledMultiColor( V(wx+padX, ry+rowH-7*MDS), V(wx+padX+bw, ry+rowH-4*MDS), u32v(col, 0.85), u32v(col, 0.25), u32v(col, 0.25), u32v(col, 0.85)) end local ic = ORE_IC[k] local ix = wx + padX if ic ~= '' then local isz = imgui.CalcTextSize(ic) DL:AddText(V(ix, ry + 4*MDS), u32v(col, 0.95 + 0.05*fl), ic) ix = ix + isz.x + 6*MDS end DL:AddText(V(ix, ry + 4*MDS), u32v(MT.text, 0.92), STAT_NAMES[k]) local cnt = tostring(counts[k]) local csz = imgui.CalcTextSize(cnt) DL:AddText(V(wx + hudW - padX - csz.x, ry + 4*MDS), u32v(counts[k] > 0 and MT.good or MT.textDim, 1), cnt) for _, pp in ipairs(hudAnim.pops) do if pp.k == k then local a = 1 - pp.t / 1.4 local up = pp.t * 16 * MDS local lbl = '+'..pp.n local ls = imgui.CalcTextSize(lbl) DL:AddText(V(wx + hudW - padX - csz.x - ls.x - 8*MDS, ry + 4*MDS - up), u32v(MT.good, a), lbl) end end end pFpop(pfr) if totalPrice[0] then local sy = wy + hdrH + #rows*rowH + 3*MDS DL:AddRectFilledMultiColor(V(wx+padX, sy), V(wx+hudW-padX, sy+1*MDS), u32v(MT.amber, 0.10), u32v(MT.amber, 0.65), u32v(MT.amber, 0.65), u32v(MT.amber, 0.10)) local pfm = pF(font[15]) local txt = IC.COINS..' '..convertToPriceFormat(math.floor(hudAnim.total)) local tsz = imgui.CalcTextSize(txt) DL:AddText(V(wx + (hudW-tsz.x)*0.5 + 1, sy + 7*MDS + 1), u32(0,0,0,0.45), txt) DL:AddText(V(wx + (hudW-tsz.x)*0.5, sy + 7*MDS), u32v(MT.amber), txt) pFpop(pfm) local pfrt = pF(font[11]) local rt = string.format(IC.WEIGHT..u8(' %d \xf8\xf2 \x95 %.0f \xf8\xf2/\xf7\xe0\xf1'), totalCnt, perHour) local rs = imgui.CalcTextSize(rt) DL:AddText(V(wx + (hudW-rs.x)*0.5, sy + 26*MDS), u32v(MT.textDim), rt) pFpop(pfrt) end imgui.End() imgui.PopStyleColor() end ) function sampev.onSetObjectMaterial(id, data) local ok, object = pcall(sampGetObjectHandleBySampId, id) if not ok or not object then return end local ok2, model = pcall(getObjectModel, object) if not ok2 then return end if doesObjectExist(object) and model == 3930 then if oreTextures[data.textureName] then local ok_c, ox, oy, oz = pcall(getObjectCoordinates, object) local x = ok_c and tonumber(ox) or nil local y = ok_c and tonumber(oy) or nil local z = ok_c and tonumber(oz) or nil if not (x and y and z) then return end local bool = true for k, v in pairs(resources) do local ok3, oh = pcall(sampGetObjectHandleBySampId, k) if ok3 and oh then local ok4, ex, ey, ez = pcall(getObjectCoordinates, oh) if ok4 then local nx2,ny2,nz2 = tonumber(ex),tonumber(ey),tonumber(ez) if nx2 and ny2 and nz2 then if safeDist3d(x,y,z,nx2,ny2,nz2) < 1 then bool = false if oreTextures[data.textureName] > v then resources[k] = nil oreObjCache[k] = nil bool = true break end end end end end end if bool then resources[id] = oreTextures[data.textureName] oreObjCache[id] = {x, y, z, oreTextures[data.textureName]} end end end end function sampev.onDestroyObject(id) if resources[id] then resources[id] = nil oreObjCache[id] = nil end end function sampev.onCreate3DText(id, color, position, dist, testLOS, player, vehicle, text) if type(text) ~= 'string' then return end if text:find('\xcc\xe5\xf1\xf2\xee\xf0\xee\xe6\xe4\xe5\xed\xe8\xe5') then local px = tonumber(type(position)=='table' and position.x or nil) local py = tonumber(type(position)=='table' and position.y or nil) local pz = tonumber(type(position)=='table' and position.z or nil) if px and py and pz then textsTable[id] = {x=px, y=py, z=pz} end end if text:find('\xcc\xe5\xf1\xf2\xee\xf0\xee\xe6\xe4\xe5\xed\xe8\xe5 \xf0\xe5\xf1\xf3\xf0\xf1\xee\xe2') then local px = tonumber(type(position)=='table' and position.x or nil) local py = tonumber(type(position)=='table' and position.y or nil) local pz = tonumber(type(position)=='table' and position.z or nil) if not (px and py and pz) then return end for k, v in ipairs(oreTimerList) do if v[1]==px and v[2]==py and v[3]==pz then table.remove(oreTimerList, k); break end end end end function sampev.onRemove3DTextLabel(id) if textsTable[id] then local info = textsTable[id] local ok, text2 = pcall(function() local t = sampGet3dTextInfoById(id) return t end) if ok and text2 and text2:find('\xcc\xe5\xf1\xf2\xee\xf0\xee\xe6\xe4\xe5\xed\xe8\xe5 \xf0\xe5\xf1\xf3\xf0\xf1\xee\xe2') then if info.x and info.y and info.z then table.insert(oreTimerList, {info.x, info.y, info.z, os.time()+375}) end end textsTable[id] = nil end end function sampev.onSendPlayerSync(data) if autoDig[0] then a = a + 1 if a >= 3 then a = 0 local px = safeNum(data.position and data.position.x) local py = safeNum(data.position and data.position.y) local pz = safeNum(data.position and data.position.z) local near = false for _, v in pairs(textsTable) do if safeDist3d(px,py,pz, v.x,v.y,v.z) < 3.0 then near = true; break end end if not near then for _, v in ipairs(ore3dCache) do if safeDist3d(px,py,pz, v[1],v[2],v[3]) < 3.0 then near = true; break end end end if near then data.keysData = 1024 end end end end function sampev.onDisplayGameText(style, time, text) if type(text) ~= 'string' then return end local oreKey = nil local lower = text:lower() if lower:find('^stone') then oreKey = 'countStone' elseif lower:find('^metal') then oreKey = 'countMetal' elseif lower:find('^bronze') then oreKey = 'countBronze' elseif lower:find('^silver') then oreKey = 'countSilver' elseif lower:find('^gold') then oreKey = 'countGold' end if oreKey then local num = tonumber(text:match('%+%s*(%d+)')) if num and num >= 1 and num <= 10 then settings.main[oreKey] = (tonumber(settings.main[oreKey]) or 0) + num saveSettingsSoon() playOreSound() end end end function sampev.onServerMessage(color, text) if type(text) ~= 'string' then return end local clean = text:gsub('{%x%x%x%x%x%x}', '') if clean:find('\xd3\xe3\xee\xeb\xfc') then local amt = tonumber(clean:match('%((%d+)%s*\xf8\xf2%)')) if amt and amt >= 1 and amt <= 10 then settings.main.countCoal = (tonumber(settings.main.countCoal) or 0) + amt saveSettingsSoon() playOreSound() end end end addEventHandler('onScriptTerminate', function(scr) if scr == script.this then pcall(saveSettingsNow) setGameKeyState(16, 0) pcall(function() if bass then if oreStream ~= 0 then bass.BASS_ChannelStop(oreStream); bass.BASS_StreamFree(oreStream) end end end) end end)