From 4fbb2a881a8431e6a6f386a8fb56dd337f30c79e Mon Sep 17 00:00:00 2001 From: Tyrel Souza <923113+tyrelsouza@users.noreply.github.com> Date: Sun, 29 Aug 2021 23:50:50 -0400 Subject: [PATCH] finished combat chapter 8 --- src/components.rs | 6 ++++ src/systems/combat.rs | 27 +++++++++++++++++ src/systems/mod.rs | 5 ++++ src/systems/player_input.rs | 58 ++++++++++++++++++++++++++++++------- src/systems/random_move.rs | 43 ++++++++++++++++++++++----- 5 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 src/systems/combat.rs diff --git a/src/components.rs b/src/components.rs index bc9fdf0..abc6b5c 100644 --- a/src/components.rs +++ b/src/components.rs @@ -21,6 +21,12 @@ pub struct WantsToMove { pub destination: Point, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct WantsToAttack { + pub attacker: Entity, + pub victim: Entity, +} + #[derive(Clone, Copy, Debug, PartialEq)] pub struct Health { pub current: i32, diff --git a/src/systems/combat.rs b/src/systems/combat.rs new file mode 100644 index 0000000..f30c886 --- /dev/null +++ b/src/systems/combat.rs @@ -0,0 +1,27 @@ +use crate::prelude::*; + +#[system] +#[read_component(WantsToAttack)] +#[write_component(Health)] +pub fn combat(ecs: &mut SubWorld, commands: &mut CommandBuffer) { + let mut attackers = <(Entity, &WantsToAttack)>::query(); + let victims: Vec<(Entity, Entity)> = attackers + .iter(ecs) + .map(|(entity, attack)| (*entity, attack.victim)) + .collect(); + victims.iter().for_each(|(message, victim)| { + if let Ok(mut health) = ecs + .entry_mut(*victim) + .unwrap() + .get_component_mut::() + { + println!("Health before attack: {}", health.current); + health.current -= 1; + if health.current < 1 { + commands.remove(*victim); + } + println!("Health after attack: {}", health.current); + } + commands.remove(*message); + }); +} diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 3a09969..c3cb65b 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +mod combat; mod end_turn; mod entity_render; mod hud; @@ -20,6 +21,8 @@ pub fn input_build_scheduler() -> Schedule { } pub fn player_build_scheduler() -> Schedule { Schedule::builder() + .add_system(combat::combat_system()) + .flush() .add_system(movement::movement_system()) .flush() .add_system(map_render::map_render_system()) @@ -32,6 +35,8 @@ pub fn monster_build_scheduler() -> Schedule { Schedule::builder() .add_system(random_move::random_move_system()) .flush() + .add_system(combat::combat_system()) + .flush() .add_system(movement::movement_system()) .flush() .add_system(map_render::map_render_system()) diff --git a/src/systems/player_input.rs b/src/systems/player_input.rs index 74d49ad..a6e4d6b 100644 --- a/src/systems/player_input.rs +++ b/src/systems/player_input.rs @@ -3,6 +3,8 @@ use crate::prelude::*; #[system] #[read_component(Point)] #[read_component(Player)] +#[read_component(Enemy)] +#[write_component(Health)] pub fn player_input( ecs: &mut SubWorld, commands: &mut CommandBuffer, @@ -18,16 +20,52 @@ pub fn player_input( VirtualKeyCode::Down => Point::new(0, 1), _ => Point::new(0, 0), }; - players.iter(ecs).for_each(|(entity, pos)| { - let destination = *pos + delta; - commands.push(( - (), - WantsToMove { - entity: *entity, - destination, - }, - )); - }); + let (player_entity, destination) = players + .iter(ecs) + .find_map(|(entity, pos)| Some((*entity, *pos + delta))) + .unwrap(); + let mut enemies = <(Entity, &Point)>::query().filter(component::()); + + let mut did_something = false; + if delta.x != 0 || delta.y != 0 { + let mut hit_something = false; + enemies + .iter(ecs) + .filter(|(_, pos)| **pos == destination) + .for_each(|(entity, _)| { + hit_something = true; + did_something = true; + + commands.push(( + (), + WantsToAttack { + attacker: player_entity, + victim: *entity, + }, + )); + }); + + if !hit_something { + did_something = true; + commands.push(( + (), + WantsToMove { + entity: player_entity, + destination, + }, + )); + } + } + + if !did_something { + if let Ok(mut health) = ecs + .entry_mut(player_entity) + .unwrap() + .get_component_mut::() + { + health.current = i32::min(health.max, health.current + 1); + } + } *turn_state = TurnState::PlayerTurn; } } diff --git a/src/systems/random_move.rs b/src/systems/random_move.rs index 0931d85..048385a 100644 --- a/src/systems/random_move.rs +++ b/src/systems/random_move.rs @@ -3,9 +3,12 @@ pub use crate::prelude::*; #[system] #[read_component(Point)] #[read_component(MovingRandomly)] +#[read_component(Health)] +#[read_component(Player)] pub fn random_move(ecs: &mut SubWorld, commands: &mut CommandBuffer) { let mut movers = <(Entity, &Point, &MovingRandomly)>::query(); - movers.iter_mut(ecs).for_each(|(entity, pos, _)| { + let mut positions = <(Entity, &Point, &Health)>::query(); + movers.iter(ecs).for_each(|(entity, pos, _)| { let mut rng = RandomNumberGenerator::new(); let destination = match rng.range(0, 4) { 0 => Point::new(-1, 0), @@ -13,12 +16,36 @@ pub fn random_move(ecs: &mut SubWorld, commands: &mut CommandBuffer) { 2 => Point::new(0, -1), _ => Point::new(0, 1), } + *pos; - commands.push(( - (), - WantsToMove { - entity: *entity, - destination, - }, - )); + let mut attacked = false; + positions + .iter(ecs) + .filter(|(_, target_pos, _)| **target_pos == destination) + .for_each(|(victim, _, _)| { + if ecs + .entry_ref(*victim) + .unwrap() + .get_component::() + .is_ok() + { + commands.push(( + (), + WantsToAttack { + attacker: *entity, + victim: *victim, + }, + )); + } + attacked = true + }); + + if !attacked { + commands.push(( + (), + WantsToMove { + entity: *entity, + destination, + }, + )); + } }); }