feat: imbuement system (#1616)

New Features:
- Imbuement Shrine UI: item/scroll selection, imbuement/clear flows, confirmation dialogs, timers, and cost display.
- New imbuement modules: selection, item/scroll handlers, and imbuement management.
- New progress bar widgets and vertical/inverted variants for status and timers.
- Exposed client APIs and protocol support for imbuement interactions.

UX Improvements:
- Resource requirement tooltips, formatted balance display, and conditional enablement of imbue actions.

Co-authored-by: kokekanon <114332266+kokekanon@users.noreply.github.com>
This commit is contained in:
André Morais 2026-05-20 11:16:46 -03:00 committed by GitHub
parent ce885ea187
commit b03c5d6e38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 3045 additions and 377 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/images/ui/item66.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -57,4 +57,4 @@ InvVerticalBar < UIVerticalProgressBarSDInverted
VerticalBar < UIVerticalProgressBarSD
size: 10 30
image-border: 1
image-border: 1

View file

@ -5,8 +5,8 @@ function UIProgressBarSD.create()
local progressbar = UIProgressBarSD.internalCreate()
progressbar:setFocusable(false)
progressbar:setOn(true)
progressbar.min = 0
progressbar.max = 100
progressbar.minimum = 0
progressbar.maximum = 100
progressbar.value = 0
progressbar.bgBorderLeft = 0
progressbar.bgBorderRight = 0

View file

@ -5,8 +5,8 @@ function UIProgressBarSDInverted.create()
local progressbar = UIProgressBarSDInverted.internalCreate()
progressbar:setFocusable(false)
progressbar:setOn(true)
progressbar.min = 0
progressbar.max = 100
progressbar.minimum = 0
progressbar.maximum = 100
progressbar.value = 0
progressbar.bgBorderLeft = 0
progressbar.bgBorderRight = 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -1,349 +1,158 @@
Imbuing = {}
local imbuingWindow
local bankGold = 0
local inventoryGold = 0
local itemImbuements = {}
local emptyImbue
local groupsCombo
local imbueLevelsCombo
local protectionBtn
local clearImbue
local selectedImbue
local imbueItems = {}
local protection = false
local clearConfirmWindow
local imbueConfirmWindow
local MODERN_IMBUEMENT_VERSION = 1510
function init()
connect(g_game, {
onGameEnd = hide,
onResourcesBalanceChange = Imbuing.onResourcesBalanceChange,
onImbuementWindow = Imbuing.onImbuementWindow,
onCloseImbuementWindow = Imbuing.onCloseImbuementWindow
})
local activeDesign
local activeDesignName
imbuingWindow = g_ui.displayUI('imbuing')
emptyImbue = imbuingWindow.emptyImbue
groupsCombo = emptyImbue.groups
imbueLevelsCombo = emptyImbue.imbuement
protectionBtn = emptyImbue.protection
clearImbue = imbuingWindow.clearImbue
imbuingWindow:hide()
local player = g_game.getLocalPlayer()
if player then
bankGold = player:getResourceBalance(ResourceTypes.BANK_BALANCE)
inventoryGold = player:getResourceBalance(ResourceTypes.GOLD_EQUIPPED)
imbuingWindow.balance:setText(tr('Balance') .. ':\n' .. (player:getTotalMoney()))
local function isModernImbuementWindow()
return g_game.getClientVersion() >= MODERN_IMBUEMENT_VERSION
end
local function terminateActiveDesign()
if activeDesign and activeDesign.terminate then
activeDesign.terminate()
end
groupsCombo.onOptionChange = function(widget)
imbueLevelsCombo:clearOptions()
if itemImbuements ~= nil then
local selectedGroup = groupsCombo:getCurrentOption().text
for _, imbuement in ipairs(itemImbuements) do
if imbuement['group'] == selectedGroup then
emptyImbue.imbuement:addOption(imbuement['name'])
end
end
imbueLevelsCombo.onOptionChange(imbueLevelsCombo) -- update options
end
activeDesign = nil
activeDesignName = nil
end
local function activateDesign(name)
if activeDesignName == name and activeDesign then
return activeDesign
end
imbueLevelsCombo.onOptionChange = function(widget)
setProtection(false)
local selectedGroup = groupsCombo:getCurrentOption().text
for _, imbuement in ipairs(itemImbuements) do
if imbuement['group'] == selectedGroup then
if #imbuement['sources'] == widget.currentIndex then
selectedImbue = imbuement
for i, source in ipairs(imbuement['sources']) do
for _, item in ipairs(imbueItems) do
if item:getId() == source['item']:getId() then
if item:getCount() >= source['item']:getCount() then
emptyImbue.imbue:setImageSource('/images/game/imbuing/imbue_green')
emptyImbue.imbue:setEnabled(true)
emptyImbue.requiredItems:getChildByIndex(i).count:setColor('white')
end
if item:getCount() < source['item']:getCount() then
emptyImbue.imbue:setEnabled(false)
emptyImbue.imbue:setImageSource('/images/game/imbuing/imbue_empty')
emptyImbue.requiredItems:getChildByIndex(i).count:setColor('red')
end
emptyImbue.requiredItems:getChildByIndex(i).count:setText(item:getCount() .. '/' ..
source['item']:getCount())
end
end
emptyImbue.requiredItems:getChildByIndex(i).item:setItemId(source['item']:getId())
emptyImbue.requiredItems:getChildByIndex(i).item:setTooltip('The imbuement requires ' ..
source['description'] .. '.')
end
for i = 3, widget.currentIndex + 1, -1 do
emptyImbue.requiredItems:getChildByIndex(i).count:setText('')
emptyImbue.requiredItems:getChildByIndex(i).item:setItemId(0)
emptyImbue.requiredItems:getChildByIndex(i).item:setTooltip('')
end
emptyImbue.protectionCost:setText(imbuement['protectionCost'])
emptyImbue.cost:setText(imbuement['cost'])
if not protection and (bankGold + inventoryGold) < imbuement['cost'] then
emptyImbue.imbue:setEnabled(false)
emptyImbue.imbue:setImageSource('/images/game/imbuing/imbue_empty')
emptyImbue.cost:setColor('red')
end
if not protection and (bankGold + inventoryGold) >= imbuement['cost'] then
emptyImbue.cost:setColor('white')
end
if protection and (bankGold + inventoryGold) < (imbuement['cost'] + imbuement['protectionCost']) then
emptyImbue.imbue:setEnabled(false)
emptyImbue.imbue:setImageSource('/images/game/imbuing/imbue_empty')
emptyImbue.cost:setColor('red')
end
if protection and (bankGold + inventoryGold) >= (imbuement['cost'] + imbuement['protectionCost']) then
emptyImbue.cost:setColor('white')
end
emptyImbue.successRate:setText(imbuement['successRate'] .. '%')
if selectedImbue['successRate'] > 50 then
emptyImbue.successRate:setColor('white')
else
emptyImbue.successRate:setColor('red')
end
emptyImbue.description:setText(imbuement['description'])
end
end
end
terminateActiveDesign()
if name == 'new' then
activeDesign = dofile('new_design/main')
elseif name == 'old' then
activeDesign = dofile('old_design/imbuing')
else
error('Unknown imbuing design: ' .. tostring(name))
end
protectionBtn.onClick = function()
setProtection(not protection)
if type(activeDesign) ~= 'table' then
error('Imbuing design "' .. tostring(name) .. '" did not return a valid API table')
end
activeDesignName = name
if activeDesign.init then
activeDesign.init()
end
return activeDesign
end
local function callActive(method, ...)
if activeDesign and activeDesign[method] then
return activeDesign[method](...)
end
end
function setProtection(value)
protection = value
if protection then
emptyImbue.cost:setText(selectedImbue['cost'] + selectedImbue['protectionCost'])
emptyImbue.successRate:setText('100%')
emptyImbue.successRate:setColor('green')
protectionBtn:setImageClip(torect('66 0 66 66'))
local function callNew(method, ...)
return activateDesign('new')[method](...)
end
local function callOld(method, ...)
return activateDesign('old')[method](...)
end
local function onGameStart()
terminateActiveDesign()
end
local function onGameEnd()
terminateActiveDesign()
end
local function onOpenImbuementWindow(...)
return callNew('onOpenImbuementWindow', ...)
end
local function onImbuementItem(...)
if isModernImbuementWindow() then
return callNew('onImbuementItem', ...)
else
if selectedImbue then
emptyImbue.cost:setText(selectedImbue['cost'])
emptyImbue.successRate:setText(selectedImbue['successRate'] .. '%')
if selectedImbue['successRate'] > 50 then
emptyImbue.successRate:setColor('white')
else
emptyImbue.successRate:setColor('red')
end
end
protectionBtn:setImageClip(torect('0 0 66 66'))
return callOld('onImbuementItem', ...)
end
end
local function onImbuementScroll(...)
return callNew('onImbuementScroll', ...)
end
local function onResourcesBalanceChange(...)
if activeDesignName == 'old' and not isModernImbuementWindow() then
return callActive('onResourcesBalanceChange', ...)
end
end
local function onCloseImbuementWindow()
terminateActiveDesign()
end
local function onMessageDialog(...)
if activeDesignName == 'new' then
return callActive('onMessageDialog', ...)
end
end
function hide()
return callActive('hide')
end
function close()
return callActive('close')
end
function onSelectItem()
return callActive('onSelectItem')
end
function onSelectScroll()
return callActive('onSelectScroll')
end
function onItemSlot(widget)
return callActive('onItemSlot', widget)
end
function onItemBaseType(selectedButtonId)
return callActive('onItemBaseType', selectedButtonId)
end
function onScrollBaseType(selectedButtonId)
return callActive('onScrollBaseType', selectedButtonId)
end
function init()
connect(g_game, {
onGameStart = onGameStart,
onGameEnd = onGameEnd,
onOpenImbuementWindow = onOpenImbuementWindow,
onImbuementItem = onImbuementItem,
onImbuementScroll = onImbuementScroll,
onResourcesBalanceChange = onResourcesBalanceChange,
onCloseImbuementWindow = onCloseImbuementWindow,
onMessageDialog = onMessageDialog
})
if g_game.isOnline() then
addEvent(onGameStart)
end
end
function terminate()
disconnect(g_game, {
onGameEnd = hide,
onResourcesBalanceChange = Imbuing.onResourcesBalanceChange,
onImbuementWindow = Imbuing.onImbuementWindow,
onCloseImbuementWindow = Imbuing.onCloseImbuementWindow
onGameStart = onGameStart,
onGameEnd = onGameEnd,
onOpenImbuementWindow = onOpenImbuementWindow,
onImbuementItem = onImbuementItem,
onImbuementScroll = onImbuementScroll,
onResourcesBalanceChange = onResourcesBalanceChange,
onCloseImbuementWindow = onCloseImbuementWindow,
onMessageDialog = onMessageDialog
})
imbuingWindow:destroy()
end
function resetSlots()
emptyImbue:setVisible(false)
clearImbue:setVisible(false)
for i = 1, 3 do
imbuingWindow.itemInfo.slots:getChildByIndex(i):setText('Slot ' .. i)
imbuingWindow.itemInfo.slots:getChildByIndex(i):setEnabled(false)
imbuingWindow.itemInfo.slots:getChildByIndex(i):setTooltip(
'Items can have up to three imbuements slots. This slot is not available for this item.')
imbuingWindow.itemInfo.slots:getChildByIndex(i).onClick = nil
end
end
function selectSlot(widget, slotId, activeSlot)
if activeSlot then
emptyImbue:setVisible(false)
widget:setText(activeSlot[1]['name'])
clearImbue.title:setText('Clear Imbuement "' .. activeSlot[1]['name'] .. '"')
clearImbue.groups:clearOptions()
clearImbue.groups:addOption(activeSlot[1]['group'])
clearImbue.imbuement:clearOptions()
clearImbue.imbuement:addOption(activeSlot[1]['name'])
clearImbue.description:setText(activeSlot[1]['description'])
hours = string.format('%02.f', math.floor(activeSlot[2] / 3600))
mins = string.format('%02.f', math.floor(activeSlot[2] / 60 - (hours * 60)))
clearImbue.time.timeRemaining:setText(hours .. ':' .. mins .. 'h')
clearImbue.cost:setText(activeSlot[3])
if (bankGold + inventoryGold) < activeSlot[3] then
emptyImbue.clear:setEnabled(false)
emptyImbue.clear:setImageSource('/images/game/imbuing/imbue_empty')
emptyImbue.cost:setColor('red')
end
local yesCallback = function()
g_game.clearImbuement(slotId)
widget:setText('Slot ' .. (slotId + 1))
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
end
local noCallback = function()
imbuingWindow:show()
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
end
clearImbue.clear.onClick = function()
imbuingWindow:hide()
clearConfirmWindow = displayGeneralBox(tr('Confirm Clearing'),
tr(
'Do you wish to spend ' .. activeSlot[3] ..
' gold coins to clear the imbuement "' ..
activeSlot[1]['name'] .. '" from your item?'), {
{
text = tr('Yes'),
callback = yesCallback
},
{
text = tr('No'),
callback = noCallback
},
anchor = AnchorHorizontalCenter
}, yesCallback, noCallback)
end
clearImbue:setVisible(true)
else
emptyImbue:setVisible(true)
clearImbue:setVisible(false)
local yesCallback = function()
g_game.applyImbuement(slotId, selectedImbue['id'], protection)
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
widget:setText(selectedImbue['name'])
imbuingWindow:show()
end
local noCallback = function()
imbuingWindow:show()
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
end
emptyImbue.imbue.onClick = function()
imbuingWindow:hide()
local cost = selectedImbue['cost']
local successRate = selectedImbue['successRate']
if protection then
cost = cost + selectedImbue['protectionCost']
successRate = '100'
end
clearConfirmWindow = displayGeneralBox(tr('Confirm Imbuing Attempt'),
'You are about to imbue your item with "' .. selectedImbue['name'] ..
'".\nYour chance to succeed is ' .. successRate ..
'%. It will consume the required astral sources and ' .. cost ..
' gold coins.\nDo you wish to proceed?', {
{
text = tr('Yes'),
callback = yesCallback
},
{
text = tr('No'),
callback = noCallback
},
anchor = AnchorHorizontalCenter
}, yesCallback, noCallback)
end
end
end
function Imbuing.onImbuementWindow(itemId, slots, activeSlots, imbuements, needItems)
if not itemId then
return
end
resetSlots()
imbueItems = table.copy(needItems)
imbuingWindow.itemInfo.item:setItemId(itemId)
for i = 1, slots do
local slot = imbuingWindow.itemInfo.slots:getChildByIndex(i)
slot.onClick = function(widget)
selectSlot(widget, i - 1)
end
slot:setTooltip(
'Use this slot to imbue your item. Depending on the item you can have up to three different imbuements.')
slot:setEnabled(true)
if slot:getId() == 'slot0' then
selectSlot(slot, i - 1)
end
end
for i, slot in pairs(activeSlots) do
local activeSlotBtn = imbuingWindow.itemInfo.slots:getChildById('slot' .. i)
activeSlotBtn.onClick = function(widget)
selectSlot(widget, i, slot)
end
if activeSlotBtn:getId() == 'slot0' then
selectSlot(activeSlotBtn, i, slot)
end
end
if imbuements ~= nil then
groupsCombo:clearOptions()
imbueLevelsCombo:clearOptions()
itemImbuements = table.copy(imbuements)
for _, imbuement in ipairs(itemImbuements) do
if not groupsCombo:isOption(imbuement['group']) then
groupsCombo:addOption(imbuement['group'])
end
end
end
show()
end
function Imbuing.onResourcesBalanceChange(balance, oldBalance, type)
if type == ResourceTypes.BANK_BALANCE then
bankGold = balance
elseif type == ResourceTypes.GOLD_EQUIPPED then
inventoryGold = balance
end
local player = g_game.getLocalPlayer()
if player then
if type == ResourceTypes.BANK_BALANCE or type == ResourceTypes.GOLD_EQUIPPED then
imbuingWindow.balance:setText(tr('Balance') .. ':\n' .. (player:getTotalMoney()))
end
end
end
function Imbuing.onCloseImbuementWindow()
resetSlots()
end
function hide()
g_game.closeImbuingWindow()
imbuingWindow:hide()
end
function show()
imbuingWindow:show()
imbuingWindow:raise()
imbuingWindow:focus()
end
function toggle()
if imbuingWindow:isVisible() then
return hide()
end
show()
terminateActiveDesign()
end

View file

@ -6,4 +6,4 @@ Module
sandboxed: true
scripts: [ imbuing ]
@onLoad: init()
@onUnload: terminate()
@onUnload: terminate()

View file

@ -0,0 +1,442 @@
return function(context)
local itemApi = {
window = nil,
confirmWindow = nil,
lastselectedwidget = nil,
selectedSlot = 0,
itemId = 0,
tier = 0,
slots = 0,
activeSlots = {},
availableImbuements = {},
needItems = {},
}
itemApi.__index = itemApi
local self = itemApi
function itemApi.setup(itemId, tier, slots, activeSlots, availableImbuements, needItems)
self.itemId = itemId
self.tier = tier
self.slots = slots
self.activeSlots = {}
for i = 0, slots - 1 do
self.activeSlots["slot"..i] = activeSlots[i] or {}
end
self.availableImbuements = availableImbuements or {}
self.needItems = needItems or {}
for i = 0, 2 do
context.imbuement.clearImbue:recursiveGetChildById("slot"..i):setBorderWidth(0)
context.imbuement.selectImbue:recursiveGetChildById("slot"..i):setBorderWidth(0)
end
self.selectedSlot = 0
self.onSelectImbuementSlot(self.selectedSlot)
-- Verificar se o slot 0 tem um imbuement ativo e passar para updateWindowState
local imbuement = self.activeSlots["slot0"]
self.updateWindowState(imbuement)
self.configureWindow(context.imbuement.selectImbue)
self.configureWindow(context.imbuement.clearImbue)
end
function itemApi.configureWindow(window)
local slots = window:recursiveGetChildById("slots")
for i = 1, 3 do
local slotWidget = slots:getChildById("slot"..i - 1)
if slotWidget then
slotWidget.resource:setImageSource("//images/game/imbuing/icons//0")
if i <= self.slots then
slotWidget:setVisible(true)
local imbuement = self.activeSlots["slot"..i - 1]
if imbuement and imbuement[1] then
if imbuement[1].id and imbuement[1].id ~= 0 then
slotWidget.resource:setImageSource("//images/game/imbuing/icons//" .. imbuement[1]["imageId"])
end
end
else
slotWidget:setVisible(false)
end
end
end
local itemName = context.getItemNameById(self.itemId)
local itemWidget = window:recursiveGetChildById("item")
if itemWidget then
itemWidget:setItemId(self.itemId)
itemWidget:setImageSmooth(true)
itemWidget:setItemCount(1)
end
local itemInformation = window:recursiveGetChildById("titleInformation")
if itemInformation then
itemInformation:setText(context.capitalize(itemName))
end
end
function itemApi.onSelectSlot(widget)
local slot = widget:getId()
itemApi.onSelectImbuementSlot(widget.slot)
local imbuement = self.activeSlots[slot]
self.updateWindowState(imbuement)
end
function itemApi.updateWindowState(imbuement)
if imbuement and imbuement[1] and imbuement[1].id ~= 0 then
context.imbuement:toggleMenu("clearImbue")
self.window = context.imbuement.clearImbue
self.onSelectSlotClear(imbuement)
else
context.imbuement:toggleMenu("selectImbue")
self.window = context.imbuement.selectImbue
self.onSelectSlotImbue()
end
end
function itemApi.onSelectImbuementSlot(slot)
context.imbuement.clearImbue:recursiveGetChildById("slot"..self.selectedSlot):setBorderWidth(0)
context.imbuement.selectImbue:recursiveGetChildById("slot"..self.selectedSlot):setBorderWidth(0)
self.selectedSlot = slot
context.imbuement.clearImbue:recursiveGetChildById("slot"..slot):setBorderWidth(1)
context.imbuement.clearImbue:recursiveGetChildById("slot"..slot):setBorderColor("white")
context.imbuement.selectImbue:recursiveGetChildById("slot"..slot):setBorderWidth(1)
context.imbuement.selectImbue:recursiveGetChildById("slot"..slot):setBorderColor("white")
end
function itemApi:shutdown()
self.window = nil
self.itemId = 0
self.tier = 0
self.slots = 0
self.activeSlots = {}
self.availableImbuements = {}
self.needItems = {}
if self.confirmWindow then
self.confirmWindow:destroy()
end
if self.lastselectedwidget then
self.lastselectedwidget:destroy()
self.lastselectedwidget = nil
end
self.confirmWindow = nil
end
function itemApi.onSelectSlotClear(imbuement)
local title = self.window.cleanImbuePanel:getChildById("title")
if title then
title:setText(string.format('Clear Imbuement "%s"', imbuement[1].name))
end
local cleanImbuementsDetails = self.window:recursiveGetChildById("cleanImbuementsDetails")
if cleanImbuementsDetails then
cleanImbuementsDetails:setText('')
end
local timeRemaining = self.window:recursiveGetChildById("timeRemaining")
if timeRemaining then
local time = imbuement[1].duration or 0
timeRemaining:setMinimum(0)
timeRemaining:setMaximum(time)
timeRemaining:setValue(imbuement[2], 0, time)
end
local imbuementReqContent = self.window:recursiveGetChildById("imbuementReqContent")
if imbuementReqContent then
local hours = string.format("%02.f", math.floor(imbuement[2]/3600))
local mins = string.format("%02.f", math.floor(imbuement[2]/60 - (hours*60)))
imbuementReqContent.time.textLabel:setText(string.format("%dh %dmin", hours, mins))
imbuementReqContent.time.onHoverChange = function(widget, hovered, itemName, hasItem)
if hovered then
cleanImbuementsDetails:setText(tr("Show the time the imbuement is still active for."))
else
cleanImbuementsDetails:setText("")
end
end
end
local clearImbuementsList = self.window:recursiveGetChildById("clearImbuementsList")
clearImbuementsList:destroyChildren()
local widget = g_ui.createWidget("SlotImbuing", clearImbuementsList)
widget.resource:setImageSource("//images/game/imbuing/icons//" .. imbuement[1]["imageId"])
widget:setBorderWidth(1)
widget:setBorderColor("white")
local selectedImbuementContent = self.window:recursiveGetChildById("selectedImbuementContent")
if selectedImbuementContent then
local imbuementsDetails = selectedImbuementContent:recursiveGetChildById("imbuementsDetails")
if imbuementsDetails then
imbuementsDetails:setText(imbuement[1].description or "")
end
end
local balance = context.getPlayerBalance()
local clearButton = self.window:recursiveGetChildById("clear")
if clearButton then
clearButton:setEnabled(balance >= imbuement[3])
clearButton.onClick = function()
if self.confirmWindow then
self.confirmWindow:destroy()
self.confirmWindow = nil
end
context.imbuement.hide()
local function confirm()
g_game.clearImbuement(self.selectedSlot)
self.confirmWindow:destroy()
self.confirmWindow = nil
context.imbuement.show()
end
local function cancelFunc()
if self.confirmWindow then
self.confirmWindow:destroy()
self.confirmWindow = nil
end
context.imbuement.show()
end
self.confirmWindow = displayGeneralBox(tr('Confirm Clearing'), tr("Do you wish to spend %s gold coins to clear the imbuement \"%s\" from your item?", context.commaValue(imbuement[3]), context.capitalize(imbuement[1].name)),
{ { text=tr('Yes'), callback=confirm },
{ text=tr('No'), callback=cancelFunc },
}, confirm, cancelFunc)
end
if balance >= imbuement[3] then
clearButton:setImageSource("/game_imbuing/images/clear")
clearButton:setImageClip("0 0 128 66")
else
clearButton:setImageSource("/game_imbuing/images/imbue_empty")
end
clearButton.onHoverChange = function(widget, hovered, itemName, hasItem)
if hovered then
cleanImbuementsDetails:setText(tr("Your needs have changed? Click here to clear the imbuement from your item for a fee."))
else
cleanImbuementsDetails:setText("")
end
end
end
local costPanel = self.window:recursiveGetChildById("costPanel")
if costPanel then
costPanel.cost:setText(context.commaValue(imbuement[3]))
costPanel.cost:setColor(balance < imbuement[3] and "#C04040" or "#C0C0C0")
end
end
function itemApi.onSelectSlotImbue()
self.selectBaseType('basicButton')
self.window:recursiveGetChildById('imbuementsDetails'):setVisible(false)
end
function itemApi.selectBaseType(selectedButtonId)
self.window:recursiveGetChildById('blockedPanels'):setVisible(true)
local qualityAndImbuementContent = self.window:recursiveGetChildById("qualityAndImbuementContent")
if not qualityAndImbuementContent then
return
end
local basicButton = qualityAndImbuementContent.basicButton
local intricateButton = qualityAndImbuementContent.intricateButton
local powerfullButton = qualityAndImbuementContent.powerfullButton
local selectedBaseType = 0
for _, button in pairs({basicButton, intricateButton, powerfullButton}) do
button:setOn(button:getId() == selectedButtonId)
if button:getId() == selectedButtonId then
selectedBaseType = button.baseImbuement or 0
end
end
local imbuementsList = self.window:recursiveGetChildById("imbuementsList")
imbuementsList:setWidth(70)
imbuementsList:destroyChildren()
local imbuementsDetails = self.window:recursiveGetChildById("imbuementsDetails")
imbuementsDetails:setVisible(false)
local maxWidth = 0
for id, imbuement in pairs(self.availableImbuements) do
local imbuementType = imbuement.type
if imbuementType == nil and imbuement.group then
if imbuement.group == 'Basic' then imbuementType = 0
elseif imbuement.group == 'Intricate' then imbuementType = 1
elseif imbuement.group == 'Powerful' then imbuementType = 2
end
end
if imbuementType == selectedBaseType then
local widget = g_ui.createWidget("SlotImbuing", imbuementsList)
widget:setId(tostring(id))
widget.resource:setImageSource("//images/game/imbuing/icons//" .. imbuement.imageId)
widget.onClick = function()
itemApi.selectImbuementWidget(widget, imbuement)
end
maxWidth = math.min(imbuementsList.maxWidth, maxWidth + imbuementsList.incrementwidth)
end
end
imbuementsList:setWidth(maxWidth)
end
function itemApi.onSelectImbuement(widget)
local imbuementId = tonumber(widget:getId())
local imbuement = self.availableImbuements[imbuementId]
if not imbuement then
return
end
self.window:recursiveGetChildById('blockedPanels'):setVisible(false)
local imbuementReqPanel = self.window:recursiveGetChildById("imbuementReqPanel")
if imbuementReqPanel then
imbuementReqPanel.title:setText(string.format('Imbue Empty Slot with "%s"', imbuement.name))
end
local itensDetails = self.window:recursiveGetChildById("itensDetails")
if itensDetails then
itensDetails:setText("")
end
end
function itemApi.selectImbuementWidget(widget, imbuement)
if self.lastselectedwidget then
self.lastselectedwidget:setBorderWidth(1)
self.lastselectedwidget:setBorderColorTop("#797979")
self.lastselectedwidget:setBorderColorLeft("#797979")
self.lastselectedwidget:setBorderColorRight("#2e2e2e")
self.lastselectedwidget:setBorderColorBottom("#2e2e2e")
end
self.lastselectedwidget = widget
widget:setBorderWidth(1)
widget:setBorderColor("white")
self.onSelectImbuement(widget)
local imbuementsDetails = self.window:recursiveGetChildById("imbuementsDetails")
if imbuementsDetails then
imbuementsDetails:setVisible(true)
imbuementsDetails:setText(imbuement.description or "")
end
local requiredItems = self.window:recursiveGetChildById("requiredItems")
local hasRequiredItems = true
if requiredItems then
for i = 1, 3 do
local itemWidget = requiredItems:getChildById("item"..i)
if itemWidget then
local source = imbuement.sources[i]
if source then
itemWidget.item:setItemId(source.item:getId())
itemWidget:setVisible(true)
local itemCount = self.needItems[source.item:getId()] or 0
itemWidget.count:setText(itemCount .."/" .. source.item:getCount())
if itemCount >= source.item:getCount() then
itemWidget.count:setColor("#C0C0C0")
else
hasRequiredItems = false
itemWidget.count:setColor("#C04040")
end
itemWidget.onHoverChange = function(widget, hovered)
local itensDetails = self.window:recursiveGetChildById("itensDetails")
if hovered then
local itemCount = self.needItems[source.item:getId()] or 0
if itemCount >= source.item:getCount() then
itensDetails:setText(string.format("The imbuement you have selected requires %s.", source.description))
else
itensDetails:setText(string.format("The imbuement requires %s. Unfortunately you do not own the needed amount.", source.description))
end
else
if itensDetails then
itensDetails:setText("")
end
end
end
else
itemWidget:setVisible(false)
end
end
end
end
local costPanel = self.window:recursiveGetChildById("costPanel")
if costPanel then
local cost = imbuement.cost or 0
costPanel.cost:setText(context.commaValue(cost))
local balance = context.getPlayerBalance()
if balance < cost then
hasRequiredItems = false
end
costPanel.cost:setColor(balance < cost and "#C04040" or "#C0C0C0")
end
local imbueApply = self.window:recursiveGetChildById("imbueApply")
if imbueApply then
imbueApply:setEnabled(hasRequiredItems)
if not hasRequiredItems then
imbueApply:setImageSource("/game_imbuing/images/imbue_empty")
imbueApply:setImageClip("0 0 128 66")
else
imbueApply:setImageSource("/game_imbuing/images/imbue_green")
end
imbueApply.onHoverChange = function(widget, hovered, itemName, hasItem)
local itensDetails = self.window:recursiveGetChildById("itensDetails")
if hovered then
itensDetails:setText(tr("Apply the selected imbuement. This will consume the required astral sources and gold."))
else
if itensDetails then
itensDetails:setText("")
end
end
end
imbueApply.onClick = function()
if self.confirmWindow then
self.confirmWindow:destroy()
self.confirmWindow = nil
end
context.imbuement.hide()
local function confirm()
g_game.applyImbuement(self.selectedSlot, imbuement.id)
self.confirmWindow:destroy()
self.confirmWindow = nil
context.imbuement.show()
end
local function cancelFunc()
if self.confirmWindow then
self.confirmWindow:destroy()
self.confirmWindow = nil
end
context.imbuement.show()
end
self.confirmWindow = displayGeneralBox(tr('Confirm Imbuing'), tr("You are about to imbue your item with \"%s\". This will consume the required astral sources and %s\ngold coins. Do you wish to proceed?", context.capitalize(imbuement.name), context.commaValue(imbuement.cost)),
{ { text=tr('Yes'), callback=confirm },
{ text=tr('No'), callback=cancelFunc },
}, confirm, cancelFunc)
end
end
end
return itemApi
end

View file

@ -0,0 +1,247 @@
return function(context)
local scrollApi = {
window = nil,
itemId = 51442,
confirmWindow = nil,
availableImbuements = {},
needItems = {}
}
scrollApi.__index = scrollApi
local self = scrollApi
function scrollApi.setup(availableImbuements, needItems)
self.availableImbuements = availableImbuements or {}
self.needItems = needItems or {}
self.window = context.imbuement.scrollImbue
local itemWidget = self.window:recursiveGetChildById("itemScroll")
if itemWidget then
itemWidget:setItemId(self.itemId)
itemWidget:setImageSmooth(true)
itemWidget:setItemCount(1)
end
self.onSelectSlotImbue()
end
function scrollApi:shutdown()
if self.confirmWindow then
self.confirmWindow:destroy()
end
self.window = nil
self.confirmWindow = nil
self.lastselectedwidget = nil
self.availableImbuements = {}
self.needItems = {}
end
function scrollApi.onSelectSlotImbue()
self.selectBaseType('powerfullButton')
self.window:recursiveGetChildById('imbuementsDetails'):setVisible(false)
end
function scrollApi.selectBaseType(selectedButtonId)
local qualityAndImbuementContent = self.window:recursiveGetChildById("qualityAndImbuementContent")
if not qualityAndImbuementContent then
return
end
local intricateButton = qualityAndImbuementContent.intricateButton
local powerfullButton = qualityAndImbuementContent.powerfullButton
local selectedBaseType = 1
for _, button in pairs({intricateButton, powerfullButton}) do
button:setOn(button:getId() == selectedButtonId)
if button:getId() == selectedButtonId then
selectedBaseType = button.baseImbuement or 1
end
end
local imbuementsList = self.window:recursiveGetChildById("imbuementsList")
imbuementsList:destroyChildren()
local imbuementsDetails = self.window:recursiveGetChildById("imbuementsDetails")
imbuementsDetails:setVisible(false)
local selected = false
local matchedCount = 0
for id, imbuement in ipairs(self.availableImbuements) do
local imbuementType = imbuement.type
if imbuementType == nil and imbuement.group then
if imbuement.group == 'Basic' then imbuementType = 0
elseif imbuement.group == 'Intricate' then imbuementType = 1
elseif imbuement.group == 'Powerful' then imbuementType = 2
end
end
if imbuementType == selectedBaseType then
matchedCount = matchedCount + 1
local widget = g_ui.createWidget("SlotImbuing", imbuementsList)
widget:setId(tostring(id))
widget.resource:setImageSource("//images/game/imbuing/icons//" .. imbuement.imageId)
if not selected then
scrollApi.selectImbuementWidget(widget, imbuement)
selected = true
end
widget.onClick = function()
scrollApi.selectImbuementWidget(widget, imbuement)
end
end
end
end
function scrollApi.selectImbuementWidget(widget, imbuement)
if self.lastselectedwidget then
self.lastselectedwidget:setBorderWidth(1)
self.lastselectedwidget:setBorderColorTop("#797979")
self.lastselectedwidget:setBorderColorLeft("#797979")
self.lastselectedwidget:setBorderColorRight("#2e2e2e")
self.lastselectedwidget:setBorderColorBottom("#2e2e2e")
end
self.lastselectedwidget = widget
widget:setBorderWidth(1)
widget:setBorderColor("white")
self.onSelectImbuement(widget)
local imbuementsDetails = self.window:recursiveGetChildById("imbuementsDetails")
if imbuementsDetails then
imbuementsDetails:setVisible(true)
imbuementsDetails:setText(imbuement.description or "")
end
local requiredItems = self.window:recursiveGetChildById("requiredItems")
local hasRequiredItems = true
if requiredItems then
for i = 1, 4 do
local itemWidget = requiredItems:getChildById("item"..i)
if itemWidget then
local source = imbuement.sources[i]
if source then
itemWidget.item:setItemId(source.item:getId())
itemWidget:setVisible(true)
local itemCount = self.needItems[source.item:getId()] or 0
itemWidget.count:setText(itemCount .."/" .. source.item:getCount())
if itemCount >= source.item:getCount() then
itemWidget.count:setColor("#C0C0C0")
else
hasRequiredItems = false
itemWidget.count:setColor("#C04040")
end
itemWidget.onHoverChange = function(widget, hovered)
local itensDetails = self.window:recursiveGetChildById("itensDetails")
if hovered then
local itemCount = self.needItems[source.item:getId()] or 0
if itemCount >= source.item:getCount() then
itensDetails:setText(string.format("The imbuement you have selected requires %s.", source.description))
else
itensDetails:setText(string.format("The imbuement requires %s. Unfortunately you do not own the needed amount.", source.description))
end
else
if itensDetails then
itensDetails:setText("")
end
end
end
else
itemWidget:setVisible(false)
end
end
end
end
local costPanel = self.window:recursiveGetChildById("costPanel")
if costPanel then
local cost = imbuement.cost or 0
costPanel.cost:setText(context.commaValue(cost))
local balance = context.getPlayerBalance()
if balance < cost then
hasRequiredItems = false
end
costPanel.cost:setColor(balance < cost and "#C04040" or "#C0C0C0")
end
local imbuescrollApply = self.window:recursiveGetChildById("imbuescrollApply")
if imbuescrollApply then
imbuescrollApply:setEnabled(hasRequiredItems)
if not hasRequiredItems then
imbuescrollApply:setImageSource("/game_imbuing/images/imbue_empty")
imbuescrollApply:setImageClip("0 0 128 66")
else
imbuescrollApply:setImageSource("/game_imbuing/images/imbue_green")
end
imbuescrollApply.onHoverChange = function(widget, hovered, itemName, hasItem)
local itensDetails = self.window:recursiveGetChildById("itensDetails")
if hovered then
itensDetails:setText(tr("Apply the selected imbuement. This will consume the required astral sources and gold."))
else
if itensDetails then
itensDetails:setText("")
end
end
end
imbuescrollApply.onClick = function()
if self.confirmWindow then
self.confirmWindow:destroy()
self.confirmWindow = nil
end
context.imbuement.hide()
local function confirm()
g_game.applyImbuement(0, imbuement.id)
self.confirmWindow:destroy()
self.confirmWindow = nil
context.imbuement.show()
end
local function cancelFunc()
if self.confirmWindow then
self.confirmWindow:destroy()
self.confirmWindow = nil
end
context.imbuement.show()
end
self.confirmWindow = displayGeneralBox(tr('Confirm Imbuing'), tr("You are about to imbue your item with \"%s\". This will consume the required astral sources and %s\ngold coins. Do you wish to proceed?", context.capitalize(imbuement.name), context.commaValue(imbuement.cost)),
{ { text=tr('Yes'), callback=confirm },
{ text=tr('No'), callback=cancelFunc },
}, confirm, cancelFunc)
end
end
end
function scrollApi.onSelectImbuement(widget)
local imbuementId = tonumber(widget:getId())
local imbuement = self.availableImbuements[imbuementId]
if not imbuement then
return
end
local imbuementReqPanel = self.window:recursiveGetChildById("imbuementReqPanel")
if imbuementReqPanel then
imbuementReqPanel.title:setText(string.format('Imbue Blank Scroll with "%s"', imbuement.name))
end
local itensDetails = self.window:recursiveGetChildById("itensDetails")
if itensDetails then
itensDetails:setText("")
end
end
return scrollApi
end

View file

@ -0,0 +1,111 @@
return function()
local selectionApi = {
pickItem = nil,
isSelectingScroll = false,
isSelecting = false,
}
selectionApi.__index = selectionApi
local self = selectionApi
function selectionApi.startUp()
self.pickItem = g_ui.createWidget('UIWidget')
self.pickItem:setVisible(false)
self.pickItem:setFocusable(false)
self.pickItem.onMouseRelease = self.onChooseItemMouseRelease
end
function selectionApi:shutdown()
if self.pickItem then
self.pickItem:ungrabMouse()
self.pickItem:destroy()
self.pickItem = nil
end
if self.isSelecting then
g_mouse.popCursor('target')
end
self.isSelectingScroll = false
self.isSelecting = false
end
function selectionApi:selectItem()
if not self.pickItem then
self:startUp()
end
if g_mouse.isPressed() or self.isSelecting then
return
end
self.isSelectingScroll = false
self.isSelecting = true
self.pickItem:grabMouse()
g_mouse.pushCursor('target')
end
function selectionApi:selectScroll()
if not self.pickItem then
self:startUp()
end
if g_mouse.isPressed() or self.isSelecting then
return
end
self.isSelectingScroll = true
self.isSelecting = true
self.pickItem:grabMouse()
g_mouse.pushCursor('target')
end
function selectionApi.onChooseItemMouseRelease(widget, mousePosition, mouseButton)
local item = nil
if mouseButton == MouseLeftButton then
local clickedWidget = modules.game_interface.getRootPanel():recursiveGetChildByPos(mousePosition, false)
if clickedWidget then
if clickedWidget:getClassName() == 'UIGameMap' then
local tile = clickedWidget:getTile(mousePosition)
if tile then
local thing = tile:getTopMoveThing()
if thing and thing:isItem() then
item = thing
end
end
elseif clickedWidget:getClassName() == 'UIItem' and not clickedWidget:isVirtual() then
item = clickedWidget:getItem()
end
end
end
if item and item:isPickupable() then
local pos = item:getPosition()
local itemId = item:getId()
local stackPos = item:getStackPos()
if self.isSelectingScroll then
g_game.selectImbuementScroll()
else
g_game.selectImbuementItem(itemId, pos, stackPos)
end
self.pickItem:ungrabMouse()
g_mouse.popCursor('target')
self.isSelectingScroll = false
self.isSelecting = false
return true
else
modules.game_textmessage.displayFailureMessage(tr('Sorry, not possible.'))
end
self.pickItem:ungrabMouse()
g_mouse.popCursor('target')
self.isSelectingScroll = false
self.isSelecting = false
return true
end
return selectionApi
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View file

@ -0,0 +1,112 @@
local function commaValue(amount)
if not amount then
return "0"
end
local formatted = tostring(amount)
while true do
local nextValue, changes = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
formatted = nextValue
if changes == 0 then
break
end
end
return formatted
end
local function capitalize(str)
if not str or str == "" then
return str
end
return str:sub(1, 1):upper() .. str:sub(2)
end
local function getPlayerBalance()
local player = g_game.getLocalPlayer()
if not player then
return 0
end
local bankGold = player:getResourceBalance(ResourceTypes.BANK_BALANCE) or 0
local inventoryGold = player:getResourceBalance(ResourceTypes.GOLD_EQUIPPED) or 0
return bankGold + inventoryGold
end
local function getItemNameById(itemId)
local itemType = g_things.getThingType(itemId, ThingCategoryItem)
if itemType and itemType.getName and type(itemType.getName) == "function" then
return itemType:getName() or "Unknown Item"
end
return "Unknown Item"
end
local context = {
commaValue = commaValue,
capitalize = capitalize,
getPlayerBalance = getPlayerBalance,
getItemNameById = getItemNameById,
}
context.imbuement = dofile('t_imbui')(context)
context.item = dofile('classes/imbuementitem')(context)
context.scroll = dofile('classes/imbuementscroll')(context)
context.selection = dofile('classes/imbuementselection')(context)
local api = {}
function api.init()
return context.imbuement.init()
end
function api.terminate()
return context.imbuement.terminate()
end
function api.close()
return context.imbuement.close()
end
function api.hide()
return context.imbuement.hide()
end
function api.onOpenImbuementWindow(...)
return context.imbuement.onOpenImbuementWindow(...)
end
function api.onImbuementItem(...)
return context.imbuement.onImbuementItem(...)
end
function api.onImbuementScroll(...)
return context.imbuement.onImbuementScroll(...)
end
function api.onMessageDialog(...)
return context.imbuement.onMessageDialog(...)
end
function api.onSelectItem()
return context.imbuement.onSelectItem()
end
function api.onSelectScroll()
return context.imbuement.onSelectScroll()
end
function api.onItemSlot(widget)
return context.item.onSelectSlot(widget)
end
function api.onItemBaseType(selectedButtonId)
return context.item.selectBaseType(selectedButtonId)
end
function api.onScrollBaseType(selectedButtonId)
return context.scroll.selectBaseType(selectedButtonId)
end
return api

View file

@ -0,0 +1,230 @@
return function(context)
local imbuementApi = {
window = nil,
selectItemOrScroll = nil,
scrollImbue = nil,
selectImbue = nil,
clearImbue = nil,
messageWindow = nil,
bankGold = 0,
inventoryGold = 0,
}
imbuementApi.__index = imbuementApi
imbuementApi.MessageDialog = {
ImbuementSuccess = 0,
ImbuementError = 1,
ImbuementRollFailed = 2,
ImbuingStationNotFound = 3,
ClearingCharmSuccess = 10,
ClearingCharmError = 11,
PreyMessage = 20,
PreyError = 21,
}
local self = imbuementApi
function imbuementApi.ensureWindow()
if self.window then
return
end
self.window = g_ui.displayUI('t_imbui')
self.selectItemOrScroll = self.window:recursiveGetChildById('selectItemOrScroll')
self.scrollImbue = self.window:recursiveGetChildById('scrollImbue')
self.selectImbue = self.window:recursiveGetChildById('selectImbue')
self.clearImbue = self.window:recursiveGetChildById('clearImbue')
self:hide()
end
function imbuementApi.destroyWindow()
self.selectItemOrScroll = nil
self.scrollImbue = nil
self.selectImbue = nil
self.clearImbue = nil
if self.window then
self.window:destroy()
self.window = nil
end
end
function imbuementApi.init()
end
function imbuementApi.terminate()
if self.messageWindow then
self.messageWindow:destroy()
self.messageWindow = nil
end
if context.item then
context.item:shutdown()
end
if context.selection then
context.selection:shutdown()
end
if context.scroll then
context.scroll:shutdown()
end
self.destroyWindow()
end
function imbuementApi.online()
self:hide()
if self.messageWindow then
self.messageWindow:destroy()
self.messageWindow = nil
end
end
function imbuementApi.offline()
self:hide()
if context.item then
context.item:shutdown()
end
if context.scroll then
context.scroll:shutdown()
end
if context.selection then
context.selection:shutdown()
end
if self.messageWindow then
self.messageWindow:destroy()
self.messageWindow = nil
end
self.destroyWindow()
end
function imbuementApi.show()
self.ensureWindow()
self.window:show(true)
self.window:raise()
self.window:focus()
if self.messageWindow then
self.messageWindow:destroy()
self.messageWindow = nil
end
end
function imbuementApi.hide()
if self.window then
self.window:hide()
end
end
function imbuementApi.close()
if g_game.isOnline() then
g_game.closeImbuingWindow()
end
if self.window then
self.window:hide()
end
end
function imbuementApi:toggleMenu(menu)
for key, value in pairs(self) do
if type(value) == 'userdata' and key ~= 'window' then
if key == menu then
value:show()
if menu == 'selectItemOrScroll' then
self.window:setHeight(388)
elseif menu == 'scrollImbue' then
self.window:setHeight(655)
elseif menu == 'selectImbue' then
self.window:setHeight(528)
elseif menu == 'clearImbue' then
self.window:setHeight(502)
end
else
value:hide()
end
end
end
end
function imbuementApi.onOpenImbuementWindow()
self.ensureWindow()
self:show()
local player = g_game.getLocalPlayer()
if player then
local bankGold = player:getResourceBalance(ResourceTypes.BANK_BALANCE) or 0
local inventoryGold = player:getResourceBalance(ResourceTypes.GOLD_EQUIPPED) or 0
local totalGold = bankGold + inventoryGold
self.window.contentPanel.gold.gold:setText(context.commaValue(totalGold))
end
self:toggleMenu("selectItemOrScroll")
end
function imbuementApi.onImbuementItem(itemId, tier, slots, activeSlots, availableImbuements, needItems)
self.ensureWindow()
local needItemsTable = {}
for _, item in ipairs(needItems) do
if item and item.getId then
local itemId = item:getId()
local count = item:getCount() or 0
needItemsTable[itemId] = count
end
end
self:show()
self:toggleMenu("selectImbue")
context.item.setup(itemId, tier, slots, activeSlots, availableImbuements, needItemsTable)
end
function imbuementApi.onImbuementScroll(availableImbuements, needItems)
self.ensureWindow()
local needItemsTable = {}
for _, item in ipairs(needItems) do
if item and item.getId then
local itemId = item:getId()
local count = item:getCount() or 0
needItemsTable[itemId] = count
end
end
self:toggleMenu("scrollImbue")
context.scroll.setup(availableImbuements, needItemsTable)
end
function imbuementApi.onSelectItem()
self:hide()
context.selection:selectItem()
end
function imbuementApi.onSelectScroll()
g_game.selectImbuementScroll()
end
function imbuementApi.onMessageDialog(type, content)
if type > imbuementApi.MessageDialog.ImbuingStationNotFound or not self.window or not self.window:isVisible() then
return
end
self:hide()
if self.messageWindow then
self.messageWindow:destroy()
self.messageWindow = nil
end
local function confirm()
self.messageWindow:destroy()
self.messageWindow = nil
imbuementApi.show()
end
self.messageWindow = displayGeneralBox(tr('Message Dialog'), content or "",
{ { text=tr('Ok'), callback=confirm },
}, confirm, confirm)
end
return imbuementApi
end

View file

@ -0,0 +1,901 @@
PickItemButton < UIButton
id: itemButton
size: 96 64
anchors.top: parent.top
anchors.left: parent.left
image-source: /game_imbuing/new_design/images/pick-item-button
image-clip: 0 0 96 64
@onClick: modules.game_imbuing.onSelectItem()
$hover !pressed:
image-clip: 0 0 96 64
$pressed:
image-clip: 0 64 96 64
ScrollItemButton < UIButton
id: scrollButton
size: 96 64
anchors.top: parent.top
anchors.left: itemButton.right
margin-left: 6
image-source: /game_imbuing/new_design/images/imbue-scroll-button
image-clip: 0 0 96 64
@onClick: modules.game_imbuing.onSelectScroll()
$hover !pressed:
image-clip: 0 0 96 64
$pressed:
image-clip: 0 64 96 64
SlotImbuing < UIButton
size: 66 66
border-width: 1
border-color-top: #797979
border-color-left: #797979
border-color-bottom: #2e2e2e
border-color-right: #2e2e2e
$checked:
border-color-top: #181818
border-color-left: #181818
border-color-bottom: #727272
border-color-right: #727272
UIWidget
id: resource
size: 64 64
anchors.left: parent.left
margin-left: 1
anchors.verticalCenter: parent.verticalCenter
image-source: /game_imbuing/new_design/images/imbuement-icons-64
image-clip: 0 0 64 64
phantom: true
RequiredItem < UIWidget
size: 66 90
UIItem
id: item
size: 66 66
anchors.left: parent.left
anchors.top: parent.top
priceable: false
phantom: true
image-source: /images/ui/item66
draggable: false
FlatLabel
id: count
margin-top: 3
text-align: center
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/ui/infoPanel
font: verdana-11px-rounded
color: white
text-offset: -2 1
SelectItemOrScroll < UIWidget
anchors.fill: parent
Panel
id: itemOrScrollPanel
height: 93
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 5
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Pick Item or Imbue a Blank Scroll')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: itemOrScrollContent
anchors.fill: parent
margin: 22 12 10 12
PickItemButton
ScrollItemButton
UIWidget
id: blockedPanels
size: 708 198
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /game_imbuing/new_design/images/blocked-panels
margin-top: 11
SelectImbue < UIWidget
anchors.fill: parent
Panel
id: itemOrScrollPanel
height: 103
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 5
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Pick Item or Imbue a Blank Scroll')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: itemOrScrollContent
anchors.fill: parent
margin: 27 12 10 12
PickItemButton
ScrollItemButton
Panel
id: slots
size: 208 66
anchors.top: prev.top
anchors.right: parent.right
margin-top: -1
margin-right: 18
SlotImbuing
id: slot0
margin-right: 6
&slot: 0
anchors.right: next.left
@onClick: modules.game_imbuing.onItemSlot(self)
SlotImbuing
id: slot1
margin-right: 6
anchors.right: next.left
&slot: 1
phantom: false
@onClick: modules.game_imbuing.onItemSlot(self)
SlotImbuing
id: slot2
&slot: 2
anchors.right: parent.right
@onClick: modules.game_imbuing.onItemSlot(self)
UIItem
id: item
size: 64 64
anchors.top: prev.top
anchors.right: prev.left
priceable: false
virtual: true
margin-top: 1
margin-right: 22
phantom: true
draggable: false
Label
id: titleInformation
anchors.top: prev.top
anchors.right: prev.left
!text: tr('Item Information')
font: verdana-11px-rounded
color: white
text-auto-resize: true
margin-top: 24
margin-right: 22
Panel
id: qualityAndImbuementPanel
height: 177
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 17
margin-top: 11
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Select Quality and Imbuement')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: qualityAndImbuementContent
anchors.fill: parent
margin: 27 12 9 12
UIButton
id: basicButton
size: 144 37
anchors.top: parent.top
anchors.left: parent.left
&baseImbuement: 0
margin-left: 116
image-source: /game_imbuing/new_design/images/basic-button
image-clip: 0 0 144 37
$hover !pressed:
image-clip: 0 0 144 37
$pressed:
image-clip: 0 37 144 37
$on:
image-clip: 0 37 144 37
@onClick: modules.game_imbuing.onItemBaseType(self:getId())
UIButton
id: intricateButton
size: 144 37
anchors.top: parent.top
anchors.left: prev.right
&baseImbuement: 1
margin-left: 11
image-source: /game_imbuing/new_design/images/intricate-button
image-clip: 0 0 144 37
$hover !pressed:
image-clip: 0 0 144 37
$pressed:
image-clip: 0 37 144 37
$on:
image-clip: 0 37 144 37
@onClick: modules.game_imbuing.onItemBaseType(self:getId())
UIButton
id: powerfullButton
size: 144 37
anchors.top: parent.top
anchors.left: prev.right
&baseImbuement: 2
margin-left: 11
image-source: /game_imbuing/new_design/images/powerfull-button
image-clip: 0 0 144 37
$hover !pressed:
image-clip: 0 0 144 37
$pressed:
image-clip: 0 37 144 37
$on:
image-clip: 0 37 144 37
@onClick: modules.game_imbuing.onItemBaseType(self:getId())
ScrollablePanel
id: imbuementsList
height: 70
width: 70
&originalwidth: 680
&maxWidth: 675
&incrementwidth: 73
anchors.top: prev.bottom
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 11
layout:
type: grid
cell-spacing: 5
cell-size: 66 66
num-columns: 9
num-rows: 3
Label
id: imbuementsDetails
anchors.bottom: parent.bottom
anchors.left: parent.left
!text: tr('Raises your walking speed by 30. Lasts for 20h 0min while equipped.')
font: verdana-11px-rounded
color: white
text-auto-resize: true
Panel
id: imbuementReqPanel
height: 141
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 17
margin-top: 11
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Imbue Empty Slot with "Imbuement Name"')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: imbuementReqContent
anchors.fill: parent
margin: 27 12 10 12
Panel
id: requiredItems
width: 210
height: 90
anchors.top: parent.top
anchors.left: parent.left
RequiredItem
id: item1
anchors.top: parent.top
anchors.left: parent.left
RequiredItem
id: item2
anchors.top: parent.top
anchors.left: prev.right
margin-left: 6
RequiredItem
id: item3
anchors.top: parent.top
anchors.left: prev.right
margin-left: 6
UIWidget
id: horizontalArrow
size: 14 25
anchors.left: prev.right
anchors.verticalCenter: requiredItems.verticalCenter
margin-left: 171
image-source: /images/ui/right-arrow
phantom: false
Label
id: itensDetails
anchors.bottom: parent.bottom
anchors.left: parent.left
!text: tr('')
font: verdana-11px-rounded
color: white
text-auto-resize: true
visible: true
UIButton
id: imbueApply
size: 128 66
anchors.top: requiredItems.top
anchors.right: parent.right
image-source: /game_imbuing/images/imbue_empty
image-clip: 0 0 128 66
$pressed:
image-clip: 0 66 128 66
FlatLabel
id: costPanel
margin-top: 3
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/ui/infoPanel
Label
id: cost
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
margin-right: 5
margin-top: 3
text: 200
text-align: center
font: verdana-11px-rounded
color: white
text-auto-resize: true
UIWidget
size: 9 9
anchors.top: cost.top
anchors.left: cost.right
margin-top: 3
margin-left: 2
image-source: /images/game/cyclopedia/icons/icon-goldcoin
UIWidget
id: blockedPanels
size: 708 141
anchors.top: prev.top
anchors.left: prev.left
image-source: /game_imbuing/new_design/images/blocked-panel
visible: false
ClearImbue < UIWidget
anchors.fill: parent
Panel
id: itemOrScrollPanel
height: 103
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 5
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Pick Item or Imbue a Blank Scroll')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: itemOrScrollContent
anchors.fill: parent
margin: 27 12 10 12
PickItemButton
ScrollItemButton
Panel
id: slots
size: 208 66
anchors.top: prev.top
anchors.right: parent.right
margin-top: -1
margin-right: 18
SlotImbuing
id: slot0
margin-right: 6
&slot: 0
anchors.right: next.left
@onClick: modules.game_imbuing.onItemSlot(self)
SlotImbuing
id: slot1
margin-right: 6
anchors.right: next.left
&slot: 1
phantom: false
@onClick: modules.game_imbuing.onItemSlot(self)
SlotImbuing
id: slot2
&slot: 2
anchors.right: parent.right
@onClick: modules.game_imbuing.onItemSlot(self)
UIItem
id: item
size: 64 64
anchors.top: prev.top
anchors.right: prev.left
priceable: false
virtual: true
phantom: true
draggable: false
margin-top: 1
margin-right: 22
Label
id: titleInformation
anchors.top: prev.top
anchors.right: prev.left
!text: tr('Item Information')
font: verdana-11px-rounded
color: white
text-auto-resize: true
margin-top: 24
margin-right: 22
Panel
id: selectedImbuementPanel
height: 152
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 17
margin-top: 11
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Selected Imbuement')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: selectedImbuementContent
anchors.fill: parent
margin: 27 12 9 12
ScrollablePanel
id: clearImbuementsList
height: 70
width: 70
&originalwidth: 680
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 20
layout:
type: grid
cell-spacing: 6
cell-size: 66 66
num-columns: 9
num-rows: 3
Label
id: imbuementsDetails
anchors.bottom: parent.bottom
anchors.left: parent.left
!text: tr('Raises your walking speed by 30. Lasts for 20h 0min while equipped.')
font: verdana-11px-rounded
color: white
text-auto-resize: true
Panel
id: cleanImbuePanel
height: 141
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 17
margin-top: 11
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Clear Imbuement "Imbuement Name"')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: imbuementReqContent
anchors.fill: parent
margin: 27 12 10 12
Panel
id: time
size: 279 20
image-source: /game_imbuing/images/imbui-timer-bg
anchors.top: parent.top
anchors.left: parent.left
margin-top: 34
margin-left: 91
phantom: false
ProgressBarSD
id: timeRemaining
size: 277 18
anchors.fill: parent
image-source: /game_imbuing/images/imbui-progress
margin: 1 1 1 1
phantom: true
percent: 1
Label
id: textLabel
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
text-align: center
font: verdana-11px-rounded
color: white
text-auto-resize: true
margin-top: 2
phantom: true
Label
id: cleanImbuementsDetails
anchors.bottom: parent.bottom
anchors.left: parent.left
font: verdana-11px-rounded
color: white
text-auto-resize: true
UIButton
id: clear
size: 128 66
anchors.top: parent.top
anchors.right: parent.right
image-source: /game_imbuing/images/clear
image-clip: 0 0 128 66
$pressed:
image-clip: 0 66 128 66
FlatLabel
id: costPanel
margin-top: 3
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/ui/infoPanel
Label
id: cost
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
margin-right: 5
margin-top: 3
text: 200
text-align: center
font: verdana-11px-rounded
color: white
text-auto-resize: true
UIWidget
size: 9 9
anchors.top: cost.top
anchors.left: cost.right
margin-top: 3
margin-left: 2
image-source: /images/game/cyclopedia/icons/icon-goldcoin
ScrollImbue < UIWidget
anchors.fill: parent
Panel
id: itemOrScrollPanel
height: 93
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 5
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Pick Item or Imbue a Blank Scroll')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: itemOrScrollContent
anchors.fill: parent
margin: 22 12 10 12
PickItemButton
ScrollItemButton
UIItem
id: itemScroll
size: 64 64
anchors.top: prev.top
anchors.right: parent.right
priceable: false
virtual: true
draggable: false
phantom: true
margin-top: 1
margin-right: 77
Label
id: titleScroll
anchors.top: prev.top
anchors.right: prev.left
!text: tr('Blank Imbuement Scroll')
font: verdana-11px-rounded
color: white
text-auto-resize: true
margin-top: 24
margin-right: 22
Panel
id: selectImbuementPanel
height: 314
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 17
margin-top: 11
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Select an Imbuement')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: qualityAndImbuementContent
anchors.fill: parent
margin: 22 12 9 12
UIButton
id: intricateButton
size: 144 37
anchors.top: parent.top
anchors.left: parent.left
margin-left: 193
&baseImbuement: 1
image-source: /game_imbuing/new_design/images/intricate-button
image-clip: 0 0 144 37
$hover !pressed:
image-clip: 0 0 144 37
$pressed:
image-clip: 0 37 144 37
$on:
image-clip: 0 37 144 37
@onClick: modules.game_imbuing.onScrollBaseType(self:getId())
UIButton
id: powerfullButton
size: 144 37
anchors.top: parent.top
anchors.left: prev.right
margin-left: 11
&baseImbuement: 2
image-source: /game_imbuing/new_design/images/powerfull-button
image-clip: 0 0 144 37
$hover !pressed:
image-clip: 0 0 144 37
$pressed:
image-clip: 0 37 144 37
$on:
image-clip: 0 37 144 37
@onClick: modules.game_imbuing.onScrollBaseType(self:getId())
ScrollablePanel
id: imbuementsList
height: 206
width: 680
anchors.top: prev.bottom
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 6
padding-left: 25
layout:
type: grid
cell-spacing: 4
cell-size: 66 66
num-columns: 9
num-rows: 3
Label
id: imbuementsDetails
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
!text: tr('Raises your walking speed by 30. Lasts for 20h 0min while equipped.')
font: verdana-11px-rounded
color: white
text-auto-resize: true
text-wrap: true
Panel
id: imbuementReqPanel
height: 141
anchors.top: prev.bottom
anchors.left: parent.left
anchors.right: parent.right
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 17
margin-top: 11
Label
id: title
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin-top: 2
!text: tr('Imbue Blank Scroll with "Imbuement Name"')
font: verdana-11px-rounded
color: #AAAAAA
text-auto-resize: true
Panel
id: imbuementReqContent
anchors.fill: parent
margin: 27 12 10 12
Panel
id: requiredItems
width: 280
height: 90
anchors.top: parent.top
anchors.left: parent.left
RequiredItem
id: item1
anchors.top: parent.top
anchors.left: parent.left
RequiredItem
id: item2
anchors.top: parent.top
anchors.left: prev.right
margin-left: 6
RequiredItem
id: item3
anchors.top: parent.top
anchors.left: prev.right
margin-left: 6
RequiredItem
id: item4
anchors.top: parent.top
anchors.left: prev.right
margin-left: 6
UIWidget
id: horizontalArrow
size: 14 25
anchors.left: prev.right
anchors.verticalCenter: requiredItems.verticalCenter
margin-left: 171
image-source: /images/ui/right-arrow
phantom: false
Label
id: itensDetails
anchors.bottom: parent.bottom
anchors.left: parent.left
!text: tr('')
font: verdana-11px-rounded
color: white
text-auto-resize: true
visible: true
UIButton
id: imbuescrollApply
size: 128 66
anchors.top: requiredItems.top
anchors.right: parent.right
image-source: /game_imbuing/images/imbue_empty
image-clip: 0 0 128 66
$pressed:
image-clip: 0 0 128 66
FlatLabel
id: costPanel
margin-top: 3
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/ui/infoPanel
Label
id: cost
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
margin-right: 5
margin-top: 3
text: 200
text-align: center
font: verdana-11px-rounded
color: white
text-auto-resize: true
UIWidget
size: 9 9
anchors.top: cost.top
anchors.left: cost.right
margin-top: 3
margin-left: 2
image-source: /images/game/cyclopedia/icons/icon-goldcoin
NewMainWindow
id: imbuingWindow
!text: tr('Imbuement Shrine')
size: 740 640
@onEscape: modules.game_imbuing.close()
Panel
id: contentPanel
anchors.fill: parent
margin: 12 12 12 12
SelectItemOrScroll
id: selectItemOrScroll
main-window-size: 740 388
visible: true
ScrollImbue
id: scrollImbue
main-window-size: 740 655
visible: false
SelectImbue
id: selectImbue
main-window-size: 740 528
visible: false
ClearImbue
id: clearImbue
main-window-size: 740 502
visible: false
HorizontalSeparator
id: bottomSep
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: close.top
margin-bottom: 11
Button
id: close
!text: tr('Close')
size: 43 20
anchors.right: parent.right
anchors.bottom: parent.bottom
@onClick: modules.game_imbuing.close()
Panel
id: gold
size: 160 20
anchors.left: parent.left
anchors.bottom: parent.bottom
image-source: /images/game/prey/balanceBg
UIWidget
id: goldIcon
anchors.top: parent.top
anchors.right: parent.right
margin-top: 6
margin-right: 3
image-source: /images/game/prey/prey_gold
UIWidget
id: gold
anchors.top: parent.top
anchors.right: prev.left
anchors.left: parent.left
margin-top: 3
margin-right: 2
text-align: right
text: 0
font: verdana-11px-rounded
color: white
text-auto-resize: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

@ -0,0 +1,674 @@
local oldDesignApi = {}
local imbuingWindow
local bankGold = 0
local inventoryGold = 0
local itemImbuements = {}
local emptyImbue
local groupsCombo
local imbueLevelsCombo
local protectionBtn
local clearImbue
local selectedImbue
local imbueItems = {}
local protection = false
local clearConfirmWindow
local imbueConfirmWindow
local infoPanel
local setProtection
local resetSlots
local selectSlot
local hide
local show
local toggle
local formatTooltipText
local setupTooltipEvents
local function destroyWindow()
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
if imbueConfirmWindow then
imbueConfirmWindow:destroy()
imbueConfirmWindow = nil
end
if imbuingWindow then
imbuingWindow:destroy()
imbuingWindow = nil
end
emptyImbue = nil
groupsCombo = nil
imbueLevelsCombo = nil
protectionBtn = nil
clearImbue = nil
infoPanel = nil
selectedImbue = nil
itemImbuements = {}
imbueItems = {}
protection = false
end
local function ensureWindow()
if imbuingWindow then
return
end
imbuingWindow = g_ui.displayUI('imbuing')
emptyImbue = imbuingWindow.emptyImbue
groupsCombo = emptyImbue.groups
imbueLevelsCombo = emptyImbue.imbuement
protectionBtn = emptyImbue.protection
clearImbue = imbuingWindow.clearImbue
infoPanel = imbuingWindow.infoPanel
imbuingWindow:hide()
local player = g_game.getLocalPlayer()
if player then
bankGold = player:getResourceBalance(ResourceTypes.BANK_BALANCE)
inventoryGold = player:getResourceBalance(ResourceTypes.GOLD_EQUIPPED)
imbuingWindow.balance:setText(tr(comma_value (player:getTotalMoney())))
end
groupsCombo.onOptionChange = function(widget)
imbueLevelsCombo:clearOptions()
if itemImbuements ~= nil then
local selectedGroup = groupsCombo:getCurrentOption().text
for _, imbuement in ipairs(itemImbuements) do
if imbuement['group'] == selectedGroup then
emptyImbue.imbuement:addOption(imbuement['name'])
end
end
imbueLevelsCombo.onOptionChange(imbueLevelsCombo) -- update options
end
end
imbueLevelsCombo.onOptionChange = function(widget)
setProtection(false)
local selectedGroup = groupsCombo:getCurrentOption().text
for _, imbuement in ipairs(itemImbuements) do
if imbuement['group'] == selectedGroup then
if #imbuement['sources'] == widget.currentIndex then
selectedImbue = imbuement
local hasAllItems = true
for i, source in ipairs(imbuement['sources']) do
local itemFound = false
for _, item in ipairs(imbueItems) do
if item:getId() == source['item']:getId() then
itemFound = true
if item:getCount() >= source['item']:getCount() then
emptyImbue.requiredItems:getChildByIndex(i).count:setColor('white')
else
hasAllItems = false
emptyImbue.requiredItems:getChildByIndex(i).count:setColor('red')
end
emptyImbue.requiredItems:getChildByIndex(i).count:setText(item:getCount() .. '/' .. source['item']:getCount())
end
end
if not itemFound then
hasAllItems = false
emptyImbue.requiredItems:getChildByIndex(i).count:setText('0/' .. source['item']:getCount())
emptyImbue.requiredItems:getChildByIndex(i).count:setColor('red')
end
emptyImbue.requiredItems:getChildByIndex(i).item:setItemId(source['item']:getId())
emptyImbue.requiredItems:getChildByIndex(i).item:setTooltip('The imbuement requires ' .. source['description'] .. '.')
end
for i = 3, widget.currentIndex + 1, -1 do
emptyImbue.requiredItems:getChildByIndex(i).count:setText('')
emptyImbue.requiredItems:getChildByIndex(i).item:setItemId(0)
emptyImbue.requiredItems:getChildByIndex(i).item:setTooltip('')
end
emptyImbue.protectionCost:setText((comma_value(imbuement['protectionCost'])))
emptyImbue.cost:setText(comma_value(imbuement['cost']))
-- Verificar se tem todos os itens e gold suficiente
local hasEnoughGold = false
if not protection then
hasEnoughGold = (bankGold + inventoryGold) >= imbuement['cost']
if not hasEnoughGold then
emptyImbue.cost:setColor('red')
else
emptyImbue.cost:setColor('white')
end
else
hasEnoughGold = (bankGold + inventoryGold) >= (imbuement['cost'] + imbuement['protectionCost'])
if not hasEnoughGold then
emptyImbue.cost:setColor('red')
else
emptyImbue.cost:setColor('white')
end
end
-- Habilitar/desabilitar botão de imbue baseado em itens E gold
if hasAllItems and hasEnoughGold then
emptyImbue.imbue:setEnabled(true)
emptyImbue.imbue:setImageSource('/game_imbuing/images/imbue_green')
else
emptyImbue.imbue:setEnabled(false)
emptyImbue.imbue:setImageSource('/game_imbuing/images/imbue_empty')
end
-- Verificar se o botão de proteção deve ser desabilitado
if (bankGold + inventoryGold) < imbuement['protectionCost'] then
protectionBtn:setEnabled(false)
emptyImbue.protection:setImageSource('/game_imbuing/old_design/images/useprotection-disabled')
emptyImbue.protectionCost:setColor('red')
else
protectionBtn:setEnabled(true)
emptyImbue.protection:setImageSource('/game_imbuing/old_design/images/100percent')
emptyImbue.protectionCost:setColor('white')
end
emptyImbue.successRate:setText(imbuement['successRate'] .. '%')
if selectedImbue['successRate'] > 50 then
emptyImbue.successRate:setColor('white')
else
emptyImbue.successRate:setColor('red')
end
emptyImbue.description:setText(imbuement['description'])
end
end
end
end
protectionBtn.onClick = function()
setProtection(not protection)
end
-- Configurar hover events para exibir tooltips no painel
setupTooltipEvents()
end
local function getCorrectIconId(id)
local iconId = id
if iconId >= 16 then iconId = iconId + 3 end -- pula 16, 17, 18
if iconId >= 22 then iconId = iconId + 3 end -- pula 22, 23, 24
if iconId >= 43 then iconId = iconId + 3 end -- pula 43, 44, 45
if iconId >= 61 then iconId = iconId + 3 end -- pula 61, 62, 63
if iconId >= 79 then iconId = iconId + 3 end -- pula 79, 80, 81
return iconId
end
function oldDesignApi.init()
end
setProtection = function(value)
protection = value
if protection then
if not selectedImbue then
protection = false
return
end
emptyImbue.cost:setText(comma_value(selectedImbue['cost'] + selectedImbue['protectionCost']))
emptyImbue.successRate:setText('100%')
emptyImbue.successRate:setColor('green')
protectionBtn:setImageClip(torect('66 0 66 66'))
-- Verificar se há gold suficiente para o custo total com proteção
if (bankGold + inventoryGold) < (selectedImbue['cost'] + selectedImbue['protectionCost']) then
emptyImbue.cost:setColor('red')
else
emptyImbue.cost:setColor('white')
end
else
if selectedImbue then
emptyImbue.cost:setText(comma_value(selectedImbue['cost']))
emptyImbue.successRate:setText(selectedImbue['successRate'] .. '%')
if selectedImbue['successRate'] > 50 then
emptyImbue.successRate:setColor('white')
else
emptyImbue.successRate:setColor('red')
end
-- Verificar se há gold suficiente para o custo sem proteção
if (bankGold + inventoryGold) < selectedImbue['cost'] then
emptyImbue.cost:setColor('red')
else
emptyImbue.cost:setColor('white')
end
protectionBtn:setImageClip(torect('0 0 66 66'))
end
end
-- Re-verificar o estado do botão de imbue quando a proteção mudar
if selectedImbue then
local hasAllItems = true
for i, source in ipairs(selectedImbue['sources']) do
local itemFound = false
for _, item in ipairs(imbueItems) do
if item:getId() == source['item']:getId() then
itemFound = true
if item:getCount() < source['item']:getCount() then
hasAllItems = false
break
end
end
end
if not itemFound then
hasAllItems = false
break
end
end
local hasEnoughGold = false
if protection then
hasEnoughGold = (bankGold + inventoryGold) >= (selectedImbue['cost'] + selectedImbue['protectionCost'])
else
hasEnoughGold = (bankGold + inventoryGold) >= selectedImbue['cost']
end
-- Habilitar/desabilitar botão de imbue baseado em itens E gold
if hasAllItems and hasEnoughGold then
emptyImbue.imbue:setEnabled(true)
emptyImbue.imbue:setImageSource('/game_imbuing/images/imbue_green')
else
emptyImbue.imbue:setEnabled(false)
emptyImbue.imbue:setImageSource('/game_imbuing/images/imbue_empty')
end
end
end
function oldDesignApi.terminate()
destroyWindow()
end
resetSlots = function()
emptyImbue:setVisible(false)
clearImbue:setVisible(false)
if infoPanel then
local tooltipContent = infoPanel:recursiveGetChildById('tooltipContent')
if tooltipContent then tooltipContent:setText('') end
end
for i = 1, 3 do
local slot = imbuingWindow.itemInfo.slots:getChildByIndex(i)
slot:setText('Slot ' .. i)
slot:getChildById('icon'):setVisible(false)
slot:setEnabled(false)
slot:setTooltip(
'Items can have up to three imbuements slots. This slot is not available for this item.')
slot.onClick = nil
end
end
selectSlot = function(widget, slotId, activeSlot)
local slotIcon = widget:getChildById('icon')
if activeSlot then
emptyImbue:setVisible(false)
widget:setText('')
slotIcon:setVisible(true)
local id = activeSlot[1]['id'] or 1
slotIcon:setImageSource('//images/game/imbuing/icons//' .. getCorrectIconId(id))
slotIcon:setImageClip(torect('0 0 64 64'))
clearImbue.title:setText('Clear Imbuement "' .. activeSlot[1]['name'] .. '"')
clearImbue.groups:clearOptions()
clearImbue.groups:addOption(activeSlot[1]['group'])
clearImbue.imbuement:clearOptions()
clearImbue.imbuement:addOption(activeSlot[1]['name'])
clearImbue.description:setText(activeSlot[1]['description'])
local hours = string.format('%02.f', math.floor(activeSlot[2] / 3600))
local mins = string.format('%02.f', math.floor(activeSlot[2] / 60 - (hours * 60)))
local totalTime = activeSlot[1].duration or 72000
local timeRemaining = clearImbue.time.timerContainer.timeRemaining
if timeRemaining then
timeRemaining:setMinimum(0)
timeRemaining:setMaximum(totalTime)
timeRemaining:setValue(activeSlot[2], 0, totalTime)
end
clearImbue.time.timerContainer.timeRemaining.text:setText(hours .. ':' .. mins .. 'h')
clearImbue.cost:setText(comma_value(activeSlot[3]))
if (bankGold + inventoryGold) < activeSlot[3] then
clearImbue.clear:setEnabled(false)
clearImbue.clear:setImageSource('/game_imbuing/images/imbue_empty')
clearImbue.cost:setColor('red')
end
local yesCallback = function()
g_game.clearImbuement(slotId)
widget:setText('Slot ' .. (slotId + 1))
slotIcon:setVisible(true)
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
end
local noCallback = function()
imbuingWindow:show()
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
end
clearImbue.clear.onClick = function()
imbuingWindow:hide()
clearConfirmWindow = displayGeneralBox(tr('Confirm Clearing'),
tr(
'Do you wish to spend ' .. activeSlot[3] ..
' gold coins to clear the imbuement "' ..
activeSlot[1]['name'] .. '" from your item?'), {
{
text = tr('Yes'),
callback = yesCallback
},
{
text = tr('No'),
callback = noCallback
},
anchor = AnchorHorizontalCenter
}, yesCallback, noCallback)
end
clearImbue:setVisible(true)
else
emptyImbue:setVisible(true)
clearImbue:setVisible(false)
local yesCallback = function()
g_game.applyImbuement(slotId, selectedImbue['id'], protection)
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
slotIcon:setVisible(true)
local id = selectedImbue['id'] or 1
slotIcon:setImageSource('//images/game/imbuing/icons//' .. getCorrectIconId(id))
imbuingWindow:show()
end
local noCallback = function()
imbuingWindow:show()
if clearConfirmWindow then
clearConfirmWindow:destroy()
clearConfirmWindow = nil
end
end
emptyImbue.imbue.onClick = function()
imbuingWindow:hide()
local cost = selectedImbue['cost']
local successRate = selectedImbue['successRate']
if protection then
cost = cost + selectedImbue['protectionCost']
successRate = '100'
end
clearConfirmWindow = displayGeneralBox(tr('Confirm Imbuing Attempt'),
'You are about to imbue your item with "' .. selectedImbue['name'] ..
'".\nYour chance to succeed is ' .. successRate ..
'%. It will consume the required astral sources and ' .. cost ..
' gold coins.\nDo you wish to proceed?', {
{
text = tr('Yes'),
callback = yesCallback
},
{
text = tr('No'),
callback = noCallback
},
anchor = AnchorHorizontalCenter
}, yesCallback, noCallback)
end
end
end
function oldDesignApi.onImbuementItem(itemId, tier, slots, activeSlots, imbuements, needItems)
if not itemId then
return
end
ensureWindow()
resetSlots()
imbueItems = table.copy(needItems)
imbuingWindow.itemInfo.item:setItemId(itemId)
for i = 1, slots do
local slot = imbuingWindow.itemInfo.slots:getChildByIndex(i)
slot.onClick = function(widget)
selectSlot(widget, i - 1)
end
slot:setTooltip(
'Use this slot to imbue your item. Depending on the item you can have up to three different imbuements.')
slot:setEnabled(true)
if slot:getId() == 'slot0' then
selectSlot(slot, i - 1)
end
end
for i, slot in pairs(activeSlots) do
local activeSlotBtn = imbuingWindow.itemInfo.slots:getChildById('slot' .. i)
activeSlotBtn.onClick = function(widget)
selectSlot(widget, i, slot)
end
-- Atualiza o ícone de todos os slots ativos imediatamente
local slotIcon = activeSlotBtn:getChildById('icon')
activeSlotBtn:setText('')
slotIcon:setVisible(true)
local id = slot[1]['id'] or 1
slotIcon:setImageSource('//images/game/imbuing/icons//' .. getCorrectIconId(id))
if activeSlotBtn:getId() == 'slot0' then
selectSlot(activeSlotBtn, i, slot)
end
end
if imbuements ~= nil then
groupsCombo:clearOptions()
imbueLevelsCombo:clearOptions()
itemImbuements = table.copy(imbuements)
for _, imbuement in ipairs(itemImbuements) do
if not groupsCombo:isOption(imbuement['group']) then
groupsCombo:addOption(imbuement['group'])
end
end
end
-- Reconfigurar eventos de hover após carregar os slots
setupTooltipEvents()
show()
end
function oldDesignApi.onResourcesBalanceChange(balance, oldBalance, type)
if type == ResourceTypes.BANK_BALANCE then
bankGold = balance
elseif type == ResourceTypes.GOLD_EQUIPPED then
inventoryGold = balance
end
if not imbuingWindow then
return
end
local player = g_game.getLocalPlayer()
if player then
if type == ResourceTypes.BANK_BALANCE or type == ResourceTypes.GOLD_EQUIPPED then
imbuingWindow.balance:setText(tr(comma_value (player:getTotalMoney())))
-- Re-verificar o estado dos botões quando o saldo mudar
if selectedImbue and emptyImbue:isVisible() then
-- Verificar botão de proteção
if (bankGold + inventoryGold) < selectedImbue['protectionCost'] then
protectionBtn:setEnabled(false)
emptyImbue.protection:setImageSource('/game_imbuing/old_design/images/useprotection-disabled')
emptyImbue.protectionCost:setColor('red')
else
protectionBtn:setEnabled(true)
emptyImbue.protection:setImageSource('/game_imbuing/old_design/images/100percent')
emptyImbue.protectionCost:setColor('white')
end
-- Verificar se tem todos os itens
local hasAllItems = true
for i, source in ipairs(selectedImbue['sources']) do
local itemFound = false
for _, item in ipairs(imbueItems) do
if item:getId() == source['item']:getId() then
itemFound = true
if item:getCount() < source['item']:getCount() then
hasAllItems = false
break
end
end
end
if not itemFound then
hasAllItems = false
break
end
end
-- Verificar gold suficiente
local hasEnoughGold = false
if protection then
hasEnoughGold = (bankGold + inventoryGold) >= (selectedImbue['cost'] + selectedImbue['protectionCost'])
if not hasEnoughGold then
emptyImbue.cost:setColor('red')
else
emptyImbue.cost:setColor('white')
end
else
hasEnoughGold = (bankGold + inventoryGold) >= selectedImbue['cost']
if not hasEnoughGold then
emptyImbue.cost:setColor('red')
else
emptyImbue.cost:setColor('white')
end
end
-- Habilitar/desabilitar botão de imbue baseado em itens E gold
if hasAllItems and hasEnoughGold then
emptyImbue.imbue:setEnabled(true)
emptyImbue.imbue:setImageSource('/game_imbuing/images/imbue_green')
else
emptyImbue.imbue:setEnabled(false)
emptyImbue.imbue:setImageSource('/game_imbuing/images/imbue_empty')
end
end
end
end
end
function oldDesignApi.onCloseImbuementWindow()
if not imbuingWindow then
return
end
resetSlots()
destroyWindow()
end
hide = function()
if g_game.isOnline() then
g_game.closeImbuingWindow()
end
if imbuingWindow then
imbuingWindow:hide()
end
end
show = function()
ensureWindow()
imbuingWindow:show()
imbuingWindow:raise()
imbuingWindow:focus()
end
toggle = function()
ensureWindow()
if imbuingWindow:isVisible() then
return hide()
end
show()
end
-- Função para formatar texto com quebra de linha automática
formatTooltipText = function(text)
if not text then return '' end
-- Definir largura máxima aproximada (em caracteres)
local maxWidth = 240
local formattedText = ''
local currentLine = ''
-- Dividir o texto em palavras
for word in text:gmatch("%S+") do
-- Se adicionar a palavra exceder a largura máxima
if #currentLine + #word + 1 > maxWidth and #currentLine > 0 then
formattedText = formattedText .. currentLine .. '\n'
currentLine = word
else
if #currentLine > 0 then
currentLine = currentLine .. ' ' .. word
else
currentLine = word
end
end
end
-- Adicionar a última linha
if #currentLine > 0 then
formattedText = formattedText .. currentLine
end
return formattedText
end
-- Função para configurar eventos de hover em elementos com tooltip
setupTooltipEvents = function()
if not infoPanel then return end
local tooltipContent = infoPanel:recursiveGetChildById('tooltipContent')
if not tooltipContent then return end
-- Função para adicionar hover a um widget
local function addHoverToWidget(widget)
if not widget or not widget.getTooltip then return end
widget.onHoverChange = function(self, hovered)
if hovered then
local tooltip = self:getTooltip()
if tooltip and tooltip ~= '' then
-- Adicionar quebras de linha para textos longos
local formattedText = formatTooltipText(tooltip)
tooltipContent:setText(formattedText)
else
tooltipContent:setText('')
end
else
tooltipContent:setText('')
end
end
end
-- Adicionar hover aos botões principais
if emptyImbue.imbue then addHoverToWidget(emptyImbue.imbue) end
if emptyImbue.protection then addHoverToWidget(emptyImbue.protection) end
if clearImbue.clear then addHoverToWidget(clearImbue.clear) end
-- Adicionar hover aos itens requeridos
if emptyImbue.requiredItems then
for i = 1, 3 do
local item = emptyImbue.requiredItems:getChildByIndex(i).item
if item then addHoverToWidget(item) end
end
end
-- Adicionar hover aos slots
if imbuingWindow.itemInfo and imbuingWindow.itemInfo.slots then
for i = 1, 3 do
local slot = imbuingWindow.itemInfo.slots:getChildByIndex(i)
if slot then addHoverToWidget(slot) end
end
end
end
oldDesignApi.hide = hide
oldDesignApi.close = hide
oldDesignApi.show = show
oldDesignApi.toggle = toggle
return oldDesignApi

View file

@ -1,11 +1,18 @@
Slot < Button
width: 70
width: 66
height: 66
anchors.verticalCenter: parent.verticalCenter
enabled: false
text-wrap: true
!tooltip: tr('Items can have up to three imbuements slots. This slot is not available for this item.')
UIWidget
id: icon
size: 64 64
anchors.centerIn: parent
phantom: true
visible: false
RequiredItem < Panel
width: 66
height: 90
@ -16,6 +23,7 @@ RequiredItem < Panel
width: 66
anchors.left: parent.left
anchors.top: parent.top
image-source: /images/ui/item66
FlatLabel
id: count
@ -24,11 +32,14 @@ RequiredItem < Panel
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
text-offset: 0 0
image-source: /images/ui/infoPanel
ItemInformation < Panel
height: 100
border: 1 black
padding: 5
padding: 3
image-source: /images/ui/t2pixel-up-frame-borderimage
image-border: 5
Label
id: title
@ -62,13 +73,26 @@ ItemInformation < Panel
!text: tr("Slot 1")
text-align: center
anchors.left: parent.left
image-source: /game_imbuing/old_design/images/slot_inactive
image-clip: 0 0 66 66
$hover !pressed:
image-clip: 0 0 66 66
$pressed:
image-source: /game_imbuing/old_design/images/slot
image-clip: 0 0 66 66
Slot
id: slot1
!text: tr("Slot 2")
text-align: center
margin-left: 10
anchors.left: prev.right
margin-left: 10
image-source: /game_imbuing/old_design/images/slot_inactive
image-clip: 0 0 66 66
$hover !pressed:
image-clip: 0 0 66 66
$pressed:
image-source: /game_imbuing/old_design/images/slot
image-clip: 0 0 66 66
Slot
id: slot2
@ -76,6 +100,13 @@ ItemInformation < Panel
text-align: center
margin-left: 10
anchors.left: prev.right
image-source: /game_imbuing/old_design/images/slot_inactive
image-clip: 0 0 66 66
$hover !pressed:
image-clip: 0 0 66 66
$pressed:
image-source: /game_imbuing/old_design/images/slot
image-clip: 0 0 66 66
Label
id: selectSlot
@ -86,8 +117,9 @@ ItemInformation < Panel
EmptyImbue < Panel
height: 240
border: 1 black
padding: 5
padding: 3 15 15 15
image-source: /images/ui/t2pixel-up-frame-borderimage_2
image-border: 5
Label
id: title
@ -126,6 +158,7 @@ EmptyImbue < Panel
anchors.bottom: prev.bottom
anchors.left: parent.left
!text: tr('Requires the following astral sources:')
margin-bottom: 10
Label
id: successRate
@ -168,7 +201,7 @@ EmptyImbue < Panel
height: 66
anchors.top: prev.top
anchors.left: prev.right
image-source: /images/game/imbuing/100percent
image-source: /game_imbuing/old_design/images/100percent
image-clip: 0 0 66 66
margin-left: 15
!tooltip: ("Bribe the fates! Click here to raise your chance to 100%. For guaranteed success use gold.")
@ -180,6 +213,7 @@ EmptyImbue < Panel
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/ui/infoPanel
UIWidget
id: horizontalArrow
@ -199,7 +233,7 @@ EmptyImbue < Panel
height: 66
anchors.top: requiredItems.top
anchors.right: parent.right
image-source: /images/game/imbuing/imbue_empty
image-source: /game_imbuing/images/imbue_empty
image-clip: 0 0 128 66
margin-left: 15
!tooltip: tr("Click here to carry out the selected imbuement. This will consume the required astral sources and gold.")
@ -214,11 +248,13 @@ EmptyImbue < Panel
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/game/prey/balanceBg
ClearImbue < Panel
height: 240
border: 1 black
padding: 5
padding: 3 15 15 15
image-source: /images/ui/t2pixel-up-frame-borderimage_2
image-border: 5
Label
id: title
@ -267,19 +303,35 @@ ClearImbue < Panel
Panel
id: time
width: 210
width: 277
height: 90
anchors.left: parent.left
anchors.bottom: parent.bottom
Panel
id: timerContainer
size: 277 18
anchors.centerIn: parent
image-source: /game_imbuing/images/imbui-timer-bg
ProgressBarSD
id: timeRemaining
size: 277 18
anchors.fill: parent
image-source: /game_imbuing/images/imbui-progress
margin: 1
phantom: true
percent: 1
FlatLabel
id: timeRemaining
size: 86 25
margin-bottom: 20
text-align: center
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Label
id: text
anchors.centerIn: parent
text-align: center
text-auto-resize: true
color: white
font: verdana-11px-rounded
margin-top: 1
phantom: true
UIButton
id: clear
@ -287,7 +339,7 @@ ClearImbue < Panel
height: 66
anchors.top: time.top
anchors.right: parent.right
image-source: /images/game/imbuing/clear
image-source: /game_imbuing/images/clear
image-clip: 0 0 128 66
margin-left: 15
!tooltip: tr("Your needs have changed? Click here to clear the imbuement from your item for a fee.")
@ -302,12 +354,29 @@ ClearImbue < Panel
anchors.left: prev.left
anchors.right: prev.right
anchors.top: prev.bottom
image-source: /images/game/prey/balanceBg
infoPanelTolltip < Panel
height: 75
padding: 10
image-source: /images/ui/2pixel_up_frame_borderimage
image-border: 5
Label
id: tooltipContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
text-align: left
color: white
font: verdana-11px-rounded
text-wrap: true
MainWindow
id: imbuingWindow
!text: tr('Imbue Item')
size: 550 430
size: 572 520
background-color: #AAAAAA
@onEscape: modules.game_imbuing.hide()
@ -330,6 +399,13 @@ MainWindow
anchors.top: emptyImbue.top
anchors.right: parent.right
infoPanelTolltip
id: infoPanel
anchors.left: parent.left
anchors.top: emptyImbue.bottom
anchors.right: parent.right
margin-top: 5
Button
id: close
!text: tr('Close')
@ -341,6 +417,14 @@ MainWindow
Label
id: balance
height: 25
anchors.right: prev.left
anchors.left: parent.left
anchors.bottom: parent.bottom
text-align: right
text-offset: -20 0
image-source: /images/game/prey/balanceBg
UIWidget
id: Icon
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
margin-right: 4
image-source: /game_cyclopedia/images/icon-goldcoin

View file

@ -630,7 +630,12 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
if lookThing:isCreature() then
g_game.inspectCharacter(lookThing:getId(), InspectCreaturesTypes.INSPECT_CREATURE)
elseif canInspect then
g_game.inspectionNormalObject(lookThing:getPosition())
local pos = lookThing:getPosition()
if pos and pos:isValid() then
g_game.inspectionNormalObject(pos)
else
g_game.inspectionObject(InspectObjectTypes.INSPECT_CYCLOPEDIA, lookThing:getId())
end
end
end, shortcut)
end
@ -2061,4 +2066,4 @@ function toggleFocus(value, reason)
gameLeftPanel:setFocusable(value)
gameRightExtraPanel:setFocusable(value)
gameLeftExtraPanel:setFocusable(value)
end
end

