-- ================================================================================ -- Jewel Bank — Client UI Module -- Custom GUI panel for jewel deposit/withdraw operations -- ================================================================================ -- Project: Jewel Bank -- Author: Everton (https://github.com/evtnlife) -- ================================================================================ -- Constantes de protocolo: veja Define.lua (PACKET_JEWELBANK_*) local PACKET_JEWELBANK_HEADER = 0xFB local PACKET_JEWELBANK_SYNC_REQ = 0x00 local PACKET_JEWELBANK_SYNC = 0x01 local PACKET_JEWELBANK_DEPOSIT = 0x02 local PACKET_JEWELBANK_WITHDRAW = 0x03 local PACKET_JEWELBANK_DENY_OPEN = 0x04 -- UI Texture IDs local UI_BTN_LEFT = 4988 local UI_BTN_LEFT_HOVER = 4989 local UI_BTN_LEFT_DISABLED = 4990 local UI_BTN_RIGHT = 4991 local UI_BTN_RIGHT_HOVER = 4992 local UI_BTN_RIGHT_DISABLED = 4993 local UI_BTN_CLOSE = 4994 local UI_BTN_CLOSE_HOVER = 4995 local UI_BTN_PLUS = 4996 local UI_BTN_PLUS_HOVER = 4997 local UI_BTN_MINUS = 4998 local UI_BTN_MINUS_HOVER = 4999 local UI_JEWELBANK_BOARD = 5001 local UI_JEWELBANK_JEWEL_BG = 5002 local UI_JEWELBANK_TOOLTIP_BG = 5003 -- Spin Animation local UI_SPIN_FRAME_COUNT = 36 local UI_SPIN_BASE_ID = 6000 local UI_SPIN_IMAGE_SIZE = 24 local PANEL = { x = 100, y = 40, w = 435, h = 352, visible = false, dragging = false, dragDX = 0, dragDY = 0, } local prevKeyF4 = false local JB_IMG = "Custom\\JewelBank\\" -- Spin animation state local animCounter = 0 local spinLoaded = {} local inputBlockedByPanel = false local function SetJewelBankInputBlocked(blocked) blocked = blocked and true or false if inputBlockedByPanel == blocked then return end inputBlockedByPanel = blocked if type(SetBlockInput) == "function" then SetBlockInput(blocked) end end local BankData = { -- Jewels [1] = { name = "Jewel of Chaos", count = 0, id = 1, renderId = 5004, folder = "jewel_03_chaos" }, [2] = { name = "Jewel of Bless", count = 0, id = 2, renderId = 5005, folder = "jewel_01_bless" }, [3] = { name = "Jewel of Soul", count = 0, id = 3, renderId = 5006, folder = "jewel_02_soul" }, [4] = { name = "Jewel of Life", count = 0, id = 4, renderId = 5007, folder = "jewel_04_life" }, [5] = { name = "Jewel of Creation", count = 0, id = 5, renderId = 5008, folder = "jewel_05_creation" }, [6] = { name = "Jewel of Guardian", count = 0, id = 6, renderId = 5009, folder = "jewel_06_guardian" }, [7] = { name = "Jewel of Harmony", count = 0, id = 7, renderId = 5010, folder = "jewel_08_harmony" }, [8] = { name = "Gemstone", count = 0, id = 8, renderId = 5011, folder = "jewel_07_gemstone" }, [9] = { name = "Jewel of Luck", count = 0, id = 9, renderId = 5012, folder = "jewel_37_luck" }, -- Stones [10] = { name = "Mysterious Stone", count = 0, id = 10, renderId = 5013, folder = "jewel_13_mysterious" }, [11] = { name = "Lapidary Stone", count = 0, id = 11, renderId = 5014, folder = "jewel_24_lapidary" }, [12] = { name = "Guardian Stone", count = 0, id = 13, renderId = 5015, folder = "jewel_15_guard_upgrade" }, [13] = { name = "Elite Guardian Stone", count = 0, id = 14, renderId = 5016, folder = "jewel_16_elite_guard" }, [14] = { name = "Lower Magic Stone", count = 0, id = 19, renderId = 5017, folder = "jewel_20_lower_magic" }, [15] = { name = "Medium Magic Stone", count = 0, id = 20, renderId = 5018, folder = "jewel_21_medium_magic" }, [16] = { name = "Higher Magic Stone", count = 0, id = 21, renderId = 5019, folder = "jewel_22_higher_magic" }, [17] = { name = "Ultimate Magic Stone", count = 0, id = 22, renderId = 5020, folder = "jewel_17_ultimate_magic" }, [18] = { name = "Lower Refining Stone", count = 0, id = 23, renderId = 5021, folder = "jewel_09_lower_refine" }, [19] = { name = "Higher Refining Stone", count = 0, id = 24, renderId = 5022, folder = "jewel_10_higher_refine" }, [20] = { name = "Artifact Upgrade Stone", count = 0, id = 25, renderId = 5023, folder = "jewel_25_artifact_upgrade" }, [21] = { name = "Wing Core Upgrade Stone", count = 0, id = 26, renderId = 5024, folder = "jewel_28_wingcore" }, -- Runes / Misc [22] = { name = "Elemental Rune", count = 0, id = 12, renderId = 5025, folder = "jewel_18_elem_rune" }, [23] = { name = "Sphere Upgrade Rune", count = 0, id = 28, renderId = 5026, folder = "jewel_19_sphere_rune" }, [24] = { name = "Ability Crystal", count = 0, id = 29, renderId = 5027, folder = "jewel_29_ability_crystal" }, [25] = { name = "Talisman of Luck", count = 0, id = 30, renderId = 5028, folder = "jewel_11_talisman" }, [26] = { name = "Elem. Talisman of Luck", count = 0, id = 31, renderId = 5029, folder = "jewel_12_elem_talisman" }, [27] = { name = "Talisman of Chaos Assembly",count = 0, id = 56, renderId = 5060, folder = "jewel_69_chaos_talisman" }, [28] = { name = "Elem. Talisman of Chaos", count = 0, id = 57, renderId = 5061, folder = "jewel_70_elemental_chaos_talisman" }, [29] = { name = "Spider Artifact Fragment", count = 0, id = 27, renderId = 5030, folder = "jewel_26_spider_fragment" }, [30] = { name = "Golden Crest", count = 0, id = 32, renderId = 5031, folder = "jewel_23_golden_crest" }, [31] = { name = "Fragment of Resurrection", count = 0, id = 33, renderId = 5032, folder = "jewel_14_fragment" }, [32] = { name = "Uriels Feather", count = 0, id = 34, renderId = 5033, folder = "jewel_27_uriels_feather" }, -- Endgame Upgrades [33] = { name = "Temple Guard Silver", count = 0, id = 15, renderId = 5035, folder = "jewel_30_tg_enhance" }, [34] = { name = "Temple Guard Gold", count = 0, id = 16, renderId = 5036, folder = "jewel_31_tg_shining" }, [35] = { name = "Imperial Silver", count = 0, id = 17, renderId = 5037, folder = "jewel_32_imperial_reinf" }, [36] = { name = "Imperial Gold", count = 0, id = 18, renderId = 5038, folder = "jewel_33_imperial_shining" }, -- Custom Jewels (grupo 18, indices 500-510; 504 ja e o ID 9 acima) [37] = { name = "Jewel of +11 [Premium]", count = 0, id = 35, renderId = 5039, folder = "jewel_44_plus11" }, [38] = { name = "Jewel of +13 [Premium]", count = 0, id = 36, renderId = 5040, folder = "jewel_45_plus13" }, [39] = { name = "Jewel of +15 [Premium]", count = 0, id = 37, renderId = 5041, folder = "jewel_46_plus15" }, [40] = { name = "Jewel of Option [Premium]", count = 0, id = 38, renderId = 5042, folder = "jewel_47_option" }, [41] = { name = "Jewel of Socket [Premium]", count = 0, id = 39, renderId = 5043, folder = "jewel_48_socket" }, [42] = { name = "Jewel of +9 [Premium]", count = 0, id = 40, renderId = 5044, folder = "jewel_52_plus9" }, -- Gold/Silver Keys e somente as caixas seladas [43] = { name = "Silver Key", count = 0, id = 41, renderId = 5045, folder = "jewel_54_silver_key" }, [44] = { name = "Gold Key", count = 0, id = 42, renderId = 5046, folder = "jewel_55_gold_key" }, [45] = { name = "Sealed Golden Box", count = 0, id = 43, renderId = 5047, folder = "jewel_56_sealed_gold_box" }, [46] = { name = "Sealed Silver Box", count = 0, id = 44, renderId = 5048, folder = "jewel_57_sealed_silver_box" }, -- Talismans vinculados de montagem das armaduras [47] = { name = "Bloodangel Chaos Talisman", count = 0, id = 45, renderId = 5049, folder = "jewel_58_tal_bloodangel" }, [48] = { name = "Darkangel Chaos Talisman", count = 0, id = 46, renderId = 5050, folder = "jewel_59_tal_darkangel" }, [49] = { name = "Holyangel Chaos Talisman", count = 0, id = 47, renderId = 5051, folder = "jewel_60_tal_holyangel" }, [50] = { name = "Soul Chaos Talisman", count = 0, id = 48, renderId = 5052, folder = "jewel_61_tal_soul" }, [51] = { name = "Blue Eye Chaos Talisman", count = 0, id = 49, renderId = 5053, folder = "jewel_62_tal_blueeye" }, [52] = { name = "Silver Heart Chaos Talisman", count = 0, id = 50, renderId = 5054, folder = "jewel_63_tal_silverheart" }, [53] = { name = "Manticore Chaos Talisman", count = 0, id = 51, renderId = 5055, folder = "jewel_64_tal_manticore" }, [54] = { name = "Brilliant Chaos Talisman", count = 0, id = 52, renderId = 5056, folder = "jewel_65_tal_brilliant" }, [55] = { name = "Apocalypse Chaos Talisman", count = 0, id = 53, renderId = 5057, folder = "jewel_66_tal_apocalypse" }, [56] = { name = "Lightning Chaos Talisman", count = 0, id = 54, renderId = 5058, folder = "jewel_67_tal_lightning" }, [57] = { name = "Ability Upgrade Stone", count = 0, id = 55, renderId = 5059, folder = "jewel_68_ability_stone" }, [58] = { name = "[Bound] Ability Crystal", count = 0, id = 58, renderId = 5062, folder = "jewel_71_bound_ability" }, [59] = { name = "Bless of Light [Greater]", count = 0, id = 59, renderId = 5063, folder = "jewel_72_bol_greater" }, [60] = { name = "Bless of Light [Middle]", count = 0, id = 60, renderId = 5064, folder = "jewel_73_bol_middle" }, [61] = { name = "Bless of Light [Low]", count = 0, id = 61, renderId = 5065, folder = "jewel_74_bol_low" }, [62] = { name = "[Bound] Bless Light [Greater]",count = 0, id = 62, renderId = 5066, folder = "jewel_75_bound_bol_greater" }, [63] = { name = "[Bound] Bless Light [Middle]", count = 0, id = 63, renderId = 5067, folder = "jewel_76_bound_bol_middle" }, [64] = { name = "[Bound] Bless Light [Low]", count = 0, id = 64, renderId = 5068, folder = "jewel_77_bound_bol_low" }, [65] = { name = "Coin of Miracle", count = 0, id = 65, renderId = 5069, folder = "jewel_78_coin_miracle" }, [66] = { name = "Varka Ticket", count = 0, id = 66, renderId = 5070, folder = "jewel_79_varka_ticket" }, [67] = { name = "Group Boss Battle Ticket", count = 0, id = 67, renderId = 5071, folder = "jewel_80_group_boss_ticket" }, [68] = { name = "[PC Room][Bound] Bless Light", count = 0, id = 68, renderId = 5072, folder = "jewel_81_pc_bound_bol_greater" }, -- Materiais de criacao de asas (Lv.1 ate Lv.5) [69] = { name = "Loch's Feather", count = 0, id = 69, renderId = 5073, folder = "jewel_82_lochs_feather" }, [70] = { name = "Condor Flame", count = 0, id = 70, renderId = 5074, folder = "jewel_83_condor_flame" }, [71] = { name = "Condor Feather", count = 0, id = 71, renderId = 5075, folder = "jewel_84_condor_feather" }, [72] = { name = "Garuda's Flame", count = 0, id = 72, renderId = 5076, folder = "jewel_85_garuda_flame" }, [73] = { name = "Garuda's Feather", count = 0, id = 73, renderId = 5077, folder = "jewel_86_garuda_feather" }, [74] = { name = "Lv.1 Wing Relic", count = 0, id = 74, renderId = 5078, folder = "jewel_87_wing_relic_1" }, [75] = { name = "Lv.2 Wing Relic", count = 0, id = 75, renderId = 5079, folder = "jewel_88_wing_relic_2" }, [76] = { name = "Lv.3 Wing Relic", count = 0, id = 76, renderId = 5080, folder = "jewel_89_wing_relic_3" }, [77] = { name = "Lv.4 Wing Relic", count = 0, id = 77, renderId = 5081, folder = "jewel_90_wing_relic_4" }, [78] = { name = "Lv.5 Wing Relic", count = 0, id = 78, renderId = 5082, folder = "jewel_91_wing_relic_5" }, [79] = { name = "[Bound] Finished Loch Solution", count = 0, id = 79, renderId = 5083, folder = "jewel_92_bound_loch_solution" }, [80] = { name = "[Bound] Finished Condor Solution",count = 0,id = 80, renderId = 5084, folder = "jewel_93_bound_condor_solution" }, [81] = { name = "Pure Wing Core Design [Type 1]", count = 0, id = 81, renderId = 5085, folder = "jewel_94_pure_wing_core_design" }, } local COLS = 2 local ITEMS_PER_PAGE = 14 local currentPage = 1 local totalPages = math.ceil(#BankData / ITEMS_PER_PAGE) local function createPacket() if type(Packet) == "function" or (getmetatable(Packet) and getmetatable(Packet).__call) then return Packet() end if type(Packet) == "table" then if type(Packet.new) == "function" then return Packet.new() end if type(Packet.New) == "function" then return Packet.New() end if type(Packet.create) == "function" then return Packet.create() end if type(Packet.Create) == "function" then return Packet.Create() end end return nil end local function sendJewelAction(subCode, jewelId, amount) local p = createPacket() if not p then return end p:WriteByte(subCode) if jewelId then p:WriteByte(jewelId) end if amount then p:WriteDword(amount) end SendPacket(PACKET_JEWELBANK_HEADER, p) end --- Get the spin texture ID for a given item index and frame local function GetSpinTexId(itemIdx, frame) return UI_SPIN_BASE_ID + ((itemIdx - 1) * UI_SPIN_FRAME_COUNT) + frame end -- ======================== OZT DECRYPTION =================================== local DECRYPT_KEY = { 122, 227, 29, 148, 184, 82, 246, 11, 199, 62, 161, 101, 217, 72, 47, 131, 92, 231, 25, 164, 107, 208, 55, 242, 142, 65, 197, 10, 118, 189, 83, 232, } local OZT_MAGIC = string.char(74, 66, 69, 78) -- "JBEN" local function DecryptOZT(inputPath, outputPath) local f = io.open(inputPath, "rb") if not f then return false end local raw = f:read("*a") f:close() local header = raw:sub(1, 4) -- Not encrypted (no JBEN header) — write raw bytes directly if header ~= OZT_MAGIC then local out = io.open(outputPath, "wb") if not out then return false end out:write(raw) out:close() return true end -- Encrypted: strip 4-byte header, XOR-decrypt the rest local payload = raw:sub(5) local keyLen = #DECRYPT_KEY local decoded = {} for i = 1, #payload do local encByte = payload:byte(i) local keyIndex = ((i - 1) % keyLen) + 1 local decByte = (encByte - DECRYPT_KEY[keyIndex]) % 256 decoded[i] = string.char(decByte) end local out = io.open(outputPath, "wb") if not out then return false end out:write(table.concat(decoded)) out:close() return true end local function OnLoadInterface_JewelBank() LoadBitmap("Custom\\JewelBank\\btn-left.tga", UI_BTN_LEFT, GL_LINEAR, GL_CLAMP, false, false) LoadBitmap("Custom\\JewelBank\\btn-right.tga", UI_BTN_RIGHT, GL_LINEAR, GL_CLAMP, false, false) LoadBitmap("Custom\\JewelBank\\btn-left-hover.tga", UI_BTN_LEFT_HOVER, GL_LINEAR, GL_CLAMP, false, false) LoadBitmap("Custom\\JewelBank\\btn-right-hover.tga", UI_BTN_RIGHT_HOVER, GL_LINEAR, GL_CLAMP, false, false) LoadBitmap("Custom\\JewelBank\\btn-left-disabled.tga", UI_BTN_LEFT_DISABLED, GL_LINEAR, GL_CLAMP, false, false) LoadBitmap("Custom\\JewelBank\\btn-right-disabled.tga", UI_BTN_RIGHT_DISABLED, GL_LINEAR, GL_CLAMP, false, false) LoadBitmap("Custom\\JewelBank\\btn-close.tga", UI_BTN_CLOSE, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\btn-close-hover.tga", UI_BTN_CLOSE_HOVER, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\btn-plus.tga", UI_BTN_PLUS, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\btn-plus-hover.tga", UI_BTN_PLUS_HOVER, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\btn-minus.tga", UI_BTN_MINUS, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\btn-minus-hover.tga", UI_BTN_MINUS_HOVER, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\Board.tga", UI_JEWELBANK_BOARD, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\jewel-bg.tga", UI_JEWELBANK_JEWEL_BG, GL_LINEAR, GL_REPEAT, false, false) LoadBitmap("Custom\\JewelBank\\tooltip_small.tga", UI_JEWELBANK_TOOLTIP_BG, GL_LINEAR, GL_REPEAT, false, false) local DATA_PATH = "Data\\Custom\\JewelBank\\" local BASE_PATH = "Custom\\JewelBank\\" local TMP_PATH = "Data\\Custom\\JewelBank\\_tmp\\" local TMP_PATH_REL = "Custom\\JewelBank\\_tmp\\" -- Load 36 spin frames per item for i, jewel in ipairs(BankData) do local allOk = true for frame = 0, UI_SPIN_FRAME_COUNT - 1 do local texId = GetSpinTexId(i, frame) local frameName = string.format("spin_%02d", frame) local uniqueName = i .. "_" .. frameName local oztSourcePath = DATA_PATH .. jewel.folder .. "\\" .. frameName .. ".ozt" local oztTmpPath = TMP_PATH .. uniqueName .. ".ozt" local tgaTmpPath = TMP_PATH_REL .. uniqueName .. ".tga" DecryptOZT(oztSourcePath, oztTmpPath) local loadResult = LoadBitmap(tgaTmpPath, texId, GL_LINEAR, GL_CLAMP, false, false) local cleanup = io.open(oztTmpPath, "wb") if cleanup then cleanup:write("\0") cleanup:close() end if loadResult == 0 then local fallbackPath = BASE_PATH .. jewel.folder .. "\\" .. frameName .. ".tga" loadResult = LoadBitmap(fallbackPath, texId, GL_LINEAR, GL_CLAMP, false, false) end if loadResult == 0 then allOk = false break end end spinLoaded[i] = allOk end end local function HandleDrag(isClick) local headerH = 24 if CheckMouseIn(PANEL.x, PANEL.y, PANEL.w - 30, headerH) and isClick then PANEL.dragging = true PANEL.dragDX = MouseX - PANEL.x PANEL.dragDY = MouseY - PANEL.y end if PANEL.dragging then if IsMouseHeld() then PANEL.x = MouseX - PANEL.dragDX PANEL.y = MouseY - PANEL.dragDY else PANEL.dragging = false end end end local function OnInterfaceRender_JewelBank() if not PANEL.visible then SetJewelBankInputBlocked(false) return end -- Impede que cliques sobre o painel atravessem para o mapa/personagem. -- Durante o arraste, o bloqueio continua mesmo se o cursor sair da janela. local mouseOverPanel = CheckMouseIn(PANEL.x, PANEL.y, PANEL.w, PANEL.h) SetJewelBankInputBlocked(mouseOverPanel or PANEL.dragging) local isClick = IsMouseClicked() HandleDrag(isClick) -- Bring to front when clicked inside panel if isClick and CheckMouseIn(PANEL.x, PANEL.y, PANEL.w, PANEL.h) then -- A ordem do ScriptMain mantem este painel na frente. end RenderImage(UI_JEWELBANK_BOARD, PANEL.x, PANEL.y, PANEL.w, PANEL.h) UIRenderText_SetFont(g_hFontBold) UIRenderText_SetTextColor(212, 181, 22, 255) UIRenderText_SetBgColor(0, 0, 0, 0) UIRenderText_RenderText(PANEL.x + 188, PANEL.y + 13, "JEWEL OF BANK", 0, 0, 0) local closeX = PANEL.x + PANEL.w - 28 local closeY = PANEL.y + 10 local closeS = 12 local hoverDn = CheckMouseIn(closeX, closeY, closeS, closeS) if hoverDn then RenderImage(UI_BTN_CLOSE_HOVER, closeX, closeY, closeS, closeS) if isClick then PANEL.visible = false PANEL.dragging = false SetJewelBankInputBlocked(false) return end else RenderImage(UI_BTN_CLOSE, closeX, closeY, closeS, closeS) end local gridStartX = PANEL.x + 18 local gridStartY = PANEL.y + 30 local cellW = 192 local cellH = 37 local colGap = 11 local rowGap = 4 local imgSize = 24 -- [PAGINATION LOOP] local tooltipJewel = nil local tooltipAmount = 0 local startIndex = (currentPage - 1) * ITEMS_PER_PAGE local endIndex = math.min(startIndex + ITEMS_PER_PAGE - 1, #BankData - 1) for slot = startIndex, endIndex do local jewel = BankData[slot + 1] local relativeSlot = slot - startIndex local col = relativeSlot % COLS local row = math.floor(relativeSlot / COLS) local cellX = gridStartX + col * (cellW + colGap) local cellY = gridStartY + row * (cellH + rowGap) RenderImage(UI_JEWELBANK_JEWEL_BG, cellX, cellY, cellW, cellH) local imgX = cellX + 3 local imgY = cellY + math.floor((cellH - imgSize) / 2) -- Spin animation (fake 3D) local itemIdx = slot + 1 local isHovering = CheckMouseIn(cellX, cellY, cellW, cellH) if spinLoaded[itemIdx] and isHovering then local frame = animCounter % UI_SPIN_FRAME_COUNT RenderImage(GetSpinTexId(itemIdx, frame), imgX, imgY, imgSize, imgSize) else RenderImage(GetSpinTexId(itemIdx, 0), imgX, imgY, imgSize, imgSize) end local textX = cellX + imgSize + 10 local textY = cellY + math.floor((cellH - 12) / 2) UIRenderText_SetFont(g_hFont) UIRenderText_SetTextColor(220, 220, 220, 255) local displayName = string.format("[%d] %s", jewel.id, jewel.name) UIRenderText_RenderText(textX, textY, displayName, 0, 0, 0) local qtyX = textX local qtyY = textY + 10 UIRenderText_SetFont(g_hFont) UIRenderText_SetTextColor(255, 220, 100, 255) UIRenderText_RenderText(qtyX, qtyY, "x " .. tostring(jewel.count), 0, 0, 0) -- Tooltip on hover (imported from JewelWarehouse) local cellHovered = CheckMouseIn(cellX, cellY, cellW, cellH) if cellHovered then tooltipJewel = jewel tooltipAmount = jewel.count end local btnUpX = cellX + cellW - 20 local btnUpY = cellY + math.floor((cellH - 22) / 2) local btnSz = 12 local hoverUp = CheckMouseIn(btnUpX, btnUpY, btnSz, btnSz) if hoverUp then RenderImage(UI_BTN_PLUS_HOVER, btnUpX, btnUpY, btnSz, btnSz) if isClick then sendJewelAction(PACKET_JEWELBANK_DEPOSIT, jewel.id, 1) end else RenderImage(UI_BTN_PLUS, btnUpX, btnUpY, btnSz, btnSz) end local btnDnX = cellX + cellW - 20 local btnDnY = cellY + math.floor((cellH + 10) / 2) local hoverDn = CheckMouseIn(btnDnX, btnDnY, btnSz, btnSz) if hoverDn then RenderImage(UI_BTN_MINUS_HOVER, btnDnX, btnDnY, btnSz, btnSz) if isClick then sendJewelAction(PACKET_JEWELBANK_WITHDRAW, jewel.id, 1) end else RenderImage(UI_BTN_MINUS, btnDnX, btnDnY, btnSz, btnSz) end end -- [PAGINATION UI CONTROLS] local pagesY = PANEL.y + PANEL.h - 20 local centerX = PANEL.x + math.floor(PANEL.w / 2) +7 local btnSize = 12 local pageText = currentPage .. " | " .. totalPages local textW = #pageText * 5 local textX = centerX - math.floor(textW / 2) local prevX = textX - btnSize - 6 local nextX = textX + textW - 8; -- Prev Button (hover / normal / disabled) if currentPage > 1 then local hoverPrev = CheckMouseIn(prevX, pagesY, btnSize, btnSize) if hoverPrev then RenderImage(UI_BTN_LEFT_HOVER, prevX, pagesY, btnSize, btnSize) if isClick then currentPage = currentPage - 1 end else RenderImage(UI_BTN_LEFT, prevX, pagesY, btnSize, btnSize) end else RenderImage(UI_BTN_LEFT_DISABLED, prevX, pagesY, btnSize, btnSize) end -- Page Info UIRenderText_SetFont(g_hFontBold) UIRenderText_SetTextColor(255, 255, 255, 255) UIRenderText_RenderText(textX, pagesY + 1, pageText, 0, 0, 0) -- Next Button (hover / normal / disabled) if currentPage < totalPages then local hoverNext = CheckMouseIn(nextX, pagesY, btnSize, btnSize) if hoverNext then RenderImage(UI_BTN_RIGHT_HOVER, nextX, pagesY, btnSize, btnSize) if isClick then currentPage = currentPage + 1 end else RenderImage(UI_BTN_RIGHT, nextX, pagesY, btnSize, btnSize) end else RenderImage(UI_BTN_RIGHT_DISABLED, nextX, pagesY, btnSize, btnSize) end -- [TOOLTIP] Rendered last so it draws on top of everything if tooltipJewel then local tipName = string.format("[%d] %s", tooltipJewel.id, tooltipJewel.name) local tipLine2 = "x " .. tostring(tooltipAmount) .. " in Bank" local tipW = 80 local tipH = 28 local tipX = MouseX + 16 local tipY = MouseY + 16 EnableAlphaTest(true) RenderImage(UI_JEWELBANK_TOOLTIP_BG, tipX - 4, tipY - 2, tipW, tipH) UIRenderText_SetFont(g_hFontBold) UIRenderText_SetTextColor(255, 220, 80, 255) UIRenderText_RenderText(tipX, tipY, tipName, 0, 0, 0) UIRenderText_SetFont(g_hFont) UIRenderText_SetTextColor(200, 200, 200, 255) UIRenderText_RenderText(tipX, tipY + 12, tipLine2, 0, 0, 0) end end local function OnTimerThread_JewelBank() -- Advance spin animation animCounter = animCounter + 1 -- F4 toggle with debounce (prevents flicker when holding key) local jNow = SEASON3B_IsPress(VK_F4) if jNow and not prevKeyF4 then if not IsWriteInterfaceOpen() then if not PANEL.visible then if type(CheckWindowOpen) == "function" and (CheckWindowOpen(37) or CheckWindowOpen(38)) then prevKeyF4 = jNow return end if type(CheckWindow) == "function" and (CheckWindow(37) or CheckWindow(38)) then prevKeyF4 = jNow return end end PANEL.visible = not PANEL.visible if PANEL.visible then sendJewelAction(PACKET_JEWELBANK_SYNC_REQ) else PANEL.dragging = false SetJewelBankInputBlocked(false) end end end prevKeyF4 = jNow end local function OnPacketRecv_JewelBank(connectionIndex, header, p) if header ~= PACKET_JEWELBANK_HEADER then return 0 end local subCode = p:ReadByte() if subCode == PACKET_JEWELBANK_SYNC then local count = #BankData for i = 1, count do BankData[i].count = p:ReadDword() end elseif subCode == PACKET_JEWELBANK_DENY_OPEN then PANEL.visible = false PANEL.dragging = false SetJewelBankInputBlocked(false) end return 1 end BridgeFunctionAttach("OnLoadInterface", OnLoadInterface_JewelBank) BridgeFunctionAttach("OnInterfaceRender", OnInterfaceRender_JewelBank) BridgeFunctionAttach("OnTimerThread", OnTimerThread_JewelBank) BridgeFunctionAttach("OnPacketRecv", OnPacketRecv_JewelBank) local function OnInterfaceActive_JewelBank() return PANEL.visible and 1 or 0 end local function OnInterfaceActiveZone_JewelBank() if PANEL.visible and CheckMouseIn(PANEL.x, PANEL.y, PANEL.w, PANEL.h) then return 1 end return 0 end BridgeFunctionAttach("OnInterfaceActive", OnInterfaceActive_JewelBank) BridgeFunctionAttach("OnInterfaceActiveZone", OnInterfaceActiveZone_JewelBank)