namespace Mr.BrickAdventures.Progression; /// /// One try at a Level: a ledger of everything that happened during the try, plus how it ended. /// Never persisted — a discarded Attempt is one that is simply thrown away. /// public sealed class Attempt { public Attempt(LevelId level) => Level = level; /// /// Which Level this is an attempt at. Settlement reads this rather than trusting a level /// supplied by the caller, so finishing a Replay cannot advance campaign position. /// public LevelId Level { get; } public AttemptOutcome Outcome { get; private set; } = AttemptOutcome.InProgress; public Coins CoinsFound { get; private set; } = Coins.Zero; /// /// Records coins picked up during this Attempt. Silently ignored once the Attempt has ended: /// a pickup firing after death is a real event, not an error, and it does not count. /// public void RecordCoinsFound(Coins amount) { if (Outcome != AttemptOutcome.InProgress) return; CoinsFound = CoinsFound.Add(amount); } public Coins CoinsSpent { get; private set; } = Coins.Zero; private readonly Dictionary _skillsBought = new(); /// /// Records a Skill bought or upgraded during this Attempt, at the level it ended up at. /// Returns false once the Attempt has ended. /// /// /// Affordability is not checked here — it spans the Attempt and the Playthrough's Bank, so it /// belongs to the caller that can see both. This records what was agreed, not whether it was /// allowed. /// public bool TryRecordPurchase(SkillId skill, SkillLevel resulting, Coins cost) { if (Outcome != AttemptOutcome.InProgress) return false; _skillsBought[skill] = resulting; CoinsSpent = CoinsSpent.Add(cost); return true; } public IReadOnlyDictionary SkillsBought => _skillsBought; /// /// Ends this Attempt in death. Returns false if it has already ended, in which case nothing /// changes — a second death event costs no further lives. /// public bool TryEndInDeath() => TryEnd(AttemptOutcome.Died); /// /// Ends this Attempt in completion. Returns false if it has already ended, in which case /// nothing changes — a second completion event banks nothing further. /// public bool TryEndInCompletion() => TryEnd(AttemptOutcome.Cleared); private bool TryEnd(AttemptOutcome outcome) { if (Outcome != AttemptOutcome.InProgress) return false; Outcome = outcome; return true; } }