use super::{ Hidden, Map, Mind, Position, Prop, Renderable, Pools }; use bracket_lib::prelude::*; use specs::prelude::*; use std::ops::Mul; use super::consts::visuals::{ VIEWPORT_W, VIEWPORT_H }; use super::consts::prelude::*; const SHOW_BOUNDARIES: bool = false; pub struct Offsets { pub x: i32, pub y: i32, } pub fn get_offset() -> Offsets { return Offsets { x: 1, y: 10 }; } pub struct ScreenBounds { pub min_x: i32, pub max_x: i32, pub min_y: i32, pub max_y: i32, pub x_offset: i32, pub y_offset: i32, } pub fn get_screen_bounds(ecs: &World, debug: bool) -> ScreenBounds { let map = ecs.fetch::(); let player_pos = if !debug { *ecs.fetch::() } else { Point::new(map.width / 2, map.height / 2) }; let (x_chars, y_chars, mut x_offset, mut y_offset) = (VIEWPORT_W, VIEWPORT_H, 1, 10); let centre_x = (x_chars / 2) as i32; let centre_y = (y_chars / 2) as i32; let min_x = if map.width < (x_chars as i32) { x_offset += ((x_chars as i32) - map.width) / 2; 0 } else { (player_pos.x - centre_x).clamp(0, map.width - (x_chars as i32)) }; let min_y = if map.height < (y_chars as i32) { y_offset += ((y_chars as i32) - map.height) / 2; 0 } else { (player_pos.y - centre_y).clamp(0, map.height - (y_chars as i32)) }; let max_x = min_x + (x_chars as i32); let max_y = min_y + (y_chars as i32); ScreenBounds { min_x, max_x, min_y, max_y, x_offset, y_offset } } pub fn in_bounds(x: i32, y: i32, min_x: i32, min_y: i32, upper_x: i32, upper_y: i32) -> bool { x >= min_x && x < upper_x && y >= min_y && y < upper_y } pub fn render_camera(ecs: &World, ctx: &mut BTerm) { let map = ecs.fetch::(); let bounds = get_screen_bounds(ecs, false); // Render map let mut y = 0; for t_y in bounds.min_y..bounds.max_y { let mut x = 0; for t_x in bounds.min_x..bounds.max_x { if t_x >= 0 && t_x < map.width && t_y >= 0 && t_y < map.height { let idx = map.xy_idx(t_x, t_y); if map.revealed_tiles[idx] { if 1 == 2 { let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id( idx, &*map, Some(*ecs.fetch::()), None ); ctx.set(x + bounds.x_offset, y + bounds.y_offset, fg, bg, glyph); } else { ctx.set_active_console(0); let (id, tint) = crate::map::themes::get_sprite_for_id( idx, &*map, Some(*ecs.fetch::()) ); ctx.add_sprite( Rect::with_size( x * 16 + bounds.x_offset * 16, y * 16 + bounds.y_offset * 16, 16, 16 ), 0, RGBA::named(WHITE), 0 // Ya ); ctx.set_active_console(TILE_LAYER); } } } else if SHOW_BOUNDARIES { ctx.set( x + bounds.x_offset, y + bounds.y_offset, RGB::named(DARKSLATEGRAY), RGB::named(BLACK), to_cp437('#') ); } x += 1; } y += 1; } // Render entities { ctx.set_active_console(ENTITY_LAYER); let positions = ecs.read_storage::(); let renderables = ecs.read_storage::(); let pools = ecs.read_storage::(); let minds = ecs.read_storage::(); let hidden = ecs.read_storage::(); let props = ecs.write_storage::(); let map = ecs.fetch::(); let entities = ecs.entities(); let mut data = (&positions, &renderables, &entities, !&hidden).join().collect::>(); data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order)); for (pos, render, ent, _hidden) in data.iter() { let idx = map.xy_idx(pos.x, pos.y); let entity_offset_x = pos.x - bounds.min_x; let entity_offset_y = pos.y - bounds.min_y; if pos.x < bounds.max_x && pos.y < bounds.max_y && pos.x >= bounds.min_x && pos.y >= bounds.min_y { let mut draw = false; let mut fg = render.fg; let bg = BLACK; // Draw entities on visible tiles if map.visible_tiles[idx] { draw = true; } else { fg = fg.mul(crate::consts::visuals::NON_VISIBLE_MULTIPLIER); // We don't darken BG, because get_tile_renderables_for_id handles this. } // Draw entities with minds within telepath range if !draw { if map.telepath_tiles[idx] { let has_mind = minds.get(*ent); if let Some(_) = has_mind { draw = true; } } } // Draw all props let is_prop = props.get(*ent); if let Some(_) = is_prop { if map.revealed_tiles[idx] { draw = true; } } if draw { /* if let Some(sprite) = render.sprite { ctx.set_active_console(0); ctx.add_sprite( Rect::with_size( entity_offset_x * 16 + bounds.x_offset * 16, entity_offset_y * 16 + bounds.y_offset * 16, 16, 16 ), render.render_order, RGBA::named(WHITE), sprite ); ctx.set_active_console(ENTITY_LAYER); } else */ { ctx.set( entity_offset_x + bounds.x_offset, entity_offset_y + bounds.y_offset, fg, bg, render.glyph ); } if let Some(pool) = pools.get(*ent) { if pool.hit_points.current < pool.hit_points.max { ctx.set_active_console(HP_BAR_LAYER); crate::gui::draw_lerping_bar( ctx, (entity_offset_x + bounds.x_offset) * 16 + 2, (entity_offset_y + bounds.y_offset) * 16 - 1, 14, pool.hit_points.current, pool.hit_points.max, RGB::named(GREEN), RGB::named(RED), false, false ); ctx.set_active_console(ENTITY_LAYER); } } } } } ctx.set_active_console(TILE_LAYER); } } pub fn render_debug_map(map: &Map, ctx: &mut BTerm) { let player_pos = Point::new(map.width / 2, map.height / 2); let (x_chars, y_chars) = ctx.get_char_size(); let center_x = (x_chars / 2) as i32; let center_y = (y_chars / 2) as i32; let min_x = player_pos.x - center_x; let max_x = min_x + (x_chars as i32); let min_y = player_pos.y - center_y; let max_y = min_y + (y_chars as i32); let map_width = map.width; let map_height = map.height; let mut y = 0; for ty in min_y..max_y { let mut x = 0; for tx in min_x..max_x { if tx >= 0 && tx < map_width && ty >= 0 && ty < map_height { let idx = map.xy_idx(tx, ty); if map.revealed_tiles[idx] { let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id( idx, &*map, None, None ); ctx.set(x, y, fg, bg, glyph); } } else if SHOW_BOUNDARIES { ctx.set(x, y, RGB::named(GRAY), RGB::named(BLACK), to_cp437('ยท')); } x += 1; } y += 1; } }