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;
}
}