use crate::rules::*;
use std::io::Read;
use weasel::creature::CreatureId;
use weasel::team::TeamId;
use weasel::{
ActivateAbility, Battle, BattleController, CreateCreature, CreateTeam, EndTurn, EntityId,
EventKind, EventReceiver, EventTrigger, Server, StartTurn, VersionedEventWrapper,
};
mod rules;
static TEAM_ID: TeamId<CustomRules> = 0;
static CREATURE_ID: CreatureId<CustomRules> = 0;
static ENTITY_ID: EntityId<CustomRules> = EntityId::Creature(CREATURE_ID);
fn main() {
print_intro();
game_loop();
println!();
println!("Goodbye!");
}
fn print_intro() {
println!("Undo");
println!();
println!("Example to demonstrate how to undo/redo player actions with weasel.");
println!("Move around the soldier on the battlefield.");
println!();
print_controls();
}
fn print_controls() {
println!(" Controls:");
println!(" w - Move up");
println!(" s - Move down");
println!(" d - Move right");
println!(" a - Move left");
println!(" u - Undo");
println!(" r - Redo");
println!(" h - Display the controls");
println!(" q - Quit");
}
fn game_loop() {
let mut server = create_game();
let mut event_buffer = Vec::new();
println!();
display_world(&server);
loop {
let input: Option<char> = std::io::stdin()
.bytes()
.next()
.and_then(|result| result.ok())
.map(|byte| byte as char);
if let Some(key) = input {
match key {
'w' => {
walk(&mut server, &mut event_buffer, Direction::Up);
display_world(&server);
}
's' => {
walk(&mut server, &mut event_buffer, Direction::Down);
display_world(&server);
}
'd' => {
walk(&mut server, &mut event_buffer, Direction::Right);
display_world(&server);
}
'a' => {
walk(&mut server, &mut event_buffer, Direction::Left);
display_world(&server);
}
'u' => {
server = undo(server, &mut event_buffer);
display_world(&server);
}
'r' => {
redo(&mut server, &mut event_buffer);
display_world(&server);
}
'h' => print_controls(),
'q' => break,
_ => {}
}
}
}
}
fn display_world(server: &Server<CustomRules>) {
let steps = server
.battle()
.history()
.events()
.iter()
.filter(|e| e.kind() == EventKind::ActivateAbility)
.count();
let battlefield = server.battle().space().model();
println!("Steps: {}\nBattlefield:\n{}", steps, battlefield);
}
fn create_server() -> Server<CustomRules> {
let battle = Battle::builder(CustomRules::new()).build();
Server::builder(battle).build()
}
fn create_game() -> Server<CustomRules> {
let mut server = create_server();
CreateTeam::trigger(&mut server, TEAM_ID).fire().unwrap();
CreateCreature::trigger(&mut server, CREATURE_ID, TEAM_ID, Square { x: 0, y: 0 })
.fire()
.unwrap();
server
}
fn walk(
server: &mut Server<CustomRules>,
event_buffer: &mut Vec<VersionedEventWrapper<CustomRules>>,
direction: Direction,
) {
event_buffer.clear();
StartTurn::trigger(server, ENTITY_ID).fire().unwrap();
let result = ActivateAbility::trigger(server, ENTITY_ID, WALK)
.activation(direction)
.fire();
if let Err(e) = result {
println!("{:?}", e.unfold());
}
EndTurn::trigger(server).fire().unwrap();
}
fn undo(
server: Server<CustomRules>,
event_buffer: &mut Vec<VersionedEventWrapper<CustomRules>>,
) -> Server<CustomRules> {
let last_activation_index = server
.battle()
.history()
.events()
.iter()
.rposition(|e| e.kind() == EventKind::ActivateAbility);
match last_activation_index {
Some(last_activation_index) => {
if event_buffer.is_empty() {
let mut events = server
.battle()
.versioned_events(std::ops::Range {
start: 0,
end: server.battle().history().len() as usize,
})
.collect();
event_buffer.append(&mut events);
}
let mut server = create_server();
let previous_start_turn_index = &event_buffer[..last_activation_index]
.iter()
.rposition(|e| e.kind() == EventKind::StartTurn);
for event in event_buffer
.iter()
.take(previous_start_turn_index.unwrap() as usize)
{
server.receive(event.clone()).unwrap();
}
server
}
None => {
server
}
}
}
fn redo(
server: &mut Server<CustomRules>,
event_buffer: &mut Vec<VersionedEventWrapper<CustomRules>>,
) {
let history_len = server.battle().history().events().len();
if event_buffer.len() > history_len {
let future_events = &event_buffer[history_len..];
let next_activation = future_events
.iter()
.position(|e| e.kind() == EventKind::ActivateAbility);
if let Some(next_activation) = next_activation {
let end_turn = &future_events[next_activation..]
.iter()
.position(|e| e.kind() == EventKind::EndTurn)
.unwrap();
let end_turn = end_turn + next_activation;
for event in &future_events[..=end_turn] {
server.receive(event.clone()).unwrap();
}
}
}
}