basic trap implementation

confusion on player is NYI
This commit is contained in:
Llywelwyn 2023-07-15 09:59:20 +01:00
parent 4dffdd361d
commit d316a55818
11 changed files with 257 additions and 43 deletions

View file

@ -209,7 +209,19 @@ pub struct Wand {
#[derive(Component, Debug, Serialize, Deserialize, Clone)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Destructible {} pub struct Destructible {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Hidden {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct SingleActivation {}
#[derive(Component, Clone, ConvertSaveload)] #[derive(Component, Clone, ConvertSaveload)]
pub struct ParticleLifetime { pub struct ParticleLifetime {
pub lifetime_ms: f32, pub lifetime_ms: f32,
} }
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct EntryTrigger {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct EntityMoved {}

View file

@ -1,6 +1,6 @@
use super::{ use super::{
gamelog, rex_assets::RexAssets, CombatStats, Equipped, HungerClock, HungerState, InBackpack, Map, Name, Player, gamelog, rex_assets::RexAssets, CombatStats, Equipped, Hidden, HungerClock, HungerState, InBackpack, Map, Name,
Point, Position, RunState, State, Viewshed, Player, Point, Position, RunState, State, Viewshed,
}; };
use rltk::{Rltk, VirtualKeyCode, RGB}; use rltk::{Rltk, VirtualKeyCode, RGB};
use specs::prelude::*; use specs::prelude::*;
@ -61,13 +61,14 @@ fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
let positions = ecs.read_storage::<Position>(); let positions = ecs.read_storage::<Position>();
let hidden = ecs.read_storage::<Hidden>();
let mouse_pos = ctx.mouse_pos(); let mouse_pos = ctx.mouse_pos();
if mouse_pos.0 >= map.width || mouse_pos.1 >= map.height { if mouse_pos.0 >= map.width || mouse_pos.1 >= map.height {
return; return;
} }
let mut tooltip: Vec<String> = Vec::new(); let mut tooltip: Vec<String> = Vec::new();
for (name, position) in (&names, &positions).join() { for (name, position, _hidden) in (&names, &positions, !&hidden).join() {
let idx = map.xy_idx(position.x, position.y); let idx = map.xy_idx(position.x, position.y);
if position.x == mouse_pos.0 && position.y == mouse_pos.1 && map.visible_tiles[idx] { if position.x == mouse_pos.0 && position.y == mouse_pos.1 && map.visible_tiles[idx] {
tooltip.push(name.name.to_string()); tooltip.push(name.name.to_string());

View file

@ -26,6 +26,7 @@ mod damage_system;
use damage_system::*; use damage_system::*;
mod hunger_system; mod hunger_system;
mod melee_combat_system; mod melee_combat_system;
mod trigger_system;
use melee_combat_system::MeleeCombatSystem; use melee_combat_system::MeleeCombatSystem;
mod inventory_system; mod inventory_system;
use inventory_system::*; use inventory_system::*;
@ -65,27 +66,31 @@ pub struct State {
impl State { impl State {
fn run_systems(&mut self) { fn run_systems(&mut self) {
let mut vis = VisibilitySystem {}; let mut vis = VisibilitySystem {};
vis.run_now(&self.ecs);
let mut mob = MonsterAI {}; let mut mob = MonsterAI {};
mob.run_now(&self.ecs);
let mut mapindex = MapIndexingSystem {}; let mut mapindex = MapIndexingSystem {};
mapindex.run_now(&self.ecs); let mut trigger_system = trigger_system::TriggerSystem {};
let mut inventory_system = ItemCollectionSystem {};
inventory_system.run_now(&self.ecs);
let mut item_use_system = ItemUseSystem {};
item_use_system.run_now(&self.ecs);
let mut item_drop_system = ItemDropSystem {};
item_drop_system.run_now(&self.ecs);
let mut item_remove_system = ItemRemoveSystem {};
item_remove_system.run_now(&self.ecs);
let mut melee_system = MeleeCombatSystem {}; let mut melee_system = MeleeCombatSystem {};
melee_system.run_now(&self.ecs);
let mut damage_system = DamageSystem {}; let mut damage_system = DamageSystem {};
damage_system.run_now(&self.ecs); let mut inventory_system = ItemCollectionSystem {};
let mut item_use_system = ItemUseSystem {};
let mut item_drop_system = ItemDropSystem {};
let mut item_remove_system = ItemRemoveSystem {};
let mut hunger_clock = hunger_system::HungerSystem {}; let mut hunger_clock = hunger_system::HungerSystem {};
hunger_clock.run_now(&self.ecs);
let mut particle_system = particle_system::ParticleSpawnSystem {}; let mut particle_system = particle_system::ParticleSpawnSystem {};
vis.run_now(&self.ecs);
mob.run_now(&self.ecs);
mapindex.run_now(&self.ecs);
trigger_system.run_now(&self.ecs);
melee_system.run_now(&self.ecs);
damage_system.run_now(&self.ecs);
inventory_system.run_now(&self.ecs);
item_use_system.run_now(&self.ecs);
item_drop_system.run_now(&self.ecs);
item_remove_system.run_now(&self.ecs);
hunger_clock.run_now(&self.ecs);
particle_system.run_now(&self.ecs); particle_system.run_now(&self.ecs);
self.ecs.maintain(); self.ecs.maintain();
} }
@ -248,12 +253,13 @@ impl GameState for State {
let positions = self.ecs.read_storage::<Position>(); let positions = self.ecs.read_storage::<Position>();
let renderables = self.ecs.read_storage::<Renderable>(); let renderables = self.ecs.read_storage::<Renderable>();
let minds = self.ecs.read_storage::<Mind>(); let minds = self.ecs.read_storage::<Mind>();
let hidden = self.ecs.read_storage::<Hidden>();
let map = self.ecs.fetch::<Map>(); let map = self.ecs.fetch::<Map>();
let entities = self.ecs.entities(); let entities = self.ecs.entities();
let mut data = (&positions, &renderables, &entities).join().collect::<Vec<_>>(); let mut data = (&positions, &renderables, &entities, !&hidden).join().collect::<Vec<_>>();
data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order)); data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order));
for (pos, render, ent) in data.iter() { for (pos, render, ent, _hidden) in data.iter() {
let idx = map.xy_idx(pos.x, pos.y); let idx = map.xy_idx(pos.x, pos.y);
let offsets = RGB::from_u8(map.red_offset[idx], map.green_offset[idx], map.blue_offset[idx]); let offsets = RGB::from_u8(map.red_offset[idx], map.green_offset[idx], map.blue_offset[idx]);
let mut bg = render.bg.add(RGB::from_u8(26, 45, 45)).add(offsets); let mut bg = render.bg.add(RGB::from_u8(26, 45, 45)).add(offsets);
@ -506,9 +512,13 @@ fn main() -> rltk::BError {
gs.ecs.register::<WantsToRemoveItem>(); gs.ecs.register::<WantsToRemoveItem>();
gs.ecs.register::<WantsToUseItem>(); gs.ecs.register::<WantsToUseItem>();
gs.ecs.register::<Consumable>(); gs.ecs.register::<Consumable>();
gs.ecs.register::<SingleActivation>();
gs.ecs.register::<Wand>(); gs.ecs.register::<Wand>();
gs.ecs.register::<ProvidesNutrition>(); gs.ecs.register::<ProvidesNutrition>();
gs.ecs.register::<Destructible>(); gs.ecs.register::<Destructible>();
gs.ecs.register::<Hidden>();
gs.ecs.register::<EntryTrigger>();
gs.ecs.register::<EntityMoved>();
gs.ecs.register::<ParticleLifetime>(); gs.ecs.register::<ParticleLifetime>();
gs.ecs.register::<SimpleMarker<SerializeMe>>(); gs.ecs.register::<SimpleMarker<SerializeMe>>();
gs.ecs.register::<SerializationHelper>(); gs.ecs.register::<SerializationHelper>();

View file

@ -127,14 +127,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
} }
let pos = positions.get(wants_melee.target); let pos = positions.get(wants_melee.target);
if let Some(pos) = pos { if let Some(pos) = pos {
particle_builder.request( particle_builder.damage_taken(pos.x, pos.y)
pos.x,
pos.y,
rltk::RGB::named(rltk::ORANGE),
rltk::RGB::named(rltk::BLACK),
rltk::to_cp437('‼'),
150.0,
);
} }
SufferDamage::new_damage(&mut inflict_damage, wants_melee.target, damage); SufferDamage::new_damage(&mut inflict_damage, wants_melee.target, damage);
} }

View file

@ -1,4 +1,6 @@
use super::{gamelog, Confusion, Map, Monster, Name, ParticleBuilder, Position, RunState, Viewshed, WantsToMelee}; use super::{
gamelog, Confusion, EntityMoved, Map, Monster, Name, ParticleBuilder, Position, RunState, Viewshed, WantsToMelee,
};
use rltk::Point; use rltk::Point;
use specs::prelude::*; use specs::prelude::*;
@ -19,6 +21,7 @@ impl<'a> System<'a> for MonsterAI {
WriteStorage<'a, Confusion>, WriteStorage<'a, Confusion>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
WriteExpect<'a, ParticleBuilder>, WriteExpect<'a, ParticleBuilder>,
WriteStorage<'a, EntityMoved>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -35,6 +38,7 @@ impl<'a> System<'a> for MonsterAI {
mut confused, mut confused,
name, name,
mut particle_builder, mut particle_builder,
mut entity_moved,
) = data; ) = data;
if *runstate != RunState::MonsterTurn { if *runstate != RunState::MonsterTurn {
@ -88,6 +92,7 @@ impl<'a> System<'a> for MonsterAI {
idx = map.xy_idx(pos.x, pos.y); idx = map.xy_idx(pos.x, pos.y);
map.blocked[idx] = true; map.blocked[idx] = true;
viewshed.dirty = true; viewshed.dirty = true;
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert marker");
} }
} }
} }

View file

@ -55,6 +55,10 @@ impl ParticleBuilder {
self.requests.push(ParticleRequest { x, y, fg, bg, glyph, lifetime }); self.requests.push(ParticleRequest { x, y, fg, bg, glyph, lifetime });
} }
pub fn damage_taken(&mut self, x: i32, y: i32) {
self.request(x, y, rltk::RGB::named(rltk::ORANGE), rltk::RGB::named(rltk::BLACK), rltk::to_cp437('‼'), 200.0);
}
// Makes a particle request in the shape of an 'x'. Sort of. // Makes a particle request in the shape of an 'x'. Sort of.
pub fn request_star(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32) { pub fn request_star(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32) {
self.request(x, y, fg, bg, glyph, lifetime * 2.0); self.request(x, y, fg, bg, glyph, lifetime * 2.0);

View file

@ -1,6 +1,6 @@
use super::{ use super::{
gamelog, CombatStats, HungerClock, HungerState, Item, Map, Monster, Name, Player, Position, RunState, State, gamelog, CombatStats, EntityMoved, Hidden, HungerClock, HungerState, Item, Map, Monster, Name, Player, Position,
Telepath, TileType, Viewshed, WantsToMelee, WantsToPickupItem, MAPHEIGHT, MAPWIDTH, RunState, State, Telepath, TileType, Viewshed, WantsToMelee, WantsToPickupItem, MAPHEIGHT, MAPWIDTH,
}; };
use rltk::{Point, RandomNumberGenerator, Rltk, VirtualKeyCode}; use rltk::{Point, RandomNumberGenerator, Rltk, VirtualKeyCode};
use specs::prelude::*; use specs::prelude::*;
@ -11,6 +11,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
let mut players = ecs.write_storage::<Player>(); let mut players = ecs.write_storage::<Player>();
let mut viewsheds = ecs.write_storage::<Viewshed>(); let mut viewsheds = ecs.write_storage::<Viewshed>();
let mut telepaths = ecs.write_storage::<Telepath>(); let mut telepaths = ecs.write_storage::<Telepath>();
let mut entity_moved = ecs.write_storage::<EntityMoved>();
let combat_stats = ecs.read_storage::<CombatStats>(); let combat_stats = ecs.read_storage::<CombatStats>();
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
@ -37,14 +38,18 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
if !map.blocked[destination_idx] { if !map.blocked[destination_idx] {
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
let hidden = ecs.read_storage::<Hidden>();
// Push every entity name in the pile to a vector of strings // Push every entity name in the pile to a vector of strings
let mut item_names: Vec<String> = Vec::new(); let mut item_names: Vec<String> = Vec::new();
let mut some = false; let mut some = false;
for entity in map.tile_content[destination_idx].iter() { for entity in map.tile_content[destination_idx].iter() {
if let Some(name) = names.get(*entity) { if let Some(_hidden) = hidden.get(*entity) {
let item_name = &name.name; } else {
item_names.push(item_name.to_string()); if let Some(name) = names.get(*entity) {
some = true; let item_name = &name.name;
item_names.push(item_name.to_string());
some = true;
}
} }
} }
// If some names were found, append. Logger = logger is necessary // If some names were found, append. Logger = logger is necessary
@ -74,6 +79,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
let mut ppos = ecs.write_resource::<Point>(); let mut ppos = ecs.write_resource::<Point>();
ppos.x = pos.x; ppos.x = pos.x;
ppos.y = pos.y; ppos.y = pos.y;
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert marker");
} }
} }
} }

