fix(magic): the foci map never loaded — casts demanded full components a focus should waive
User report: with the correct focus, scarab and tapers in the pack, a level 1
spell would not cast, and the spell examine window listed the full legacy
component recipe where retail shows only scarab and taper. The question asked
was whether the 2013 client data is too old for foci. It is not -- the EoR
dats carry the map, and the whole client-side mechanism (the requirement
service, the scarab-only formula port, the examine-window routing) was already
built and wired. It was fed an empty table.
MagicCatalog resolved the school-to-foci map with
Resolve(enumValue: 0x10000001, enumCategory: 0x28). Retail's
SpellComponentTable::SchoolOfMagic2WCID @ 0x005BC1F0 calls
DBObj::GetByEnum(0x10000001, 4): master map -> category 0x10000001 -> key 4
-> the school->WCID EnumIDMap. The 0x28 on that call is the EnumIDMap DBTYPE
tag, and it had been read as a lookup category. The master map has no
category 0x28, the resolver returned 0, and the foci map loaded EMPTY --
silently, so a carried focus was never detected: HasRequiredComponents
demanded the full account-customized formula (refusing the cast) and
GetExamineComponents displayed it.
Found by measurement rather than re-reading the code: a SpellDump --foci probe
proved category 0x28 absent, then brute-forced the portal enum tree for ACE's
FociWCIDs and found them at 0x27000003 under category 0x10000001 key 4:
school 1 -> 15271 Foci of Strife (War)
school 2 -> 15270 Foci of Verdancy (Life)
school 3 -> 15269 Foci of Artifice (Item)
school 4 -> 15268 Foci of Enchantment (Creature)
school 5 -> 43173 Foci of Shadow (Void)
The new Lane=InstalledDat test pins exactly that: the loaded catalog must map
every school to ACE's FociWCIDs -- external constants from the server-side
authority, deliberately not derived from the code under test, so an empty or
wrongly-resolved map cannot pass vacuously.
The infusion-augmentation half of the retail gate (properties 0x126-0x129,
0x148) was already correct against the decomp, as were the scarab-only ID set
{1..6, 0x6E, 0x6F, 0x70, 0xC0, 0xC1} and the taper-count table.
Complete Release suite: 14,469 tests pass on the standard hermetic lane
filter, 0 failures; the new installed-DAT test passes against the real dats.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cd6eefd0ba
commit
255b0aaeda
3 changed files with 123 additions and 4 deletions
|
|
@ -85,6 +85,14 @@ public sealed class MagicCatalog
|
|||
public bool IsComponentPack(uint weenieClassId) =>
|
||||
Components.ContainsKey(weenieClassId);
|
||||
|
||||
/// <summary>
|
||||
/// The foci (magic pack) WCID for a retail school id (1..5), or 0 when
|
||||
/// unmapped. Exposed for the installed-DAT conformance test; production
|
||||
/// reads go through <see cref="CreateRequirementService"/>.
|
||||
/// </summary>
|
||||
public uint MagicPackWcidForSchool(uint school) =>
|
||||
_magicPackWcidBySchool.TryGetValue(school, out uint wcid) ? wcid : 0u;
|
||||
|
||||
public int GetSpellLevel(uint spellId) =>
|
||||
_spellLevels.TryGetValue(spellId, out int level)
|
||||
? level
|
||||
|
|
@ -162,12 +170,19 @@ public sealed class MagicCatalog
|
|||
}
|
||||
|
||||
var magicPackWcidBySchool = new Dictionary<uint, uint>();
|
||||
// Retail IsComponentPack resolves enum key 0x10000001 in category
|
||||
// 0x28; that key is not itself a portal.dat file id.
|
||||
// Retail SpellComponentTable::SchoolOfMagic2WCID @ 0x005BC1F0:
|
||||
// DBObj::GetByEnum(0x10000001, 4) resolves master map -> category
|
||||
// 0x10000001 -> key 4 -> the school->foci-WCID EnumIDMap
|
||||
// (0x27000003 in the EoR dats: 1->15271 Strife, 2->15270 Verdancy,
|
||||
// 3->15269 Artifice, 4->15268 Enchantment, 5->43173 Shadow —
|
||||
// matching ACE's FociWCIDs). The decomp's 0x28 on that call is the
|
||||
// EnumIDMap DBTYPE tag, not a lookup key; passing it as the category
|
||||
// resolved nothing, so this map loaded EMPTY and a carried focus was
|
||||
// never detected — every cast demanded the full component list.
|
||||
uint magicPackMapDid = RetailDataIdResolver.Resolve(
|
||||
dats,
|
||||
0x10000001u,
|
||||
0x28u);
|
||||
enumValue: 0x4u,
|
||||
enumCategory: 0x10000001u);
|
||||
if (magicPackMapDid != 0u
|
||||
&& dats.Portal.TryGet<EnumIDMap>(
|
||||
magicPackMapDid,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue