feat: port retail magic lifecycle and retained spell UI

Complete the retail cast-intent, target, component, enchantment, and busy-state paths; mount the DAT-authored spell bar, spellbook, component book, effects panels, and shared panel lifecycle; and add scoped input plus conformance coverage.

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-15 10:55:22 +02:00
parent 7b7ffcd278
commit 07be994d97
84 changed files with 17822 additions and 1051 deletions

View file

@ -207,6 +207,9 @@ public static class CreateObject
// PublicWeenieDesc._ammoType, gated by WeenieHeader flag 0x100.
// AMMO_NONE is the explicit wire value zero; null means absent.
ushort? AmmoType = null,
// PublicWeenieDesc._spellID, gated by PWD_Packed_SpellID. The packed
// wire field is u16 and widens into retail's u32 runtime member.
uint? SpellId = null,
// Complete immutable PhysicsDesc projection. Kept alongside the
// legacy convenience fields while live-entity ownership migrates to
// LiveEntityRuntime in Step 2.
@ -862,6 +865,7 @@ public static class CreateObject
byte? radarBehavior = null;
byte? combatUse = null;
ushort? ammoType = null;
uint? spellId = null;
uint iconOverlayId = 0;
uint iconUnderlayId = 0;
uint uiEffects = 0;
@ -1011,6 +1015,7 @@ public static class CreateObject
if ((weenieFlags & 0x00400000u) != 0) // Spell u16
{
if (body.Length - pos < 2) throw new FormatException("trunc Spell");
spellId = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(pos));
pos += 2;
}
if ((weenieFlags & 0x02000000u) != 0) // HouseOwner u32
@ -1113,6 +1118,7 @@ public static class CreateObject
PluralName: pluralName,
PetOwnerId: petOwnerId,
AmmoType: ammoType,
SpellId: spellId,
Physics: physics);
}
catch