Add artifact win condition #3

Merged
mlangkabel merged 6 commits from feature/win-condition-artifacts into master 2026-07-01 20:27:30 +00:00
Owner

Summary

  • Adds an artifact win condition: when enemy defence stations are destroyed, a configurable chance (formula of station level) is rolled to include an "Artifact" option in the schematic choice dialog. If selected, the player's artifact count increments; reaching the configured win count ends the game with a "Won!" screen.
  • The current/max artifact count is always shown in the header bar as Artifacts: x/y.
  • Two new config fields in world.toml under [artifacts]: artifact_chance_formula (formula, x = station level) and artifact_win_count (integer).
  • 11 new Catch2 tests covering config parsing, artifact presence/absence in choices, count tracking, win condition, and reset behaviour.

Changes

  • WorldConfig.h — new WorldArtifacts sub-struct
  • ConfigLoader.cpp — parses [artifacts] section
  • world.toml (app + test) — new [artifacts] section
  • SchematicChoiceOption.hArtifact added to SchematicType enum
  • Simulation.h/.cpp — artifact count + win state, accessors, reset, generateSchematicChoices, applySchematicChoice
  • ArtifactCountChangedEvent.h, WinEvent.h — two new events
  • GameWorldView.h/.cpp — polls artifact count and win state, fires events
  • HeaderBar.h/.cpp — shows Artifacts: x/y label
  • MainWindow.h/.cpp — handles WinEvent, shows win screen
  • SchematicChoiceDialog.cpp — renders Artifact card without unlock annotation
  • src/test/ArtifactWinConditionTest.cpp — 11 new tests
## Summary - Adds an artifact win condition: when enemy defence stations are destroyed, a configurable chance (formula of station level) is rolled to include an "Artifact" option in the schematic choice dialog. If selected, the player's artifact count increments; reaching the configured win count ends the game with a "Won!" screen. - The current/max artifact count is always shown in the header bar as `Artifacts: x/y`. - Two new config fields in `world.toml` under `[artifacts]`: `artifact_chance_formula` (formula, x = station level) and `artifact_win_count` (integer). - 11 new Catch2 tests covering config parsing, artifact presence/absence in choices, count tracking, win condition, and reset behaviour. ## Changes - `WorldConfig.h` — new `WorldArtifacts` sub-struct - `ConfigLoader.cpp` — parses `[artifacts]` section - `world.toml` (app + test) — new `[artifacts]` section - `SchematicChoiceOption.h` — `Artifact` added to `SchematicType` enum - `Simulation.h/.cpp` — artifact count + win state, accessors, reset, `generateSchematicChoices`, `applySchematicChoice` - `ArtifactCountChangedEvent.h`, `WinEvent.h` — two new events - `GameWorldView.h/.cpp` — polls artifact count and win state, fires events - `HeaderBar.h/.cpp` — shows `Artifacts: x/y` label - `MainWindow.h/.cpp` — handles `WinEvent`, shows win screen - `SchematicChoiceDialog.cpp` — renders Artifact card without unlock annotation - `src/test/ArtifactWinConditionTest.cpp` — 11 new tests
mlangkabel added 3 commits 2026-06-30 08:22:42 +00:00
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
- Add [artifacts] config section to world.toml with artifact_chance_formula (x = station level) and artifact_win_count
- Roll artifact chance before each schematic drop; on success show 2 schematics + Artifact option instead of 3
- Selecting Artifact increments artifact count; reaching artifact_win_count triggers win screen
- Display "Artifacts: x/y" in header bar via ArtifactCountChangedEvent
- Win screen mirrors game-over screen with "Won!" caption and same Restart/Quit buttons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
mlangkabel added 1 commit 2026-07-01 19:32:45 +00:00
Resolves conflicts from the merged replay/command-chokepoint work:

- src/test/CMakeLists.txt: keep both new test sets (artifact + replay).
- GameWorldView::onFrame: keep the replay gate (if (!m_replayPlayer)) and
  place the artifact-count / win / game-over polls inside it, de-duplicating
  the game-over check.
- ArtifactWinConditionTest.cpp: route applySchematicChoice through
  SimulationTestAccess (the mutator is now private post-lockdown).
- Simulation::computeStateChecksum: fold in m_isWon and m_artifactCount so the
  new artifact state is covered by determinism/replay desync detection.

Simulation.h/.cpp auto-merged cleanly (applySchematicChoice landed private;
artifact accessors public; reset() clears artifact state; the artifact roll
draws from m_rng so it stays deterministic under replay).

All targets build; 365 cases / 3469 assertions pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
mlangkabel added 1 commit 2026-07-01 20:06:35 +00:00
The artifact-count poll was gated behind if (!m_replayPlayer) (from the merge
resolution), so ArtifactCountChangedEvent never fired in replay mode: the header
stayed at its initial "Artifacts: 0/?" literal and never reflected replayed
artifact picks.

Unlike the schematic/win/game-over polls (live-input sources / interruptions
that stay gated), artifact count is a passive reflection of sim state. Move it
out of the replay gate so it tracks m_sim->artifactCount() during playback too,
including the first-frame emit that populates the win-count max.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
mlangkabel added 1 commit 2026-07-01 20:14:44 +00:00
Playback only stopped when the recorded command stream ran out, so a run that
ended on the artifact win (e.g. 3/3) kept ticking during replay because win and
game-over are gated off in replay mode and the recording ran a few ticks past
the win.

Stop advancing when m_sim->isWon() || isGameOver() (in addition to the stream
end), and show it in the replay overlay: "Replay ended — Victory" / "— Defeat"
(desync still takes priority). This matches where the real game froze.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
mlangkabel merged commit 0a7e9a34ef into master 2026-07-01 20:27:30 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mlangkabel/dota_factory#3