Add a basic hidden trap mechanism
This commit is contained in:
parent
32874bf9f5
commit
804904dd4b
@ -199,6 +199,15 @@ pub struct ProvidesFood {}
|
|||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct MagicMapper {}
|
pub struct MagicMapper {}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Hidden {}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct EntryTrigger {}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct EntityMoved {}
|
||||||
|
|
||||||
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
|
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
|
||||||
// Entity.
|
// Entity.
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::components::{
|
use crate::components::{
|
||||||
CombatStats, HungerClock, HungerState, InBackpack, Name, Player, Position, Viewshed,
|
CombatStats, HungerClock, HungerState, InBackpack, Name, Player, Position, Viewshed,
|
||||||
};
|
};
|
||||||
use crate::{game_log::GameLog, rex_assets::RexAssets, Equipped, Map, RunState, State};
|
use crate::{game_log::GameLog, rex_assets::RexAssets, Equipped, Hidden, Map, RunState, State};
|
||||||
use rltk::{Point, Rltk, VirtualKeyCode, RGB};
|
use rltk::{Point, Rltk, VirtualKeyCode, RGB};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
@ -98,6 +98,7 @@ 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 {
|
||||||
@ -105,7 +106,7 @@ fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||||||
}
|
}
|
||||||
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());
|
||||||
|
13
src/main.rs
13
src/main.rs
@ -19,6 +19,7 @@ mod rect;
|
|||||||
mod rex_assets;
|
mod rex_assets;
|
||||||
pub mod saveload_system;
|
pub mod saveload_system;
|
||||||
mod spawner;
|
mod spawner;
|
||||||
|
mod trigger_system;
|
||||||
mod visibility_system;
|
mod visibility_system;
|
||||||
|
|
||||||
use crate::inventory_system::ItemRemoveSystem;
|
use crate::inventory_system::ItemRemoveSystem;
|
||||||
@ -85,6 +86,9 @@ impl State {
|
|||||||
let mut mob = MonsterAI {};
|
let mut mob = MonsterAI {};
|
||||||
mob.run_now(&self.ecs);
|
mob.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut triggers = trigger_system::TriggerSystem {};
|
||||||
|
triggers.run_now(&self.ecs);
|
||||||
|
|
||||||
let mut mapindex = MapIndexingSystem {};
|
let mut mapindex = MapIndexingSystem {};
|
||||||
mapindex.run_now(&self.ecs);
|
mapindex.run_now(&self.ecs);
|
||||||
|
|
||||||
@ -129,17 +133,19 @@ impl GameState for State {
|
|||||||
|
|
||||||
match newrunstate {
|
match newrunstate {
|
||||||
RunState::MainMenu { .. } => {}
|
RunState::MainMenu { .. } => {}
|
||||||
|
RunState::GameOver { .. } => {}
|
||||||
_ => {
|
_ => {
|
||||||
// Draw the UI
|
// Draw the UI
|
||||||
draw_map(&self.ecs, ctx);
|
draw_map(&self.ecs, ctx);
|
||||||
{
|
{
|
||||||
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 hidden = self.ecs.read_storage::<Hidden>();
|
||||||
let map = self.ecs.fetch::<Map>();
|
let map = self.ecs.fetch::<Map>();
|
||||||
|
|
||||||
let mut data: Vec<_> = (&positions, &renderables).join().collect();
|
let mut data: Vec<_> = (&positions, &renderables, !&hidden).join().collect();
|
||||||
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) in data.iter() {
|
for (pos, render, _hidden) in data.iter() {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
|
||||||
if map.visible_tiles[idx] {
|
if map.visible_tiles[idx] {
|
||||||
@ -511,6 +517,9 @@ fn main() -> rltk::BError {
|
|||||||
HungerClock,
|
HungerClock,
|
||||||
ProvidesFood,
|
ProvidesFood,
|
||||||
MagicMapper,
|
MagicMapper,
|
||||||
|
Hidden,
|
||||||
|
EntryTrigger,
|
||||||
|
EntityMoved,
|
||||||
);
|
);
|
||||||
|
|
||||||
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::components::{Confusion, Monster, Position, Viewshed, WantsToMelee};
|
use crate::components::{Confusion, Monster, Position, Viewshed, WantsToMelee};
|
||||||
use crate::{particle_system::ParticleBuilder, Map, RunState};
|
use crate::{particle_system::ParticleBuilder, EntityMoved, Map, RunState};
|
||||||
use rltk::{Point, RGB};
|
use rltk::{Point, RGB};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
WriteStorage<'a, WantsToMelee>,
|
WriteStorage<'a, WantsToMelee>,
|
||||||
WriteStorage<'a, Confusion>,
|
WriteStorage<'a, Confusion>,
|
||||||
WriteExpect<'a, ParticleBuilder>,
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
WriteStorage<'a, EntityMoved>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -34,6 +35,7 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
mut wants_to_melee,
|
mut wants_to_melee,
|
||||||
mut confused,
|
mut confused,
|
||||||
mut particle_builder,
|
mut particle_builder,
|
||||||
|
mut entity_moved,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
if *runstate != RunState::MonsterTurn {
|
if *runstate != RunState::MonsterTurn {
|
||||||
@ -91,6 +93,10 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
pos.x = path.steps[1] as i32 % map.width;
|
pos.x = path.steps[1] as i32 % map.width;
|
||||||
pos.y = path.steps[1] as i32 / map.width;
|
pos.y = path.steps[1] as i32 / map.width;
|
||||||
|
|
||||||
|
entity_moved
|
||||||
|
.insert(entity, EntityMoved {})
|
||||||
|
.expect("Unable to add EntityMoved flag to monster");
|
||||||
|
|
||||||
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;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::components::{
|
use crate::components::{
|
||||||
CombatStats, HungerClock, HungerState, Item, Monster, Player, Position, Viewshed, WantsToMelee,
|
CombatStats, EntityMoved, HungerClock, HungerState, Item, Monster, Player, Position, Viewshed,
|
||||||
WantsToPickupItem,
|
WantsToMelee, WantsToPickupItem,
|
||||||
};
|
};
|
||||||
use crate::{game_log::GameLog, Map, RunState, State, TileType};
|
use crate::{game_log::GameLog, Map, RunState, State, TileType};
|
||||||
use rltk::{Point, Rltk, VirtualKeyCode};
|
use rltk::{Point, Rltk, VirtualKeyCode};
|
||||||
@ -15,6 +15,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
|
|||||||
let combat_stats = ecs.read_storage::<CombatStats>();
|
let combat_stats = ecs.read_storage::<CombatStats>();
|
||||||
let map = ecs.fetch::<Map>();
|
let map = ecs.fetch::<Map>();
|
||||||
let mut wants_to_melee = ecs.write_storage::<WantsToMelee>();
|
let mut wants_to_melee = ecs.write_storage::<WantsToMelee>();
|
||||||
|
let mut entity_moved = ecs.write_storage::<EntityMoved>();
|
||||||
|
|
||||||
for (entity, _player, pos, viewshed) in
|
for (entity, _player, pos, viewshed) in
|
||||||
(&entities, &players, &mut positions, &mut viewsheds).join()
|
(&entities, &players, &mut positions, &mut viewsheds).join()
|
||||||
@ -45,6 +46,9 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
|
|||||||
if !map.blocked[destination_idx] {
|
if !map.blocked[destination_idx] {
|
||||||
pos.x = min(79, max(0, pos.x + delta_x));
|
pos.x = min(79, max(0, pos.x + delta_x));
|
||||||
pos.y = min(49, max(0, pos.y + delta_y));
|
pos.y = min(49, max(0, pos.y + delta_y));
|
||||||
|
entity_moved
|
||||||
|
.insert(entity, EntityMoved {})
|
||||||
|
.expect("Failed to add EntityMoved flag to player");
|
||||||
|
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
let mut ppos = ecs.write_resource::<Point>();
|
let mut ppos = ecs.write_resource::<Point>();
|
||||||
|
@ -79,6 +79,9 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
HungerClock,
|
HungerClock,
|
||||||
ProvidesFood,
|
ProvidesFood,
|
||||||
MagicMapper,
|
MagicMapper,
|
||||||
|
Hidden,
|
||||||
|
EntryTrigger,
|
||||||
|
EntityMoved,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +167,9 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
HungerClock,
|
HungerClock,
|
||||||
ProvidesFood,
|
ProvidesFood,
|
||||||
MagicMapper,
|
MagicMapper,
|
||||||
|
Hidden,
|
||||||
|
EntryTrigger,
|
||||||
|
EntityMoved,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ fn room_table(map_depth: i32) -> RandomTable {
|
|||||||
.add("Tower Shield", map_depth - 1)
|
.add("Tower Shield", map_depth - 1)
|
||||||
.add("Rations", 10)
|
.add("Rations", 10)
|
||||||
.add("Magic Mapping Scroll", 2)
|
.add("Magic Mapping Scroll", 2)
|
||||||
|
.add("Bear Trap", 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// fills a room with stuff!
|
/// fills a room with stuff!
|
||||||
@ -101,6 +102,7 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
|
|||||||
"Tower Shield" => tower_shield(ecs, x, y),
|
"Tower Shield" => tower_shield(ecs, x, y),
|
||||||
"Rations" => rations(ecs, x, y),
|
"Rations" => rations(ecs, x, y),
|
||||||
"Magic Mapping Scroll" => magic_mapping_scroll(ecs, x, y),
|
"Magic Mapping Scroll" => magic_mapping_scroll(ecs, x, y),
|
||||||
|
"Bear Trap" => bear_trap(ecs, x, y),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,3 +320,20 @@ fn magic_mapping_scroll(ecs: &mut World, x: i32, y: i32) {
|
|||||||
.marked::<SimpleMarker<SerializeMe>>()
|
.marked::<SimpleMarker<SerializeMe>>()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::RED),
|
||||||
|
bg: RGB::named(rltk::BLACK),
|
||||||
|
render_order: 2,
|
||||||
|
})
|
||||||
|
.with(Name::from("Bear Trap"))
|
||||||
|
.with(Hidden {})
|
||||||
|
.with(EntryTrigger {})
|
||||||
|
.with(InflictsDamage { damage: 6 })
|
||||||
|
.marked::<SimpleMarker<SerializeMe>>()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
84
src/trigger_system.rs
Normal file
84
src/trigger_system.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use crate::components::{
|
||||||
|
EntityMoved, EntryTrigger, Hidden, InflictsDamage, Name, Position, SufferDamage,
|
||||||
|
};
|
||||||
|
use crate::{game_log::GameLog, particle_system::ParticleBuilder, Map};
|
||||||
|
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>,
|
||||||
|
WriteStorage<'a, Hidden>,
|
||||||
|
ReadStorage<'a, Name>,
|
||||||
|
Entities<'a>,
|
||||||
|
WriteExpect<'a, GameLog>,
|
||||||
|
ReadStorage<'a, InflictsDamage>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
WriteStorage<'a, SufferDamage>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
let (
|
||||||
|
map,
|
||||||
|
mut entity_moved,
|
||||||
|
position,
|
||||||
|
entry_trigger,
|
||||||
|
mut hidden,
|
||||||
|
names,
|
||||||
|
entities,
|
||||||
|
mut log,
|
||||||
|
inflicts_damage,
|
||||||
|
mut particle_builder,
|
||||||
|
mut inflict_damage,
|
||||||
|
) = data;
|
||||||
|
|
||||||
|
// Iterate the entities that moved and their final position
|
||||||
|
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() {
|
||||||
|
// Do not bother to check yourself for being a trap!
|
||||||
|
if entity != *entity_id {
|
||||||
|
match entry_trigger.get(*entity_id) {
|
||||||
|
None => {}
|
||||||
|
Some(_trigger) => {
|
||||||
|
// We triggered it
|
||||||
|
if let Some(name) = names.get(*entity_id) {
|
||||||
|
log.append(format!("{} triggers!", &name.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The trap is no longer hidden
|
||||||
|
hidden.remove(*entity_id);
|
||||||
|
|
||||||
|
// If the trap is damage inflicting, do it
|
||||||
|
if let Some(damage) = inflicts_damage.get(*entity_id) {
|
||||||
|
particle_builder.request(
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
rltk::RGB::named(rltk::ORANGE),
|
||||||
|
rltk::RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('‼'),
|
||||||
|
200.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
SufferDamage::new_damage(
|
||||||
|
&mut inflict_damage,
|
||||||
|
entity,
|
||||||
|
damage.damage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all entity movement markers
|
||||||
|
entity_moved.clear();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user