Done (compiled cleanly 10:00; waiting on the user to play)
- Stats take modifiers:
Stats/StatCalculator.cs(pure): final = (base + flat) × (1 + Σ% ÷ 100); percent bonuses add, then multiply once.CharacterStatsgainedAddModifiers(source, …)/RemoveModifiers(source)and aChangedevent; every system already readsGet(), so a worn item is felt in combat immediately (Damage, Attack Speed → attack interval, Armour → mitigation). Combat/Health.cs: gaining Max Health heals by the gain; losing it only caps.Inventory/(namespaceEmbersOfOlympus.Inventory; no class is calledInventory):EquipSlot(10, two rings),InventoryGrid(8×4 bag, one item per cell),Equipment(rings fill Ring 1 → Ring 2 → replace Ring 1; charms can't be worn),PlayerItems(pure: equip swaps the old item into the same cell, so it works with a full bag; unequip needs a free cell),PlayerInventory(component: pushes each worn item's modifiers into CharacterStats, with the item as the modifier source).Loot/LootDrop.cs: registry of drops on the ground +Collect().Loot/LootPicker.cs(on Player): walk within 1.2 m of a beam → item into the bag; full bag leaves it on the ground with a Console note.Core/UIInputBlock.cs+PlayerInputReader: a mouse press that starts over the UI is ignored by the game until released (no camera orbit / target click behind the window; no zoom while scrolling over it). New action: I / B (gamepad Select) toggles the bag.UI/InventoryWindow.cs(namespaceEmbersOfOlympus.UI): UI Toolkit, built in code (no TextMesh Pro import needed). Equipment slots (labelled when empty), a stat sheet (Health, Damage, Attack Speed %, Armour, Umbral/Divine %), the 8×4 bag. Click a bag item to wear it, click a worn item to take it off, hover for a tooltip (coloured name, rarity, stat lines, "Click to equip"). Changed stats flash green (up) or red (down) and grow for 1.5 s: the "number visibly changes" from the plan. Esc also closes it.Assets/_Project/UI/Inventory.uss(styles, ember/bronze on near-black; rarity by border width + colour) andGameTheme.tss(Unity's default runtime theme, for fonts).- Scene builder: Player gets PlayerInventory + LootPicker; new
UIobject (UIDocument + InventoryWindow);UI/PS_Game.assetPanelSettings (1920×1080 reference, scale with screen), created only if missing. - Localization (systems.csv): window/section titles, hint "Press I to open your inventory", tooltip footers, 9 slot names, 6 stat names,
ui.stats.percent. Renamed the unusedstat.health.name→stat.max_health.nameto match the other stat keys. - Tests:
StatCalculatorTests(6) +CharacterStatsModifierTests(3),PlayerItemsTests(9). Expected total ≈ 66.
Decisions
- UI Toolkit over uGUI: no TMP import, the layout is code + one USS file Claude can edit, and it's Unity's recommended runtime UI going forward.
- One item per cell for now (no Diablo "tetris" sizes); click to equip (drag & drop later).
- Walk-over pickup only; click-to-pick-up can come with the HUD if wanted.
- (Later, same day) Generated two companion files from
demo-art-list.md:plan-version-2/demo-art-prompts.md: the full ready-to-paste prompt for all 189 images (162 demo, 27 stretch). Each includes the style, the subject and the avoid list, plus the image's size and file name.plan-version-2/demo-art-images.md: the image list and tracker. For each image: type, generate-at and final size, background, file name (CA_concept andREF_prop reference stay on the NAS;T_textures and sprites go into Unity), destination folder, use, and a status column (☐ → 🖼 → ✅ → 📦, 📒 = ledger row). Also the Unity import settings per type.- The generator is
plan-version-2/build-demo-art-docs.py. Edit the list, then rerun it. - The count went up from about 145 because dialogue portraits for the 10 speaking characters, the second skybox, the drachma pile and four separate elemental damage icons are now separate images.
- No image tool is available to Claude in this session. The user generates the images.
Bug: picked-up items didn't show in the bag
- Found in Editor.log: on entering Play,
InventoryWindow.Build()threw a NullReferenceException at line 161 (_inventory.Items.Grid). The UI object'sOnEnableran before the Player'sPlayerInventory.Awake, so the bag didn't exist yet. Build stopped halfway: no bag cells, no tooltip, noChangedsubscription. So pick-up worked (Console said so) but the window never refreshed, and every hover threw inMoveTooltip. - Fix:
PlayerInventory.Itemsis created on first use (_items ??= CreateItems()), not in Awake, so it no longer matters which object starts first. - Lesson (added to the
unity-csharp-scriptskill): never rely on another object's Awake having run in your OnEnable/Awake. Unity doesn't order Awake across objects. - (Update) User confirmed the fix: items appear in the bag, equipping works.