View file

@ -55,8 +55,11 @@ pub fn save_game(ecs: &mut World) {
Cursed, Cursed,
DefenceBonus, DefenceBonus,
Destructible, Destructible,
EntityMoved,
EntryTrigger,
Equippable, Equippable,
Equipped, Equipped,
Hidden,
HungerClock, HungerClock,
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
@ -73,6 +76,7 @@ pub fn save_game(ecs: &mut World) {
ProvidesNutrition, ProvidesNutrition,
Ranged, Ranged,
Renderable, Renderable,
SingleActivation,
SufferDamage, SufferDamage,
Telepath, Telepath,
Viewshed, Viewshed,
@ -143,8 +147,11 @@ pub fn load_game(ecs: &mut World) {
Cursed, Cursed,
DefenceBonus, DefenceBonus,
Destructible, Destructible,
EntityMoved,
EntryTrigger,
Equippable, Equippable,
Equipped, Equipped,
Hidden,
HungerClock, HungerClock,
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
@ -161,6 +168,7 @@ pub fn load_game(ecs: &mut World) {
ProvidesNutrition, ProvidesNutrition,
Ranged, Ranged,
Renderable, Renderable,
SingleActivation,
SufferDamage, SufferDamage,
Telepath, Telepath,
Viewshed, Viewshed,

View file

@ -1,8 +1,8 @@
use super::{ use super::{
random_table::RandomTable, BlocksTile, CombatStats, Confusion, Consumable, Cursed, DefenceBonus, Destructible, random_table::RandomTable, BlocksTile, CombatStats, Confusion, Consumable, Cursed, DefenceBonus, Destructible,
EquipmentSlot, Equippable, HungerClock, HungerState, InflictsDamage, Item, MagicMapper, MeleePowerBonus, Mind, EntryTrigger, EquipmentSlot, Equippable, Hidden, HungerClock, HungerState, InflictsDamage, Item, MagicMapper,
Monster, Name, Player, Position, ProvidesHealing, ProvidesNutrition, Ranged, Rect, Renderable, SerializeMe, MeleePowerBonus, Mind, Monster, Name, Player, Position, ProvidesHealing, ProvidesNutrition, Ranged, Rect,
Viewshed, Wand, AOE, MAPWIDTH, Renderable, SerializeMe, SingleActivation, Viewshed, Wand, AOE, MAPWIDTH,
}; };
use rltk::{console, RandomNumberGenerator, RGB}; use rltk::{console, RandomNumberGenerator, RGB};
use specs::prelude::*; use specs::prelude::*;
@ -99,6 +99,7 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
"mob" => spawn_table = mob_table(map_depth), "mob" => spawn_table = mob_table(map_depth),
"item" => spawn_table = item_table(map_depth), "item" => spawn_table = item_table(map_depth),
"food" => spawn_table = food_table(map_depth), "food" => spawn_table = food_table(map_depth),
"trap" => spawn_table = trap_table(map_depth),
_ => spawn_table = debug_table(), _ => spawn_table = debug_table(),
} }
spawn_points.insert(idx, spawn_table.roll(&mut rng)); spawn_points.insert(idx, spawn_table.roll(&mut rng));
@ -138,16 +139,20 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
// Wands // Wands
"magic missile wand" => magic_missile_wand(ecs, x, y), "magic missile wand" => magic_missile_wand(ecs, x, y),
"fireball wand" => fireball_wand(ecs, x, y), "fireball wand" => fireball_wand(ecs, x, y),
"confusion wand" => confusion_wand(ecs, x, y),
// Food // Food
"rations" => rations(ecs, x, y), "rations" => rations(ecs, x, y),
// Traps
"bear trap" => bear_trap(ecs, x, y),
"confusion trap" => confusion_trap(ecs, x, y),
_ => console::log("Tried to spawn nothing. Bugfix needed!"), _ => console::log("Tried to spawn nothing. Bugfix needed!"),
} }
} }
} }
// 10 mobs : 3 items : 1 food // 20 mobs : 6 items : 2 food : 1 trap
fn category_table() -> RandomTable { fn category_table() -> RandomTable {
return RandomTable::new().add("mob", 9).add("item", 3).add("food", 1); return RandomTable::new().add("mob", 20).add("item", 6).add("food", 2).add("trap", 1000);
} }
fn debug_table() -> RandomTable { fn debug_table() -> RandomTable {
@ -183,13 +188,18 @@ fn item_table(_map_depth: i32) -> RandomTable {
.add("cursed magic map scroll", 2) .add("cursed magic map scroll", 2)
// Wands // Wands
.add("magic missile wand", 1) .add("magic missile wand", 1)
.add("fireball wand", 1); .add("fireball wand", 1)
.add("confusion wand", 1);
} }
fn food_table(_map_depth: i32) -> RandomTable { fn food_table(_map_depth: i32) -> RandomTable {
return RandomTable::new().add("rations", 1); return RandomTable::new().add("rations", 1);
} }
fn trap_table(_map_depth: i32) -> RandomTable {
return RandomTable::new().add("bear trap", 0).add("confusion trap", 1);
}
fn health_potion(ecs: &mut World, x: i32, y: i32) { fn health_potion(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity() ecs.create_entity()
.with(Position { x, y }) .with(Position { x, y })
@ -478,7 +488,7 @@ fn magic_missile_wand(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity() ecs.create_entity()
.with(Position { x, y }) .with(Position { x, y })
.with(Renderable { .with(Renderable {
glyph: rltk::to_cp437('?'), glyph: rltk::to_cp437('/'),
fg: RGB::named(rltk::BLUE), fg: RGB::named(rltk::BLUE),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 2, render_order: 2,
@ -492,3 +502,59 @@ fn magic_missile_wand(ecs: &mut World, x: i32, y: i32) {
.marked::<SimpleMarker<SerializeMe>>() .marked::<SimpleMarker<SerializeMe>>()
.build(); .build();
} }
fn confusion_wand(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('/'),
fg: RGB::named(rltk::PURPLE),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "wand of confusion".to_string() })
.with(Item {})
.with(Wand { uses: 3, max_uses: 3 })
.with(Destructible {})
.with(Ranged { range: 10 })
.with(Confusion { turns: 4 })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}
// TRAPS
fn bear_trap(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('^'),
fg: RGB::named(rltk::GREY),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "bear trap".to_string() })
.with(Hidden {})
.with(EntryTrigger {})
.with(SingleActivation {})
.with(InflictsDamage { amount: 6 })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}
fn confusion_trap(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('^'),
fg: RGB::named(rltk::PURPLE),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "magic trap".to_string() })
.with(Hidden {})
.with(EntryTrigger {})
.with(SingleActivation {})
.with(Confusion { turns: 3 })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}

88
src/trigger_system.rs Normal file
View file

@ -0,0 +1,88 @@
use super::{
gamelog, Confusion, EntityMoved, EntryTrigger, Hidden, InflictsDamage, Map, Name, ParticleBuilder, Position,
SingleActivation, SufferDamage,
};
use specs::prelude::*;
pub struct TriggerSystem {}
impl<'a> System<'a> for TriggerSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
ReadExpect<'a, Map>,
WriteStorage<'a, EntityMoved>,
ReadStorage<'a, Position>,
ReadStorage<'a, EntryTrigger>,
ReadStorage<'a, InflictsDamage>,
WriteStorage<'a, Confusion>,
WriteStorage<'a, SufferDamage>,
WriteStorage<'a, Hidden>,
ReadStorage<'a, SingleActivation>,
ReadStorage<'a, Name>,
WriteExpect<'a, ParticleBuilder>,
Entities<'a>,
);
fn run(&mut self, data: Self::SystemData) {
let (
map,
mut entity_moved,
position,
entry_trigger,
inflicts_damage,
mut confusion,
mut inflict_damage,
mut hidden,
single_activation,
names,
mut particle_builder,
entities,
) = data;
// Iterate entities that moved, and their final position
let mut remove_entities: Vec<Entity> = Vec::new();
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() {
let idx = map.xy_idx(pos.x, pos.y);
for entity_id in map.tile_content[idx].iter() {
if entity != *entity_id {
let maybe_trigger = entry_trigger.get(*entity_id);
match maybe_trigger {
None => {}
Some(_trigger) => {
// Something on this pos had a trigger
let name = names.get(*entity_id);
hidden.remove(*entity_id);
if let Some(name) = name {
gamelog::Logger::new().item_name(&name.name).append("triggers!").log();
}
let damage = inflicts_damage.get(*entity_id);
if let Some(damage) = damage {
particle_builder.damage_taken(pos.x, pos.y);
SufferDamage::new_damage(&mut inflict_damage, entity, damage.amount);
}
let confuses = confusion.get(*entity_id);
if let Some(confuses) = confuses {
confusion
.insert(entity, Confusion { turns: confuses.turns })
.expect("Unable to insert confusion");
}
let sa = single_activation.get(*entity_id);
if let Some(_sa) = sa {
remove_entities.push(*entity_id);
}
}
}
}
}
}
for trap in remove_entities.iter() {
entities.delete(*trap).expect("Unable to delete trap");
}
entity_moved.clear();
}
}

