feat(progression): use cases (slice 6)
ProgressionService holds the loaded Profile, active Playthrough and active Attempt, so "exactly one active Attempt" has a testable home. EnterLevel always announces LevelStarted - the reason ghost recording and splits never worked on level 1 or after a Continue. Refuses unreachable levels. Does not touch campaign position, so a Replay leaves it alone. SkillCatalogue returns null for a skill with no authored upgrades, killing the Upgrades[0].Cost overrun. PurchaseSkill reads the current level from the ledger first, so one Attempt can unlock then upgrade. HandlePlayerDeath now persists - death was free if you quit. SkillLevel.First/Next driven out here by a real caller. 53 tests.
This commit is contained in:
@@ -4,12 +4,22 @@ namespace Mr.BrickAdventures.Progression;
|
||||
/// How far a Skill has been upgraded. Starts at one; there is no zero, because a Playthrough
|
||||
/// records only the Skills it owns and absence from that record is what "unowned" means.
|
||||
/// </summary>
|
||||
public readonly struct SkillLevel
|
||||
public readonly struct SkillLevel : IEquatable<SkillLevel>
|
||||
{
|
||||
public int Value { get; }
|
||||
|
||||
private SkillLevel(int value) => Value = value;
|
||||
|
||||
/// <summary>The level a Skill is at the moment it is first bought.</summary>
|
||||
public static readonly SkillLevel First = new(1);
|
||||
|
||||
public SkillLevel Next() => new(Value + 1);
|
||||
|
||||
public bool Equals(SkillLevel other) => Value == other.Value;
|
||||
public override bool Equals(object? obj) => obj is SkillLevel other && Equals(other);
|
||||
public override int GetHashCode() => Value;
|
||||
public override string ToString() => Value.ToString();
|
||||
|
||||
public static SkillLevel Of(int value) => value < 1
|
||||
? throw new ArgumentOutOfRangeException(nameof(value), value, "A skill level starts at 1; unowned is absence, not level 0.")
|
||||
: new SkillLevel(value);
|
||||
|
||||
Reference in New Issue
Block a user