WikiArk21
Member
- Joined
- Oct 24, 2023
- Messages
- 30
- Reaction score
- 6
I have a problem that I've tried to solve in several ways, but I think my knowledge wasn't sufficient. The problem is that when I reset a slot or change a hotkey spell, it duplicates. For example, if I press 1, the sword strike appears once. If I reset the slot and press 1 again, the sword strike appears twice, and this is used to reset or change a slot spell of any spell in the list. This only happens with hotkeys (1 to 0); this bug doesn't occur with left-click.
LUA:
local spellBarWindow = nil
local clickedSlot = nil
local newKey = nil
local slotHotkey = nil
local comboLabel = nil
local comboPreview = nil
local vocation = 0
local STORAGE_KEY = 'custom_spellbar_slots_v1'
local customSlots = {}
local function explode(str, sep)
if str == nil then return {} end
local t = {}
for s in string.gmatch(str, "([^"..sep.."]+)") do
table.insert(t, s)
end
return t
end
local function loadCustomSlots()
local raw = g_settings.get(STORAGE_KEY) or ''
if raw == '' then
customSlots = {}
return
end
local parts = explode(raw, '|')
for i = 1, 10 do
customSlots[i] = parts[i] and parts[i] ~= '' and parts[i] or nil
end
end
local function saveCustomSlots()
local parts = {}
for i = 1, 10 do
parts[i] = customSlots[i] or ''
end
g_settings.set(STORAGE_KEY, table.concat(parts, '|'))
end
local spelllist = {
[1] = {
[1] = {
["sword strike"] = {name = 'Sword Strike', exhaustion = 2, icon = 'Academy/sword_strike', level = 1, mana = 10, key = "1", desc = "Delivers a basic slash with your zanpakuto. A fundamental technique taught to every Shinigami recruit. \nReliable and swift, it forms the base of all future swordsmanship."},
["rest"] = {name = 'Rest', exhaustion = 60, icon = 'Academy/rest', level = 5, mana = 0, key = "2", desc = "Assumes a brief stance of meditation, channeling your spiritual energy. \nRestores 5% of your maximum Health and Mana each second for 10 seconds."},
["run"] = {name = 'Run', exhaustion = 30, icon = 'Academy/run', level = 10, mana = 30, key = "3", desc = "Focuses spiritual pressure into your legs, greatly enhancing your movement. \nGain +100 Movement Speed for 33 seconds."},
["reiatsu explosion"] = {name = 'Reiatsu Explosion', exhaustion = 2, icon = 'Academy/reiatsu_explosion', level = 20, mana = 20, key = "4", desc = "Reiatsu Explosion"},
["jump"] = {name = 'Jump', exhaustion = 2, icon = 'Academy/jump', level = 40, mana = 20, key = "5", desc = "Harnesses reiatsu in your legs to leap over obstacles. \nShinigami rely on this technique to scale walls and reach heights without ladders or ropes."},
["6"] = {name = '6', exhaustion = 2, icon = 'SpellsBase/slot', level = 60, mana = 20, key = "6", desc = "Leap over obstacles using reiatsu."},
["7"] = {name = '7', exhaustion = 2, icon = 'SpellsBase/slot', level = 70, mana = 20, key = "7", desc = "Leap over obstacles using reiatsu."},
["8"] = {name = '8', exhaustion = 2, icon = 'SpellsBase/slot', level = 80, mana = 20, key = "8", desc = "Leap over obstacles using reiatsu."},
["9"] = {name = '9', exhaustion = 2, icon = 'SpellsBase/slot', level = 90, mana = 20, key = "9", desc = "Leap over obstacles using reiatsu."},
["10"] = {name = '10', exhaustion = 2, icon = 'SpellsBase/slot', level = 100, mana = 20, key = "0", desc = "Leap over obstacles using reiatsu."},
}
},
}
function init()
bottomPanel = modules.game_interface.gameBottomPanel
spellBarWindow = g_ui.loadUI('game_spellbar', bottomPanel)
spellBarWindow:hide()
loadCustomSlots()
connect(g_game, {onGameStart = onGameStart})
connect(g_game, {onGameEnd = offline})
connect(LocalPlayer, {onLevelChange = onLevelChange})
connect(LocalPlayer, {onManaChange = onManaChange})
connect(g_game, 'onTalk', onTalk)
ProtocolGame.registerExtendedOpcode(17, function(protocol, opcode, buffer)
createSpellBar(buffer)
end)
end
function terminate()
disconnect(g_game, {onGameStart = onGameStart})
disconnect(g_game, {onGameEnd = offline})
disconnect(LocalPlayer, {onLevelChange = onLevelChange})
disconnect(LocalPlayer, {onManaChange = onManaChange})
disconnect(g_game, 'onTalk', onTalk)
ProtocolGame.unregisterExtendedOpcode(17)
spellBarWindow:destroy()
end
function createSpellBar(buffer)
vocation = tonumber(buffer) or 1
if not spelllist[vocation] then
print('Vocation '..vocation..' não tem lista de spells definida.')
return
end
createSpellsIcons()
spellBarWindow:show()
onManaChange(g_game.getLocalPlayer(), g_game.getLocalPlayer():getMana(), g_game.getLocalPlayer():getMaxMana())
end
function onGameStart()
scheduleEvent(function()
g_game.getProtocolGame():sendExtendedOpcode(17, 'refresh')
end, 10)
end
function offline()
spellBarWindow:hide()
for i = 1, 10 do
local w = spellBarWindow:recursiveGetChildById('slot-'..i)
if w then w:destroy() end
end
end
function onLevelChange(localPlayer, value, percent)
if not spelllist[vocation] then return end
for _, list in pairs(spelllist[vocation]) do
if list and list.name then
local spell = spellBarWindow:recursiveGetChildById('spell-'..list.name:lower())
if spell then
local progress = spellBarWindow:recursiveGetChildById('progress-'..list.name:lower())
if progress and localPlayer:getMana() >= spell.mana then
if progress:getText() == '' then
if localPlayer:getLevel() < spell.lvl then
progress:setImageSource('img/lockedicon')
progress:setPercent(0)
else
progress:setImageSource()
progress:setPercent(100)
end
end
end
end
end
end
end
function onManaChange(localPlayer, mana, maxMana)
if not spelllist[vocation] then return end
for _, list in pairs(spelllist[vocation]) do
if list and list.name then
local spell = spellBarWindow:recursiveGetChildById('spell-'..list.name:lower())
if spell then
local progress = spellBarWindow:recursiveGetChildById('progress-'..list.name:lower())
if progress and localPlayer:getLevel() >= spell.lvl then
if progress:getText() == '' then
if localPlayer:getMana() < spell.mana then
progress:setPercent(0)
else
progress:setPercent(100)
end
end
end
end
end
end
end
function createSpellsIcons()
if not g_game.getLocalPlayer() then return end
local spells_icon = {}
for _, group in pairs(spelllist[vocation] or {}) do
for spellName, spellData in pairs(group) do
table.insert(spells_icon, spellData)
end
end
table.sort(spells_icon, function(a, b) return a.level < b.level end)
for i = 1, 10 do
local slotSpell = g_ui.createWidget('SlotSpell', spellBarWindow)
slotSpell:setId('slot-'..i)
slotSpell:setMarginLeft((i - 1) * 46 + 68)
local assigned = customSlots[i]
local chosenSpell = nil
if assigned then
for _, s in ipairs(spells_icon) do
if s.name:lower() == assigned then
chosenSpell = s
break
end
end
end
if not chosenSpell then
chosenSpell = spells_icon[i]
end
if chosenSpell then
local icon = slotSpell:getChildById('spellButton')
icon:setId('spell-'..chosenSpell.name:lower())
icon:setTooltip('Name: '..chosenSpell.name..'\nEnergy: '..chosenSpell.mana..'\nExhaustion: '..chosenSpell.exhaustion..'\n'..chosenSpell.desc)
icon.exhaustion = chosenSpell.exhaustion
icon:setImageSource('img/vocations/'..chosenSpell.icon)
icon.lvl = chosenSpell.level
icon.mana = chosenSpell.mana
icon.nowexausted = os.time()
icon.key = g_keyboard.bindKeyPress(chosenSpell.key, function() useSpell(chosenSpell.name:lower()) end, modules.game_interface.getRootPanel())
icon.keypress = chosenSpell.key
icon.onMousePress = function(self, pos, button)
if button == MouseRightButton then
openSpellSelect(i)
return true
elseif button == MouseLeftButton then
useSpell(chosenSpell.name:lower())
return true
end
return false
end
local progress = slotSpell:getChildById('spellProgress')
progress:setId('progress-'..chosenSpell.name:lower())
progress:setText('')
progress:setPercent(100)
if g_game.getLocalPlayer():getLevel() < chosenSpell.level then
progress:setImageSource('img/lockedicon')
progress:setPercent(0)
end
if g_game.getLocalPlayer():getMana() < chosenSpell.mana then
progress:setPercent(0)
end
end
local label = slotSpell:getChildById('spellHotkey')
label:setId('htk-'..i)
label:setText(i < 10 and i or 0)
end
end
local currentSpellPage = 1
function openSpellSelect(slotIndex)
if not g_game.getLocalPlayer() then return end
local vocationData = spelllist[vocation]
if not vocationData then return end
local totalPages = 0
for k, _ in pairs(vocationData) do
totalPages = totalPages + 1
end
local function buildMenu(page)
local pageData = vocationData[page]
if not pageData then return end
local sortedSpells = {}
for _, spellData in pairs(pageData) do
table.insert(sortedSpells, spellData)
end
table.sort(sortedSpells, function(a, b) return a.level < b.level end)
local menu = g_ui.createWidget('PopupMenu')
menu:setGameMenu(true)
menu:addOption('Reset Slot', function()
customSlots[slotIndex] = nil
saveCustomSlots()
reloadSpellbar()
end)
menu:addSeparator()
for _, s in ipairs(sortedSpells) do
local label = s.name .. ' (lvl ' .. s.level .. ' / ' .. s.mana .. ' mana)'
menu:addOption(label, function()
customSlots[slotIndex] = s.name:lower()
saveCustomSlots()
reloadSpellbar()
end)
end
menu:addSeparator()
if page > 1 then
menu:addOption('Previous Page', function()
currentSpellPage = page - 1
buildMenu(currentSpellPage)
end)
end
if page < totalPages then
menu:addOption('Next Page', function()
currentSpellPage = page + 1
buildMenu(currentSpellPage)
end)
end
local slotWidget = spellBarWindow:recursiveGetChildById('slot-'..slotIndex)
if slotWidget then
local pos = slotWidget:getPosition()
menu:display({x = pos.x+25, y = pos.y-20})
else
menu:display()
end
end
buildMenu(currentSpellPage)
end
function reloadSpellbar()
for i = 1, 10 do
local s = spellBarWindow:recursiveGetChildById('slot-'..i)
if s then s:destroy() end
end
createSpellsIcons()
end
function useSpell(getspell)
if not g_game.getLocalPlayer() then return end
local spellData = nil
for _, group in pairs(spelllist[vocation] or {}) do
for spellName, s in pairs(group) do
if s.name:lower() == getspell then
spellData = s
break
end
end
end
if not spellData then return end
local spellWidget = spellBarWindow:recursiveGetChildById('spell-'..getspell)
local progress = spellBarWindow:recursiveGetChildById('progress-'..getspell)
if not spellWidget or not progress then return end
if progress:getText() ~= '' or progress:getPercent() < 100 then return end
g_game.talk(spellData.name)
end
function onTalk(name, level, mode, text, channelId, pos)
if not g_game.getLocalPlayer() then return end
if g_game.getLocalPlayer():getName() ~= name then return end
for _, group in pairs(spelllist[vocation] or {}) do
if group[text:lower()] then
startDownDelay(text:lower())
end
end
end
function startDownDelay(getspell)
local spell = spellBarWindow:recursiveGetChildById('spell-'..getspell)
local progress = spellBarWindow:recursiveGetChildById('progress-'..getspell)
if not spell then return end
progress:setPercent(0)
spell.nowexausted = os.time()+spell.exhaustion
scheduleEvent(function() spellReload(getspell) end, 100)
end
function spellReload(getspell)
if not g_game.getLocalPlayer() then return end
local spell = spellBarWindow:recursiveGetChildById('spell-'..getspell)
local progress = spellBarWindow:recursiveGetChildById('progress-'..getspell)
if not spell then return end
local exausted = spell.nowexausted
if g_game.getLocalPlayer():getLevel() < spell.lvl then
progress:setImageSource('img/lockedicon')
progress:setPercent(0)
progress:setText('')
return true
else
local perc = math.ceil((spell.exhaustion-(exausted-os.time()))*100/spell.exhaustion)
local timeall = tonumber(math.ceil(exausted-os.time()))
local timepart = ((1-(math.ceil(timeall/60)-(timeall/60)))*60)
if timepart >= 60 then timepart = 0 end
if progress:getPercent() >= 100 or timeall < 0 then return true end
if progress:getPercent() < 100 then
if perc < 100 then
progress:setPercent(perc)
if timeall > 60 then
progress:setText(''..math.floor(timeall/60)..'m\n'..timepart..'s')
else
progress:setText(''..timeall..'s')
end
else
if g_game.getLocalPlayer():getMana() < spell.mana then
progress:setPercent(0)
else
progress:setPercent(100)
end
progress:setText('')
end
end
end
scheduleEvent(function() spellReload(getspell, exausted) end, 500)
end