mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-24 16:10:14 +00:00
Add character screen model preview, item icons, stats panel, and fix targeting bugs
Enhanced the C-key character screen with a 3-column layout featuring a 3D character model preview (with drag-to-rotate), item icons loaded from BLP textures via ItemDisplayInfo.dbc, and a stats panel showing base + equipment bonuses. Fixed selection circle clipping under terrain by adding a Z offset, and corrected faction hostility logic that was wrongly marking hostile mobs as friendly.
This commit is contained in:
parent
7128ea1417
commit
394e91cd9e
12 changed files with 738 additions and 53 deletions
|
|
@ -72,8 +72,39 @@ public:
|
|||
y = py;
|
||||
z = pz;
|
||||
orientation = o;
|
||||
isMoving_ = false; // Instant position set cancels interpolation
|
||||
}
|
||||
|
||||
// Movement interpolation (syncs entity position with renderer during movement)
|
||||
void startMoveTo(float destX, float destY, float destZ, float destO, float durationSec) {
|
||||
if (durationSec <= 0.0f) {
|
||||
setPosition(destX, destY, destZ, destO);
|
||||
return;
|
||||
}
|
||||
moveStartX_ = x; moveStartY_ = y; moveStartZ_ = z;
|
||||
moveEndX_ = destX; moveEndY_ = destY; moveEndZ_ = destZ;
|
||||
moveDuration_ = durationSec;
|
||||
moveElapsed_ = 0.0f;
|
||||
orientation = destO;
|
||||
isMoving_ = true;
|
||||
}
|
||||
|
||||
void updateMovement(float deltaTime) {
|
||||
if (!isMoving_) return;
|
||||
moveElapsed_ += deltaTime;
|
||||
float t = moveElapsed_ / moveDuration_;
|
||||
if (t >= 1.0f) {
|
||||
x = moveEndX_; y = moveEndY_; z = moveEndZ_;
|
||||
isMoving_ = false;
|
||||
} else {
|
||||
x = moveStartX_ + (moveEndX_ - moveStartX_) * t;
|
||||
y = moveStartY_ + (moveEndY_ - moveStartY_) * t;
|
||||
z = moveStartZ_ + (moveEndZ_ - moveStartZ_) * t;
|
||||
}
|
||||
}
|
||||
|
||||
bool isEntityMoving() const { return isMoving_; }
|
||||
|
||||
// Object type
|
||||
ObjectType getType() const { return type; }
|
||||
void setType(ObjectType t) { type = t; }
|
||||
|
|
@ -108,6 +139,13 @@ protected:
|
|||
|
||||
// Update fields (dynamic values)
|
||||
std::map<uint16_t, uint32_t> fields;
|
||||
|
||||
// Movement interpolation state
|
||||
bool isMoving_ = false;
|
||||
float moveStartX_ = 0, moveStartY_ = 0, moveStartZ_ = 0;
|
||||
float moveEndX_ = 0, moveEndY_ = 0, moveEndZ_ = 0;
|
||||
float moveDuration_ = 0;
|
||||
float moveElapsed_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -162,6 +200,12 @@ public:
|
|||
// Returns true if NPC has interaction flags (gossip/vendor/quest/trainer)
|
||||
bool isInteractable() const { return npcFlags != 0; }
|
||||
|
||||
// Faction-based hostility
|
||||
uint32_t getFactionTemplate() const { return factionTemplate; }
|
||||
void setFactionTemplate(uint32_t f) { factionTemplate = f; }
|
||||
bool isHostile() const { return hostile; }
|
||||
void setHostile(bool h) { hostile = h; }
|
||||
|
||||
protected:
|
||||
std::string name;
|
||||
uint32_t health = 0;
|
||||
|
|
@ -174,6 +218,8 @@ protected:
|
|||
uint32_t displayId = 0;
|
||||
uint32_t unitFlags = 0;
|
||||
uint32_t npcFlags = 0;
|
||||
uint32_t factionTemplate = 0;
|
||||
bool hostile = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -294,6 +294,9 @@ public:
|
|||
using CreatureDespawnCallback = std::function<void(uint64_t guid)>;
|
||||
void setCreatureDespawnCallback(CreatureDespawnCallback cb) { creatureDespawnCallback_ = std::move(cb); }
|
||||
|
||||
// Faction hostility map (populated from FactionTemplate.dbc by Application)
|
||||
void setFactionHostileMap(std::unordered_map<uint32_t, bool> map) { factionHostileMap_ = std::move(map); }
|
||||
|
||||
// Creature move callback (online mode - triggered by SMSG_MONSTER_MOVE)
|
||||
// Parameters: guid, x, y, z (canonical), duration_ms (0 = instant)
|
||||
using CreatureMoveCallback = std::function<void(uint64_t guid, float x, float y, float z, uint32_t durationMs)>;
|
||||
|
|
@ -644,6 +647,13 @@ private:
|
|||
// Quest log
|
||||
std::vector<QuestLogEntry> questLog_;
|
||||
|
||||
// Faction hostility lookup (populated from FactionTemplate.dbc)
|
||||
std::unordered_map<uint32_t, bool> factionHostileMap_;
|
||||
bool isHostileFaction(uint32_t factionTemplateId) const {
|
||||
auto it = factionHostileMap_.find(factionTemplateId);
|
||||
return it != factionHostileMap_.end() ? it->second : true; // default hostile if unknown
|
||||
}
|
||||
|
||||
// Vendor
|
||||
bool vendorWindowOpen = false;
|
||||
ListInventoryData currentVendorItems;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ struct NpcSpawnDef {
|
|||
float rotation; // radians around Z
|
||||
float scale;
|
||||
bool isCritter; // critters don't do humanoid emotes
|
||||
uint32_t faction = 0; // faction template ID from creature_template
|
||||
uint32_t npcFlags = 0; // NPC interaction flags from creature_template
|
||||
};
|
||||
|
||||
struct NpcInstance {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ public:
|
|||
int getWidth() const { return fboWidth_; }
|
||||
int getHeight() const { return fboHeight_; }
|
||||
|
||||
CharacterRenderer* getCharacterRenderer() { return charRenderer_.get(); }
|
||||
uint32_t getInstanceId() const { return instanceId_; }
|
||||
uint32_t getModelId() const { return PREVIEW_MODEL_ID; }
|
||||
bool isModelLoaded() const { return modelLoaded_; }
|
||||
|
||||
private:
|
||||
void createFBO();
|
||||
void destroyFBO();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "game/game_handler.hpp"
|
||||
#include "game/inventory.hpp"
|
||||
#include "rendering/world_map.hpp"
|
||||
#include "rendering/character_preview.hpp"
|
||||
#include "ui/inventory_screen.hpp"
|
||||
#include "ui/quest_log_screen.hpp"
|
||||
#include "ui/spellbook_screen.hpp"
|
||||
|
|
|
|||
|
|
@ -1,21 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/inventory.hpp"
|
||||
#include "game/character.hpp"
|
||||
#include "game/world_packets.hpp"
|
||||
#include <GL/glew.h>
|
||||
#include <imgui.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace rendering { class CharacterPreview; class CharacterRenderer; }
|
||||
namespace game { class GameHandler; }
|
||||
namespace ui {
|
||||
|
||||
class InventoryScreen {
|
||||
public:
|
||||
~InventoryScreen();
|
||||
|
||||
/// Render bags window (B key). Positioned at bottom of screen.
|
||||
void render(game::Inventory& inventory, uint64_t moneyCopper);
|
||||
|
||||
/// Render character screen (C key). Standalone equipment window.
|
||||
void renderCharacterScreen(game::Inventory& inventory);
|
||||
void renderCharacterScreen(game::GameHandler& gameHandler);
|
||||
|
||||
bool isOpen() const { return open; }
|
||||
void toggle() { open = !open; }
|
||||
|
|
@ -31,6 +39,21 @@ public:
|
|||
gameHandler_ = handler;
|
||||
}
|
||||
|
||||
/// Set asset manager for icon/model loading
|
||||
void setAssetManager(pipeline::AssetManager* am) { assetManager_ = am; }
|
||||
|
||||
/// Store player appearance for character preview
|
||||
void setPlayerAppearance(game::Race race, game::Gender gender,
|
||||
uint8_t skin, uint8_t face,
|
||||
uint8_t hairStyle, uint8_t hairColor,
|
||||
uint8_t facialHair);
|
||||
|
||||
/// Mark the character preview as needing equipment update
|
||||
void markPreviewDirty() { previewDirty_ = true; }
|
||||
|
||||
/// Update the preview animation (call each frame)
|
||||
void updatePreview(float deltaTime);
|
||||
|
||||
/// Returns true if equipment changed since last call, and clears the flag.
|
||||
bool consumeEquipmentDirty() { bool d = equipmentDirty; equipmentDirty = false; return d; }
|
||||
/// Returns true if any inventory slot changed since last call, and clears the flag.
|
||||
|
|
@ -48,6 +71,30 @@ private:
|
|||
bool vendorMode_ = false;
|
||||
game::GameHandler* gameHandler_ = nullptr;
|
||||
|
||||
// Asset manager for icons and preview
|
||||
pipeline::AssetManager* assetManager_ = nullptr;
|
||||
|
||||
// Item icon cache: displayInfoId -> GL texture
|
||||
std::unordered_map<uint32_t, GLuint> iconCache_;
|
||||
GLuint getItemIcon(uint32_t displayInfoId);
|
||||
|
||||
// Character model preview
|
||||
std::unique_ptr<rendering::CharacterPreview> charPreview_;
|
||||
bool previewInitialized_ = false;
|
||||
bool previewDirty_ = false;
|
||||
|
||||
// Stored player appearance for preview
|
||||
game::Race playerRace_ = game::Race::HUMAN;
|
||||
game::Gender playerGender_ = game::Gender::MALE;
|
||||
uint8_t playerSkin_ = 0;
|
||||
uint8_t playerFace_ = 0;
|
||||
uint8_t playerHairStyle_ = 0;
|
||||
uint8_t playerHairColor_ = 0;
|
||||
uint8_t playerFacialHair_ = 0;
|
||||
|
||||
void initPreview();
|
||||
void updatePreviewEquipment(game::Inventory& inventory);
|
||||
|
||||
// Drag-and-drop held item state
|
||||
bool holdingItem = false;
|
||||
game::ItemDef heldItem;
|
||||
|
|
@ -58,6 +105,7 @@ private:
|
|||
|
||||
void renderEquipmentPanel(game::Inventory& inventory);
|
||||
void renderBackpackPanel(game::Inventory& inventory);
|
||||
void renderStatsPanel(game::Inventory& inventory, uint32_t playerLevel);
|
||||
|
||||
// Slot rendering with interaction support
|
||||
enum class SlotKind { BACKPACK, EQUIPMENT };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue