Icons = {} Icons[PlayerStates.Poison] = { tooltip = tr('You are poisoned'), path = '/images/game/states/poisoned', id = 'condition_poisoned' } Icons[PlayerStates.Burn] = { tooltip = tr('You are burning'), path = '/images/game/states/burning', id = 'condition_burning' } Icons[PlayerStates.Energy] = { tooltip = tr('You are electrified'), path = '/images/game/states/electrified', id = 'condition_electrified' } Icons[PlayerStates.Drunk] = { tooltip = tr('You are drunk'), path = '/images/game/states/drunk', id = 'condition_drunk' } Icons[PlayerStates.ManaShield] = { tooltip = tr('You are protected by a magic shield'), path = '/images/game/states/magic_shield', id = 'condition_magic_shield' } Icons[PlayerStates.Paralyze] = { tooltip = tr('You are paralysed'), path = '/images/game/states/slowed', id = 'condition_slowed' } Icons[PlayerStates.Haste] = { tooltip = tr('You are hasted'), path = '/images/game/states/haste', id = 'condition_haste' } Icons[PlayerStates.Swords] = { tooltip = tr('You may not logout during a fight'), path = '/images/game/states/logout_block', id = 'condition_logout_block' } Icons[PlayerStates.Drowning] = { tooltip = tr('You are drowning'), path = '/images/game/states/drowning', id = 'condition_drowning' } Icons[PlayerStates.Freezing] = { tooltip = tr('You are freezing'), path = '/images/game/states/freezing', id = 'condition_freezing' } Icons[PlayerStates.Dazzled] = { tooltip = tr('You are dazzled'), path = '/images/game/states/dazzled', id = 'condition_dazzled' } Icons[PlayerStates.Cursed] = { tooltip = tr('You are cursed'), path = '/images/game/states/cursed', id = 'condition_cursed' } Icons[PlayerStates.PartyBuff] = { tooltip = tr('You are strengthened'), path = '/images/game/states/strengthened', id = 'condition_strengthened' } Icons[PlayerStates.PzBlock] = { tooltip = tr('You may not logout or enter a protection zone'), path = '/images/game/states/protection_zone_block', id = 'condition_protection_zone_block' } Icons[PlayerStates.Pz] = { tooltip = tr('You are within a protection zone'), path = '/images/game/states/protection_zone', id = 'condition_protection_zone' } Icons[PlayerStates.Bleeding] = { tooltip = tr('You are bleeding'), path = '/images/game/states/bleeding', id = 'condition_bleeding' } Icons[PlayerStates.Hungry] = { tooltip = tr('You are hungry'), path = '/images/game/states/hungry', id = 'condition_hungry' } local iconsTable = { ["Experience"] = 8, ["Magic"] = 0, ["Axe"] = 2, ["Club"] = 1, ["Distance"] = 3, ["Fist"] = 4, ["Shielding"] = 5, ["Sword"] = 6, ["Fishing"] = 7 } local healthBar = nil local manaBar = nil local topBar = nil local states = nil local experienceTooltip = 'You have %d%% to advance to level %d.' local settings = {} function init() connect(LocalPlayer, { onHealthChange = onHealthChange, onManaChange = onManaChange, onLevelChange = onLevelChange, onStatesChange = onStatesChange, onMagicLevelChange = onMagicLevelChange, onBaseMagicLevelChange = onBaseMagicLevelChange, onSkillChange = onSkillChange, onBaseSkillChange = onBaseSkillChange }) connect(g_game, {onGameStart = refresh, onGameEnd = offline}) -- load condition icons for k, v in pairs(Icons) do g_textures.preload(v.path) end if g_game.isOnline() then refresh() end end function terminate() disconnect(LocalPlayer, { onHealthChange = onHealthChange, onManaChange = onManaChange, onLevelChange = onLevelChange, onStatesChange = onStatesChange, onMagicLevelChange = onMagicLevelChange, onBaseMagicLevelChange = onBaseMagicLevelChange, onSkillChange = onSkillChange, onBaseSkillChange = onBaseSkillChange }) disconnect(g_game, {onGameStart = refresh, onGameEnd = offline}) end function setupTopBar() local topPanel = modules.game_interface.getTopBar() topBar = topBar or g_ui.loadUI('TopBar', topPanel) topBar = topBar or g_ui.createWidget('TopBar', topPanel) manaBar = topBar.stats.mana healthBar = topBar.stats.health states = topBar.stats.states.box topBar.onMouseRelease = function(widget, mousePos, mouseButton) menu(mouseButton) end end function refresh(profileChange) local player = g_game.getLocalPlayer() if not player then return end setupTopBar() load() setupSkills() show() refreshVisibleBars() onLevelChange(player, player:getLevel(), player:getLevelPercent()) onHealthChange(player, player:getHealth(), player:getMaxHealth()) onManaChange(player, player:getMana(), player:getMaxMana()) onMagicLevelChange(player, player:getMagicLevel(), player:getMagicLevelPercent()) if not profileChange then onStatesChange(player, player:getStates(), 0) end onHealthChange(player, player:getHealth(), player:getMaxHealth()) onManaChange(player, player:getMana(), player:getMaxMana()) onLevelChange(player, player:getLevel(), player:getLevelPercent()) for i = Skill.Fist, Skill.ManaLeechAmount do onSkillChange(player, i, player:getSkillLevel(i), player:getSkillLevelPercent(i)) onBaseSkillChange(player, i, player:getSkillBaseLevel(i)) end topBar.skills.onGeometryChange = setSkillsLayout end function refreshVisibleBars() local ids = {"Experience", "Magic", "Axe", "Club", "Distance", "Fist", "Shielding", "Sword", "Fishing"} for i, id in ipairs(ids) do local panel = topBar[id] or topBar.skills[id] if panel then -- experience is exeption if id == "Experience" then if not settings[id] then panel:setVisible(true) end else panel:setVisible(settings[id] or false) end end end end function setSkillsLayout() local visible = 0 local skills = topBar.skills local width = skills:getWidth() for i, child in ipairs(skills:getChildren()) do visible = child:isVisible() and visible + 1 or visible end local many = visible > 1 width = many and (width / 2) or width skills:getLayout():setCellSize({width = width, height = 19}) end function offline() local player = g_game.getLocalPlayer() if player then onStatesChange(player, 0, player:getStates()) end save() end function toggleIcon(bitChanged) local content = states if not content then return end local icon = content:getChildById(Icons[bitChanged].id) if icon then icon:destroy() else icon = loadIcon(bitChanged) icon:setParent(content) end end function loadIcon(bitChanged) local icon = g_ui.createWidget('ConditionWidget', content) icon:setId(Icons[bitChanged].id) icon:setImageSource(Icons[bitChanged].path) icon:setTooltip(Icons[bitChanged].tooltip) return icon end function onHealthChange(localPlayer, health, maxHealth) if not healthBar then return end if health > maxHealth then maxHealth = health end local healthPercent = (health / maxHealth) * 100 healthBar:setText(comma_value(health) .. ' / ' .. comma_value(maxHealth)) healthBar:setValue(health, 0, maxHealth) healthBar:setPercent(healthPercent) if healthPercent > 92 then healthBar:setBackgroundColor("#00BC00FF") elseif healthPercent > 60 then healthBar:setBackgroundColor("#50A150FF") elseif healthPercent > 30 then healthBar:setBackgroundColor("#A1A100FF") elseif healthPercent > 8 then healthBar:setBackgroundColor("#BF0A0AFF") elseif healthPercent > 3 then healthBar:setBackgroundColor("#910F0FFF") else healthBar:setBackgroundColor("#850C0CFF") end end function onManaChange(localPlayer, mana, maxMana) if not manaBar then return end if mana > maxMana then maxMana = mana end local manaPercent = (mana / maxMana) * 100 if manaPercent < 0 then return end manaBar:setText(comma_value(mana) .. ' / ' .. comma_value(maxMana)) manaBar:setValue(mana, 0, maxMana) manaBar:setPercent(manaPercent) end function onLevelChange(localPlayer, value, percent) if not topBar then return end local experienceBar = topBar.Experience.progress local levelLabel = topBar.Experience.level experienceBar:setTooltip(tr(experienceTooltip, 100-percent, value + 1)) experienceBar:setPercent(percent) levelLabel:setText(value) end function onStatesChange(localPlayer, now, old) if now == old then return end local bitsChanged = bit32.bxor(now, old) for i = 1, 32 do local pow = math.pow(2, i - 1) if pow > bitsChanged then break end local bitChanged = bit32.band(bitsChanged, pow) if bitChanged ~= 0 then toggleIcon(bitChanged) end end end function show() if not g_game.isOnline() then return end topBar:setVisible(g_settings.getBoolean("topBar", false)) end function setupSkillPanel(id, parent, experience, defaultOff) local widget = g_ui.createWidget('SkillPanel', parent) widget:setId(id) widget.level:setTooltip(id) widget.icon:setTooltip(id) widget.icon:setImageClip({x = iconsTable[id]*9, y = 0, width = 9,height = 9}) if not experience then widget.progress:setBackgroundColor('#00c000') widget.shop:setVisible(false) widget.shop:disable() widget.shop:setWidth(0) widget.progress:setMarginRight(1) end settings[id] = settings[id] ~= nil and settings[id] or defaultOff if settings[id] == false then widget:setVisible(false) end -- breakers widget.onGeometryChange = function() local margin = widget.progress:getWidth() / 4 local left = widget.left local right = widget.right left:setMarginRight(margin) right:setMarginRight(margin) end end function menu(mouseButton) if mouseButton ~= 2 then return end local menu = g_ui.createWidget('PopupMenu') menu:setId("topBarMenu") menu:setGameMenu(true) local expPanel = topBar.Experience local start = expPanel:isVisible() and "Hide" or "Show" menu:addOption(start .. " Experience Level", function() toggleSkillPanel(id) end) for i, child in ipairs(topBar.skills:getChildren()) do local id = child:getId() if id ~= "stats" then local start = child:isVisible() and "Hide" or "Show" menu:addOption(start .. " " .. id .. " Level", function() toggleSkillPanel(id) end) end end menu:display(mousePos) return true end function setupSkills() local t = { "Experience", "Magic", "Axe", "Club", "Distance", "Fist", "Shielding", "Sword", "Fishing" } for i, id in ipairs(t) do if not topBar[id] and not topBar.skills[id] then setupSkillPanel(id, i == 1 and topBar or topBar.skills, i == 1, i == 1) end end local child = topBar.Experience topBar:moveChildToIndex(child, 2) end function toggleSkillPanel(id) if not topBar then return end local panel = topBar.skills[id] panel = panel or topBar.Experience if not panel then return end panel:setVisible(not panel:isVisible()) settings[id] = panel:isVisible() setSkillsLayout() end function setSkillValue(id, value) if not topBar then return end local panel = topBar.skills[id] if not panel then return end panel.level:setText(value) end function setSkillPercent(id, percent, tooltip) if not topBar then return end local panel = topBar.skills[id] if not panel then return end panel.progress:setPercent(math.floor(percent)) end function setSkillBase(id, value, baseValue) if not topBar then return end local panel = topBar.skills[id] if not panel then return end local progress = topBar.skills[id].progress local progressDesc = "You have " .. 100 - math.floor(progress:getPercent()) .. " percent to go" local level = topBar.skills[id].level if baseValue <= 0 or value < 0 then return end if value > baseValue then level:setColor('#008b00') -- green progress:setTooltip(value .. " = " .. baseValue .. ' + ' .. (value - baseValue) .. "\n" .. progressDesc) elseif value < baseValue then level:setColor('#b22222') -- red progress:setTooltip(baseValue .. ' ' .. (value - baseValue)) else level:setColor('#bbbbbb') -- default progress:removeTooltip() end end function onMagicLevelChange(localPlayer, magiclevel, percent) setSkillValue('Magic', magiclevel) setSkillPercent('Magic', percent) onBaseMagicLevelChange(localPlayer, localPlayer:getBaseMagicLevel()) end function onBaseMagicLevelChange(localPlayer, baseMagicLevel) setSkillBase('Magic', localPlayer:getMagicLevel(), baseMagicLevel) end function onSkillChange(localPlayer, id, level, percent) id = id + 1 local t = { "Fist", "Club", "Sword", "Axe", "Distance", "Shielding", "Fishing" } -- imbues, ignore if id > #t then return end setSkillValue(t[id], level) setSkillPercent(t[id], percent) setSkillBase(t[id], level, localPlayer:getSkillBaseLevel(id - 1)) end function onBaseSkillChange(localPlayer, id, baseLevel) id = id + 1 local t = { "Fist", "Club", "Sword", "Axe", "Distance", "Shielding", "Fishing" } -- imbues, ignore if id > #t then return end setSkillBase(id, localPlayer:getSkillLevel(id), baseLevel) end function save() local settingsFile = modules.client_profiles.getSettingsFilePath("topbar.json") local status, result = pcall(function() return json.encode(settings, 2) end) if not status then return onError( "Error while saving top bar settings. Data won't be saved. Details: " .. result) end if result:len() > 100 * 1024 * 1024 then return onError( "Something went wrong, file is above 100MB, won't be saved") end g_resources.writeFileContents(settingsFile, result) end function load() local settingsFile = modules.client_profiles.getSettingsFilePath("topbar.json") if g_resources.fileExists(settingsFile) then local status, result = pcall(function() return json.decode(g_resources.readFileContents(settingsFile)) end) if not status then return onError( "Error while reading top bar settings file. To fix this problem you can delete storage.json. Details: " .. result) end settings = result else settings = {} end end