View file

@ -96,7 +96,7 @@ function init()
onGameStart = onGameStart,
onDestinyWheel = WheelOfDestiny.onDestinyWheel,
--onUnlockGem = GemAtelier.onUnlockGem, --disabled because it's in TODO
onResourceBalance = onResourceBalance,
onResourcesBalanceChange = onResourceBalance,
})
if modules.game_mainpanel then
@ -112,7 +112,7 @@ function terminate()
onGameStart = onGameStart,
onDestinyWheel = WheelOfDestiny.onDestinyWheel,
--onUnlockGem = GemAtelier.onUnlockGem, --disabled because it's in TODO
onResourceBalance = onResourceBalance
onResourcesBalanceChange = onResourceBalance
})
if wheelWindow then

View file

@ -1888,6 +1888,22 @@ void Game::closeImbuingWindow()
m_protocolGame->sendCloseImbuingWindow();
}
void Game::selectImbuementItem(const uint16_t itemId, const Position& pos, const uint8_t stackpos)
{
if (!canPerformGameAction())
return;
m_protocolGame->sendImbuementWindowAction(Otc::IMBUEMENT_WINDOW_SELECT_ITEM, itemId, pos, stackpos);
}
void Game::selectImbuementScroll()
{
if (!canPerformGameAction())
return;
m_protocolGame->sendImbuementWindowAction(Otc::IMBUEMENT_WINDOW_SCROLL);
}
void Game::imbuementDurations(const bool isOpen)
{
if (!canPerformGameAction())

View file

@ -408,6 +408,8 @@ public:
void clearImbuement(uint8_t slot);
void closeImbuingWindow();
void imbuementDurations(bool isOpen = false);
void selectImbuementItem(uint16_t itemId, const Position& pos, uint8_t stackpos);
void selectImbuementScroll();
// weapon proficiency related
void sendWeaponProficiencyAction(uint8_t actionType, uint16_t itemId = 0);

View file

@ -384,6 +384,8 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "applyImbuement", &Game::applyImbuement, &g_game);
g_lua.bindSingletonFunction("g_game", "clearImbuement", &Game::clearImbuement, &g_game);
g_lua.bindSingletonFunction("g_game", "closeImbuingWindow", &Game::closeImbuingWindow, &g_game);
g_lua.bindSingletonFunction("g_game", "selectImbuementItem", &Game::selectImbuementItem, &g_game);
g_lua.bindSingletonFunction("g_game", "selectImbuementScroll", &Game::selectImbuementScroll, &g_game);
g_lua.bindSingletonFunction("g_game", "isUsingProtobuf", &Game::isUsingProtobuf, &g_game);
g_lua.bindSingletonFunction("g_game", "enableTileThingLuaCallback", &Game::enableTileThingLuaCallback, &g_game);
g_lua.bindSingletonFunction("g_game", "isTileThingLuaCallbackEnabled", &Game::isTileThingLuaCallbackEnabled, &g_game);

View file

@ -148,6 +148,7 @@ public:
void sendApplyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm);
void sendClearImbuement(uint8_t slot);
void sendCloseImbuingWindow();
void sendImbuementWindowAction(uint8_t type, uint16_t itemId = 0, const Position& pos = Position(), uint8_t stackpos = 0);
void sendOpenRewardWall();
void sendOpenRewardHistory();
void sendGetRewardDaily(const uint8_t bonusShrine, const std::map<uint16_t, uint8_t>& items);

View file

@ -5912,53 +5912,70 @@ Imbuement ProtocolGame::getImbuementInfo(const InputMessagePtr& msg)
void ProtocolGame::parseImbuementWindow(const InputMessagePtr& msg)
{
const bool isModernImbuementWindow = g_game.getClientVersion() >= 1510;
uint8_t windowType = Otc::IMBUEMENT_WINDOW_SELECT_ITEM;
if (g_game.getClientVersion() >= 1510) {
if (isModernImbuementWindow) {
windowType = static_cast<Otc::Imbuement_Window_t>(msg->getU8()); // window type
msg->getU8(); // unknown byte
if (std::cmp_greater(windowType, static_cast<uint8_t>(Otc::IMBUEMENT_WINDOW_SCROLL))) {
g_logger.warning(fmt::format("ProtocolGame::parseImbuementWindow: unexpected windowType {}", windowType));
return;
}
}
switch (windowType) {
case Otc::IMBUEMENT_WINDOW_CHOICE: {
if (isModernImbuementWindow) {
msg->getU8(); // unknown
}
const uint16_t itemId = msg->getU16(); // item client ID
const uint32_t unknown = msg->getU32(); // unknown
g_lua.callGlobalField("g_game", "onOpenImbuementWindow", itemId, unknown);
break;
}
case Otc::IMBUEMENT_WINDOW_SCROLL: {
msg->getU8(); // unknown byte
msg->getU8(); // unknown byte
if (isModernImbuementWindow) {
msg->getU8(); // unknown byte
}
const uint16_t imbuementsSize = msg->getU16();
std::vector<Imbuement> imbuements;
for (auto i = 0; i < imbuementsSize; ++i) {
imbuements.reserve(imbuementsSize);
for (uint16_t i = 0; std::cmp_less(i, imbuementsSize); ++i) {
imbuements.push_back(getImbuementInfo(msg));
}
const uint32_t neededItemsListCount = msg->getU32();
std::vector<ItemPtr> neededItemsList;
neededItemsList.reserve(neededItemsListCount);
for (uint32_t i = 0; i < neededItemsListCount; ++i) {
for (uint32_t i = 0; std::cmp_less(i, neededItemsListCount); ++i) {
const uint16_t needItemId = msg->getU16();
const uint16_t count = msg->getU16();
const auto& needItem = Item::create(needItemId);
needItem->setCount(count);
neededItemsList.push_back(needItem);
}
g_lua.callGlobalField("g_game", "onImbuementScroll", imbuements, neededItemsList);
break;
}
case Otc::IMBUEMENT_WINDOW_SELECT_ITEM: {
const uint16_t itemId = msg->getU16(); // item client ID
uint16_t itemId = 0;
uint8_t tier = 0;
if (isModernImbuementWindow) {
msg->getU8(); // unknown
}
itemId = msg->getU16(); // item client ID
const auto& thing = g_things.getThingType(itemId, ThingCategoryItem);
if (isModernImbuementWindow && !thing) {
throw Exception("ProtocolGame::parseImbuementWindow: unable to resolve thing type for item id {}", itemId);
}
if (thing) {
const uint16_t classification = thing->getClassification();
if (classification > 0) {
msg->getU8(); // upgradeClass
if (std::cmp_greater(classification, 0)) {
tier = msg->getU8();
}
}
const uint8_t slot = msg->getU8();
const uint8_t slots = msg->getU8();
std::unordered_map<int, std::tuple<Imbuement, uint32_t, uint32_t>> activeSlots;
for (auto i = 0; i < slot; i++) {
for (uint8_t i = 0; std::cmp_less(i, slots); ++i) {
const uint8_t firstByte = msg->getU8();
if (firstByte == 0x01) {
Imbuement imbuement = getImbuementInfo(msg);
@ -5969,20 +5986,21 @@ void ProtocolGame::parseImbuementWindow(const InputMessagePtr& msg)
}
const uint16_t imbuementsSize = msg->getU16();
std::vector<Imbuement> imbuements;
for (auto i = 0; i < imbuementsSize; ++i) {
imbuements.reserve(imbuementsSize);
for (uint16_t i = 0; std::cmp_less(i, imbuementsSize); ++i) {
imbuements.push_back(getImbuementInfo(msg));
}
const uint32_t neededItemsListCount = msg->getU32();
std::vector<ItemPtr> neededItemsList;
neededItemsList.reserve(neededItemsListCount);
for (uint32_t i = 0; i < neededItemsListCount; ++i) {
for (uint32_t i = 0; std::cmp_less(i, neededItemsListCount); ++i) {
const uint16_t needItemId = msg->getU16();
const uint16_t count = msg->getU16();
const auto& needItem = Item::create(needItemId);
needItem->setCount(count);
neededItemsList.push_back(needItem);
}
g_lua.callGlobalField("g_game", "onImbuementWindow", itemId, slot, activeSlots, imbuements, neededItemsList);
g_lua.callGlobalField("g_game", "onImbuementItem", itemId, tier, slots, activeSlots, imbuements, neededItemsList);
break;
}
}

View file

@ -1550,6 +1550,21 @@ void ProtocolGame::sendCloseImbuingWindow()
send(msg);
}
void ProtocolGame::sendImbuementWindowAction(const uint8_t type, const uint16_t itemId, const Position& pos, const uint8_t stackpos)
{
const auto& msg = std::make_shared<OutputMessage>();
msg->addU8(Proto::ClientImbuementWindowAction);
msg->addU8(type); // 1 = SELECT_ITEM, 2 = SCROLL
if (type == Otc::IMBUEMENT_WINDOW_SELECT_ITEM) {
addPosition(msg, pos);
msg->addU16(itemId);
msg->addU8(stackpos);
}
send(msg);
}
void ProtocolGame::sendOpenRewardWall()
{
const auto& msg = std::make_shared<OutputMessage>();
@ -1627,7 +1642,6 @@ void ProtocolGame::sendImbuementDurations(const bool isOpen)
send(msg);
}
void ProtocolGame::sendQuickLoot(const uint8_t variant, const Position& pos, const uint16_t itemId, const uint8_t stackpos)
{
const auto msg = std::make_shared<OutputMessage>();