fix(ui): match retail vitae and character info

Restore Vitae's omitted penalty paragraph, replace the invented character summary with gmCharacterInfoUI's ordered report and property meanings, preserve authored translucent body surfaces, and initialize the end-session button in its visible Normal DAT state.

Release build and all 5,830 tests pass with five intentional skips. Connected visual gate pending.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-17 12:06:14 +02:00
parent d1d603105f
commit 16c21e299c
21 changed files with 771 additions and 303 deletions

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
namespace AcDream.App.UI.Layout;
@ -70,6 +71,12 @@ public sealed class CharacterSheet
/// <summary>Total deaths (retail InqInt(0x2b) = NumDeaths).</summary>
public int Deaths { get; init; }
/// <summary>Raw retail PropertyInt 0x62. Null means the quality was absent.</summary>
public int? BirthTimestamp { get; init; }
/// <summary>Raw retail PropertyInt 0x7D seconds. Null means the quality was absent.</summary>
public int? TotalPlayTimeSeconds { get; init; }
// ── Vitals (UpdateEnduranceInfo 0x004b8eb0) ─────────────────────────────
public int HealthCurrent { get; init; }
@ -90,12 +97,18 @@ public sealed class CharacterSheet
public int Self { get; init; }
// ── Skills (UpdateFakeSkills 0x004b8930) ────────────────────────────────
// Retail InqInt(0xb5) = SkillCredits; InqInt(0xc0) = AvailableSkillCredits.
// Character Information uses 0xB5/0xC0 for Chess/Fishing; skill credits use 0x18.
// InqInt(0x18) = available skill credits — footer 0x10000245 in the Attributes tab.
public int UnspentSkillCredits { get; init; }
public int SpecializedSkillCredits { get; init; }
/// <summary>Retail Character Information PropertyInt 0xB5.</summary>
public int ChessRank { get; init; }
/// <summary>Retail Character Information PropertyInt 0xC0.</summary>
public int FishingSkill { get; init; }
/// <summary>
/// Available (unspent) skill credits shown in the Attributes tab footer State-A.
/// Retail InqInt(0x18) — gmStatManagementUI::DisplayDefaultFooter (0x0049cde0).
@ -144,11 +157,20 @@ public sealed class CharacterSheet
/// e.g. "Swords", "Two Handed Weapons". Null = "None".</summary>
public string? AugmentationName { get; init; }
/// <summary>
/// Raw PropertyInt snapshot used by retail's data-driven mastery,
/// luminance, and augmentation report. The controller reads only the
/// quality ids cited by <c>gmCharacterInfoUI::UpdateAugmentations</c>.
/// </summary>
public IReadOnlyDictionary<uint, int> CharacterInfoProperties { get; init; }
= new Dictionary<uint, int>();
// ── Burden / load (UpdateLoad 0x004b8a20) ───────────────────────────────
// Retail InqLoad + EncumbranceCapacity(Strength, AugEncumbrance).
public int BurdenCurrent { get; init; }
public int BurdenMax { get; init; }
public int EncumbranceAugmentations { get; init; }
}
public enum CharacterSkillAdvancementClass