fix(chargen): Campaign CC gate round 1 closeout — Group 2: Skills page four-bucket model
Ports the last remaining half of retail's Skills page: the four-bucket sorted skill list (Specialized/Trained/UseableUntrained/UnuseableUntrained, UpdateSkillEntry's own iMinlevel <= 1 test), plus the info box's description + formula completion. - ChargenSkillDetail/ChargenSkillFormula (Core) thread SkillBase.MinLevel/ Description/Formula from the global SkillTable, exposed via a new ChargenOptions.TryGetSkillDetail (nullable-with-default parameter, so every pre-existing ChargenOptions call site compiles unchanged). ChargenTableReader.Project populates it from the same SkillTable loop that already builds GlobalSkillCostsBySkillId. - CharacterCreationSkillsPage.RebuildRows now groups every costable skill into SkillBucket, sorts each bucket alphabetically by name (InsertEntrySorted's wcscmp, ported as string.CompareOrdinal), and builds one Templates[0] header row per bucket ahead of that bucket's Templates[1] skill rows — DoSkillRecords' own unconditional 4-header-then-populate order. A level change re-buckets the row (detected per-refresh against each row's own cached bucket, then a full rebuild with the current selection explicitly preserved). - RefreshInfoBox now composes description (word-wrapped via DatRichText.Compose) + the level-gated bonus line (an exact, unwrapped literal — NOT routed through word-wrap, which would have collapsed its authored double-space formatting) + ComposeFormula's "Formula : ..." line (MakeSkillFormula ported with high confidence for the prefix/ per-attribute-term/divisor/bonus-suffix shape; the two-attribute connector text is a disclosed approximation, register AP-231, since the decompiled function's own connector literals could not be recovered byte-exact by this session's static-only tooling). Register: AP-213 RETIRED (160 active rows). Live-DAT gate: the installed SkillTable's MinLevel distribution matches the investigation's own recorded finding exactly (38 entries, 23 useable-untrained / 15 trained-required). 3 new fixture tests + 1 new live-DAT test; 3 pre-existing integration tests fixed (they captured row widget references before a bucket-changing click, which now rebuilds and discards those references — a real, correct consequence of the new model, not a bug). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e1d7d09599
commit
0fed5fdd91
6 changed files with 712 additions and 121 deletions
|
|
@ -81,22 +81,39 @@ public static class ChargenTableReader
|
|||
heritagesById[pair.Key] = ProjectHeritage(pair.Key, pair.Value);
|
||||
|
||||
var globalSkillCosts = new Dictionary<uint, ChargenSkillCost>(skillTable?.Skills.Count ?? 0);
|
||||
// Group 2 (Campaign CC gate round 1 closeout): SkillBase.MinLevel/
|
||||
// Description/Formula — GLOBAL only, no per-heritage counterpart
|
||||
// (see ChargenSkillDetail's own doc).
|
||||
var globalSkillDetails = new Dictionary<uint, ChargenSkillDetail>(skillTable?.Skills.Count ?? 0);
|
||||
if (skillTable is not null)
|
||||
{
|
||||
foreach (KeyValuePair<DatReaderWriter.Enums.SkillId, SkillBase> pair in skillTable.Skills)
|
||||
{
|
||||
uint skillId = (uint)pair.Key;
|
||||
SkillBase skill = pair.Value;
|
||||
globalSkillCosts[skillId] = new ChargenSkillCost(
|
||||
skillId,
|
||||
pair.Value.TrainedCost,
|
||||
pair.Value.SpecializedCost);
|
||||
skill.TrainedCost,
|
||||
skill.SpecializedCost);
|
||||
globalSkillDetails[skillId] = new ChargenSkillDetail(
|
||||
skillId,
|
||||
skill.MinLevel,
|
||||
skill.Description.Value,
|
||||
new ChargenSkillFormula(
|
||||
skill.Formula.AdditiveBonus,
|
||||
skill.Formula.Attribute1Multiplier,
|
||||
skill.Formula.Attribute2Multiplier,
|
||||
skill.Formula.Divisor,
|
||||
(uint)skill.Formula.Attribute1,
|
||||
(uint)skill.Formula.Attribute2));
|
||||
}
|
||||
}
|
||||
|
||||
return new ChargenOptions(
|
||||
Array.AsReadOnly(starterAreas),
|
||||
heritagesById.ToFrozenDictionary(),
|
||||
globalSkillCosts.ToFrozenDictionary());
|
||||
globalSkillCosts.ToFrozenDictionary(),
|
||||
globalSkillDetails.ToFrozenDictionary());
|
||||
}
|
||||
|
||||
private static ChargenStarterArea ProjectStarterArea(int index, StartingArea area)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue