Fix hair/vendor/loot bugs, revamp spellbook with tabs and icons, clean up action bar, add talent placeholder

- Fix white hair: always override M2 type-6 texture with DBC hair texture when available
- Fix vendor sell: add sellPrice to ItemDef/ItemTemplateRow, use directly instead of empty cache
- Fix empty loot: skip loot window when corpse has no items and no gold
- Revamp spellbook (P key): tabbed UI (General/Active/Passive), spell icons from SpellIcon.dbc, rank text
- Clean up action bar: only auto-populate Attack and Hearthstone, rest assigned via spellbook
- Add talent placeholder (N key): 3-tab window with level/talent point display
- Fix ffplay cleanup: non-blocking waitpid with SIGKILL fallback to prevent orphaned audio processes
- Fix pre-existing getQualityColor visibility for loot window rendering
This commit is contained in:
Kelsi 2026-02-06 16:04:25 -08:00
parent 2ddef93f52
commit caeb6f56f7
12 changed files with 426 additions and 119 deletions

View file

@ -7,6 +7,7 @@
#include "ui/inventory_screen.hpp"
#include "ui/quest_log_screen.hpp"
#include "ui/spellbook_screen.hpp"
#include "ui/talent_screen.hpp"
#include <GL/glew.h>
#include <imgui.h>
#include <string>
@ -150,6 +151,7 @@ private:
InventoryScreen inventoryScreen;
QuestLogScreen questLogScreen;
SpellbookScreen spellbookScreen;
TalentScreen talentScreen;
rendering::WorldMap worldMap;
bool actionSpellDbAttempted = false;

View file

@ -126,6 +126,7 @@ private:
game::EquipSlot getEquipSlotForType(uint8_t inventoryType, game::Inventory& inv);
void renderHeldItem();
public:
static ImVec4 getQualityColor(game::ItemQuality quality);
};

View file

@ -1,8 +1,10 @@
#pragma once
#include "game/game_handler.hpp"
#include <GL/glew.h>
#include <imgui.h>
#include <string>
#include <vector>
#include <unordered_map>
namespace wowee {
@ -11,6 +13,17 @@ namespace pipeline { class AssetManager; }
namespace ui {
struct SpellInfo {
uint32_t spellId = 0;
std::string name;
std::string rank;
uint32_t iconId = 0; // SpellIconID
uint32_t attributes = 0; // Spell attributes (field 75)
bool isPassive() const { return (attributes & 0x40) != 0; }
};
enum class SpellTab { GENERAL, ACTIVE, PASSIVE };
class SpellbookScreen {
public:
void render(game::GameHandler& gameHandler, pipeline::AssetManager* assetManager);
@ -22,16 +35,33 @@ private:
bool open = false;
bool pKeyWasDown = false;
// Spell name cache (loaded from Spell.dbc)
// Spell data (loaded from Spell.dbc)
bool dbcLoaded = false;
bool dbcLoadAttempted = false;
std::unordered_map<uint32_t, std::string> spellNames;
std::unordered_map<uint32_t, SpellInfo> spellData;
// Icon data (loaded from SpellIcon.dbc)
bool iconDbLoaded = false;
std::unordered_map<uint32_t, std::string> spellIconPaths; // SpellIconID -> path
std::unordered_map<uint32_t, GLuint> spellIconCache; // SpellIconID -> GL texture
// Categorized spell lists (rebuilt when spell list changes)
std::vector<const SpellInfo*> generalSpells;
std::vector<const SpellInfo*> activeSpells;
std::vector<const SpellInfo*> passiveSpells;
size_t lastKnownSpellCount = 0;
// Tab state
SpellTab currentTab = SpellTab::GENERAL;
// Action bar assignment
int assigningSlot = -1; // Which action bar slot is being assigned (-1 = none)
int assigningSlot = -1;
void loadSpellDBC(pipeline::AssetManager* assetManager);
std::string getSpellName(uint32_t spellId) const;
void loadSpellIconDBC(pipeline::AssetManager* assetManager);
void categorizeSpells(const std::vector<uint32_t>& knownSpells);
GLuint getSpellIcon(uint32_t iconId, pipeline::AssetManager* assetManager);
const SpellInfo* getSpellInfo(uint32_t spellId) const;
};
} // namespace ui

View file

@ -0,0 +1,22 @@
#pragma once
#include "game/game_handler.hpp"
#include <imgui.h>
namespace wowee {
namespace ui {
class TalentScreen {
public:
void render(game::GameHandler& gameHandler);
bool isOpen() const { return open; }
void toggle() { open = !open; }
void setOpen(bool o) { open = o; }
private:
bool open = false;
bool nKeyWasDown = false;
};
} // namespace ui
} // namespace wowee