View file

@ -1,4 +1,4 @@
use super::{Map, Player, Position, Telepath, Viewshed}; use super::{gamelog, Hidden, Map, Name, Player, Position, Telepath, Viewshed};
use rltk::{FieldOfViewAlg::SymmetricShadowcasting, Point}; use rltk::{FieldOfViewAlg::SymmetricShadowcasting, Point};
use specs::prelude::*; use specs::prelude::*;
@ -7,15 +7,18 @@ pub struct VisibilitySystem {}
impl<'a> System<'a> for VisibilitySystem { impl<'a> System<'a> for VisibilitySystem {
type SystemData = ( type SystemData = (
WriteExpect<'a, Map>, WriteExpect<'a, Map>,
WriteExpect<'a, rltk::RandomNumberGenerator>,
Entities<'a>, Entities<'a>,
WriteStorage<'a, Viewshed>, WriteStorage<'a, Viewshed>,
WriteStorage<'a, Telepath>, WriteStorage<'a, Telepath>,
WriteStorage<'a, Position>, WriteStorage<'a, Position>,
ReadStorage<'a, Player>, ReadStorage<'a, Player>,
WriteStorage<'a, Hidden>,
ReadStorage<'a, Name>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let (mut map, entities, mut viewshed, mut telepath, pos, player) = data; let (mut map, mut rng, entities, mut viewshed, mut telepath, pos, player, mut hidden, names) = data;
for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() { for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() {
if viewshed.dirty { if viewshed.dirty {
@ -44,6 +47,24 @@ impl<'a> System<'a> for VisibilitySystem {
let idx = map.xy_idx(vis.x, vis.y); let idx = map.xy_idx(vis.x, vis.y);
map.revealed_tiles[idx] = true; map.revealed_tiles[idx] = true;
map.visible_tiles[idx] = true; map.visible_tiles[idx] = true;
// Reveal hidden things
for thing in map.tile_content[idx].iter() {
let is_hidden = hidden.get(*thing);
if let Some(_is_hidden) = is_hidden {
if rng.roll_dice(1, 20) == 1 {
let name = names.get(*thing);
if let Some(name) = name {
gamelog::Logger::new()
.append("You spot a")
.item_name_n(&name.name)
.period()
.log();
}
hidden.remove(*thing);
}
}
}
} }
} }
} }