ui+app+formats: the Spell.dbc row, and seven columns that answered nil
`GetSpellRecField` knew three names. Counting what the corpus actually asks it for: `name` (4 sites), `school` (3), `stackAmount` (2), `spellIconID` (2), then one each of `rank`, `rangeIndex`, `mechanic`, `manaCost`, `effectMechanic`, `effectApplyAuraName`. Seven of those ten answered nil, and each was a feature quietly off rather than an error — DoiteAuras caps its stack display on `stackAmount` (DoitePlayerAuras.lua:539) and SuperCleveRoidMacros classifies a crowd-control effect off the two arrays (Utility.lua:7776-7794). The eighty field names are the DLL's own, read off its pool in Spell.dbc column order. The mapping to `SpellDisplay` lives in `ui_script/spell_rec.rs`, beside the struct it reads — a copy on the VM side would be free to drift — and `GetSpellRec(spellId)` is that same field list walked through that same per-field reader, so the two verbs cannot answer differently for one name. A test asserts exactly that, key by key, over one row. The array columns are a 1-based table of three, which is measured, not guessed: SuperCleveRoidMacros walks `effectMechanic` as `for i = 1, 3 do local em = effectMechanics[i]`. `totem`, `reagent` and `reagentCount` take the same shape, two and eight long. One new DBC column — `StackAmount`, 39, bracketed by two constants this tree already had (38 ModalNextSpell, 40 Totem[0]). It is the only one added: fifteen further names upstream answers are left nil rather than putting fifteen unused u32s on a struct the spell catalog holds one of per row. They are listed at `FIELDS` with that reason, so the gap is a decision rather than an omission. `GetSpellRecField`'s three string columns keep the spellbook fallback the verb had before the probe, so a VM with a book and no catalog — a capture, or the boot VM before the catalog loads — still answers a learnt spell's name and rank. Every other column is a DBC row and has nowhere else to come from, which is why the fallback is exactly three names wide and says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
+39
-2
@@ -726,6 +726,43 @@ in the corpus calls the global at all — the only mention is a comment in
|
||||
`SuperCleveRoidMacros/ClassicAPI.lua:272` saying it reads the same client field. A bare name match
|
||||
is not a call site.
|
||||
|
||||
### The `Spell.dbc` row — `GetSpellRec` and seven columns `GetSpellRecField` answered nil for
|
||||
|
||||
**Built**, and this one is a measured gap rather than a completeness exercise. Counting what the
|
||||
corpus actually asks `GetSpellRecField` for: `name` (4 sites), `school` (3), `stackAmount` (2),
|
||||
`spellIconID` (2), then one each of `rank`, `rangeIndex`, `mechanic`, `manaCost`,
|
||||
`effectMechanic`, `effectApplyAuraName`. **Seven of those ten answered nil** — the binding knew
|
||||
three names. DoiteAuras caps its stack display on `stackAmount` (`DoitePlayerAuras.lua:539`) and
|
||||
`SuperCleveRoidMacros` classifies a crowd-control effect off the two arrays
|
||||
(`Utility.lua:7776-7794`), so each nil was a feature quietly off.
|
||||
|
||||
The names are the DLL's own, read off its pool in `Spell.dbc` column order (`0x91d68`–`0x92460`):
|
||||
eighty of them. The mapping to `benilla_formats::SpellDisplay` lives in
|
||||
`benilla-app`'s `ui_script/spell_rec.rs` — beside the struct it reads, because a copy on the VM side
|
||||
would be free to drift — and `GetSpellRec(spellId)` is that same field list walked through that
|
||||
same per-field reader, so the two verbs cannot answer differently for one name. A test asserts
|
||||
exactly that, key by key, over one row.
|
||||
|
||||
**The array columns are a 1-based table of three, which is measured and not guessed.**
|
||||
`SuperCleveRoidMacros` walks `GetSpellRecField(spellID, "effectMechanic")` as
|
||||
`for i = 1, 3 do local em = effectMechanics[i]`. `totem`, `reagent` and `reagentCount` take the
|
||||
same shape, two and eight long.
|
||||
|
||||
One new DBC column: `StackAmount`, column **39**, bracketed by two constants this tree already had
|
||||
(38 `ModalNextSpell`, 40 `Totem[0]`). It is the only one added — fifteen further names upstream
|
||||
answers are left nil rather than putting fifteen unused `u32`s on a struct the spell catalog holds
|
||||
one of per row. They are listed at `FIELDS` with that reason, so the gap is a decision and not an
|
||||
omission: `attributesEx4`, `targetCreatureType`, `procFlags`, `procCharges`,
|
||||
`manaPerSecondPerLevel`, `maxTargetLevel`, `maxAffectedTargets`, `dmgClass`, `spellPriority`,
|
||||
`spellVisual2`, `minFactionId`, `minReputation`, `requiredAuraVision`,
|
||||
`effectPointsPerComboPoint`, `dmgMultiplier`.
|
||||
|
||||
`GetSpellRecField`'s three string columns keep the spellbook fallback the verb had before the
|
||||
probe: a VM with a book and no catalog — a capture, or the boot VM before `ui_action`'s loader
|
||||
runs — still answers a learnt spell's name and rank, which is what `GetSpellNameAndRankForId`
|
||||
beside it does from the same `spell_display`. Every other column is a DBC row and has nowhere else
|
||||
to come from.
|
||||
|
||||
### The whole registered list, accounted for
|
||||
|
||||
With the registration table read (the section above), the surface is no longer a count of what a
|
||||
@@ -742,10 +779,10 @@ comm -23 /tmp/np /tmp/ours
|
||||
|
||||
| Bucket | Count | Names |
|
||||
|---|---|---|
|
||||
| **Built** | 37 | `CancelPlayerAuraSlot`, `CancelPlayerAuraSpellId`, `CastSpellByName`, `CastSpellByNameNoQueue`, `CastSpellNoQueue`, `FindPlayerItemSlot`, `GetBagItem`, `GetBagItems`, `GetEquippedItem`, `GetEquippedItems`, `GetItemIconTexture`, `GetItemIdCooldown`, `GetItemLevel`, `GetItemStats`, `GetItemStatsField`, `GetNampowerVersion`, `GetPlayerAuraDuration`, `GetSpellDuration`, `GetSpellIconTexture`, `GetSpellIdCooldown`, `GetSpellIdForName`, `GetSpellModifiers`, `GetSpellNameAndRankForId`, `GetSpellRecField`, `GetSpellSlotTypeIdForName`, `GetTrinkets`, `GetUnitField`, `GetUnitGUID`, `IsAuraHidden`, `IsSpellInRange`, `IsSpellUsable`, `PlayerIsMoving`, `PlayerIsRooted`, `PlayerIsSwimming`, `SetMouseoverUnit`, `UseItemIdOrName` |
|
||||
| **Built** | 38 | `CancelPlayerAuraSlot`, `CancelPlayerAuraSpellId`, `CastSpellByName`, `CastSpellByNameNoQueue`, `CastSpellNoQueue`, `FindPlayerItemSlot`, `GetBagItem`, `GetBagItems`, `GetEquippedItem`, `GetEquippedItems`, `GetItemIconTexture`, `GetItemIdCooldown`, `GetItemLevel`, `GetItemStats`, `GetItemStatsField`, `GetNampowerVersion`, `GetPlayerAuraDuration`, `GetSpellDuration`, `GetSpellIconTexture`, `GetSpellIdCooldown`, `GetSpellIdForName`, `GetSpellModifiers`, `GetSpellNameAndRankForId`, `GetSpellRec`, `GetSpellRecField`, `GetSpellSlotTypeIdForName`, `GetTrinkets`, `GetUnitField`, `GetUnitGUID`, `IsAuraHidden`, `IsSpellInRange`, `IsSpellUsable`, `PlayerIsMoving`, `PlayerIsRooted`, `PlayerIsSwimming`, `SetMouseoverUnit`, `UseItemIdOrName` |
|
||||
| **Withheld pending grom's say-so** | 8 | `WriteCustomFile`, `ReadCustomFile`, `CustomFileExists`, `ImportFile`, `ExportFile`, `ExecuteCustomLuaFile`, `StartItemExport` (writes a file of its own), `EncryptPassword` + `EncryptedServerLogin` |
|
||||
| **Not ours to add** | 4 | `QueueSpellByName`, `QueueScript`, `ChannelStopCastingNextTick`, `LearnTalentRank` |
|
||||
| **To build, in corpus-call order** | 13 | `DisenchantAll` (5 call sites outside the API layer), then `GetSpellPower`, `GetSpellRec`, `GetTrinketCooldown`, `UseTrinket`, `GetUnitData`, `GetSpellRangeData`, `CombatLogFlush`, `GetRaidTargets`, `SetLocalRaidTargetIndex`, `GetQuestLogQuestIds`, `GetQuestDialogQuestId`, `StartItemExport` (0 each — present for completeness, not need) |
|
||||
| **To build, in corpus-call order** | 12 | `DisenchantAll` (5 call sites outside the API layer), then `GetSpellPower`, `GetTrinketCooldown`, `UseTrinket`, `GetUnitData`, `GetSpellRangeData`, `CombatLogFlush`, `GetRaidTargets`, `SetLocalRaidTargetIndex`, `GetQuestLogQuestIds`, `GetQuestDialogQuestId`, `StartItemExport` (0 each — present for completeness, not need) |
|
||||
|
||||
The two that were at the head of that last bucket are now built — see "The cast feed" above for
|
||||
why they came first and what each decision cost.
|
||||
|
||||
Reference in New Issue
Block a user