Skip to content

Commit

Permalink
fix: ActionBar packets (sendEquipItem) + Tier in actionbar
Browse files Browse the repository at this point in the history
The function sendEquipItem (which only affects game_actionbar) was sending 2 packets:
according OTCR
u16 the itemId
u8 or u16 countOrSubType
But this is incorrect.
According to Canary, the 2 packets to send are:

u16 the itemId
u8 tier.
This error manifests when trying to equip an item with a tier through the action bar.
The client sends the itemId and count (1).
For example, attempting to equip an Helmet tier +5.
The server interprets itemId and tier = 1(count), failing to find the item.
As a result, it doesn't work.
  • Loading branch information
kokekanon authored Jan 28, 2025
1 parent 2f45a1f commit 90b4062
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 31 deletions.
1 change: 1 addition & 0 deletions modules/corelib/ui/uiactionslot.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ function UIActionSlot.create()
slot.useType = nil
slot.autoSend = nil
slot.parameter = nil
slot.getTier = nil
return slot
end
2 changes: 1 addition & 1 deletion modules/game_actionbar/assign_object.otui
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PreviewItem < UIItem
PreviewItem < Item
size: 85 85
//background-color: gray
padding: 10
Expand Down
36 changes: 30 additions & 6 deletions modules/game_actionbar/game_actionbar.lua
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ function copySlot(fromSlotId, toSlotId, visible)
tmpslot.text = fromSlot.text
tmpslot.parameter = fromSlot.parameter
tmpslot.useType = fromSlot.useType
tmpslot.getTier = fromSlot.getTier
tmpslot:getChildById('text'):setText(fromSlot:getChildById('text'):getText())
tmpslot:setTooltip(fromSlot:getTooltip())
end
Expand Down Expand Up @@ -188,6 +189,7 @@ function setupActionBar()
slot.words = nil
slot.text = nil
slot.useType = nil
slot.getTier = nil
g_mouse.bindPress(slot, function()
slotToEdit = 'slot' .. i .. ''
end, MouseLeftButton)
Expand Down Expand Up @@ -359,6 +361,8 @@ function clearSlot()
slot.words = nil
slot.text = nil
slot.useType = nil
slot.getTier = nil
slot:getChildById('tier'):setVisible(false)
slot:getChildById('text'):setText('')
slot:setTooltip('')
end
Expand All @@ -374,6 +378,8 @@ function clearSlotById(slotId)
slot.words = nil
slot.text = nil
slot.useType = nil
slot.getTier = nil
slot:getChildById('tier'):setVisible(false)
slot:getChildById('text'):setText('')
slot:setTooltip('')
end
Expand Down Expand Up @@ -486,6 +492,8 @@ function objectAssignAccept()
slot:setImageSource('/images/game/actionbar/item-background')
slot:setBorderWidth(0)
slot.itemId = item:getId()
slot.getTier = objectAssignWindow:getChildById('previewItem').auxTier
ItemsDatabase.setTier(slot, slot.getTier)
if item:isFluidContainer() then
slot.subType = item:getSubType()
end
Expand Down Expand Up @@ -517,6 +525,9 @@ function onChooseItemMouseRelease(self, mousePosition, mouseButton)

if item and item:getPosition().x == 65535 and slotToEdit then
objectAssignWindow:getChildById('previewItem'):setItemId(item:getId())
local tier = item:getTier()
ItemsDatabase.setTier(objectAssignWindow:getChildById('previewItem'), tier)
objectAssignWindow:getChildById('previewItem').auxTier = tier
objectAssignWindow:getChildById('previewItem'):setItemCount(1)
objectAssignWindow:getChildById('equipCheckbox'):setEnabled(false)
objectAssignWindow:getChildById('useCheckbox'):setEnabled(false)
Expand Down Expand Up @@ -562,6 +573,9 @@ function onChooseItemByDrag(self, mousePosition, item)
if item and item:getPosition().x == 65535 and slotToEdit then
openObjectAssignWindow()
objectAssignWindow:getChildById('previewItem'):setItemId(item:getId())
local tier = item:getTier()
ItemsDatabase.setTier(objectAssignWindow:getChildById('previewItem'), tier)
objectAssignWindow:getChildById('previewItem').auxTier = tier
objectAssignWindow:getChildById('previewItem'):setItemCount(1)
objectAssignWindow:getChildById('equipCheckbox'):setEnabled(false)
objectAssignWindow:getChildById('useCheckbox'):setEnabled(false)
Expand Down Expand Up @@ -664,7 +678,7 @@ function setupHotkeys()
elseif slot.useType == 'useOnSelf' then
modules.game_hotkeys.executeHotkeyItem(HOTKEY_USEONSELF, slot.itemId, slot.subType)
elseif slot.useType == 'equip' then
local item = g_game.findPlayerItem(slot.itemId, -1)
local item = g_game.findPlayerItem(slot.itemId, -1, slot.getTier)
if item then
g_game.equipItem(item)
end
Expand Down Expand Up @@ -707,7 +721,7 @@ function setupHotkeys()
elseif slot.useType == 'useOnSelf' then
modules.game_hotkeys.executeHotkeyItem(HOTKEY_USEONSELF, slot.itemId, slot.subType)
elseif slot.useType == 'equip' then
local item = g_game.findPlayerItem(slot.itemId, -1)
local item = g_game.findPlayerItem(slot.itemId, -1, slot.getTier)
if item then
g_game.equipItem(item)
end
Expand Down Expand Up @@ -819,7 +833,8 @@ function saveActionBar()
useType = slot.useType,
text = slot.text,
words = slot.words,
parameter = slot.parameter
parameter = slot.parameter,
getTier = slot.getTier
}
end

Expand All @@ -843,6 +858,7 @@ function loadObject(slot)
slot:setImageClip('0 0 0 0')
slot:getChildById('text'):setText('')
slot:setBorderWidth(0)
ItemsDatabase.setTier(slot, slot.getTier)
setupHotkeys()
end

Expand Down Expand Up @@ -882,6 +898,8 @@ function loadActionBar()
slot.useType = setting.useType
slot.autoSend = setting.autoSend
slot.parameter = setting.parameter
slot.getTier = setting.getTier
ItemsDatabase.setTier(slot, slot.getTier)
if slot.hotkey then
local text = slot.hotkey
if type(text) == 'string' then
Expand All @@ -907,7 +925,7 @@ end

function setActionBarVisible(visible)
if visible then
actionBar:setHeight(34)
actionBar:setHeight(38)
actionBar:show()
else
actionBar:setHeight(0)
Expand All @@ -934,7 +952,10 @@ function updateCooldown(progressRect, duration, spellId, count)
end, 100)
else
cooldown[spellId] = nil
progressRect:destroy()
if progressRect and not progressRect:isDestroyed() then
progressRect:destroy()
progressRect = nil
end
end
end

Expand All @@ -952,7 +973,10 @@ function updateGroupCooldown(progressRect, duration, groupId)
end, 100)
else
groupCooldown[groupId] = nil
progressRect:destroy()
if progressRect and not progressRect:isDestroyed() then
progressRect:destroy()
progressRect = nil
end
end
end

Expand Down
14 changes: 14 additions & 0 deletions modules/game_actionbar/game_actionbar.otui
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ ActionSlot < UIActionSlot
opacity: 0.7
$!pressed:
opacity: 1.0

UIWidget
id: tier
size: 10 9
image-source: /images/inventory/tiers-strip
image-clip: 0 0 10 9
image-size: 10 9
anchors.top: parent.top
anchors.right: parent.right
phantom: true
focusable: false
visible: false
image-smooth: true

Label
id: key
anchors.top: parent.top
Expand Down
4 changes: 2 additions & 2 deletions modules/gamelib/game.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function g_game.getRsa()
return G.currentRsa
end

function g_game.findPlayerItem(itemId, subType)
function g_game.findPlayerItem(itemId, subType, tier)
local localPlayer = g_game.getLocalPlayer()
if localPlayer then
for slot = InventorySlotFirst, InventorySlotLast do
Expand All @@ -13,7 +13,7 @@ function g_game.findPlayerItem(itemId, subType)
end
end

return g_game.findItemInContainers(itemId, subType)
return g_game.findItemInContainers(itemId, subType, tier or 0)
end

function g_game.chooseRsa(host)
Expand Down
19 changes: 8 additions & 11 deletions modules/gamelib/items.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,33 @@ local function clipfunction(value)
end

function ItemsDatabase.setRarityItem(widget, item, style)
if not g_game.getFeature(GameColorizedLootValue) then
if not g_game.getFeature(GameColorizedLootValue) or not widget then
return
end

if not widget then
return
end

local frameOption = modules.client_options.getOption('framesRarity')
if frameOption == "none" then
return
end
local imagePath = '/images/ui/item'
local clip = nil
if item then
local price = type(item) == "number" and item or (item and item:getMeanPrice()) or 0
local itemRarity = getColorForValue(price)
if itemRarity then
local clip = clipfunction(price)
clip = clipfunction(price)
if clip ~= "" then
local imagePath = '/images/ui/item'
if frameOption == "frames" then
imagePath = "/images/ui/rarity_frames"
elseif frameOption == "corners" then
imagePath = "/images/ui/containerslot-coloredges"
end
widget:setImageClip(clip)
widget:setImageSource(imagePath)
else
clip = nil
end
end
end

widget:setImageClip(clip)
widget:setImageSource(imagePath)
if style then
widget:setStyle(style)
end
Expand Down
4 changes: 2 additions & 2 deletions src/client/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ void Container::onAddItem(const ItemPtr& item, int slot)
callLuaField("onAddItem", slot, item);
}

ItemPtr Container::findItemById(const uint32_t itemId, const int subType) const
ItemPtr Container::findItemById(const uint32_t itemId, const int subType, const uint8_t tier) const
{
for (const auto& item : m_items)
if (item->getId() == itemId && (subType == -1 || item->getSubType() == subType))
if (item->getId() == itemId && (subType == -1 || item->getSubType() == subType) && item->getTier() == tier)
return item;
return nullptr;
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Container final : public LuaObject
bool hasPages() { return m_hasPages; }
int getSize() { return m_size; }
int getFirstIndex() { return m_firstIndex; }
ItemPtr findItemById(uint32_t itemId, int subType) const;
ItemPtr findItemById(uint32_t itemId, int subType, uint8_t tier) const;

protected:
Container(const uint8_t id, const uint8_t capacity, const std::string_view name, ItemPtr containerItem, const bool hasParent, const bool isUnlocked, const bool hasPages, const uint16_t containerSize, const uint16_t firstIndex)
Expand Down
10 changes: 7 additions & 3 deletions src/client/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,11 +858,11 @@ void Game::useInventoryItemWith(const uint16_t itemId, const ThingPtr& toThing)
g_lua.callGlobalField("g_game", "onUseWith", pos, itemId, toThing, 0);
}

ItemPtr Game::findItemInContainers(const uint32_t itemId, const int subType)
ItemPtr Game::findItemInContainers(const uint32_t itemId, const int subType, const uint8_t tier)
{
for (const auto& it : m_containers) {
if (const auto& container = it.second) {
if (const auto& item = container->findItemById(itemId, subType)) {
if (const auto& item = container->findItemById(itemId, subType, tier)) {
return item;
}
}
Expand Down Expand Up @@ -1412,7 +1412,11 @@ void Game::equipItem(const ItemPtr& item)
if (!canPerformGameAction())
return;

m_protocolGame->sendEquipItem(item->getId(), item->getCountOrSubType());
if (g_game.getFeature(Otc::GameThingUpgradeClassification) && item->getClassification() > 0) {
m_protocolGame->sendEquipItemWithTier(item->getId(), item->getTier());
} else {
m_protocolGame->sendEquipItemWithCountOrSubType(item->getId(), item->getCountOrSubType());
}
}

void Game::mount(const bool mount)
Expand Down
2 changes: 1 addition & 1 deletion src/client/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ class Game
void useWith(const ItemPtr& item, const ThingPtr& toThing);
void useInventoryItem(uint16_t itemId);
void useInventoryItemWith(uint16_t itemId, const ThingPtr& toThing);
ItemPtr findItemInContainers(uint32_t itemId, int subType);
ItemPtr findItemInContainers(uint32_t itemId, int subType, uint8_t tier);

// container related
int open(const ItemPtr& item, const ContainerPtr& previousContainer);
Expand Down
3 changes: 2 additions & 1 deletion src/client/protocolgame.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class ProtocolGame final : public Protocol
void sendTurnSouth();
void sendTurnWest();
void sendGmTeleport(const Position& pos);
void sendEquipItem(uint16_t itemId, uint16_t countOrSubType);
void sendEquipItemWithTier(uint16_t itemId, uint8_t tierOrFluid);
void sendEquipItemWithCountOrSubType(uint16_t itemId, uint16_t tierOrFluid);
void sendMove(const Position& fromPos, uint16_t thingId, uint8_t stackpos, const Position& toPos, uint16_t count);
void sendInspectNpcTrade(uint16_t itemId, uint16_t count);
void sendBuyItem(uint16_t itemId, uint8_t subType, uint16_t amount, bool ignoreCapacity, bool buyWithBackpack);
Expand Down
16 changes: 13 additions & 3 deletions src/client/protocolgamesend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,15 +292,25 @@ void ProtocolGame::sendGmTeleport(const Position& pos)
send(msg);
}

void ProtocolGame::sendEquipItem(const uint16_t itemId, const uint16_t countOrSubType)
void ProtocolGame::sendEquipItemWithTier(const uint16_t itemId, const uint8_t tier)
{
const auto& msg = std::make_shared<OutputMessage>();
msg->addU8(Proto::ClientEquipItem);
msg->addU16(itemId);
if (g_game.getFeature(Otc::GameCountU16))
msg->addU8(tier);
send(msg);
}

void ProtocolGame::sendEquipItemWithCountOrSubType(const uint16_t itemId, const uint16_t countOrSubType)
{
const auto& msg = std::make_shared<OutputMessage>();
msg->addU8(Proto::ClientEquipItem);
msg->addU16(itemId);
if (g_game.getFeature(Otc::GameCountU16)) {
msg->addU16(countOrSubType);
else
} else {
msg->addU8(static_cast<uint8_t>(countOrSubType));
}
send(msg);
}

Expand Down

0 comments on commit 90b4062

Please sign in to comment.