feat: lives and death move to the new domain (commit C of the swap)
fixes the regression commit B introduced: coins and skills lived in the Attempt ledger, but nothing discarded it, because LivesStateHandler still called the old store and HandlePlayerDeath was never invoked. Dying kept everything earned that level. Discard-on-death is the ledger's purpose, so it could not be separated from it. new AttemptFailed(remaining, runOver) event, raised after the life is spent and the ledger discarded. DeathScreen and GameOverScreen react to that instead of being wired to HealthComponent.Death by scene connections which fired *before* the life was charged - on the last life game-over saw one life left and showed nothing, then the death screen saw zero and refused to reload. 18 scene connections deleted; the race is now unrepresentable rather than fixed. DeathScreen also had two read paths for lives - a signal and a direct store read - because neither was reliable alone. Now one. Hud reads both facts from signals; only health still polls, and that belongs to the component rather than to progression. GameManager no longer touches GameStateStore or SaveSystem at all.
This commit is contained in:
@@ -230,6 +230,50 @@ public class ProgressionServiceTests
|
||||
Assert.False(service.CanEnter(Second));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_settled_death_announces_the_outcome_so_no_screen_has_to_read_lives_itself()
|
||||
{
|
||||
// DeathScreen and GameOverScreen were both wired to HealthComponent.Death by scene
|
||||
// connections that fire before lives are decremented, so on the last life neither saw zero.
|
||||
// Announcing the settled result means the value is already correct when they hear about it.
|
||||
var service = ServiceWithSkills();
|
||||
|
||||
service.HandlePlayerDeath();
|
||||
|
||||
var failed = service.DrainEvents().OfType<AttemptFailed>().Single();
|
||||
Assert.Equal(2, failed.Remaining.Value);
|
||||
Assert.False(failed.RunOver);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dying_on_the_last_life_announces_the_run_is_over_in_the_same_breath()
|
||||
{
|
||||
var service = new ProgressionService(
|
||||
Profile.Empty(), new InMemoryPlaythroughStore(), new InMemoryProfileStore(),
|
||||
TwoLevels(), Skills(), Lives.Of(1));
|
||||
service.StartPlaythrough(Id);
|
||||
service.EnterLevel(First);
|
||||
service.DrainEvents();
|
||||
|
||||
service.HandlePlayerDeath();
|
||||
|
||||
var events = service.DrainEvents();
|
||||
Assert.True(events.OfType<AttemptFailed>().Single().RunOver);
|
||||
Assert.Single(events.OfType<RunEnded>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_repeated_death_event_announces_nothing_further()
|
||||
{
|
||||
var service = ServiceWithSkills();
|
||||
service.HandlePlayerDeath();
|
||||
service.DrainEvents();
|
||||
|
||||
service.HandlePlayerDeath();
|
||||
|
||||
Assert.Empty(service.DrainEvents().OfType<AttemptFailed>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_collected_skill_is_granted_free_and_only_once()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user