namespace AcDream.Core.CharGen; /// /// One profession preset offered on the Profession page. Retail's /// gmCGProfessionPage::UpdateProfession @ 0x004821b0 switches on /// CharGenState.template_ and resolves BOTH the button to highlight /// AND the description string from the SAME 0..6 index: 0 → button /// 0x100003d9 / ID_CharGen_CustomText ("Custom"), 1 → 0x100003da /// (Bow Hunter), 2 → 0x100003df (Swashbuckler), 3 → 0x100003db (Life /// Caster), 4 → 0x100003dc (War Caster), 5 → 0x100003dd (Wayfarer), 6 → /// 0x100003de (Soldier). "Custom" is therefore template index 0, NOT a /// special UI-only mode with no data — it is a real /// entry (confirmed against the installed DAT: each human heritage ships /// this row as "Adventurer", sitting at the attribute floor rather than /// spending the full credit budget). The seven profession buttons all wire /// to CharGenState::SetTemplate(state, N, 1) @ 0x005C5A60 (N = /// 0..6, the second arg a "commit" flag); SetTemplate writes /// template_ = N and, because N != 0xffffffff (retail's /// no-template sentinel — never sent by any button), immediately calls /// CharGenState::ApplyTemplate @ 0x005C5080, which re-reads that /// template row's six attributes and skill list and re-applies them. /// Selecting "Custom" therefore RESETS the attribute sliders and skill /// picks to the Adventurer row's floor spread rather than leaving the /// current values untouched — retail's own Custom-button handler /// (gmCGProfessionPage::ListenToElementMessage case 0xed) calls /// SetTemplate(state, 0, 1) then gmCGProfessionPage::UpdateToDefaultAttributes /// @ 0x00482860 to refresh the slider UI to match. ACE's /// PlayerFactory.CreatePlayer confirms the same indexing server-side: /// it indexes heritageGroup.Templates[characterCreateInfo.TemplateOption] /// with no special-cased "no template" branch /// (references/ACE/Source/ACE.Server/Factories/PlayerFactory.cs:135-138). /// Retail schema: Template_CG::Serialize @ 0x005C0450 (ACE's /// TemplateCG.Unpack mirrors the same field order). /// public sealed record ChargenTemplate( string Name, uint IconId, uint TitleStringId, ChargenAttributeValues Attributes, IReadOnlyList NormalSkills, IReadOnlyList PrimarySkills);