mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Add separate draggable bag windows, fix dismount and player equipment
Bags are now individual draggable ImGui windows (backpack + each equipped bag) with per-bag toggle from the bag bar. B key opens/closes all. A settings toggle under Gameplay lets users switch back to the original aggregate single-window mode. Window width adapts to bag item name length. Fix dismount by clearing local mount state immediately (optimistic) instead of waiting for server confirmation, and allow buff bar right-click dismount regardless of the aura's buff flag. Fix other players appearing naked by queuing them for auto-inspect when the visible item field layout hasn't been detected yet.
This commit is contained in:
parent
89ccb0720a
commit
85864ab05b
5 changed files with 264 additions and 62 deletions
|
|
@ -82,6 +82,7 @@ private:
|
|||
int pendingUiOpacity = 65;
|
||||
bool pendingMinimapRotate = false;
|
||||
bool pendingMinimapSquare = false;
|
||||
bool pendingSeparateBags = true;
|
||||
|
||||
// UI element transparency (0.0 = fully transparent, 1.0 = fully opaque)
|
||||
float uiOpacity_ = 0.65f;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "game/world_packets.hpp"
|
||||
#include <GL/glew.h>
|
||||
#include <imgui.h>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
|
@ -29,6 +30,14 @@ public:
|
|||
void toggle() { open = !open; }
|
||||
void setOpen(bool o) { open = o; }
|
||||
|
||||
// Separate bag window controls
|
||||
void toggleBackpack();
|
||||
void toggleBag(int idx);
|
||||
void openAllBags();
|
||||
void closeAllBags();
|
||||
void setSeparateBags(bool sep) { separateBags_ = sep; }
|
||||
bool isSeparateBags() const { return separateBags_; }
|
||||
|
||||
bool isCharacterOpen() const { return characterOpen; }
|
||||
void toggleCharacter() { characterOpen = !characterOpen; }
|
||||
void setCharacterOpen(bool o) { characterOpen = o; }
|
||||
|
|
@ -64,6 +73,9 @@ private:
|
|||
bool open = false;
|
||||
bool characterOpen = false;
|
||||
bool bKeyWasDown = false;
|
||||
bool separateBags_ = true;
|
||||
bool backpackOpen_ = false;
|
||||
std::array<bool, 4> bagOpen_{};
|
||||
bool cKeyWasDown = false;
|
||||
bool equipmentDirty = false;
|
||||
bool inventoryDirty = false;
|
||||
|
|
@ -106,6 +118,10 @@ private:
|
|||
int heldBackpackIndex = -1;
|
||||
game::EquipSlot heldEquipSlot = game::EquipSlot::NUM_SLOTS;
|
||||
|
||||
void renderSeparateBags(game::Inventory& inventory, uint64_t moneyCopper);
|
||||
void renderAggregateBags(game::Inventory& inventory, uint64_t moneyCopper);
|
||||
void renderBagWindow(const char* title, bool& isOpen, game::Inventory& inventory,
|
||||
int bagIndex, float defaultX, float defaultY, uint64_t moneyCopper);
|
||||
void renderEquipmentPanel(game::Inventory& inventory);
|
||||
void renderBackpackPanel(game::Inventory& inventory);
|
||||
void renderStatsPanel(game::Inventory& inventory, uint32_t playerLevel);
|
||||
|
|
|
|||
|
|
@ -5539,7 +5539,13 @@ void GameHandler::maybeDetectVisibleItemLayout() {
|
|||
|
||||
void GameHandler::updateOtherPlayerVisibleItems(uint64_t guid, const std::map<uint16_t, uint32_t>& fields) {
|
||||
if (guid == 0 || guid == playerGuid) return;
|
||||
if (visibleItemEntryBase_ < 0 || visibleItemStride_ <= 0) return;
|
||||
if (visibleItemEntryBase_ < 0 || visibleItemStride_ <= 0) {
|
||||
// Layout not detected yet — queue this player for inspect as fallback.
|
||||
if (socket && state == WorldState::IN_WORLD) {
|
||||
pendingAutoInspect_.insert(guid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<uint32_t, 19> newEntries{};
|
||||
for (int s = 0; s < 19; s++) {
|
||||
|
|
@ -5713,18 +5719,16 @@ void GameHandler::handleAttackStop(network::Packet& packet) {
|
|||
|
||||
void GameHandler::dismount() {
|
||||
if (!socket) return;
|
||||
if (!isMounted()) {
|
||||
// Local/server desync guard: clear visual mount even when server says unmounted.
|
||||
// Clear local mount state immediately (optimistic dismount).
|
||||
// Server will confirm via SMSG_UPDATE_OBJECT with mountDisplayId=0.
|
||||
if (currentMountDisplayId_ != 0 || taxiMountActive_) {
|
||||
if (mountCallback_) {
|
||||
mountCallback_(0);
|
||||
}
|
||||
currentMountDisplayId_ = 0;
|
||||
taxiMountActive_ = false;
|
||||
taxiMountDisplayId_ = 0;
|
||||
onTaxiFlight_ = false;
|
||||
taxiActivatePending_ = false;
|
||||
taxiClientActive_ = false;
|
||||
LOG_INFO("Dismount desync recovery: force-cleared local mount state");
|
||||
LOG_INFO("Dismount: cleared local mount state");
|
||||
}
|
||||
network::Packet pkt(wireOpcode(Opcode::CMSG_CANCEL_MOUNT_AURA));
|
||||
socket->send(pkt);
|
||||
|
|
|
|||
|
|
@ -2860,8 +2860,10 @@ void GameScreen::renderBagBar(game::GameHandler& gameHandler) {
|
|||
ImVec2(0, 0), ImVec2(1, 1),
|
||||
ImVec4(0.1f, 0.1f, 0.1f, 0.9f),
|
||||
ImVec4(1, 1, 1, 1))) {
|
||||
// TODO: Open specific bag
|
||||
inventoryScreen.toggle();
|
||||
if (inventoryScreen.isSeparateBags())
|
||||
inventoryScreen.toggleBag(i);
|
||||
else
|
||||
inventoryScreen.toggle();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", bagItem.item.name.c_str());
|
||||
|
|
@ -2870,7 +2872,7 @@ void GameScreen::renderBagBar(game::GameHandler& gameHandler) {
|
|||
// Empty bag slot
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.15f, 0.15f, 0.8f));
|
||||
if (ImGui::Button("##empty", ImVec2(slotSize, slotSize))) {
|
||||
// Empty slot - maybe show equipment to find a bag?
|
||||
// Empty slot - no bag equipped
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
@ -2902,11 +2904,17 @@ void GameScreen::renderBagBar(game::GameHandler& gameHandler) {
|
|||
ImVec2(0, 0), ImVec2(1, 1),
|
||||
ImVec4(0.1f, 0.1f, 0.1f, 0.9f),
|
||||
ImVec4(1, 1, 1, 1))) {
|
||||
inventoryScreen.toggle();
|
||||
if (inventoryScreen.isSeparateBags())
|
||||
inventoryScreen.toggleBackpack();
|
||||
else
|
||||
inventoryScreen.toggle();
|
||||
}
|
||||
} else {
|
||||
if (ImGui::Button("B", ImVec2(slotSize, slotSize))) {
|
||||
inventoryScreen.toggle();
|
||||
if (inventoryScreen.isSeparateBags())
|
||||
inventoryScreen.toggleBackpack();
|
||||
else
|
||||
inventoryScreen.toggle();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
@ -3398,10 +3406,10 @@ void GameScreen::renderBuffBar(game::GameHandler& gameHandler) {
|
|||
}
|
||||
|
||||
// Right-click to cancel buffs / dismount
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right) && isBuff) {
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
if (gameHandler.isMounted()) {
|
||||
gameHandler.dismount();
|
||||
} else {
|
||||
} else if (isBuff) {
|
||||
gameHandler.cancelAura(aura.spellId);
|
||||
}
|
||||
}
|
||||
|
|
@ -4981,6 +4989,14 @@ void GameScreen::renderSettingsWindow() {
|
|||
}
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Text("Bags");
|
||||
ImGui::Separator();
|
||||
if (ImGui::Checkbox("Separate Bag Windows", &pendingSeparateBags)) {
|
||||
inventoryScreen.setSeparateBags(pendingSeparateBags);
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
|
@ -4991,6 +5007,8 @@ void GameScreen::renderSettingsWindow() {
|
|||
pendingUiOpacity = 65;
|
||||
pendingMinimapRotate = false;
|
||||
pendingMinimapSquare = false;
|
||||
pendingSeparateBags = true;
|
||||
inventoryScreen.setSeparateBags(true);
|
||||
uiOpacity_ = 0.65f;
|
||||
minimapRotate_ = false;
|
||||
minimapSquare_ = false;
|
||||
|
|
@ -5438,6 +5456,7 @@ void GameScreen::saveSettings() {
|
|||
out << "ui_opacity=" << pendingUiOpacity << "\n";
|
||||
out << "minimap_rotate=" << (pendingMinimapRotate ? 1 : 0) << "\n";
|
||||
out << "minimap_square=" << (pendingMinimapSquare ? 1 : 0) << "\n";
|
||||
out << "separate_bags=" << (pendingSeparateBags ? 1 : 0) << "\n";
|
||||
|
||||
// Audio
|
||||
out << "master_volume=" << pendingMasterVolume << "\n";
|
||||
|
|
@ -5487,6 +5506,9 @@ void GameScreen::loadSettings() {
|
|||
int v = std::stoi(val);
|
||||
minimapSquare_ = (v != 0);
|
||||
pendingMinimapSquare = minimapSquare_;
|
||||
} else if (key == "separate_bags") {
|
||||
pendingSeparateBags = (std::stoi(val) != 0);
|
||||
inventoryScreen.setSeparateBags(pendingSeparateBags);
|
||||
}
|
||||
// Audio
|
||||
else if (key == "master_volume") pendingMasterVolume = std::clamp(std::stoi(val), 0, 100);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
#include "core/logger.hpp"
|
||||
#include <imgui.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace wowee {
|
||||
|
|
@ -529,13 +531,30 @@ void InventoryScreen::renderHeldItem() {
|
|||
// Bags window (B key) — bottom of screen, no equipment panel
|
||||
// ============================================================
|
||||
|
||||
void InventoryScreen::toggleBackpack() {
|
||||
backpackOpen_ = !backpackOpen_;
|
||||
}
|
||||
|
||||
void InventoryScreen::toggleBag(int idx) {
|
||||
if (idx >= 0 && idx < 4)
|
||||
bagOpen_[idx] = !bagOpen_[idx];
|
||||
}
|
||||
|
||||
void InventoryScreen::openAllBags() {
|
||||
backpackOpen_ = true;
|
||||
for (auto& b : bagOpen_) b = true;
|
||||
}
|
||||
|
||||
void InventoryScreen::closeAllBags() {
|
||||
backpackOpen_ = false;
|
||||
for (auto& b : bagOpen_) b = false;
|
||||
}
|
||||
|
||||
void InventoryScreen::render(game::Inventory& inventory, uint64_t moneyCopper) {
|
||||
// B key toggle (edge-triggered)
|
||||
bool uiWantsKeyboard = ImGui::GetIO().WantCaptureKeyboard;
|
||||
bool bDown = !uiWantsKeyboard && core::Input::getInstance().isKeyPressed(SDL_SCANCODE_B);
|
||||
if (bDown && !bKeyWasDown) {
|
||||
open = !open;
|
||||
}
|
||||
bool bToggled = bDown && !bKeyWasDown;
|
||||
bKeyWasDown = bDown;
|
||||
|
||||
// C key toggle for character screen (edge-triggered)
|
||||
|
|
@ -545,6 +564,18 @@ void InventoryScreen::render(game::Inventory& inventory, uint64_t moneyCopper) {
|
|||
}
|
||||
cKeyWasDown = cDown;
|
||||
|
||||
if (separateBags_) {
|
||||
if (bToggled) {
|
||||
bool anyOpen = backpackOpen_;
|
||||
for (auto b : bagOpen_) anyOpen |= b;
|
||||
if (anyOpen) closeAllBags();
|
||||
else openAllBags();
|
||||
}
|
||||
open = backpackOpen_ || std::any_of(bagOpen_.begin(), bagOpen_.end(), [](bool b){ return b; });
|
||||
} else {
|
||||
if (bToggled) open = !open;
|
||||
}
|
||||
|
||||
if (!open) {
|
||||
if (holdingItem) cancelPickup(inventory);
|
||||
return;
|
||||
|
|
@ -560,53 +591,12 @@ void InventoryScreen::render(game::Inventory& inventory, uint64_t moneyCopper) {
|
|||
cancelPickup(inventory);
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
float screenW = io.DisplaySize.x;
|
||||
float screenH = io.DisplaySize.y;
|
||||
|
||||
// Calculate bag window size
|
||||
constexpr float slotSize = 40.0f;
|
||||
constexpr int columns = 4;
|
||||
int rows = (inventory.getBackpackSize() + columns - 1) / columns;
|
||||
float bagContentH = rows * (slotSize + 4.0f) + 40.0f; // slots + header + money
|
||||
|
||||
// Check for extra bags and add space
|
||||
for (int bag = 0; bag < game::Inventory::NUM_BAG_SLOTS; bag++) {
|
||||
int bagSize = inventory.getBagSize(bag);
|
||||
if (bagSize <= 0) continue;
|
||||
int bagRows = (bagSize + columns - 1) / columns;
|
||||
bagContentH += bagRows * (slotSize + 4.0f) + 30.0f; // slots + header
|
||||
if (separateBags_) {
|
||||
renderSeparateBags(inventory, moneyCopper);
|
||||
} else {
|
||||
renderAggregateBags(inventory, moneyCopper);
|
||||
}
|
||||
|
||||
float windowW = columns * (slotSize + 4.0f) + 30.0f;
|
||||
float windowH = bagContentH + 50.0f; // padding
|
||||
|
||||
// Position at bottom-right of screen
|
||||
float posX = screenW - windowW - 10.0f;
|
||||
float posY = screenH - windowH - 60.0f; // above action bar area
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(posX, posY), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(windowW, windowH), ImGuiCond_Always);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
|
||||
if (!ImGui::Begin("Bags", &open, flags)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
renderBackpackPanel(inventory);
|
||||
|
||||
// Money display
|
||||
ImGui::Spacing();
|
||||
uint64_t gold = moneyCopper / 10000;
|
||||
uint64_t silver = (moneyCopper / 100) % 100;
|
||||
uint64_t copper = moneyCopper % 100;
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.84f, 0.0f, 1.0f), "%llug %llus %lluc",
|
||||
static_cast<unsigned long long>(gold),
|
||||
static_cast<unsigned long long>(silver),
|
||||
static_cast<unsigned long long>(copper));
|
||||
ImGui::End();
|
||||
|
||||
// Detect held item dropped outside inventory windows → drop confirmation
|
||||
if (holdingItem && heldItem.itemId != 6948 && ImGui::IsMouseReleased(ImGuiMouseButton_Left) &&
|
||||
!ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) &&
|
||||
|
|
@ -646,6 +636,175 @@ void InventoryScreen::render(game::Inventory& inventory, uint64_t moneyCopper) {
|
|||
renderHeldItem();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Aggregate mode — original single-window bags
|
||||
// ============================================================
|
||||
|
||||
void InventoryScreen::renderAggregateBags(game::Inventory& inventory, uint64_t moneyCopper) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
float screenW = io.DisplaySize.x;
|
||||
float screenH = io.DisplaySize.y;
|
||||
|
||||
constexpr float slotSize = 40.0f;
|
||||
constexpr int columns = 4;
|
||||
int rows = (inventory.getBackpackSize() + columns - 1) / columns;
|
||||
float bagContentH = rows * (slotSize + 4.0f) + 40.0f;
|
||||
|
||||
for (int bag = 0; bag < game::Inventory::NUM_BAG_SLOTS; bag++) {
|
||||
int bagSize = inventory.getBagSize(bag);
|
||||
if (bagSize <= 0) continue;
|
||||
int bagRows = (bagSize + columns - 1) / columns;
|
||||
bagContentH += bagRows * (slotSize + 4.0f) + 30.0f;
|
||||
}
|
||||
|
||||
float windowW = columns * (slotSize + 4.0f) + 30.0f;
|
||||
float windowH = bagContentH + 50.0f;
|
||||
|
||||
float posX = screenW - windowW - 10.0f;
|
||||
float posY = screenH - windowH - 60.0f;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(posX, posY), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(windowW, windowH), ImGuiCond_Always);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
|
||||
if (!ImGui::Begin("Bags", &open, flags)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
renderBackpackPanel(inventory);
|
||||
|
||||
ImGui::Spacing();
|
||||
uint64_t gold = moneyCopper / 10000;
|
||||
uint64_t silver = (moneyCopper / 100) % 100;
|
||||
uint64_t copper = moneyCopper % 100;
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.84f, 0.0f, 1.0f), "%llug %llus %lluc",
|
||||
static_cast<unsigned long long>(gold),
|
||||
static_cast<unsigned long long>(silver),
|
||||
static_cast<unsigned long long>(copper));
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Separate mode — individual draggable bag windows
|
||||
// ============================================================
|
||||
|
||||
void InventoryScreen::renderSeparateBags(game::Inventory& inventory, uint64_t moneyCopper) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
float screenW = io.DisplaySize.x;
|
||||
float screenH = io.DisplaySize.y;
|
||||
|
||||
constexpr float slotSize = 40.0f;
|
||||
constexpr int columns = 4;
|
||||
constexpr float baseWindowW = columns * (slotSize + 4.0f) + 30.0f;
|
||||
|
||||
// Backpack window (rightmost, bottom-right)
|
||||
if (backpackOpen_) {
|
||||
int bpRows = (inventory.getBackpackSize() + columns - 1) / columns;
|
||||
float bpH = bpRows * (slotSize + 4.0f) + 80.0f; // header + money + padding
|
||||
float defaultX = screenW - baseWindowW - 10.0f;
|
||||
float defaultY = screenH - bpH - 60.0f;
|
||||
renderBagWindow("Backpack", backpackOpen_, inventory, -1, defaultX, defaultY, moneyCopper);
|
||||
}
|
||||
|
||||
// Extra bag windows (stacked to the left of backpack)
|
||||
for (int bag = 0; bag < game::Inventory::NUM_BAG_SLOTS; bag++) {
|
||||
if (!bagOpen_[bag]) continue;
|
||||
int bagSize = inventory.getBagSize(bag);
|
||||
if (bagSize <= 0) {
|
||||
bagOpen_[bag] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
int bagRows = (bagSize + columns - 1) / columns;
|
||||
float bagH = bagRows * (slotSize + 4.0f) + 60.0f;
|
||||
float defaultX = screenW - (baseWindowW + 10.0f) * (bag + 2) - 10.0f;
|
||||
float defaultY = screenH - bagH - 60.0f;
|
||||
|
||||
// Build title from equipped bag item name
|
||||
char title[64];
|
||||
game::EquipSlot bagSlot = static_cast<game::EquipSlot>(static_cast<int>(game::EquipSlot::BAG1) + bag);
|
||||
const auto& bagItem = inventory.getEquipSlot(bagSlot);
|
||||
if (!bagItem.empty() && !bagItem.item.name.empty()) {
|
||||
snprintf(title, sizeof(title), "%s##bag%d", bagItem.item.name.c_str(), bag);
|
||||
} else {
|
||||
snprintf(title, sizeof(title), "Bag %d##bag%d", bag + 1, bag);
|
||||
}
|
||||
|
||||
renderBagWindow(title, bagOpen_[bag], inventory, bag, defaultX, defaultY, 0);
|
||||
}
|
||||
|
||||
// Update open state based on individual windows
|
||||
open = backpackOpen_ || std::any_of(bagOpen_.begin(), bagOpen_.end(), [](bool b){ return b; });
|
||||
}
|
||||
|
||||
void InventoryScreen::renderBagWindow(const char* title, bool& isOpen,
|
||||
game::Inventory& inventory, int bagIndex,
|
||||
float defaultX, float defaultY, uint64_t moneyCopper) {
|
||||
constexpr float slotSize = 40.0f;
|
||||
constexpr int columns = 4;
|
||||
|
||||
int numSlots = (bagIndex < 0) ? inventory.getBackpackSize() : inventory.getBagSize(bagIndex);
|
||||
if (numSlots <= 0) return;
|
||||
|
||||
int rows = (numSlots + columns - 1) / columns;
|
||||
float contentH = rows * (slotSize + 4.0f) + 10.0f;
|
||||
if (bagIndex < 0) contentH += 25.0f; // money display for backpack
|
||||
float gridW = columns * (slotSize + 4.0f) + 30.0f;
|
||||
// Ensure window is wide enough for the title + close button
|
||||
const char* displayTitle = title;
|
||||
const char* hashPos = strstr(title, "##");
|
||||
float titleW = ImGui::CalcTextSize(displayTitle, hashPos).x + 50.0f; // close button + padding
|
||||
float windowW = std::max(gridW, titleW);
|
||||
float windowH = contentH + 40.0f; // title bar + padding
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(defaultX, defaultY), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(windowW, windowH), ImGuiCond_Always);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize;
|
||||
if (!ImGui::Begin(title, &isOpen, flags)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// Render item slots in 4-column grid
|
||||
for (int i = 0; i < numSlots; i++) {
|
||||
if (i % columns != 0) ImGui::SameLine();
|
||||
|
||||
const game::ItemSlot& slot = (bagIndex < 0)
|
||||
? inventory.getBackpackSlot(i)
|
||||
: inventory.getBagSlot(bagIndex, i);
|
||||
|
||||
char id[32];
|
||||
if (bagIndex < 0) {
|
||||
snprintf(id, sizeof(id), "##sbp_%d", i);
|
||||
} else {
|
||||
snprintf(id, sizeof(id), "##sb%d_%d", bagIndex, i);
|
||||
}
|
||||
ImGui::PushID(id);
|
||||
|
||||
// For backpack slots, pass actual backpack index for drag/drop
|
||||
int bpIdx = (bagIndex < 0) ? i : -1;
|
||||
renderItemSlot(inventory, slot, slotSize, nullptr,
|
||||
SlotKind::BACKPACK, bpIdx, game::EquipSlot::NUM_SLOTS);
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Money display at bottom of backpack
|
||||
if (bagIndex < 0 && moneyCopper > 0) {
|
||||
ImGui::Spacing();
|
||||
uint64_t gold = moneyCopper / 10000;
|
||||
uint64_t silver = (moneyCopper / 100) % 100;
|
||||
uint64_t copper = moneyCopper % 100;
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.84f, 0.0f, 1.0f), "%llug %llus %lluc",
|
||||
static_cast<unsigned long long>(gold),
|
||||
static_cast<unsigned long long>(silver),
|
||||
static_cast<unsigned long long>(copper));
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Character screen (C key) — equipment + model preview + stats
|
||||
// ============================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue