mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 09:33:51 +00:00
feat(animation): 452 named constants, 30-phase character animation state machine
Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND, anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1) lookup, and flyVariant() compact 218-element ground→FLY_* resolver. Expand AnimationController into a full state machine with 20+ named states: spell cast (directed→omni→cast fallback chain, instant one-shot release), hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle, stealth animation substitution, loot, fishing channel, sit/sleep/kneel down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons (BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY, vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS), emote state variants, off-hand/pierce/dual-wield alternation, NPC birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell. Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo (12 constants) namespaces; replace all magic numbers in spell_handler.cpp. Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire GameObjectStateCallback. Add DBC cross-validation on world entry. Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and asset_pipeline_gui.py. Add tests/test_animation_ids.cpp. Bug fixes included: - Stand state 1 was animating READY_2H(27) — fixed to SITTING(97) - Spell casts ended freeze-frame — add one-shot release animation - NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff) - Chair sits (states 2/4/5/6) incorrectly played floor-sit transition - STOP(3) used for all spell casts — replaced with model-aware chain
This commit is contained in:
parent
d54e262048
commit
e58f9b4b40
59 changed files with 3903 additions and 483 deletions
|
|
@ -261,6 +261,10 @@ public:
|
|||
uint32_t getNpcFlags() const { return npcFlags; }
|
||||
void setNpcFlags(uint32_t f) { npcFlags = f; }
|
||||
|
||||
// NPC emote state (UNIT_NPC_EMOTESTATE) — persistent looping animation for NPCs
|
||||
uint32_t getNpcEmoteState() const { return npcEmoteState; }
|
||||
void setNpcEmoteState(uint32_t e) { npcEmoteState = e; }
|
||||
|
||||
// Returns true if NPC has interaction flags (gossip/vendor/quest/trainer)
|
||||
bool isInteractable() const { return npcFlags != 0; }
|
||||
|
||||
|
|
@ -284,6 +288,7 @@ protected:
|
|||
uint32_t unitFlags = 0;
|
||||
uint32_t dynamicFlags = 0;
|
||||
uint32_t npcFlags = 0;
|
||||
uint32_t npcEmoteState = 0;
|
||||
uint32_t factionTemplate = 0;
|
||||
bool hostile = false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ private:
|
|||
struct UnitFieldIndices {
|
||||
uint16_t health, maxHealth, powerBase, maxPowerBase;
|
||||
uint16_t level, faction, flags, dynFlags;
|
||||
uint16_t displayId, mountDisplayId, npcFlags;
|
||||
uint16_t displayId, mountDisplayId, npcFlags, npcEmoteState;
|
||||
uint16_t bytes0, bytes1;
|
||||
static UnitFieldIndices resolve();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -934,7 +934,8 @@ public:
|
|||
void setGhostStateCallback(GhostStateCallback cb) { ghostStateCallback_ = std::move(cb); }
|
||||
|
||||
// Melee swing callback (for driving animation/SFX)
|
||||
using MeleeSwingCallback = std::function<void()>;
|
||||
// spellId: 0 = regular auto-attack swing, non-zero = melee ability (special attack)
|
||||
using MeleeSwingCallback = std::function<void(uint32_t spellId)>;
|
||||
void setMeleeSwingCallback(MeleeSwingCallback cb) { meleeSwingCallback_ = std::move(cb); }
|
||||
|
||||
// Spell cast animation callbacks — true=start cast/channel, false=finish/cancel
|
||||
|
|
@ -959,6 +960,23 @@ public:
|
|||
using NpcSwingCallback = std::function<void(uint64_t guid)>;
|
||||
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
|
||||
|
||||
// Hit reaction callback — triggers victim animation (dodge, block, wound, crit wound)
|
||||
enum class HitReaction : uint8_t { WOUND, CRIT_WOUND, DODGE, PARRY, BLOCK, SHIELD_BLOCK };
|
||||
using HitReactionCallback = std::function<void(uint64_t victimGuid, HitReaction reaction)>;
|
||||
void setHitReactionCallback(HitReactionCallback cb) { hitReactionCallback_ = std::move(cb); }
|
||||
|
||||
// Stun state callback — fires when UNIT_FLAG_STUNNED changes on the local player
|
||||
using StunStateCallback = std::function<void(bool stunned)>;
|
||||
void setStunStateCallback(StunStateCallback cb) { stunStateCallback_ = std::move(cb); }
|
||||
|
||||
// Stealth state callback — fires when UNIT_FLAG_SNEAKING changes on the local player
|
||||
using StealthStateCallback = std::function<void(bool stealthed)>;
|
||||
void setStealthStateCallback(StealthStateCallback cb) { stealthStateCallback_ = std::move(cb); }
|
||||
|
||||
// Player health changed callback — fires when local player HP changes
|
||||
using PlayerHealthCallback = std::function<void(uint32_t health, uint32_t maxHealth)>;
|
||||
void setPlayerHealthCallback(PlayerHealthCallback cb) { playerHealthCallback_ = std::move(cb); }
|
||||
|
||||
// NPC greeting callback (plays voice line when NPC is clicked)
|
||||
using NpcGreetingCallback = std::function<void(uint64_t guid, const glm::vec3& position)>;
|
||||
void setNpcGreetingCallback(NpcGreetingCallback cb) { npcGreetingCallback_ = std::move(cb); }
|
||||
|
|
@ -1093,6 +1111,19 @@ public:
|
|||
using GameObjectCustomAnimCallback = std::function<void(uint64_t guid, uint32_t animId)>;
|
||||
void setGameObjectCustomAnimCallback(GameObjectCustomAnimCallback cb) { gameObjectCustomAnimCallback_ = std::move(cb); }
|
||||
|
||||
// GameObject state change callback (triggered when GAMEOBJECT_BYTES_1 updates — state byte changes)
|
||||
// goState: 0=READY(closed), 1=OPEN, 2=DESTROYED
|
||||
using GameObjectStateCallback = std::function<void(uint64_t guid, uint8_t goState)>;
|
||||
void setGameObjectStateCallback(GameObjectStateCallback cb) { gameObjectStateCallback_ = std::move(cb); }
|
||||
|
||||
// Sprint aura callback — fired when sprint-type aura active state changes on player
|
||||
using SprintAuraCallback = std::function<void(bool active)>;
|
||||
void setSprintAuraCallback(SprintAuraCallback cb) { sprintAuraCallback_ = std::move(cb); }
|
||||
|
||||
// Vehicle state callback — fired when player enters/exits a vehicle
|
||||
using VehicleStateCallback = std::function<void(bool entered, uint32_t vehicleId)>;
|
||||
void setVehicleStateCallback(VehicleStateCallback cb) { vehicleStateCallback_ = 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); }
|
||||
|
||||
|
|
@ -1806,6 +1837,10 @@ public:
|
|||
using ItemLootCallback = std::function<void(uint32_t itemId, uint32_t count, uint32_t quality, const std::string& name)>;
|
||||
void setItemLootCallback(ItemLootCallback cb) { itemLootCallback_ = std::move(cb); }
|
||||
|
||||
// Loot window open/close callback (for loot kneel animation)
|
||||
using LootWindowCallback = std::function<void(bool open)>;
|
||||
void setLootWindowCallback(LootWindowCallback cb) { lootWindowCallback_ = std::move(cb); }
|
||||
|
||||
// Quest turn-in completion callback
|
||||
using QuestCompleteCallback = std::function<void(uint32_t questId, const std::string& questTitle)>;
|
||||
void setQuestCompleteCallback(QuestCompleteCallback cb) { questCompleteCallback_ = std::move(cb); }
|
||||
|
|
@ -2532,6 +2567,9 @@ private:
|
|||
GameObjectMoveCallback gameObjectMoveCallback_;
|
||||
GameObjectDespawnCallback gameObjectDespawnCallback_;
|
||||
GameObjectCustomAnimCallback gameObjectCustomAnimCallback_;
|
||||
GameObjectStateCallback gameObjectStateCallback_;
|
||||
SprintAuraCallback sprintAuraCallback_;
|
||||
VehicleStateCallback vehicleStateCallback_;
|
||||
|
||||
// Transport tracking
|
||||
struct TransportAttachment {
|
||||
|
|
@ -3111,6 +3149,10 @@ private:
|
|||
UnitAnimHintCallback unitAnimHintCallback_;
|
||||
UnitMoveFlagsCallback unitMoveFlagsCallback_;
|
||||
NpcSwingCallback npcSwingCallback_;
|
||||
HitReactionCallback hitReactionCallback_;
|
||||
StunStateCallback stunStateCallback_;
|
||||
StealthStateCallback stealthStateCallback_;
|
||||
PlayerHealthCallback playerHealthCallback_;
|
||||
NpcGreetingCallback npcGreetingCallback_;
|
||||
NpcFarewellCallback npcFarewellCallback_;
|
||||
NpcVendorCallback npcVendorCallback_;
|
||||
|
|
@ -3210,6 +3252,9 @@ private:
|
|||
// ---- Item loot callback ----
|
||||
ItemLootCallback itemLootCallback_;
|
||||
|
||||
// ---- Loot window callback ----
|
||||
LootWindowCallback lootWindowCallback_;
|
||||
|
||||
// ---- Quest completion callback ----
|
||||
QuestCompleteCallback questCompleteCallback_;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,38 @@ enum class EquipSlot : uint8_t {
|
|||
NUM_SLOTS // = 23
|
||||
};
|
||||
|
||||
// WoW InventoryType field values (from ItemDisplayInfo / Item.dbc / CMSG_ITEM_QUERY)
|
||||
// Used in ItemDef::inventoryType and equipment update packets.
|
||||
namespace InvType {
|
||||
constexpr uint8_t NON_EQUIP = 0; // Not equippable / unarmed
|
||||
constexpr uint8_t HEAD = 1;
|
||||
constexpr uint8_t NECK = 2;
|
||||
constexpr uint8_t SHOULDERS = 3;
|
||||
constexpr uint8_t SHIRT = 4;
|
||||
constexpr uint8_t CHEST = 5; // Chest armor
|
||||
constexpr uint8_t WAIST = 6;
|
||||
constexpr uint8_t LEGS = 7;
|
||||
constexpr uint8_t FEET = 8;
|
||||
constexpr uint8_t WRISTS = 9;
|
||||
constexpr uint8_t HANDS = 10;
|
||||
constexpr uint8_t FINGER = 11; // Ring
|
||||
constexpr uint8_t TRINKET = 12;
|
||||
constexpr uint8_t ONE_HAND = 13; // One-handed weapon (sword, mace, dagger, fist)
|
||||
constexpr uint8_t SHIELD = 14;
|
||||
constexpr uint8_t RANGED_BOW = 15; // Bow
|
||||
constexpr uint8_t BACK = 16; // Cloak
|
||||
constexpr uint8_t TWO_HAND = 17; // Two-handed weapon (also polearm/staff by inventoryType alone)
|
||||
constexpr uint8_t BAG = 18;
|
||||
constexpr uint8_t TABARD = 19;
|
||||
constexpr uint8_t ROBE = 20; // Chest (robe variant)
|
||||
constexpr uint8_t MAIN_HAND = 21; // Main-hand only weapon
|
||||
constexpr uint8_t OFF_HAND = 22; // Off-hand (held-in-off-hand items, not weapons)
|
||||
constexpr uint8_t HOLDABLE = 23; // Off-hand holdable (books, orbs)
|
||||
constexpr uint8_t AMMO = 24;
|
||||
constexpr uint8_t THROWN = 25;
|
||||
constexpr uint8_t RANGED_GUN = 26; // Gun / Crossbow / Wand
|
||||
} // namespace InvType
|
||||
|
||||
struct ItemDef {
|
||||
uint32_t itemId = 0;
|
||||
std::string name;
|
||||
|
|
|
|||
|
|
@ -300,5 +300,76 @@ inline const char* getSpellCastResultString(uint8_t result, int powerType = -1)
|
|||
}
|
||||
}
|
||||
|
||||
// ── SpellEffect — SMSG_SPELLLOGEXECUTE effectType field (3.3.5a) ──────────
|
||||
// Full WoW enum has 164 entries; only values used in the codebase or commonly
|
||||
// relevant are defined here. Values match SharedDefines.h SpellEffects enum.
|
||||
namespace SpellEffect {
|
||||
constexpr uint8_t NONE = 0;
|
||||
constexpr uint8_t INSTAKILL = 1;
|
||||
constexpr uint8_t SCHOOL_DAMAGE = 2;
|
||||
constexpr uint8_t DUMMY = 3;
|
||||
constexpr uint8_t TELEPORT_UNITS = 5;
|
||||
constexpr uint8_t APPLY_AURA = 6;
|
||||
constexpr uint8_t ENVIRONMENTAL_DAMAGE = 7;
|
||||
constexpr uint8_t POWER_DRAIN = 10;
|
||||
constexpr uint8_t HEALTH_LEECH = 11;
|
||||
constexpr uint8_t HEAL = 12;
|
||||
constexpr uint8_t WEAPON_DAMAGE_NOSCHOOL = 16;
|
||||
constexpr uint8_t RESURRECT = 18;
|
||||
constexpr uint8_t EXTRA_ATTACKS = 19;
|
||||
constexpr uint8_t CREATE_ITEM = 24;
|
||||
constexpr uint8_t WEAPON_DAMAGE = 25;
|
||||
constexpr uint8_t INTERRUPT_CAST = 26;
|
||||
constexpr uint8_t OPEN_LOCK = 27;
|
||||
constexpr uint8_t APPLY_AREA_AURA_PARTY = 35;
|
||||
constexpr uint8_t LEARN_SPELL = 36;
|
||||
constexpr uint8_t DISPEL = 38;
|
||||
constexpr uint8_t SUMMON = 40;
|
||||
constexpr uint8_t ENERGIZE = 43;
|
||||
constexpr uint8_t WEAPON_PERCENT_DAMAGE = 44;
|
||||
constexpr uint8_t TRIGGER_SPELL = 45;
|
||||
constexpr uint8_t FEED_PET = 49;
|
||||
constexpr uint8_t DISMISS_PET = 50;
|
||||
constexpr uint8_t ENCHANT_ITEM_PERM = 53;
|
||||
constexpr uint8_t ENCHANT_ITEM_TEMP = 54;
|
||||
constexpr uint8_t SUMMON_PET = 56;
|
||||
constexpr uint8_t LEARN_PET_SPELL = 57;
|
||||
constexpr uint8_t WEAPON_DAMAGE_PLUS = 58;
|
||||
constexpr uint8_t CREATE_HOUSE = 60;
|
||||
constexpr uint8_t DUEL = 62;
|
||||
constexpr uint8_t QUEST_COMPLETE = 63;
|
||||
constexpr uint8_t NORMALIZED_WEAPON_DMG = 75;
|
||||
constexpr uint8_t OPEN_LOCK_ITEM = 79;
|
||||
constexpr uint8_t APPLY_AREA_AURA_RAID = 81;
|
||||
constexpr uint8_t ACTIVATE_RUNE = 92;
|
||||
constexpr uint8_t KNOCK_BACK = 99;
|
||||
constexpr uint8_t PULL = 100;
|
||||
constexpr uint8_t DISPEL_MECHANIC = 108;
|
||||
constexpr uint8_t RESURRECT_NEW = 113;
|
||||
constexpr uint8_t CREATE_ITEM2 = 114;
|
||||
constexpr uint8_t MILLING = 115;
|
||||
constexpr uint8_t PROSPECTING = 118;
|
||||
constexpr uint8_t CHARGE = 126;
|
||||
constexpr uint8_t TITAN_GRIP = 155;
|
||||
constexpr uint8_t TOTAL_SPELL_EFFECTS = 164;
|
||||
} // namespace SpellEffect
|
||||
|
||||
// ── SpellMissInfo — SMSG_SPELLLOGMISS / SMSG_SPELL_GO miss type (3.3.5a) ─
|
||||
namespace SpellMissInfo {
|
||||
constexpr uint8_t NONE = 0; // Miss
|
||||
constexpr uint8_t MISS = 0;
|
||||
constexpr uint8_t DODGE = 1;
|
||||
constexpr uint8_t PARRY = 2;
|
||||
constexpr uint8_t BLOCK = 3;
|
||||
constexpr uint8_t EVADE = 4;
|
||||
constexpr uint8_t IMMUNE = 5;
|
||||
constexpr uint8_t DEFLECT = 6;
|
||||
constexpr uint8_t ABSORB = 7;
|
||||
constexpr uint8_t RESIST = 8;
|
||||
constexpr uint8_t IMMUNE2 = 9; // Second immunity flag
|
||||
constexpr uint8_t IMMUNE3 = 10; // Third immunity flag
|
||||
constexpr uint8_t REFLECT = 11;
|
||||
} // namespace SpellMissInfo
|
||||
|
||||
} // namespace game
|
||||
} // namespace wowee
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ enum class UF : uint16_t {
|
|||
UNIT_FIELD_AURAS, // Start of aura spell ID array (48 consecutive uint32 slots, classic/vanilla only)
|
||||
UNIT_FIELD_AURAFLAGS, // Aura flags packed 4-per-uint32 (12 uint32 slots); 0x01=cancelable,0x02=harmful,0x04=helpful
|
||||
UNIT_NPC_FLAGS,
|
||||
UNIT_NPC_EMOTESTATE, // Persistent NPC emote animation ID (uint32)
|
||||
UNIT_DYNAMIC_FLAGS,
|
||||
UNIT_FIELD_RESISTANCES, // Physical armor (index 0 of the resistance array)
|
||||
UNIT_FIELD_STAT0, // Strength (effective base, includes items)
|
||||
|
|
@ -84,6 +85,7 @@ enum class UF : uint16_t {
|
|||
|
||||
// GameObject fields
|
||||
GAMEOBJECT_DISPLAYID,
|
||||
GAMEOBJECT_BYTES_1,
|
||||
|
||||
// Item fields
|
||||
ITEM_FIELD_STACK_COUNT,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue