using AcDream.App.UI.Layout; using AcDream.Core.Items; namespace AcDream.App.Studio; /// /// Static sample data for the UI Studio fixture provider. /// Provides a pre-built populated with a /// representative player, their main-pack items, side bags, and equipped gear, /// so the 2-D inventory / paperdoll panels render populated when previewed in /// the studio without a live game session. /// /// Icon ids used (all real 0x06xxxxxx RenderSurface ids confirmed in the dats): /// Inventory empty-slot sprite : 0x06004D20 /// Generic "misc" item : 0x060011D4 (icon_misc_underlay / fallback) /// Iron Sword (melee weapon) : 0x060011CBu (acclient default weapon underlay) /// Leather Breastplate (armor) : 0x060011CFu (acclient default armor underlay) /// Leather Gloves : 0x060011F3u (acclient default clothing underlay) /// Steel Ring : 0x060011D5u (acclient default jewelry underlay) /// Healing Kit : 0x060011D4u (generic misc fallback) /// Spell components : 0x060011D4u (generic misc fallback) /// Side-bag 1 (Container) : 0x06004D20u /// Side-bag 2 (Container) : 0x06004D20u /// Equipped helm (HeadWear) : 0x060011F3u /// Equipped chest armor : 0x060011CFu /// Equipped melee weapon : 0x060011CBu /// /// These are the icon *base* RenderSurface ids — the same ids GameWindow passes /// as `iconId` into the iconIds lambda. FixtureProvider resolves them via /// and returns the raw GL handle. /// public static class SampleData { // ── Guids ──────────────────────────────────────────────────────────────── /// Fake server guid for the studio's synthetic player. public const uint PlayerGuid = 0x50000001u; // Items in main pack (slots 0–5). private const uint SwordGuid = 0x50000010u; private const uint ChestGuid = 0x50000011u; private const uint GlovesGuid = 0x50000012u; private const uint RingGuid = 0x50000013u; private const uint HealKitGuid = 0x50000014u; private const uint CompGuid = 0x50000015u; // Side bags (also in main pack, ContainerId = PlayerGuid; slots 6 & 7). private const uint Bag1Guid = 0x50000020u; private const uint Bag2Guid = 0x50000021u; // Equipped items (ContainerId = PlayerGuid, CurrentlyEquippedLocation set). private const uint HelmGuid = 0x50000030u; private const uint ChestEqGuid = 0x50000031u; private const uint WeaponEqGuid = 0x50000032u; // ── Icon ids (0x06xxxxxx RenderSurface dat ids) ─────────────────────────── // These are the same underlay/fallback icon ids the IconComposer tests pin. private const uint IconWeapon = 0x060011CBu; // weapon underlay private const uint IconArmor = 0x060011CFu; // armor underlay private const uint IconClothing = 0x060011F3u; // clothing underlay private const uint IconJewelry = 0x060011D5u; // jewelry underlay private const uint IconMisc = 0x060011D4u; // misc / fallback underlay // ── Public API ────────────────────────────────────────────────────────── /// /// Build a fresh populated with the /// studio's sample player + a realistic inventory snapshot. /// The table is owned by the caller and should be kept alive for the /// window's lifetime. /// public static ClientObjectTable BuildObjectTable() { var t = new ClientObjectTable(); // ── Player object ───────────────────────────────────────────────── t.AddOrUpdate(new ClientObject { ObjectId = PlayerGuid, Name = "Studio Player", Type = ItemType.Creature, ItemsCapacity = 102, ContainersCapacity = 7, }); // ── Loose items in main pack (slots 0–5) ────────────────────────── AddItem(t, SwordGuid, ItemType.MeleeWeapon, IconWeapon, "Iron Sword", PlayerGuid, 0, burden: 60); AddItem(t, ChestGuid, ItemType.Armor, IconArmor, "Leather Breastplate", PlayerGuid, 1, burden: 200); AddItem(t, GlovesGuid, ItemType.Clothing, IconClothing, "Leather Gloves", PlayerGuid, 2, burden: 50); AddItem(t, RingGuid, ItemType.Jewelry, IconJewelry, "Steel Ring", PlayerGuid, 3, burden: 10); AddItem(t, HealKitGuid, ItemType.Misc, IconMisc, "Healing Kit", PlayerGuid, 4, burden: 30); AddItem(t, CompGuid, ItemType.SpellComponents, IconMisc, "Spell Comps", PlayerGuid, 5, burden: 25, stackSize: 50, stackMax: 100); // ── Side bags (Container items in main pack, slots 6 & 7) ───────── AddItem(t, Bag1Guid, ItemType.Container, IconMisc, "Small Pack 1", containerId: PlayerGuid, slot: 6, burden: 20, itemsCapacity: 24); AddItem(t, Bag2Guid, ItemType.Container, IconMisc, "Small Pack 2", containerId: PlayerGuid, slot: 7, burden: 20, itemsCapacity: 24); // ── Equipped items (ContainerId = PlayerGuid, CurrentlyEquippedLocation set) ── AddEquipped(t, HelmGuid, ItemType.Armor, IconClothing, "Tin Helm", EquipMask.HeadWear); AddEquipped(t, ChestEqGuid, ItemType.Armor, IconArmor, "Chain Coat", EquipMask.ChestArmor); AddEquipped(t, WeaponEqGuid, ItemType.MeleeWeapon, IconWeapon, "Wooden Sword", EquipMask.MeleeWeapon); return t; } // ── Sample vital constants (used by FixtureProvider) ──────────────────── public const float HealthPct = 0.8f; public const float StaminaPct = 0.6f; public const float ManaPct = 0.9f; // ── Sample character sheet (used by CharacterController in the Studio) ─── /// /// Returns a representative for the studio's /// synthetic character. Values are plausible retail-scale numbers so the /// report renders with well-proportioned text in all sections. /// public static CharacterSheet SampleCharacter() => new() { Name = "Studio Player", Level = 126, Race = "Aluvian", Heritage = "Aluvian Heritage", Title = "the Adventurer", BirthDate = "January 5, 2001", PlayTime = "2 years, 114 days, 4 hours", Deaths = 42, PkStatus = "Non-Player Killer", TotalXp = 1_250_000_000, XpToNextLevel = 42_000_000, XpFraction = 0.63f, // Vitals: retail screenshot spec (Pass 1 acceptance criteria §Goal). HealthCurrent = 5, HealthMax = 5, StaminaCurrent = 10, StaminaMax = 10, ManaCurrent = 10, ManaMax = 10, // Attributes: Strength + Quickness = 200; all others = 10 (retail screenshot spec §Goal). Strength = 200, Endurance = 10, Quickness = 200, Coordination = 10, Focus = 10, Self = 10, UnspentSkillCredits = 12, SpecializedSkillCredits = 4, // Available skill credits (retail InqInt(0x18)); shown in Attributes tab footer State-A. SkillCredits = 96, // Unassigned (banked) XP (retail InqInt64(2)); footer State-A line-2 value. UnassignedXp = 87_757_321_741L, // Raise costs in retail display order (Strength, Endurance, Coordination, Quickness, // Focus, Self, Health, Stamina, Mana). // Str@200 = maxed → 0 (disabled). Quickness@200 = maxed → 0. Others @10 → affordable. // Focus@10 → 110 matches the authoritative retail screenshot (spec §4). // Formula bracket at value=10: ExperienceToAttributeLevel(11) − ExperienceToAttributeLevel(10). AttributeRaiseCosts = new long[] { 0L, 95L, 100L, 0L, 110L, 105L, 90L, 88L, 112L }, AugmentationName = "Swords", BurdenCurrent = 1200, BurdenMax = 4500, }; // ── Helpers ───────────────────────────────────────────────────────────── private static void AddItem( ClientObjectTable t, uint guid, ItemType type, uint iconId, string name, uint containerId, int slot, int burden = 0, int stackSize = 1, int stackMax = 1, int itemsCapacity = 0) { t.AddOrUpdate(new ClientObject { ObjectId = guid, Name = name, Type = type, IconId = iconId, Burden = burden, StackSize = stackSize, StackSizeMax = stackMax, ItemsCapacity = itemsCapacity, }); t.MoveItem(guid, containerId, slot); } private static void AddEquipped( ClientObjectTable t, uint guid, ItemType type, uint iconId, string name, EquipMask equipMask) { t.AddOrUpdate(new ClientObject { ObjectId = guid, Name = name, Type = type, IconId = iconId, ValidLocations = equipMask, CurrentlyEquippedLocation = equipMask, ContainerId = PlayerGuid, }); // Update the equip location on the object via MoveItem (sets ContainerId + // CurrentlyEquippedLocation via the equip overload). t.MoveItem(guid, PlayerGuid, newSlot: -1, newEquipLocation: equipMask); } }