mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-28 09:33:52 +00:00
Emulate server loot/xp and combat feedback in single-player
This commit is contained in:
parent
1383e6c159
commit
3ca8944ced
17 changed files with 830 additions and 29 deletions
|
|
@ -29,6 +29,7 @@ public:
|
|||
void setCharacterVoiceProfile(const std::string& modelName);
|
||||
void playWaterEnter();
|
||||
void playWaterExit();
|
||||
void playMeleeSwing();
|
||||
|
||||
private:
|
||||
struct Sample {
|
||||
|
|
@ -48,6 +49,7 @@ private:
|
|||
std::vector<Sample> splashExitClips;
|
||||
std::vector<Sample> swimLoopClips;
|
||||
std::vector<Sample> hardLandClips;
|
||||
std::vector<Sample> meleeSwingClips;
|
||||
std::array<SurfaceLandingSet, 7> landingSets;
|
||||
|
||||
bool swimmingActive = false;
|
||||
|
|
@ -61,6 +63,8 @@ private:
|
|||
std::chrono::steady_clock::time_point lastJumpAt{};
|
||||
std::chrono::steady_clock::time_point lastLandAt{};
|
||||
std::chrono::steady_clock::time_point lastSplashAt{};
|
||||
std::chrono::steady_clock::time_point lastMeleeSwingAt{};
|
||||
bool meleeSwingWarned = false;
|
||||
std::string voiceProfileKey;
|
||||
|
||||
void preloadCandidates(std::vector<Sample>& out, const std::vector<std::string>& candidates);
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ public:
|
|||
*/
|
||||
void addLocalChatMessage(const MessageChatData& msg);
|
||||
|
||||
// Money (copper)
|
||||
uint64_t getMoneyCopper() const { return playerMoneyCopper_; }
|
||||
|
||||
// Inventory
|
||||
Inventory& getInventory() { return inventory; }
|
||||
const Inventory& getInventory() const { return inventory; }
|
||||
|
|
@ -212,6 +215,10 @@ public:
|
|||
using NpcDeathCallback = std::function<void(uint64_t guid)>;
|
||||
void setNpcDeathCallback(NpcDeathCallback cb) { npcDeathCallback_ = std::move(cb); }
|
||||
|
||||
// Melee swing callback (for driving animation/SFX)
|
||||
using MeleeSwingCallback = std::function<void()>;
|
||||
void setMeleeSwingCallback(MeleeSwingCallback cb) { meleeSwingCallback_ = std::move(cb); }
|
||||
|
||||
// Local player stats (single-player)
|
||||
uint32_t getLocalPlayerHealth() const { return localPlayerHealth_; }
|
||||
uint32_t getLocalPlayerMaxHealth() const { return localPlayerMaxHealth_; }
|
||||
|
|
@ -378,6 +385,12 @@ private:
|
|||
void handleGossipMessage(network::Packet& packet);
|
||||
void handleGossipComplete(network::Packet& packet);
|
||||
void handleListInventory(network::Packet& packet);
|
||||
LootResponseData generateLocalLoot(uint64_t guid);
|
||||
void simulateLootResponse(const LootResponseData& data);
|
||||
void simulateLootRelease();
|
||||
void simulateLootRemove(uint8_t slotIndex);
|
||||
void simulateXpGain(uint64_t victimGuid, uint32_t totalXp);
|
||||
void addMoneyCopper(uint32_t amount);
|
||||
|
||||
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource);
|
||||
void addSystemChatMessage(const std::string& message);
|
||||
|
|
@ -484,6 +497,12 @@ private:
|
|||
// ---- Phase 5: Loot ----
|
||||
bool lootWindowOpen = false;
|
||||
LootResponseData currentLoot;
|
||||
struct LocalLootState {
|
||||
LootResponseData data;
|
||||
bool moneyTaken = false;
|
||||
};
|
||||
std::unordered_map<uint64_t, LocalLootState> localLootState_;
|
||||
uint64_t playerMoneyCopper_ = 0;
|
||||
|
||||
// Gossip
|
||||
bool gossipWindowOpen = false;
|
||||
|
|
@ -501,7 +520,7 @@ private:
|
|||
uint32_t playerXp_ = 0;
|
||||
uint32_t playerNextLevelXp_ = 0;
|
||||
uint32_t serverPlayerLevel_ = 1;
|
||||
void awardLocalXp(uint32_t victimLevel);
|
||||
void awardLocalXp(uint64_t victimGuid, uint32_t victimLevel);
|
||||
void levelUp();
|
||||
static uint32_t xpForLevel(uint32_t level);
|
||||
static uint32_t killXp(uint32_t playerLevel, uint32_t victimLevel);
|
||||
|
|
@ -511,6 +530,7 @@ private:
|
|||
float swingTimer_ = 0.0f;
|
||||
static constexpr float SWING_SPEED = 2.0f;
|
||||
NpcDeathCallback npcDeathCallback_;
|
||||
MeleeSwingCallback meleeSwingCallback_;
|
||||
uint32_t localPlayerHealth_ = 0;
|
||||
uint32_t localPlayerMaxHealth_ = 0;
|
||||
uint32_t localPlayerLevel_ = 1;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class EntityManager;
|
|||
|
||||
struct NpcSpawnDef {
|
||||
std::string mapName;
|
||||
uint32_t entry = 0;
|
||||
std::string name;
|
||||
std::string m2Path;
|
||||
uint32_t level;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public:
|
|||
void writeUInt16(uint16_t value);
|
||||
void writeUInt32(uint32_t value);
|
||||
void writeUInt64(uint64_t value);
|
||||
void writeFloat(float value);
|
||||
void writeString(const std::string& value);
|
||||
void writeBytes(const uint8_t* data, size_t length);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public:
|
|||
void removeInstance(uint32_t instanceId);
|
||||
bool getAnimationState(uint32_t instanceId, uint32_t& animationId, float& animationTimeMs, float& animationDurationMs) const;
|
||||
bool hasAnimation(uint32_t instanceId, uint32_t animationId) const;
|
||||
bool getAnimationSequences(uint32_t instanceId, std::vector<pipeline::M2Sequence>& out) const;
|
||||
bool getInstanceModelName(uint32_t instanceId, std::string& modelName) const;
|
||||
|
||||
/** Attach a weapon model to a character instance at the given attachment point. */
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ public:
|
|||
// Targeting support
|
||||
void setTargetPosition(const glm::vec3* pos);
|
||||
bool isMoving() const;
|
||||
void triggerMeleeSwing();
|
||||
|
||||
// CPU timing stats (milliseconds, last frame).
|
||||
double getLastUpdateMs() const { return lastUpdateMs; }
|
||||
|
|
@ -198,12 +199,13 @@ private:
|
|||
float characterYaw = 0.0f;
|
||||
|
||||
// Character animation state
|
||||
enum class CharAnimState { IDLE, WALK, RUN, JUMP_START, JUMP_MID, JUMP_END, SIT_DOWN, SITTING, EMOTE, SWIM_IDLE, SWIM };
|
||||
enum class CharAnimState { IDLE, WALK, RUN, JUMP_START, JUMP_MID, JUMP_END, SIT_DOWN, SITTING, EMOTE, SWIM_IDLE, SWIM, MELEE_SWING };
|
||||
CharAnimState charAnimState = CharAnimState::IDLE;
|
||||
void updateCharacterAnimation();
|
||||
bool isFootstepAnimationState() const;
|
||||
bool shouldTriggerFootstepEvent(uint32_t animationId, float animationTimeMs, float animationDurationMs);
|
||||
audio::FootstepSurface resolveFootstepSurface() const;
|
||||
uint32_t resolveMeleeAnimId();
|
||||
|
||||
// Emote state
|
||||
bool emoteActive = false;
|
||||
|
|
@ -223,6 +225,11 @@ private:
|
|||
bool sfxPrevFalling = false;
|
||||
bool sfxPrevSwimming = false;
|
||||
|
||||
float meleeSwingTimer = 0.0f;
|
||||
float meleeSwingCooldown = 0.0f;
|
||||
float meleeAnimDurationMs = 0.0f;
|
||||
uint32_t meleeAnimId = 0;
|
||||
|
||||
bool terrainEnabled = true;
|
||||
bool terrainLoaded = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace ui {
|
|||
|
||||
class InventoryScreen {
|
||||
public:
|
||||
void render(game::Inventory& inventory);
|
||||
void render(game::Inventory& inventory, uint64_t moneyCopper);
|
||||
bool isOpen() const { return open; }
|
||||
void toggle() { open = !open; }
|
||||
void setOpen(bool o) { open = o; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue