Files
healer-man/docs/ENEMY_EQUIPMENT_MAPPING_2026-10-06.md
2026-10-06 22:25:34 -04:00

6.5 KiB

Pinned enemy equipment mapping — 2026-10-06

Result

Recovered the exact AzerothCore creature_equip_template.sql at the currently pinned world commit and added its hash-checked fixture and importer path. The generated reference now joins imported spawn GUIDs and selectors to equipment sets, then to Item.dbc class and inventory type. The runtime helper resolves only an explicit source spawn GUID and entry; unknown, mismatched, unsupported, or unresolvable assignments produce no equipment contract.

The recovered SQL is dungeon-pipeline/source-fixtures/azerothcore-4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3/creature_equip_template.sql. It hashes to 877205c149fd447b08f0ff2c65976f20c862cd42f068a6fcc294a76c7108936a and belongs to AzerothCore commit 4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3, matching the active creature.sql and creature_template.sql pins. Its schema is CreatureID, ID, ItemID1, ItemID2, ItemID3, VerifiedBuild; the source contains 10,854 SQL rows. The importer checks the full file hash before publishing the equipment mapping and records it in azerothCoreSourceLock.json.

Imported runtime scope

azerothCoreReference.json stores three related mappings under creature.equipment*:

  • equipmentAssignmentsBySpawnGuid[guid] records the source id1, optional alternate entries id2/id3, and original equipment_id selector.
  • equipmentTemplatesByEntry[entry][equipmentId] records raw source item IDs and the three virtual item IDs retained after core loader validation.
  • equipmentItemsById[itemId] stores the pinned Item.dbc itemClass and inventoryType for IDs referenced by those equipment rows.

These assignments cover the source dungeon maps imported by the pipeline, not all 149,879 rows in the world spawn table. The current generated snapshot has 13,277 spawn-GUID assignments, 755 equipment entries, 763 equipment sets, and 442 referenced item IDs. The spawn selectors are 7,632 zeroes, 5,637 ones, two twos, and six -1 values. Twenty-three spawn rows have alternate creature entries. All 1,034 nonzero virtual item slots in this imported scope resolve through the pinned Item.dbc and pass its hand-inventory validation.

The Item.dbc input is the WotLK 3.3.5a client file at ../wow335a/Data/patch-A.MPQ/DBFilesClient/Item.dbc, SHA-256 22061a811523790ddd2ee95b36ade2ac6e0c79a8b3121324d32a639acf50567f. Its 46,149 rows use eight 4-byte fields per 32-byte record; Class is field 1 and InventoryType is field 6. The importer rejects a different hash or DBC layout. Both pins and field indexes appear in the generated source lock and reference.

Source behavior and selectors

The source behavior was checked against the exact commit-pinned Creature.cpp (SHA-256 ea19df5312b632bb7b9faf4323c1612fff8d8104e390d7193bae584318e3e11b) and ObjectMgr.cpp (SHA-256 e4eae029cc30f84c26c258ba806d39eea61200f623aead1ee0813f6adebeed37). The relevant operations are ObjectMgr::GetEquipmentInfo, ObjectMgr::LoadEquipmentTemplates, spawn data loading, Creature::LoadEquipment, and Creature::HasWeapon.

For a database spawn, selector 0 means no equipment. A positive selector looks up that exact equipment ID. Selector -1 chooses a random row from the entry's equipment map, then mutates the selector to distance(begin, row) + 1. That is an ordinal-based ID, not the selected row's actual key. ObjectMgr checks nonzero alternate entries using the mutated selector and clears the assignment if a required alternate row is absent; the later creature load again looks up the concrete ID. The runtime helper mirrors this sequence with an injected uniform value in [0, 1). It fails closed if the resulting exact lookup or any alternate lookup is absent rather than choosing the row's key as a substitute.

This distinction matters for sparse IDs. The pinned table has creature 32239 with only equipment ID 2. Its one-row -1 selection rewrites to ID 1, so a later ID-1 lookup has no result; the helper will not grant its ID-2 equipment under a random selector. An explicit selector 2 can resolve that row. The focused test covers this ordinal-plus-one behavior.

ObjectMgr::LoadEquipmentTemplates also removes missing items and item rows whose Item.dbc InventoryType is not one of 13, 14, 15, 17, 21, 22, 23, 25, 26 (weapon, shield, ranged, two-handed weapon, main-hand weapon, off-hand weapon, holdable, thrown, or ranged-right). The importer applies this same whitelist to all three virtual slots. After that validation, Creature::HasWeapon(OFF_ATTACK) in AUTO mode checks the resolved Item.dbc ClassID == ITEM_CLASS_WEAPON (2). No item_template lookup is needed for that gate; this import does not claim to model item stats or item damage.

The helper enemySpawnEquipmentContract(entry, sourceCreatureGuid, randomUnit?) returns the resolved virtual item IDs and offhand class, plus the existing autoOffhand contract when the offhand item is a weapon. It requires a source GUID whose imported entry list contains the requested creature. Database spawns with selector zero resolve to empty virtual slots. Missing GUIDs, synthetic spawns, entry mismatches, older references without equipment maps, and failed selector lookups return no contract. Core's separate no-spawn-data default LoadEquipment() selects ID 1; the GUID-based helper does not infer that creation path for synthetic actors.

The mapping only supplies source equipment and AUTO offhand capability. It does not schedule attacks, import item stats, change loot, alter the level-80 cap, or certify CoA/native balance. Ready-five remains the certification set; CoA and native balance remain Needs Testing.

Validation

  • node --test scripts/dungeon-pipeline/import-azerothcore-world.test.mjs — 10 focused tests passed.
  • npx vitest run src/game/enemyEquipment.test.ts — 7 focused tests passed.
  • node scripts/dungeon-pipeline/import-azerothcore-world.mjs --item-dbc "F:\\Projects\\wow335a\\Data\\patch-A.MPQ\\DBFilesClient\\Item.dbc" — green; 54 imported dungeon snapshots, 13,277 creature spawns, 494 encounters, with the three expected Ascension-only fallback maps.

The isolated source-data subprocess did not run a production build or live QA. Root's combined continuation subsequently passes the standard build, Ready-five, avatar checks and the one frozen Cellblock Rush clear. Targorr's live source GUID 84027 resolves virtual slots [5305, 5305, 0] and weapon Class 2; eight offhand outcomes are observed. Combined evidence and limitations are in the continuation report.