map memory

This commit is contained in:
Llywelwyn 2023-09-27 02:32:51 +01:00
parent 054468bbae
commit cfbe4098b7
3 changed files with 86 additions and 60 deletions

View file

@ -154,7 +154,6 @@ const SHOW_BOUNDARIES: bool = false; // Config setting
enum DrawType {
None,
Visible,
VisibleAndRemember,
Telepathy,
}
@ -170,12 +169,12 @@ struct DrawInfo {
}
fn draw_camera(
map: &Map,
ecs: &World,
draw: &mut Draw,
atlas: &HashMap<String, Texture>,
font: &notan::draw::Font
) {
let map = ecs.fetch::<Map>();
render_map_in_view(&*map, ecs, draw, atlas, false);
{
let bounds = crate::camera::get_screen_bounds(ecs, false);
@ -204,17 +203,8 @@ fn draw_camera(
)
{
let draw_type = if map.visible_tiles[idx] {
let is_prop = props.get(*e);
let is_item = items.get(*e);
if is_prop.is_some() || is_item.is_some() {
// If it's a static entity, we want to draw it, and
// also save it's location so that we remember where
// it was last seen after it leaves vision.
DrawType::VisibleAndRemember
} else {
// If it's anything else, just draw it.
DrawType::Visible
}
// If it's anything else, just draw it.
DrawType::Visible
} else if map.telepath_tiles[idx] {
let has_mind = minds.get(*e);
if has_mind.is_some() {
@ -317,50 +307,6 @@ fn draw_camera(
.v_align_middle();
}
}
DrawType::VisibleAndRemember => {
// TODO: PUT THIS INTO A FUNCTION!
let renderable = renderables.get(entry.1.e).unwrap();
if let Some(spriteinfo) = &renderable.sprite {
let id = if let Some(sprite) = atlas.get(&spriteinfo.id) {
sprite
} else {
panic!("No entity sprite found for ID: {}", spriteinfo.id);
};
draw.image(id)
.position(
((entry.0.x as f32) + spriteinfo.offset.0) * TILESIZE,
((entry.0.y as f32) + spriteinfo.offset.1) * TILESIZE
)
.color(
if spriteinfo.recolour {
Color::from_rgb(
renderable.fg.r,
renderable.fg.g,
renderable.fg.b
)
} else {
Color::WHITE
}
);
} else {
// Fallback to drawing text.
draw.text(
&font,
&format!("{}", bracket_lib::terminal::to_char(renderable.glyph as u8))
)
.position(
((entry.0.x as f32) + 0.5) * TILESIZE,
((entry.0.y as f32) + 0.5) * TILESIZE
)
.color(
Color::from_rgb(renderable.fg.r, renderable.fg.g, renderable.fg.b)
)
.size(FONTSIZE)
.h_align_center()
.v_align_middle();
}
// TODO: Update map memory.
}
_ => {}
}
}
@ -408,6 +354,34 @@ fn render_map_in_view(
)
.color(tint);
}
if !map.visible_tiles[idx] {
// Recall map memory. TODO: Improve this? Optimize? Do we need to remember more fields?
if let Some(memories) = map.memory.get(&idx) {
let mut sorted: Vec<_> = memories.iter().collect();
sorted.sort_by(|a, b| a.render_order.cmp(&b.render_order));
for memory in sorted.iter() {
let sprite = if let Some(sprite) = atlas.get(&memory.sprite) {
sprite
} else {
panic!("No sprite found for ID: {}", memory.sprite);
};
draw.image(sprite)
.position(
(((x + bounds.x_offset) as f32) + memory.offset.0) *
TILESIZE,
(((y + bounds.y_offset) as f32) + memory.offset.1) *
TILESIZE
)
.color(
if memory.recolour {
Color::from_rgb(memory.fg.r, memory.fg.g, memory.fg.b)
} else {
Color::from_rgb(0.75, 0.75, 0.75)
}
);
}
}
}
}
} else if SHOW_BOUNDARIES {
// TODO: Draw boundaries
@ -524,7 +498,8 @@ fn draw(_app: &mut App, gfx: &mut Graphics, gs: &mut State) {
let mut draw = gfx.create_draw();
draw.clear(Color::BLACK);
let mut log = false;
match *gs.ecs.fetch::<RunState>() {
let runstate = *gs.ecs.fetch::<RunState>();
match runstate {
| RunState::MainMenu { .. }
| RunState::CharacterCreation { .. }
| RunState::PreRun { .. } => {}
@ -541,13 +516,14 @@ fn draw(_app: &mut App, gfx: &mut Graphics, gs: &mut State) {
}
}
_ => {
let map = gs.ecs.fetch::<Map>();
draw_bg(&gs.ecs, &mut draw, &gs.atlas);
draw_camera(&gs.ecs, &mut draw, &gs.atlas, &gs.font);
draw_camera(&*map, &gs.ecs, &mut draw, &gs.atlas, &gs.font);
gui::draw_ui2(&gs.ecs, &mut draw, &gs.atlas, &gs.font);
log = true;
}
}
match *gs.ecs.fetch::<RunState>() {
match runstate {
RunState::Farlook { x, y } => {
gui::draw_farlook(x, y, &mut draw, &gs.atlas);
//draw_tooltips(&gs.ecs, ctx, Some((x, y))); TODO: Put this in draw loop

View file

@ -26,6 +26,15 @@ use super::consts::visuals::{
// i.e. on a map size of 40*40, only entities to the left of the player are rendered.
// on a map size of 42*42, the player can see entities up to 2 tiles to their right.
#[derive(Clone, Serialize, Deserialize)]
pub struct MapMemory {
pub sprite: String,
pub fg: RGB,
pub recolour: bool,
pub offset: (f32, f32),
pub render_order: i32,
}
#[derive(Default, Serialize, Deserialize, Clone)]
pub struct Map {
pub overmap: bool,
@ -33,6 +42,7 @@ pub struct Map {
pub width: i32,
pub height: i32,
pub revealed_tiles: Vec<bool>,
pub memory: HashMap<usize, Vec<MapMemory>>,
pub visible_tiles: Vec<bool>,
pub lit_tiles: Vec<bool>,
pub telepath_tiles: Vec<bool>,
@ -71,6 +81,7 @@ impl Map {
width: width,
height: height,
revealed_tiles: vec![false; map_tile_count],
memory: HashMap::new(),
visible_tiles: vec![false; map_tile_count],
lit_tiles: vec![true; map_tile_count], // NYI: Light sources. Once those exist, we can set this to false.
telepath_tiles: vec![false; map_tile_count],

View file

@ -10,6 +10,8 @@ use super::{
Telepath,
Viewshed,
Renderable,
Prop,
Item,
gui::renderable_colour,
tile_blocks_telepathy,
};
@ -35,6 +37,8 @@ impl<'a> System<'a> for VisibilitySystem {
ReadStorage<'a, Blind>,
ReadStorage<'a, BlocksVisibility>,
ReadStorage<'a, Renderable>,
ReadStorage<'a, Prop>,
ReadStorage<'a, Item>,
);
fn run(&mut self, data: Self::SystemData) {
@ -51,6 +55,8 @@ impl<'a> System<'a> for VisibilitySystem {
blind_entities,
blocks_visibility,
renderables,
prop,
item,
) = data;
map.view_blocked.clear();
@ -59,6 +65,7 @@ impl<'a> System<'a> for VisibilitySystem {
map.view_blocked.insert(idx);
}
let mut player_was_dirty = false;
for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() {
if viewshed.dirty {
viewshed.dirty = false;
@ -81,6 +88,7 @@ impl<'a> System<'a> for VisibilitySystem {
// If this is the player, reveal what they can see
let _p: Option<&Player> = player.get(ent);
if let Some(_p) = _p {
player_was_dirty = true;
for t in map.visible_tiles.iter_mut() {
*t = false;
}
@ -139,6 +147,37 @@ impl<'a> System<'a> for VisibilitySystem {
}
}
}
if player_was_dirty {
// Refresh the memory of our visible tiles, by removing whatever
// was stored for every index we can currently see, and placing
// back in updated data.
let mut to_remove: Vec<usize> = Vec::new();
for (i, &t) in map.visible_tiles.iter().enumerate() {
if t {
to_remove.push(i);
}
}
for idx in to_remove.iter() {
map.memory.remove(idx);
}
for (e, r, p, _h) in (&entities, &renderables, &pos, !&hidden).join() {
if prop.get(e).is_some() || item.get(e).is_some() {
let idx = map.xy_idx(p.x, p.y);
if map.visible_tiles[idx] {
if let Some(spriteinfo) = &r.sprite {
map.memory.entry(idx).or_insert(Vec::new()).push(crate::MapMemory {
sprite: spriteinfo.id.clone(),
fg: r.fg,
recolour: spriteinfo.recolour,
offset: spriteinfo.offset,
render_order: r.render_order,
});
}
}
}
}
}
}
}