main
Elijah C. Voigt 1 year ago
parent fcf89e91fc
commit d045800ae3

@ -269,4 +269,12 @@ QueenRed = "QueenRedPieceIdle"
fast_movement_speed = 1.0
fast_text_speed = 999.0
fast_dissolve_speed = 1.0
fast_light_speed = 1.0
fast_light_speed = 1.0
##############
### Game rules
##############
# 0: Disabled
# -1: No limit
# N: Some value in-between
undo_limit = -1

@ -1117,7 +1117,7 @@ fn capture_piece_end(
mut events: RemovedComponents<Dissolving>,
mut query: Query<(Entity, &Dissolvable, &Side, &mut Transform), With<BeingCaptured>>,
mut commands: Commands,
board: Res<game::Board>,
score: Res<game::Score>,
) {
events.read().for_each(|e| {
@ -1128,7 +1128,7 @@ fn capture_piece_end(
.entity(entity)
.insert(Dissolving::In(dissolvable.duration))
.remove::<BeingCaptured>()
.insert(Captured);
.insert(Captured { epoch: board.current_epoch() - 1 });
}
});
}

@ -12,7 +12,10 @@ impl Plugin for GamePlugin {
.add_systems(OnEnter(GameState::Play), hide_valid_moves)
.add_systems(
Update,
manage_state_entities::<GameState>().run_if(state_changed::<GameState>),
(
manage_state_entities::<GameState>().run_if(state_changed::<GameState>),
undo_move.run_if(just_pressed(KeyCode::KeyU)),
)
)
.add_systems(
Update,
@ -183,7 +186,9 @@ pub(crate) struct BeingCaptured;
/// Marker for component which is captured
#[derive(Debug, Component)]
pub(crate) struct Captured;
pub(crate) struct Captured {
pub epoch: usize,
}
#[derive(Debug, Component)]
pub(crate) struct Promoted;
@ -253,6 +258,7 @@ pub(crate) struct Board {
#[derive(Debug, Default, Event, Clone)]
pub(crate) struct Move {
pub epoch: usize,
pub piece: Option<Piece>,
pub from: BoardIndex,
pub to: Option<BoardIndex>,
pub move_type: MoveType,
@ -437,6 +443,7 @@ impl Board {
if self.inner[to.y][to.x].is_some() {
moves.push(Move {
epoch,
piece: self.at(to).copied(),
from: to,
to: None,
move_type: move_type.clone(),
@ -446,6 +453,7 @@ impl Board {
// Capture the intended move in the moves ledger
moves.push(Move {
epoch,
piece: self.at(from).copied(),
from,
to: Some(to),
move_type: move_type.clone(),
@ -478,6 +486,29 @@ impl Board {
}
}
/// Undo the last move
fn undo_move(&mut self) -> Vec<Move> {
let latest_epoch = self.current_epoch() - 1;
let mut moves = vec![];
while let Some(last) = self.moves.last() {
if last.epoch == latest_epoch {
let last = self.moves.pop().unwrap();
self.inner[last.from.y][last.from.x] = last.piece;
if let Some(to) = last.to {
self.inner[to.y][to.x] = None;
}
moves.push(last);
} else {
break;
}
}
info!("Remaining moves: {:?}", self.moves);
return moves;
}
/// Returns the Side of a piece
pub(crate) fn side(BoardIndex { x, .. }: BoardIndex) -> Result<Side, GameError> {
match x {
@ -576,6 +607,7 @@ impl Board {
Some(MoveType::Capture)
}
None => {
info!("Last move: {:?}", self.moves.last());
// move is valid if it does not un-do the previous move for this piece
match self.moves.last() {
Some(previous) => {
@ -1505,4 +1537,58 @@ fn assert_piece_consistency(
info!("Active: {} | being captured: {} | captured: {}", active_count, being_captured_count, captured_count);
let total_count = active_count + being_captured_count + captured_count;
assert_eq!(total_count, 18, "Pieces does does not add up!");
}
// When user presses 'u' last move is undone
fn undo_move(
mut board: ResMut<Board>,
mut active_pieces: Query<&mut BoardIndex, With<Piece>>,
captured_pieces: Query<(Entity, &Captured), With<Piece>>,
turn: Res<State<TurnState>>,
mut next_turn: ResMut<NextState<TurnState>>,
mut commands: Commands,
) {
// Keep track of the current side in case we need to go back
let mut side = turn.get().0;
board
.undo_move()
.iter()
.for_each(|Move { epoch, from, to, .. }| {
// If we have any moves to do, go back to the opposite side
if side == turn.get().0 {
side = !turn.get().0;
}
info!("Reverting move {:?} {:?} -> {:?}", epoch, from, to);
match to { Some(to_idx) => { info!("Moving piece back from {:?}", to_idx);
// Find piece currently at "to_idx" and update it's position to "from"
active_pieces
.iter_mut()
.filter(|idx| {
(idx.x, idx.y) == (to_idx.x, to_idx.y)
})
.for_each(|mut idx| {
*idx = *from
});
},
None => {
captured_pieces
.iter()
.find_map(|(entity, captured)| {
(captured.epoch == *epoch).then_some(entity)
})
.iter()
.for_each(|entity| {
commands
.entity(*entity)
.remove::<Captured>()
.insert(*from);
});
}
}
});
// Set the turn state (may be a no-op)
next_turn.set(TurnState(side));
}
Loading…
Cancel
Save