feat(engine,core,data): add Challenge mode with seed list and level-5 gate
Phase 6 part 4b (partial): - GameMode::Challenge variant in solitaire_core. undo() returns RuleViolation when mode is Challenge so the player commits to each decision. - solitaire_data::challenge defines a stable CHALLENGE_SEEDS list with challenge_seed_for(index) wrapping modulo length. - PlayerProgress.challenge_index (serde-default for older saves) tracks how far the player has progressed. - ChallengePlugin advances the cursor on Challenge-mode wins, persists, and emits ChallengeAdvancedEvent. Pressing X starts a Challenge-mode game with the current seed; gated to level >= CHALLENGE_UNLOCK_LEVEL (5). - InputPlugin's Z key (Zen mode) is now also gated to level >= 5. Time Attack and unlock UI still deferred. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -24,10 +24,12 @@ use solitaire_core::pile::PileType;
|
||||
use solitaire_core::rules::{can_place_on_foundation, can_place_on_tableau};
|
||||
|
||||
use crate::card_plugin::{CardEntity, TABLEAU_FAN_FRAC};
|
||||
use crate::challenge_plugin::CHALLENGE_UNLOCK_LEVEL;
|
||||
use crate::events::{
|
||||
DrawRequestEvent, MoveRequestEvent, NewGameRequestEvent, StateChangedEvent, UndoRequestEvent,
|
||||
};
|
||||
use crate::game_plugin::GameMutation;
|
||||
use crate::progress_plugin::ProgressResource;
|
||||
use crate::layout::{Layout, LayoutResource};
|
||||
use crate::resources::{DragState, GameStateResource};
|
||||
|
||||
@@ -61,6 +63,7 @@ impl Plugin for InputPlugin {
|
||||
|
||||
fn handle_keyboard(
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
progress: Option<Res<ProgressResource>>,
|
||||
mut undo: EventWriter<UndoRequestEvent>,
|
||||
mut new_game: EventWriter<NewGameRequestEvent>,
|
||||
mut draw: EventWriter<DrawRequestEvent>,
|
||||
@@ -72,10 +75,20 @@ fn handle_keyboard(
|
||||
new_game.send(NewGameRequestEvent::default());
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyZ) {
|
||||
new_game.send(NewGameRequestEvent {
|
||||
seed: None,
|
||||
mode: Some(solitaire_core::game_state::GameMode::Zen),
|
||||
});
|
||||
// Zen / Challenge / Time Attack are gated to level >= CHALLENGE_UNLOCK_LEVEL.
|
||||
// X is gated separately by ChallengePlugin.
|
||||
let level = progress.as_ref().map_or(0, |p| p.0.level);
|
||||
if level >= CHALLENGE_UNLOCK_LEVEL {
|
||||
new_game.send(NewGameRequestEvent {
|
||||
seed: None,
|
||||
mode: Some(solitaire_core::game_state::GameMode::Zen),
|
||||
});
|
||||
} else {
|
||||
info!(
|
||||
"Zen mode locked — reach level {} (currently {}).",
|
||||
CHALLENGE_UNLOCK_LEVEL, level
|
||||
);
|
||||
}
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyD) {
|
||||
draw.send(DrawRequestEvent);
|
||||
|
||||
Reference in New Issue
Block a user