diff --git a/src/camera.rs b/src/camera.rs index eb268d4..a790317 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -5,9 +5,10 @@ use crate::{Hidden, Map, Position, Renderable, TileType}; const SHOW_BOUNDARIES: bool = false; -pub fn get_screen_bounds(ecs: &World, ctx: &mut Rltk) -> (i32, i32, i32, i32) { +pub fn get_screen_bounds(ecs: &World, _ctx: &mut Rltk) -> (i32, i32, i32, i32) { let player_pos = ecs.fetch::(); - let (x_chars, y_chars) = ctx.get_char_size(); + // let (x_chars, y_chars) = ctx.get_char_size(); + let (x_chars, y_chars) = (48, 44); let center_x = (x_chars / 2) as i32; let center_y = (y_chars / 2) as i32; diff --git a/src/gui.rs b/src/gui.rs index cce6b91..6dc3a3d 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -2,102 +2,129 @@ use ::rltk::{Point, Rltk, VirtualKeyCode, RGB}; use ::specs::prelude::*; use crate::components::{ - HungerClock, HungerState, InBackpack, Name, Player, Pools, Position, Viewshed, + Attribute, HungerClock, HungerState, InBackpack, Name, Player, Pools, Position, Viewshed, }; use crate::game_log::GameLog; use crate::rex_assets::RexAssets; use crate::{camera, Equipped, Hidden, Map, RunState, State}; +pub fn draw_hollow_box( + console: &mut Rltk, + sx: i32, + sy: i32, + width: i32, + height: i32, + fg: RGB, + bg: RGB, +) { + use rltk::to_cp437; + + console.set(sx, sy, fg, bg, to_cp437('┌')); + console.set(sx + width, sy, fg, bg, to_cp437('┐')); + console.set(sx, sy + height, fg, bg, to_cp437('└')); + console.set(sx + width, sy + height, fg, bg, to_cp437('┘')); + + for x in sx + 1..sx + width { + console.set(x, sy, fg, bg, to_cp437('─')); + console.set(x, sy + height, fg, bg, to_cp437('─')); + } + for y in sy + 1..sy + height { + console.set(sx, y, fg, bg, to_cp437('│')); + console.set(sx + width, y, fg, bg, to_cp437('│')); + } +} + pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { - ctx.draw_box( - 0, - 43, - 79, - 6, - RGB::named(rltk::WHITE), - RGB::named(rltk::BLACK), - ); + use rltk::to_cp437; + let box_gray: RGB = RGB::from_hex("#999999").expect("Ooops"); + let black = RGB::named(rltk::BLACK); + let white = RGB::named(rltk::WHITE); - let combat_stats = ecs.read_storage::(); - let players = ecs.read_storage::(); - let hunger = ecs.read_storage::(); + draw_hollow_box(ctx, 0, 0, 79, 59, box_gray, black); // Overall box + draw_hollow_box(ctx, 0, 0, 49, 45, box_gray, black); // Map box + draw_hollow_box(ctx, 0, 45, 79, 14, box_gray, black); // Log box + draw_hollow_box(ctx, 49, 0, 30, 8, box_gray, black); // Top-right panel - // Display player health - for (_player, stats, hc) in (&players, &combat_stats, &hunger).join() { - let health = format!( - " HP: {} / {} ", - stats.hit_points.current, stats.hit_points.max - ); - ctx.print_color( - 12, - 43, - RGB::named(rltk::YELLOW), - RGB::named(rltk::BLACK), - &health, - ); - - ctx.draw_bar_horizontal( - 29, - 43, - 51, - stats.hit_points.current, - stats.hit_points.max, - RGB::named(rltk::RED), - RGB::named(rltk::BLACK), - ); - - match hc.state { - HungerState::WellFed => ctx.print_color( - 71, - 42, - RGB::named(rltk::GREEN), - RGB::named(rltk::BLACK), - "Well Fed", - ), - HungerState::Normal => {} - HungerState::Hungry => ctx.print_color( - 71, - 42, - RGB::named(rltk::ORANGE), - RGB::named(rltk::BLACK), - "Hungry", - ), - HungerState::Starving => ctx.print_color( - 71, - 42, - RGB::named(rltk::RED), - RGB::named(rltk::BLACK), - "Starving", - ), - } - } + ctx.set(0, 45, box_gray, black, to_cp437('├')); + ctx.set(49, 8, box_gray, black, to_cp437('├')); + ctx.set(49, 0, box_gray, black, to_cp437('┬')); + ctx.set(49, 45, box_gray, black, to_cp437('┴')); + ctx.set(79, 8, box_gray, black, to_cp437('┤')); + ctx.set(79, 45, box_gray, black, to_cp437('┤')); + // Draw the town name let map = ecs.fetch::(); - let depth = format!("Depth: {}", map.depth); - ctx.print_color( - 2, - 43, - RGB::named(rltk::YELLOW), - RGB::named(rltk::BLACK), - &depth, + let name_length = map.name.len() + 2; + let x_pos = (22 - (name_length / 2)) as i32; + ctx.set(x_pos, 0, box_gray, black, to_cp437('┤')); + ctx.set( + x_pos + name_length as i32, + 0, + box_gray, + black, + to_cp437('├'), ); + ctx.print_color(x_pos + 1, 0, white, black, &map.name); + std::mem::drop(map); - // Display logs - let log = ecs.fetch::(); - let mut y = 44; - for s in log.entries.iter().rev() { - if y < 49 { - ctx.print(2, y, s); - } + // Draw stats + let player_entity = ecs.fetch::(); + let pools = ecs.read_storage::(); + let player_pools = pools.get(*player_entity).unwrap(); + let health = format!( + "Health: {}/{}", + player_pools.hit_points.current, player_pools.hit_points.max + ); + let mana = format!( + "Mana: {}/{}", + player_pools.mana.current, player_pools.mana.max + ); + ctx.print_color(50, 1, white, black, &health); + ctx.print_color(50, 2, white, black, &mana); + ctx.draw_bar_horizontal( + 64, + 1, + 14, + player_pools.hit_points.current, + player_pools.hit_points.max, + RGB::named(rltk::RED), + RGB::named(rltk::BLACK), + ); + ctx.draw_bar_horizontal( + 64, + 2, + 14, + player_pools.mana.current, + player_pools.mana.max, + RGB::named(rltk::BLUE), + RGB::named(rltk::BLACK), + ); +} - y += 1; +fn draw_attribute(name: &str, attribute: &Attribute, y: i32, ctx: &mut Rltk) { + let black = RGB::named(rltk::BLACK); + let attr_gray = RGB::from_hex("#CCCCCC").expect("Oops"); + ctx.print_color(50, y, attr_gray, black, name); + + let color = if attribute.modifiers < 0 { + RGB::from_f32(1.0, 0.0, 0.0) + } else if attribute.modifiers == 0 { + RGB::named(rltk::WHITE) + } else { + RGB::from_f32(0.0, 1.0, 0.0) + }; + ctx.print_color( + 67, + y, + color, + black, + &format!("{}", attribute.base + attribute.modifiers), + ); + ctx.print_color(73, y, color, black, &format!("{}", attribute.bonus)); + + if attribute.bonus > 0 { + ctx.set(72, y, color, black, rltk::to_cp437('+')); } - - // Mouse cursor - let mouse_pos = ctx.mouse_pos(); - ctx.set_bg(mouse_pos.0, mouse_pos.1, RGB::named(rltk::MAGENTA)); - - draw_tooltips(ecs, ctx); } fn draw_tooltips(ecs: &World, ctx: &mut Rltk) { diff --git a/src/main.rs b/src/main.rs index d517161..9c3545e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,7 +53,7 @@ macro_rules! register { } } -const SHOW_MAPGEN_VISUALIZER: bool = true; +const SHOW_MAPGEN_VISUALIZER: bool = false; #[derive(PartialEq, Copy, Clone)] pub enum RunState { @@ -486,7 +486,8 @@ impl State { } fn main() -> ::rltk::BError { - let context = ::rltk::RltkBuilder::simple80x50() + let context = ::rltk::RltkBuilder::simple(80, 60) + .unwrap() .with_title("Roguelike Tutorial") .build()?; @@ -544,7 +545,7 @@ fn main() -> ::rltk::BError { raws::load_raws(); - gs.ecs.insert(Map::new(1, 64, 64)); + gs.ecs.insert(Map::new(1, 64, 64, "New Map")); gs.ecs.insert(Point::zero()); gs.ecs.insert(RandomNumberGenerator::new()); diff --git a/src/map.rs b/src/map.rs index 9f90d0f..d1b8731 100644 --- a/src/map.rs +++ b/src/map.rs @@ -20,6 +20,7 @@ pub struct Map { pub depth: i32, pub bloodstains: HashSet, pub view_blocked: HashSet, + pub name: String, #[serde(skip_serializing)] #[serde(skip_deserializing)] @@ -54,7 +55,7 @@ impl Map { } /// Generates an empty map, consisting entirely of solid walls - pub fn new(new_depth: i32, width: i32, height: i32) -> Map { + pub fn new(new_depth: i32, width: i32, height: i32, name: S) -> Map { let map_tile_count = (width * height) as usize; Map { @@ -68,6 +69,7 @@ impl Map { depth: new_depth, bloodstains: HashSet::new(), view_blocked: HashSet::new(), + name: name.to_string(), } } } diff --git a/src/map_builders.rs b/src/map_builders.rs index bd47b4d..55f83d0 100644 --- a/src/map_builders.rs +++ b/src/map_builders.rs @@ -73,10 +73,10 @@ pub struct BuilderMap { } impl BuilderMap { - fn new(new_depth: i32, width: i32, height: i32) -> BuilderMap { + fn new(new_depth: i32, width: i32, height: i32, name: S) -> BuilderMap { BuilderMap { spawn_list: Vec::new(), - map: Map::new(new_depth, width, height), + map: Map::new(new_depth, width, height, name), starting_position: None, rooms: None, corridors: None, @@ -104,11 +104,11 @@ pub struct BuilderChain { } impl BuilderChain { - pub fn new(new_depth: i32, width: i32, height: i32) -> BuilderChain { + pub fn new(new_depth: i32, width: i32, height: i32, name: S) -> BuilderChain { BuilderChain { starter: None, builders: Vec::new(), - build_data: BuilderMap::new(new_depth, width, height), + build_data: BuilderMap::new(new_depth, width, height, name), } } @@ -301,7 +301,7 @@ pub fn random_builder( width: i32, height: i32, ) -> BuilderChain { - let mut builder = BuilderChain::new(new_depth, width, height); + let mut builder = BuilderChain::new(new_depth, width, height, "New Map"); match rng.roll_dice(1, 2) { 1 => random_room_builder(rng, &mut builder), diff --git a/src/map_builders/town.rs b/src/map_builders/town.rs index 12d48fa..dbf9ba8 100644 --- a/src/map_builders/town.rs +++ b/src/map_builders/town.rs @@ -11,7 +11,7 @@ pub fn town_builder( width: i32, height: i32, ) -> BuilderChain { - let mut chain = BuilderChain::new(new_depth, width, height); + let mut chain = BuilderChain::new(new_depth, width, height, "The Town of Ion"); chain.start_with(TownBuilder::new()); chain diff --git a/src/map_builders/waveform_collapse.rs b/src/map_builders/waveform_collapse.rs index b576e4c..1165bab 100644 --- a/src/map_builders/waveform_collapse.rs +++ b/src/map_builders/waveform_collapse.rs @@ -33,7 +33,12 @@ impl WaveformCollapseBuilder { let constraints = patterns_to_constraints(patterns, CHUNK_SIZE); self.render_tile_gallery(&constraints, CHUNK_SIZE, build_data); - build_data.map = Map::new(build_data.map.depth, build_data.width, build_data.height); + build_data.map = Map::new( + build_data.map.depth, + build_data.width, + build_data.height, + &build_data.map.name, + ); loop { let mut solver = Solver::new(constraints.clone(), CHUNK_SIZE, &build_data.map); while !solver.iteration(&mut build_data.map, rng) { @@ -54,7 +59,7 @@ impl WaveformCollapseBuilder { chunk_size: i32, build_data: &mut BuilderMap, ) { - build_data.map = Map::new(0, build_data.width, build_data.height); + build_data.map = Map::new(0, build_data.width, build_data.height, &build_data.map.name); let mut counter = 0; let mut x = 1; let mut y = 1; @@ -71,7 +76,8 @@ impl WaveformCollapseBuilder { if y + chunk_size > build_data.map.height { // Move to the next page build_data.take_snapshot(); - build_data.map = Map::new(0, build_data.width, build_data.height); + build_data.map = + Map::new(0, build_data.width, build_data.height, &build_data.map.name); x = 1; y = 1;