using Theriapolis.Core.Rules.Stats; namespace Theriapolis.Core.Rules.Character; /// /// Pure data describing the *deltas* a level-up produces. Phase 6.5 M0: /// computes one of these from /// (character, targetLevel, levelUpSeed); the player confirms; then /// applies it. /// /// Splitting compute from apply keeps the level-up screen previewable /// (the player sees the rolled HP and feature list before committing) and /// makes mid-flight save/load deterministic — the same seed always produces /// the same payload. /// public sealed class LevelUpResult { /// The level being advanced *to*. After Apply, Character.Level == NewLevel. public int NewLevel { get; init; } /// HP gained on this level-up. Already incorporates CON modifier. public int HpGained { get; init; } /// Average-rounded-up HP value used (for "take average" path); rolled value used otherwise. public int HpHitDieResult { get; init; } /// True if the player picked the "take average" option; false if rolled. public bool HpWasAveraged { get; init; } /// Class feature ids unlocked at this level (per ). public string[] ClassFeaturesUnlocked { get; init; } = Array.Empty(); /// /// Subclass feature ids unlocked at this level (post-L3, when SubclassId /// is set). Empty for pre-subclass and non-subclass-feature levels. /// public string[] SubclassFeaturesUnlocked { get; init; } = Array.Empty(); /// True if this level grants a subclass selection slot (level 3 by default). public bool GrantsSubclassChoice { get; init; } /// True if this level grants an Ability Score Improvement choice (levels 4 / 8 / 12 / 16 / 19). public bool GrantsAsiChoice { get; init; } /// The proficiency bonus *after* this level-up. public int NewProficiencyBonus { get; init; } } /// /// The player's choices at level-up that need confirmation before /// commits the deltas. Leave fields /// null/empty when the corresponding slot isn't open at this level. /// public sealed class LevelUpChoices { /// /// At level 3 (or whatever /// becomes), the player picks a subclass id. Must reference one of /// character.ClassDef.SubclassIds. /// public string? SubclassId { get; set; } /// /// At ASI levels (), the player picks ability /// score improvements. Either: /// - one ability +2 (cap at ) /// - two abilities +1 each (each cap at ) /// public Dictionary AsiAdjustments { get; set; } = new(); /// /// True if the player picked "take average HP" instead of "roll". /// Default is "average" — predictable, avoids the dump-stat-roll problem. /// public bool TakeAverageHp { get; set; } = true; }