diff --git a/src/components.rs b/src/components.rs index 9ba7e95..2d39775 100644 --- a/src/components.rs +++ b/src/components.rs @@ -69,3 +69,19 @@ impl FieldOfView { } } } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ProvidesHealing { + pub amount: i32, +} +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ProvidesDungeonMap; + +#[derive(Clone, PartialEq)] +pub struct Carried(pub Entity); + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ActivateItem { + pub used_by: Entity, + pub item: Entity, +} diff --git a/src/main.rs b/src/main.rs index 6fc17fd..53eac14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ impl State { map_builder .monster_spawns .iter() - .for_each(|pos| spawn_monster(&mut ecs, &mut rng, *pos)); + .for_each(|pos| spawn_entity(&mut ecs, &mut rng, *pos)); resources.insert(map_builder.map); resources.insert(Camera::new(map_builder.player_start)); @@ -95,7 +95,7 @@ impl State { map_builder .monster_spawns .iter() - .for_each(|pos| spawn_monster(&mut self.ecs, &mut rng, *pos)); + .for_each(|pos| spawn_entity(&mut self.ecs, &mut rng, *pos)); self.resources.insert(map_builder.map); self.resources.insert(Camera::new(map_builder.player_start)); self.resources.insert(TurnState::AwaitingInput); diff --git a/src/spawners.rs b/src/spawners.rs index 563aa98..65fec49 100644 --- a/src/spawners.rs +++ b/src/spawners.rs @@ -58,3 +58,36 @@ pub fn spawn_amulet_of_yala(ecs: &mut World, pos: Point) { Name("Amulet of Yala".to_string()), )); } +pub fn spawn_healing_potion(ecs: &mut World, pos: Point) { + ecs.push(( + Item, + pos, + Render { + color: ColorPair::new(WHITE, BLACK), + glyph: to_cp437('!'), + }, + Name("Healing Potion".to_string()), + ProvidesHealing { amount: 6 }, + )); +} +pub fn spawn_magic_mapper(ecs: &mut World, pos: Point) { + ecs.push(( + Item, + pos, + Render { + color: ColorPair::new(WHITE, BLACK), + glyph: to_cp437('{'), + }, + Name("Magic Map".to_string()), + ProvidesDungeonMap {}, + )); +} + +pub fn spawn_entity(ecs: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { + let roll = rng.roll_dice(1, 6); + match roll { + 1 => spawn_healing_potion(ecs, pos), + 2 => spawn_magic_mapper(ecs, pos), + _ => spawn_monster(ecs, rng, pos), + } +} diff --git a/src/systems/hud.rs b/src/systems/hud.rs index b64fa1f..710de75 100644 --- a/src/systems/hud.rs +++ b/src/systems/hud.rs @@ -3,6 +3,9 @@ use crate::prelude::*; #[system] #[read_component(Health)] #[read_component(Player)] +#[read_component(Item)] +#[read_component(Carried)] +#[read_component(Name)] pub fn hud(ecs: &SubWorld) { let mut health_query = <&Health>::query().filter(component::()); let player_health = health_query.iter(ecs).nth(0).unwrap(); @@ -22,5 +25,27 @@ pub fn hud(ecs: &SubWorld) { format!(" Health: {}/{} ", player_health.current, player_health.max,), ColorPair::new(WHITE, RED), ); + + let player = <(Entity, &Player)>::query() + .iter(ecs) + .find_map(|(entity, _player)| Some(*entity)) + .unwrap(); + let mut item_query = <(&Item, &Name, &Carried)>::query(); + let mut y = 3; + item_query + .iter(ecs) + .filter(|(_, _, carried)| carried.0 == player) + .for_each(|(_, name, _)| { + draw_batch.print(Point::new(3, y), format!("{} : {}", y - 2, &name.0)); + y += 1; + }); + if y > 3 { + draw_batch.print_color( + Point::new(3, 2), + "Items Carried", + ColorPair::new(YELLOW, BLACK), + ); + } + draw_batch.submit(10000).expect("Batch Error"); } diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 64d7c52..f58143d 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -10,6 +10,7 @@ mod movement; mod player_input; mod random_move; mod tooltips; +mod use_items; pub fn build_input_scheduler() -> Schedule { Schedule::builder() @@ -24,6 +25,7 @@ pub fn build_input_scheduler() -> Schedule { } pub fn build_player_scheduler() -> Schedule { Schedule::builder() + .add_system(use_items::use_items_system()) .add_system(combat::combat_system()) .flush() .add_system(movement::movement_system()) @@ -43,6 +45,7 @@ pub fn build_monster_scheduler() -> Schedule { .flush() .add_system(fov::fov_system()) .flush() + .add_system(use_items::use_items_system()) .add_system(combat::combat_system()) .flush() .add_system(movement::movement_system()) diff --git a/src/systems/player_input.rs b/src/systems/player_input.rs index a6e4d6b..5d9aa6a 100644 --- a/src/systems/player_input.rs +++ b/src/systems/player_input.rs @@ -5,6 +5,8 @@ use crate::prelude::*; #[read_component(Player)] #[read_component(Enemy)] #[write_component(Health)] +#[read_component(Item)] +#[read_component(Carried)] pub fn player_input( ecs: &mut SubWorld, commands: &mut CommandBuffer, @@ -18,6 +20,30 @@ pub fn player_input( VirtualKeyCode::Right => Point::new(1, 0), VirtualKeyCode::Up => Point::new(0, -1), VirtualKeyCode::Down => Point::new(0, 1), + VirtualKeyCode::G => { + let (player, player_pos) = players + .iter(ecs) + .find_map(|(entity, pos)| Some((*entity, *pos))) + .unwrap(); + let mut items = <(Entity, &Item, &Point)>::query(); + items + .iter(ecs) + .filter(|(_entity, _item, &item_pos)| item_pos == player_pos) + .for_each(|(entity, _item, _item_pos)| { + commands.remove_component::(*entity); + commands.add_component(*entity, Carried(player)); + }); + Point::new(0, 0) + } + VirtualKeyCode::Key1 => use_item(0, ecs, commands), + VirtualKeyCode::Key2 => use_item(1, ecs, commands), + VirtualKeyCode::Key3 => use_item(2, ecs, commands), + VirtualKeyCode::Key4 => use_item(3, ecs, commands), + VirtualKeyCode::Key5 => use_item(4, ecs, commands), + VirtualKeyCode::Key6 => use_item(5, ecs, commands), + VirtualKeyCode::Key7 => use_item(6, ecs, commands), + VirtualKeyCode::Key8 => use_item(7, ecs, commands), + VirtualKeyCode::Key9 => use_item(8, ecs, commands), _ => Point::new(0, 0), }; let (player_entity, destination) = players @@ -57,15 +83,30 @@ pub fn player_input( } } - 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; } } + +fn use_item(n: usize, ecs: &mut SubWorld, commands: &mut CommandBuffer) -> Point { + let player_entity = <(Entity, &Point)>::query() + .iter(ecs) + .find_map(|(entity, _player)| Some(*entity)) + .unwrap(); + let item_entity = <(Entity, &Item, &Carried)>::query() + .iter(ecs) + .filter(|(_, _, carried)| carried.0 == player_entity) + .enumerate() + .filter(|(item_count, (_, _, _))| *item_count == n) + .find_map(|(_, (item_entity, _, _))| Some(*item_entity)); + if let Some(item_entity) = item_entity { + commands.push(( + (), + ActivateItem { + used_by: player_entity, + item: item_entity, + }, + )); + } + + Point::zero() +} diff --git a/src/systems/use_items.rs b/src/systems/use_items.rs new file mode 100644 index 0000000..4eb7d56 --- /dev/null +++ b/src/systems/use_items.rs @@ -0,0 +1,32 @@ +use crate::prelude::*; + +#[system] +#[read_component(ActivateItem)] +#[read_component(ProvidesHealing)] +#[write_component(Health)] +#[read_component(ProvidesDungeonMap)] +pub fn use_items(ecs: &mut SubWorld, commands: &mut CommandBuffer, #[resource] map: &mut Map) { + let mut healing_to_apply = Vec::<(Entity, i32)>::new(); + <(Entity, &ActivateItem)>::query() + .iter(ecs) + .for_each(|(entity, activate)| { + let item = ecs.entry_ref(activate.item); + if let Ok(item) = item { + if let Ok(healing) = item.get_component::() { + healing_to_apply.push((activate.used_by, healing.amount)); + } + if let Ok(_mapper) = item.get_component::() { + map.revealed_tiles.iter_mut().for_each(|t| *t = true); + } + } + commands.remove(activate.item); + commands.remove(*entity); + }); + for heal in healing_to_apply.iter() { + if let Ok(mut target) = ecs.entry_mut(heal.0) { + if let Ok(health) = target.get_component_mut::() { + health.current = i32::min(health.max, health.current + heal.1); + } + } + } +}