Extract spatial indexing (tile contents, and if a tile is blocked) into its own module
This commit is contained in:
parent
eb29e28ec6
commit
f9e73479d0
@ -1,8 +1,8 @@
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Faction, MyTurn, Position, WantsToMelee};
|
use crate::components::{Faction, MyTurn, Position, WantsToMelee};
|
||||||
use crate::raws::Reaction;
|
use crate::raws::{self, Reaction, RAWS};
|
||||||
use crate::Map;
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct AdjacentAI {}
|
pub struct AdjacentAI {}
|
||||||
|
|
||||||
@ -116,21 +116,17 @@ impl<'a> System<'a> for AdjacentAI {
|
|||||||
|
|
||||||
fn evaluate(
|
fn evaluate(
|
||||||
idx: usize,
|
idx: usize,
|
||||||
map: &Map,
|
_map: &Map,
|
||||||
factions: &ReadStorage<Faction>,
|
factions: &ReadStorage<Faction>,
|
||||||
my_faction: &str,
|
my_faction: &str,
|
||||||
reactions: &mut Vec<(Entity, Reaction)>,
|
reactions: &mut Vec<(Entity, Reaction)>,
|
||||||
) {
|
) {
|
||||||
for other_entity in map.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |other_entity| {
|
||||||
if let Some(faction) = factions.get(*other_entity) {
|
if let Some(faction) = factions.get(other_entity) {
|
||||||
reactions.push((
|
reactions.push((
|
||||||
*other_entity,
|
other_entity,
|
||||||
crate::raws::faction_reaction(
|
raws::faction_reaction(my_faction, &faction.name, &RAWS.lock().unwrap()),
|
||||||
my_faction,
|
|
||||||
&faction.name,
|
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use ::rltk::a_star_search;
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MyTurn, Position, Viewshed, WantsToApproach};
|
use crate::components::{EntityMoved, MyTurn, Position, Viewshed, WantsToApproach};
|
||||||
use crate::Map;
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct ApproachAI {}
|
pub struct ApproachAI {}
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ impl<'a> System<'a> for ApproachAI {
|
|||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
WriteStorage<'a, WantsToApproach>,
|
WriteStorage<'a, WantsToApproach>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
WriteStorage<'a, Viewshed>,
|
||||||
WriteStorage<'a, EntityMoved>,
|
WriteStorage<'a, EntityMoved>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
@ -23,7 +23,7 @@ impl<'a> System<'a> for ApproachAI {
|
|||||||
mut turns,
|
mut turns,
|
||||||
mut want_approach,
|
mut want_approach,
|
||||||
mut positions,
|
mut positions,
|
||||||
mut map,
|
map,
|
||||||
mut viewsheds,
|
mut viewsheds,
|
||||||
mut entity_moved,
|
mut entity_moved,
|
||||||
entities,
|
entities,
|
||||||
@ -48,16 +48,15 @@ impl<'a> System<'a> for ApproachAI {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if path.success && path.steps.len() > 1 {
|
if path.success && path.steps.len() > 1 {
|
||||||
let mut idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.blocked[idx] = false;
|
|
||||||
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
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Unable to insert moved marker");
|
.expect("Unable to insert moved marker");
|
||||||
|
|
||||||
idx = map.xy_idx(pos.x, pos.y);
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.blocked[idx] = true;
|
spatial::move_entity(entity, idx, new_idx);
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Chasing, EntityMoved, MyTurn, Position, Viewshed};
|
use crate::components::{Chasing, EntityMoved, MyTurn, Position, Viewshed};
|
||||||
use crate::Map;
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct ChaseAI {}
|
pub struct ChaseAI {}
|
||||||
|
|
||||||
@ -13,22 +13,15 @@ impl<'a> System<'a> for ChaseAI {
|
|||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
WriteStorage<'a, Chasing>,
|
WriteStorage<'a, Chasing>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
WriteStorage<'a, Viewshed>,
|
||||||
WriteStorage<'a, EntityMoved>,
|
WriteStorage<'a, EntityMoved>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (
|
let (mut turns, mut chasing, mut positions, map, mut viewsheds, mut entity_moved, entities) =
|
||||||
mut turns,
|
data;
|
||||||
mut chasing,
|
|
||||||
mut positions,
|
|
||||||
mut map,
|
|
||||||
mut viewsheds,
|
|
||||||
mut entity_moved,
|
|
||||||
entities,
|
|
||||||
) = data;
|
|
||||||
|
|
||||||
let mut targets: HashMap<Entity, (i32, i32)> = HashMap::new();
|
let mut targets: HashMap<Entity, (i32, i32)> = HashMap::new();
|
||||||
let mut end_chase: Vec<Entity> = Vec::new();
|
let mut end_chase: Vec<Entity> = Vec::new();
|
||||||
@ -58,17 +51,16 @@ impl<'a> System<'a> for ChaseAI {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if path.success && path.steps.len() > 1 && path.steps.len() < 15 {
|
if path.success && path.steps.len() > 1 && path.steps.len() < 15 {
|
||||||
let mut idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.blocked[idx] = false;
|
|
||||||
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
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Unable to insert movement marker");
|
.expect("Unable to insert movement marker");
|
||||||
|
|
||||||
idx = map.xy_idx(pos.x, pos.y);
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.blocked[idx] = true;
|
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
|
spatial::move_entity(entity, idx, new_idx);
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
} else {
|
} else {
|
||||||
end_chase.push(entity);
|
end_chase.push(entity);
|
||||||
|
@ -2,7 +2,7 @@ use ::rltk::RandomNumberGenerator;
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MoveMode, Movement, MyTurn, Position, Viewshed};
|
use crate::components::{EntityMoved, MoveMode, Movement, MyTurn, Position, Viewshed};
|
||||||
use crate::{tile_walkable, Map};
|
use crate::{spatial, tile_walkable, Map};
|
||||||
|
|
||||||
pub struct DefaultMoveAI {}
|
pub struct DefaultMoveAI {}
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
WriteStorage<'a, MoveMode>,
|
WriteStorage<'a, MoveMode>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
WriteStorage<'a, Viewshed>,
|
||||||
WriteStorage<'a, EntityMoved>,
|
WriteStorage<'a, EntityMoved>,
|
||||||
WriteExpect<'a, RandomNumberGenerator>,
|
WriteExpect<'a, RandomNumberGenerator>,
|
||||||
@ -24,7 +24,7 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
mut turns,
|
mut turns,
|
||||||
mut move_mode,
|
mut move_mode,
|
||||||
mut positions,
|
mut positions,
|
||||||
mut map,
|
map,
|
||||||
mut viewsheds,
|
mut viewsheds,
|
||||||
mut entity_moved,
|
mut entity_moved,
|
||||||
mut rng,
|
mut rng,
|
||||||
@ -59,15 +59,14 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
|
|
||||||
if x > 0 && x < map.width - 1 && y > 0 && y < map.height - 1 {
|
if x > 0 && x < map.width - 1 && y > 0 && y < map.height - 1 {
|
||||||
let dest_idx = map.xy_idx(x, y);
|
let dest_idx = map.xy_idx(x, y);
|
||||||
if !map.blocked[dest_idx] {
|
if !spatial::is_blocked(dest_idx) {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.blocked[idx] = false;
|
|
||||||
pos.x = x;
|
pos.x = x;
|
||||||
pos.y = y;
|
pos.y = y;
|
||||||
entity_moved
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Unable to insert movement marker");
|
.expect("Unable to insert movement marker");
|
||||||
map.blocked[dest_idx] = true;
|
crate::spatial::move_entity(entity, idx, dest_idx);
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,18 +74,17 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
Movement::RandomWaypoint { path } => {
|
Movement::RandomWaypoint { path } => {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
// We have a target - go there
|
// We have a target - go there
|
||||||
let mut idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
if path.len() > 1 {
|
if path.len() > 1 {
|
||||||
if !map.blocked[path[1]] {
|
if !spatial::is_blocked(path[1]) {
|
||||||
map.blocked[idx] = false;
|
|
||||||
pos.x = (path[1] as i32 % map.width) as i32;
|
pos.x = (path[1] as i32 % map.width) as i32;
|
||||||
pos.y = (path[1] as i32 / map.width) as i32;
|
pos.y = (path[1] as i32 / map.width) as i32;
|
||||||
entity_moved
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Unable to insert movement marker");
|
.expect("Unable to insert movement marker");
|
||||||
|
|
||||||
idx = map.xy_idx(pos.x, pos.y);
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.blocked[idx] = true;
|
spatial::move_entity(entity, idx, new_idx);
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
path.remove(0); // Remove the first step in the path
|
path.remove(0); // Remove the first step in the path
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use ::rltk::DijkstraMap;
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MyTurn, Position, Viewshed, WantsToFlee};
|
use crate::components::{EntityMoved, MyTurn, Position, Viewshed, WantsToFlee};
|
||||||
use crate::Map;
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct FleeAI {}
|
pub struct FleeAI {}
|
||||||
|
|
||||||
@ -46,9 +46,8 @@ impl<'a> System<'a> for FleeAI {
|
|||||||
|
|
||||||
let flee_map = DijkstraMap::new(map.width, map.height, &flee.indices, &*map, 100.0);
|
let flee_map = DijkstraMap::new(map.width, map.height, &flee.indices, &*map, 100.0);
|
||||||
if let Some(flee_target) = DijkstraMap::find_highest_exit(&flee_map, my_idx, &*map) {
|
if let Some(flee_target) = DijkstraMap::find_highest_exit(&flee_map, my_idx, &*map) {
|
||||||
if !map.blocked[flee_target] {
|
if !spatial::is_blocked(flee_target) {
|
||||||
map.blocked[my_idx] = false;
|
spatial::move_entity(entity, my_idx, flee_target);
|
||||||
map.blocked[flee_target] = true;
|
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
pos.x = flee_target as i32 % map.width;
|
pos.x = flee_target as i32 % map.width;
|
||||||
pos.y = flee_target as i32 / map.width;
|
pos.y = flee_target as i32 / map.width;
|
||||||
|
@ -3,8 +3,8 @@ use ::specs::prelude::*;
|
|||||||
use crate::components::{
|
use crate::components::{
|
||||||
Chasing, Faction, MyTurn, Position, Viewshed, WantsToApproach, WantsToFlee,
|
Chasing, Faction, MyTurn, Position, Viewshed, WantsToApproach, WantsToFlee,
|
||||||
};
|
};
|
||||||
use crate::raws::Reaction;
|
use crate::raws::{self, Reaction, RAWS};
|
||||||
use crate::Map;
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct VisibleAI {}
|
pub struct VisibleAI {}
|
||||||
|
|
||||||
@ -87,22 +87,18 @@ impl<'a> System<'a> for VisibleAI {
|
|||||||
|
|
||||||
fn evaluate(
|
fn evaluate(
|
||||||
idx: usize,
|
idx: usize,
|
||||||
map: &Map,
|
_map: &Map,
|
||||||
factions: &ReadStorage<Faction>,
|
factions: &ReadStorage<Faction>,
|
||||||
my_faction: &str,
|
my_faction: &str,
|
||||||
reactions: &mut Vec<(usize, Reaction, Entity)>,
|
reactions: &mut Vec<(usize, Reaction, Entity)>,
|
||||||
) {
|
) {
|
||||||
for other_entity in map.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |other_entity| {
|
||||||
if let Some(faction) = factions.get(*other_entity) {
|
if let Some(faction) = factions.get(other_entity) {
|
||||||
reactions.push((
|
reactions.push((
|
||||||
idx,
|
idx,
|
||||||
crate::raws::faction_reaction(
|
raws::faction_reaction(my_faction, &faction.name, &RAWS.lock().unwrap()),
|
||||||
my_faction,
|
other_entity,
|
||||||
&faction.name,
|
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
|
||||||
),
|
|
||||||
*other_entity,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use ::specs::prelude::*;
|
|||||||
use crate::components::*;
|
use crate::components::*;
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::particle_system::ParticleBuilder;
|
use crate::particle_system::ParticleBuilder;
|
||||||
use crate::{Map, RunState};
|
use crate::{spatial, Map, RunState};
|
||||||
|
|
||||||
pub struct ItemCollectionSystem {}
|
pub struct ItemCollectionSystem {}
|
||||||
|
|
||||||
@ -116,9 +116,7 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
None => {
|
None => {
|
||||||
// Single target in tile
|
// Single target in tile
|
||||||
let idx = map.xy_idx(target.x, target.y);
|
let idx = map.xy_idx(target.x, target.y);
|
||||||
for mob in map.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |mob| targets.push(mob));
|
||||||
targets.push(*mob);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(area_effect) => {
|
Some(area_effect) => {
|
||||||
// AoE
|
// AoE
|
||||||
@ -130,9 +128,7 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
|
|
||||||
for tile_idx in blast_tiles.iter() {
|
for tile_idx in blast_tiles.iter() {
|
||||||
let idx = map.xy_idx(tile_idx.x, tile_idx.y);
|
let idx = map.xy_idx(tile_idx.x, tile_idx.y);
|
||||||
for mob in map.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |mob| targets.push(mob));
|
||||||
targets.push(*mob);
|
|
||||||
}
|
|
||||||
|
|
||||||
particle_builder.request(
|
particle_builder.request(
|
||||||
tile_idx.x,
|
tile_idx.x,
|
||||||
|
@ -19,6 +19,7 @@ pub mod raws;
|
|||||||
mod rect;
|
mod rect;
|
||||||
mod rex_assets;
|
mod rex_assets;
|
||||||
pub mod saveload_system;
|
pub mod saveload_system;
|
||||||
|
mod spatial;
|
||||||
mod spawner;
|
mod spawner;
|
||||||
mod trigger_system;
|
mod trigger_system;
|
||||||
mod visibility_system;
|
mod visibility_system;
|
||||||
|
20
src/map.rs
20
src/map.rs
@ -6,13 +6,13 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use ::rltk::{Algorithm2D, BaseMap, Point, SmallVec};
|
use ::rltk::{Algorithm2D, BaseMap, Point, SmallVec};
|
||||||
use ::serde::{Deserialize, Serialize};
|
use ::serde::{Deserialize, Serialize};
|
||||||
use ::specs::prelude::*;
|
|
||||||
pub use dungeon::*;
|
pub use dungeon::*;
|
||||||
use rltk::RGB;
|
use rltk::RGB;
|
||||||
pub use themes::*;
|
pub use themes::*;
|
||||||
pub use tiletype::{tile_opaque, tile_walkable, TileType};
|
pub use tiletype::{tile_opaque, tile_walkable, TileType};
|
||||||
|
|
||||||
use crate::map::tiletype::tile_cost;
|
use crate::map::tiletype::tile_cost;
|
||||||
|
use crate::spatial;
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
@ -21,17 +21,12 @@ pub struct Map {
|
|||||||
pub height: i32,
|
pub height: i32,
|
||||||
pub revealed_tiles: Vec<bool>,
|
pub revealed_tiles: Vec<bool>,
|
||||||
pub visible_tiles: Vec<bool>,
|
pub visible_tiles: Vec<bool>,
|
||||||
pub blocked: Vec<bool>,
|
|
||||||
pub depth: i32,
|
pub depth: i32,
|
||||||
pub bloodstains: HashSet<usize>,
|
pub bloodstains: HashSet<usize>,
|
||||||
pub view_blocked: HashSet<usize>,
|
pub view_blocked: HashSet<usize>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub outdoors: bool,
|
pub outdoors: bool,
|
||||||
pub light: Vec<RGB>,
|
pub light: Vec<RGB>,
|
||||||
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub tile_content: Vec<Vec<Entity>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
@ -46,24 +41,21 @@ impl Map {
|
|||||||
|
|
||||||
let idx = self.xy_idx(x, y);
|
let idx = self.xy_idx(x, y);
|
||||||
|
|
||||||
!self.blocked[idx]
|
!spatial::is_blocked(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn populate_blocked(&mut self) {
|
pub fn populate_blocked(&mut self) {
|
||||||
for (i, tile) in self.tiles.iter_mut().enumerate() {
|
spatial::populate_blocked_from_map(self);
|
||||||
self.blocked[i] = !tile_walkable(*tile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_content_index(&mut self) {
|
pub fn clear_content_index(&mut self) {
|
||||||
for content in self.tile_content.iter_mut() {
|
spatial::clear();
|
||||||
content.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates an empty map, consisting entirely of solid walls
|
/// Generates an empty map, consisting entirely of solid walls
|
||||||
pub fn new<S: ToString>(new_depth: i32, width: i32, height: i32, name: S) -> Map {
|
pub fn new<S: ToString>(new_depth: i32, width: i32, height: i32, name: S) -> Map {
|
||||||
let map_tile_count = (width * height) as usize;
|
let map_tile_count = (width * height) as usize;
|
||||||
|
crate::spatial::set_size(map_tile_count);
|
||||||
|
|
||||||
Map {
|
Map {
|
||||||
tiles: vec![TileType::Wall; map_tile_count],
|
tiles: vec![TileType::Wall; map_tile_count],
|
||||||
@ -71,8 +63,6 @@ impl Map {
|
|||||||
height,
|
height,
|
||||||
revealed_tiles: vec![false; map_tile_count],
|
revealed_tiles: vec![false; map_tile_count],
|
||||||
visible_tiles: vec![false; map_tile_count],
|
visible_tiles: vec![false; map_tile_count],
|
||||||
blocked: vec![false; map_tile_count],
|
|
||||||
tile_content: vec![Vec::new(); map_tile_count],
|
|
||||||
depth: new_depth,
|
depth: new_depth,
|
||||||
bloodstains: HashSet::new(),
|
bloodstains: HashSet::new(),
|
||||||
view_blocked: HashSet::new(),
|
view_blocked: HashSet::new(),
|
||||||
|
@ -26,10 +26,7 @@ impl MasterDungeonMap {
|
|||||||
|
|
||||||
pub fn get_map(&self, depth: i32) -> Option<Map> {
|
pub fn get_map(&self, depth: i32) -> Option<Map> {
|
||||||
if self.maps.contains_key(&depth) {
|
if self.maps.contains_key(&depth) {
|
||||||
let mut result = self.maps[&depth].clone();
|
Some(self.maps[&depth].clone())
|
||||||
result.tile_content = vec![Vec::new(); (result.width * result.height) as usize];
|
|
||||||
|
|
||||||
Some(result)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,26 @@
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::{BlocksTile, Map, Position};
|
use crate::{spatial, BlocksTile, Map, Position};
|
||||||
|
|
||||||
pub struct MapIndexingSystem {}
|
pub struct MapIndexingSystem {}
|
||||||
|
|
||||||
impl<'a> System<'a> for MapIndexingSystem {
|
impl<'a> System<'a> for MapIndexingSystem {
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
ReadStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
ReadStorage<'a, BlocksTile>,
|
ReadStorage<'a, BlocksTile>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (mut map, position, blockers, entities) = data;
|
let (map, position, blockers, entities) = data;
|
||||||
|
|
||||||
map.populate_blocked();
|
spatial::clear();
|
||||||
map.clear_content_index();
|
spatial::populate_blocked_from_map(&*map);
|
||||||
|
|
||||||
for (entity, position) in (&entities, &position).join() {
|
for (entity, position) in (&entities, &position).join() {
|
||||||
let idx = map.xy_idx(position.x, position.y);
|
let idx = map.xy_idx(position.x, position.y);
|
||||||
|
spatial::index_entity(entity, idx, blockers.get(entity).is_some());
|
||||||
// If it's a blocking entity, note that in the map object
|
|
||||||
if let Some(_p) = blockers.get(entity) {
|
|
||||||
map.blocked[idx] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push a copy of the entity to the indexed slot
|
|
||||||
map.tile_content[idx].push(entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
122
src/player.rs
122
src/player.rs
@ -8,8 +8,8 @@ use crate::components::{
|
|||||||
Item, Player, Pools, Position, Renderable, Viewshed, WantsToMelee, WantsToPickupItem,
|
Item, Player, Pools, Position, Renderable, Viewshed, WantsToMelee, WantsToPickupItem,
|
||||||
};
|
};
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::raws::Reaction;
|
use crate::raws::{self, Reaction, RAWS};
|
||||||
use crate::{Map, RunState, State, TileType};
|
use crate::{spatial, Map, RunState, State, TileType};
|
||||||
|
|
||||||
pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState {
|
pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState {
|
||||||
let mut positions = ecs.write_storage::<Position>();
|
let mut positions = ecs.write_storage::<Position>();
|
||||||
@ -41,68 +41,74 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
}
|
}
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
||||||
for potential_target in map.tile_content[destination_idx].iter() {
|
result =
|
||||||
let mut hostile = true;
|
spatial::for_each_tile_content_with_gamemode(destination_idx, |potential_target| {
|
||||||
if combat_stats.get(*potential_target).is_some() {
|
let mut hostile = true;
|
||||||
if let Some(faction) = factions.get(*potential_target) {
|
if combat_stats.get(potential_target).is_some() {
|
||||||
let reaction = crate::raws::faction_reaction(
|
if let Some(faction) = factions.get(potential_target) {
|
||||||
&faction.name,
|
let reaction = crate::raws::faction_reaction(
|
||||||
"Player",
|
&faction.name,
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
"Player",
|
||||||
);
|
&RAWS.lock().unwrap(),
|
||||||
if reaction != Reaction::Attack {
|
);
|
||||||
hostile = false;
|
if reaction != Reaction::Attack {
|
||||||
|
hostile = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if !hostile {
|
||||||
if !hostile {
|
// Note that we want to move the bystander
|
||||||
// Note that we want to move the bystander
|
swap_entities.push((potential_target, pos.x, pos.y));
|
||||||
swap_entities.push((*potential_target, pos.x, pos.y));
|
|
||||||
|
|
||||||
// Move the player
|
// Move the player
|
||||||
pos.x = min(map.width - 1, max(0, pos.x + delta_x));
|
pos.x = min(map.width - 1, max(0, pos.x + delta_x));
|
||||||
pos.y = min(map.height - 1, max(0, pos.y + delta_y));
|
pos.y = min(map.height - 1, max(0, pos.y + delta_y));
|
||||||
entity_moved
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Unable to insert marker");
|
.expect("Unable to insert marker");
|
||||||
|
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
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;
|
||||||
} else {
|
|
||||||
let target = combat_stats.get(*potential_target);
|
return Some(RunState::Ticking);
|
||||||
if let Some(_target) = target {
|
} else if combat_stats.get(potential_target).is_some() {
|
||||||
wants_to_melee
|
wants_to_melee
|
||||||
.insert(
|
.insert(
|
||||||
entity,
|
entity,
|
||||||
WantsToMelee {
|
WantsToMelee {
|
||||||
target: *potential_target,
|
target: potential_target,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.expect("Add target failed");
|
.expect("Add target failed");
|
||||||
|
|
||||||
return RunState::Ticking;
|
return Some(RunState::Ticking);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let door = doors.get_mut(*potential_target);
|
|
||||||
if let Some(door) = door {
|
|
||||||
door.open = true;
|
|
||||||
blocks_visibility.remove(*potential_target);
|
|
||||||
blocks_movement.remove(*potential_target);
|
|
||||||
let glyph = renderables.get_mut(*potential_target).unwrap();
|
|
||||||
glyph.glyph = rltk::to_cp437('/');
|
|
||||||
viewshed.dirty = true;
|
|
||||||
result = RunState::Ticking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !map.blocked[destination_idx] {
|
if let Some(door) = doors.get_mut(potential_target) {
|
||||||
|
door.open = true;
|
||||||
|
blocks_visibility.remove(potential_target);
|
||||||
|
blocks_movement.remove(potential_target);
|
||||||
|
let glyph = renderables.get_mut(potential_target).unwrap();
|
||||||
|
glyph.glyph = rltk::to_cp437('/');
|
||||||
|
viewshed.dirty = true;
|
||||||
|
|
||||||
|
return Some(RunState::Ticking);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
if !spatial::is_blocked(destination_idx) {
|
||||||
|
let old_idx = map.xy_idx(pos.x, pos.y);
|
||||||
pos.x = min(map.width - 1, max(0, pos.x + delta_x));
|
pos.x = min(map.width - 1, max(0, pos.x + delta_x));
|
||||||
pos.y = min(map.height - 1, max(0, pos.y + delta_y));
|
pos.y = min(map.height - 1, max(0, pos.y + delta_y));
|
||||||
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
entity_moved
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Failed to add EntityMoved flag to player");
|
.expect("Failed to add EntityMoved flag to player");
|
||||||
|
spatial::move_entity(entity, old_idx, new_idx);
|
||||||
|
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
let mut ppos = ecs.write_resource::<Point>();
|
let mut ppos = ecs.write_resource::<Point>();
|
||||||
@ -120,8 +126,13 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
for m in swap_entities.iter() {
|
for m in swap_entities.iter() {
|
||||||
let their_pos = positions.get_mut(m.0);
|
let their_pos = positions.get_mut(m.0);
|
||||||
if let Some(their_pos) = their_pos {
|
if let Some(their_pos) = their_pos {
|
||||||
|
let old_idx = map.xy_idx(their_pos.x, their_pos.y);
|
||||||
their_pos.x = m.1;
|
their_pos.x = m.1;
|
||||||
their_pos.y = m.2;
|
their_pos.y = m.2;
|
||||||
|
let new_idx = map.xy_idx(their_pos.x, their_pos.y);
|
||||||
|
spatial::move_entity(m.0, old_idx, new_idx);
|
||||||
|
|
||||||
|
result = RunState::Ticking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,21 +216,16 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
|||||||
let viewshed = viewshed_components.get(*player_entity).unwrap();
|
let viewshed = viewshed_components.get(*player_entity).unwrap();
|
||||||
for tile in viewshed.visible_tiles.iter() {
|
for tile in viewshed.visible_tiles.iter() {
|
||||||
let idx = worldmap_resource.xy_idx(tile.x, tile.y);
|
let idx = worldmap_resource.xy_idx(tile.x, tile.y);
|
||||||
for entity_id in worldmap_resource.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |entity_id| match factions.get(entity_id) {
|
||||||
match factions.get(*entity_id) {
|
None => {}
|
||||||
None => {}
|
Some(faction) => {
|
||||||
Some(faction) => {
|
let reaction =
|
||||||
let reaction = crate::raws::faction_reaction(
|
raws::faction_reaction(&faction.name, "Player", &RAWS.lock().unwrap());
|
||||||
&faction.name,
|
if reaction == Reaction::Attack {
|
||||||
"Player",
|
can_heal = false;
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
|
||||||
);
|
|
||||||
if reaction == Reaction::Attack {
|
|
||||||
can_heal = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow healing when hungry or starving
|
// Don't allow healing when hungry or starving
|
||||||
|
@ -11,6 +11,7 @@ use ::specs::saveload::{
|
|||||||
|
|
||||||
use crate::components::*;
|
use crate::components::*;
|
||||||
use crate::map::{Map, MasterDungeonMap};
|
use crate::map::{Map, MasterDungeonMap};
|
||||||
|
use crate::spatial;
|
||||||
|
|
||||||
macro_rules! serialize_individually {
|
macro_rules! serialize_individually {
|
||||||
($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*,) => {
|
($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*,) => {
|
||||||
@ -233,7 +234,7 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
for (e, h) in (&entities, &helper).join() {
|
for (e, h) in (&entities, &helper).join() {
|
||||||
let mut worldmap = ecs.write_resource::<Map>();
|
let mut worldmap = ecs.write_resource::<Map>();
|
||||||
*worldmap = h.map.clone();
|
*worldmap = h.map.clone();
|
||||||
worldmap.tile_content = vec![Vec::new(); (worldmap.height * worldmap.width) as usize];
|
spatial::set_size((worldmap.height * worldmap.width) as usize);
|
||||||
deleteme = Some(e);
|
deleteme = Some(e);
|
||||||
}
|
}
|
||||||
for (e, h) in (&entities, &helper2).join() {
|
for (e, h) in (&entities, &helper2).join() {
|
||||||
|
121
src/spatial.rs
Normal file
121
src/spatial.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::{tile_walkable, Map, RunState};
|
||||||
|
|
||||||
|
struct SpatialMap {
|
||||||
|
blocked: Vec<(bool, bool)>,
|
||||||
|
tile_content: Vec<Vec<(Entity, bool)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpatialMap {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
blocked: Vec::new(),
|
||||||
|
tile_content: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SPATIAL_MAP: Mutex<SpatialMap> = Mutex::new(SpatialMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_size(map_tile_count: usize) {
|
||||||
|
let mut lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
lock.blocked = vec![(false, false); map_tile_count];
|
||||||
|
lock.tile_content = vec![Vec::new(); map_tile_count];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear() {
|
||||||
|
let mut lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
lock.blocked.iter_mut().for_each(|b| {
|
||||||
|
b.0 = false;
|
||||||
|
b.1 = false;
|
||||||
|
});
|
||||||
|
for content in lock.tile_content.iter_mut() {
|
||||||
|
content.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn populate_blocked_from_map(map: &Map) {
|
||||||
|
let mut lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
for (i, tile) in map.tiles.iter().enumerate() {
|
||||||
|
lock.blocked[i].0 = !tile_walkable(*tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index_entity(entity: Entity, idx: usize, blocks_tile: bool) {
|
||||||
|
let mut lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
lock.tile_content[idx].push((entity, blocks_tile));
|
||||||
|
if blocks_tile {
|
||||||
|
lock.blocked[idx].1 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_blocked(idx: usize) -> bool {
|
||||||
|
let lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
|
||||||
|
lock.blocked[idx].0 || lock.blocked[idx].1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_each_tile_content<F>(idx: usize, mut f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(Entity),
|
||||||
|
{
|
||||||
|
let lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
for entity in lock.tile_content[idx].iter() {
|
||||||
|
f(entity.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_each_tile_content_with_gamemode<F>(idx: usize, mut f: F) -> RunState
|
||||||
|
where
|
||||||
|
F: FnMut(Entity) -> Option<RunState>,
|
||||||
|
{
|
||||||
|
let lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
for entity in lock.tile_content[idx].iter() {
|
||||||
|
if let Some(rs) = f(entity.0) {
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RunState::AwaitingInput
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move an entity on the map from `moving_from` index to the `moving_to` index.
|
||||||
|
/// This also recalculates if these two tiles are blocked based on the entities
|
||||||
|
/// within these tiles.
|
||||||
|
pub fn move_entity(entity: Entity, moving_from: usize, moving_to: usize) {
|
||||||
|
let mut lock = SPATIAL_MAP.lock().unwrap();
|
||||||
|
let mut entity_blocks = false;
|
||||||
|
|
||||||
|
lock.tile_content[moving_from].retain(|(e, blocks)| {
|
||||||
|
if *e == entity {
|
||||||
|
entity_blocks = *blocks;
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lock.tile_content[moving_to].push((entity, entity_blocks));
|
||||||
|
|
||||||
|
// Recalculate blocks for both tiles
|
||||||
|
let mut from_blocked = false;
|
||||||
|
let mut to_blocked = false;
|
||||||
|
lock.tile_content[moving_from]
|
||||||
|
.iter()
|
||||||
|
.for_each(|(_, blocks)| {
|
||||||
|
if *blocks {
|
||||||
|
from_blocked = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lock.tile_content[moving_to].iter().for_each(|(_, blocks)| {
|
||||||
|
if *blocks {
|
||||||
|
to_blocked = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lock.blocked[moving_from].1 = from_blocked;
|
||||||
|
lock.blocked[moving_to].1 = to_blocked;
|
||||||
|
}
|
@ -6,7 +6,7 @@ use crate::components::{
|
|||||||
};
|
};
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::particle_system::ParticleBuilder;
|
use crate::particle_system::ParticleBuilder;
|
||||||
use crate::Map;
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct TriggerSystem {}
|
pub struct TriggerSystem {}
|
||||||
|
|
||||||
@ -48,22 +48,22 @@ impl<'a> System<'a> for TriggerSystem {
|
|||||||
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() {
|
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
|
||||||
for entity_id in map.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |entity_id| {
|
||||||
// Do not bother to check yourself for being a trap!
|
// Do not bother to check yourself for being a trap!
|
||||||
if entity != *entity_id {
|
if entity != entity_id {
|
||||||
match entry_trigger.get(*entity_id) {
|
match entry_trigger.get(entity_id) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(_trigger) => {
|
Some(_trigger) => {
|
||||||
// We triggered it
|
// We triggered it
|
||||||
if let Some(name) = names.get(*entity_id) {
|
if let Some(name) = names.get(entity_id) {
|
||||||
log.append(format!("{} triggers!", &name.name));
|
log.append(format!("{} triggers!", &name.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The trap is no longer hidden
|
// The trap is no longer hidden
|
||||||
hidden.remove(*entity_id);
|
hidden.remove(entity_id);
|
||||||
|
|
||||||
// If the trap is damage inflicting, do it
|
// If the trap is damage inflicting, do it
|
||||||
if let Some(damage) = inflicts_damage.get(*entity_id) {
|
if let Some(damage) = inflicts_damage.get(entity_id) {
|
||||||
particle_builder.request(
|
particle_builder.request(
|
||||||
pos.x,
|
pos.x,
|
||||||
pos.y,
|
pos.y,
|
||||||
@ -82,13 +82,13 @@ impl<'a> System<'a> for TriggerSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If it is single activation, it needs to be removed
|
// If it is single activation, it needs to be removed
|
||||||
if let Some(_sa) = single_activation.get(*entity_id) {
|
if single_activation.get(entity_id).is_some() {
|
||||||
remove_entities.push(*entity_id);
|
remove_entities.push(entity_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any single activation traps
|
// Remove any single activation traps
|
||||||
|
@ -3,7 +3,7 @@ use ::specs::prelude::*;
|
|||||||
|
|
||||||
use crate::components::{BlocksVisibility, Hidden, Name};
|
use crate::components::{BlocksVisibility, Hidden, Name};
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::{Map, Player, Position, Viewshed};
|
use crate::{spatial, Map, Player, Position, Viewshed};
|
||||||
|
|
||||||
pub struct VisibilitySystem {}
|
pub struct VisibilitySystem {}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ impl<'a> System<'a> for VisibilitySystem {
|
|||||||
.retain(|p| p.x >= 0 && p.x < map.width && p.y >= 0 && p.y < map.height);
|
.retain(|p| p.x >= 0 && p.x < map.width && p.y >= 0 && p.y < map.height);
|
||||||
|
|
||||||
// if this is the player, reveal what they can see
|
// if this is the player, reveal what they can see
|
||||||
if let Some(_p) = player.get(ent) {
|
if player.get(ent).is_some() {
|
||||||
for t in map.visible_tiles.iter_mut() {
|
for t in map.visible_tiles.iter_mut() {
|
||||||
*t = false
|
*t = false
|
||||||
}
|
}
|
||||||
@ -64,17 +64,18 @@ impl<'a> System<'a> for VisibilitySystem {
|
|||||||
map.visible_tiles[idx] = true;
|
map.visible_tiles[idx] = true;
|
||||||
|
|
||||||
// Chance to reveal hidden things
|
// Chance to reveal hidden things
|
||||||
for e in map.tile_content[idx].iter() {
|
spatial::for_each_tile_content(idx, |e| {
|
||||||
if let Some(_maybe_hidden) = hidden.get(*e) {
|
let maybe_hidden = hidden.get(e);
|
||||||
|
if let Some(_maybe_hidden) = maybe_hidden {
|
||||||
if rng.roll_dice(1, 24) == 1 {
|
if rng.roll_dice(1, 24) == 1 {
|
||||||
if let Some(name) = names.get(*e) {
|
let name = names.get(e);
|
||||||
log.append(format!("You spotted a {}.", &name.name));
|
if let Some(name) = name {
|
||||||
|
log.entries.push(format!("You spotted a {}.", &name.name));
|
||||||
}
|
}
|
||||||
|
hidden.remove(e);
|
||||||
hidden.remove(*e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user