feat: coins and skills move to the new domain (commit B of the swap)
atomic pair - purchasing couples them, so neither moves alone. SkillData.Level is gone. It was an [Export] on a cached Resource: one instance per process, so the level never persisted, leaked between save slots, and made "unowned" indistinguishable from "level 1". Level now comes from the Playthrough and is passed to ISkill.Initialize. SkillManager reconciles from SkillSetChanged instead of being told by each caller. The old shape was "record it, then tell SkillManager" as two calls at four sites; AddSkill's early return when no player is registered left the skill owned but inert. Reconciliation also tracks the level each component was built at, so an upgrade rebuilds it rather than being patched in from outside. SkillUnlockerComponent collapses to one TryBuy - unlock and upgrade were two methods each doing affordability, debit, level mutation and manager notification in order. The guard three components copy-pasted around Upgrades[Level - 1] - and which BrickArmor omitted - now lives once in SkillComponentBase. Hud reads coins from CoinsChanged instead of rebuilding translated strings every frame. Lives still polls; it moves with the death path.
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.Progression;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Handles coin collection events and updates the GameStateStore.
|
||||
/// Replaces the manual coin logic in GameManager.
|
||||
/// Records collected coins against the current Attempt.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Coins are banked only by a First Clear, so dying loses what was found this attempt — including
|
||||
/// anything spent from it. See docs/adr/0002-attempt-is-a-ledger.md.
|
||||
/// </remarks>
|
||||
public partial class CoinStateHandler : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
@@ -17,13 +21,13 @@ public partial class CoinStateHandler : Node
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.CoinCollected -= OnCoinCollected;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCoinCollected(int amount, Vector2 position)
|
||||
{
|
||||
GameStateStore.Instance?.AddSessionCoins(amount);
|
||||
if (amount <= 0) return;
|
||||
|
||||
ProgressionRoot.Instance?.RecordCoinsFound(Coins.Of(amount));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.Progression;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Handles skill collection events and unlocks skills via GameStateStore.
|
||||
/// Skills are immediately activated but only persisted on level complete.
|
||||
/// Grants a skill picked up in a level.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only records that it is owned. Attaching the live component is SkillManager's job, driven by
|
||||
/// SkillSetChanged — previously this did both as two separate calls, and the second could silently do
|
||||
/// nothing if no player was registered yet, leaving the skill owned but inert.
|
||||
/// </remarks>
|
||||
public partial class SkillCollectHandler : Node
|
||||
{
|
||||
private SkillManager SkillManager => SkillManager.Instance;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
EventBus.Instance.SkillCollected += OnSkillCollected;
|
||||
@@ -20,22 +23,13 @@ public partial class SkillCollectHandler : Node
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.SkillCollected -= OnSkillCollected;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSkillCollected(SkillData skill, Vector2 position)
|
||||
{
|
||||
if (skill == null) return;
|
||||
if (skill == null || string.IsNullOrWhiteSpace(skill.Name)) return;
|
||||
|
||||
// Unlock in session (will be committed on level complete, lost on death)
|
||||
GameStateStore.Instance?.UnlockSkillInSession(skill);
|
||||
|
||||
// Immediately activate the skill for the player
|
||||
SkillManager?.AddSkill(skill);
|
||||
|
||||
// Emit skill unlocked event for UI/achievements
|
||||
EventBus.EmitSkillUnlocked(skill.Name, skill.Level);
|
||||
ProgressionRoot.Instance?.GrantSkill(SkillId.Of(skill.Name));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user