From 61f2ec5d6aa73f44bd66cf020aeccfaf53d6487f Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 2 Feb 2022 11:02:18 -0500 Subject: [PATCH] Batch draw the game hud --- src/gui/hud.rs | 337 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 224 insertions(+), 113 deletions(-) diff --git a/src/gui/hud.rs b/src/gui/hud.rs index e8662c9..de3c580 100644 --- a/src/gui/hud.rs +++ b/src/gui/hud.rs @@ -11,36 +11,112 @@ use crate::components::{ }; use crate::{colors, gamelog, Map}; -pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { - ctx.draw_hollow_box(0, 0, 79, 59, colors::BOX_GRAY, colors::BLACK); // Overall box - ctx.draw_hollow_box(0, 0, 49, 45, colors::BOX_GRAY, colors::BLACK); // Map box - ctx.draw_hollow_box(0, 45, 79, 14, colors::BOX_GRAY, colors::BLACK); // Log box - ctx.draw_hollow_box(49, 0, 30, 8, colors::BOX_GRAY, colors::BLACK); // Top-right panel +fn draw_attribute(name: &str, attribute: &Attribute, y: i32, draw_batch: &mut DrawBatch) { + draw_batch.print_color( + Point::new(50, y), + name, + ColorPair::new(colors::ATTR_GRAY, colors::BLACK), + ); - ctx.set(0, 45, colors::BOX_GRAY, colors::BLACK, to_cp437('├')); - ctx.set(49, 8, colors::BOX_GRAY, colors::BLACK, to_cp437('├')); - ctx.set(49, 0, colors::BOX_GRAY, colors::BLACK, to_cp437('┬')); - ctx.set(49, 45, colors::BOX_GRAY, colors::BLACK, to_cp437('┴')); - ctx.set(79, 8, colors::BOX_GRAY, colors::BLACK, to_cp437('┤')); - ctx.set(79, 45, colors::BOX_GRAY, colors::BLACK, to_cp437('┤')); + let color = match attribute.modifiers.cmp(&0) { + Ordering::Less => colors::RED, + Ordering::Equal => colors::WHITE, + Ordering::Greater => colors::GREEN, + }; - // Draw the town name + draw_batch.print_color( + Point::new(67, y), + &format!("{}", attribute.base + attribute.modifiers), + ColorPair::new(color, colors::BLACK), + ); + draw_batch.print_color( + Point::new(73, y), + &format!("{}", attribute.bonus), + ColorPair::new(color, colors::BLACK), + ); + + if attribute.bonus > 0 { + draw_batch.set( + Point::new(72, y), + ColorPair::new(color, colors::BLACK), + rltk::to_cp437('+'), + ); + } +} + +fn box_framework(draw_batch: &mut DrawBatch) { + draw_batch.draw_hollow_box( + Rect::with_size(0, 0, 79, 59), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + ); // Overall box + draw_batch.draw_hollow_box( + Rect::with_size(0, 0, 49, 45), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + ); // Map box + draw_batch.draw_hollow_box( + Rect::with_size(0, 45, 79, 14), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + ); // Log box + draw_batch.draw_hollow_box( + Rect::with_size(49, 0, 30, 8), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + ); // Top-right panel + + // Draw box connectors + draw_batch.set( + Point::new(0, 45), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('├'), + ); + draw_batch.set( + Point::new(49, 8), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('├'), + ); + draw_batch.set( + Point::new(49, 0), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('┬'), + ); + draw_batch.set( + Point::new(49, 45), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('┴'), + ); + draw_batch.set( + Point::new(79, 8), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('┤'), + ); + draw_batch.set( + Point::new(79, 45), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('┤'), + ); +} + +pub fn map_label(ecs: &World, draw_batch: &mut DrawBatch) { let map = ecs.fetch::(); let name_length = map.name.len() + 2; let x_pos = (22 - (name_length / 2)) as i32; - ctx.set(x_pos, 0, colors::BOX_GRAY, colors::BLACK, to_cp437('┤')); - ctx.set( - x_pos + name_length as i32, - 0, - colors::BOX_GRAY, - colors::BLACK, + draw_batch.set( + Point::new(x_pos, 0), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), + to_cp437('┤'), + ); + draw_batch.set( + Point::new(x_pos + name_length as i32, 0), + ColorPair::new(colors::BOX_GRAY, colors::BLACK), to_cp437('├'), ); - ctx.print_color(x_pos + 1, 0, colors::WHITE, colors::BLACK, &map.name); - std::mem::drop(map); + draw_batch.print_color( + Point::new(x_pos + 1, 0), + &map.name, + ColorPair::new(colors::WHITE, colors::BLACK), + ); +} - // Draw stats - let player_entity = ecs.fetch::(); +fn draw_stats(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity) { let pools = ecs.read_storage::(); let player_pools = pools.get(*player_entity).unwrap(); let health = format!( @@ -52,77 +128,84 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { player_pools.mana.current, player_pools.mana.max ); let xp = format!("Level: {}", player_pools.level); - ctx.print_color(50, 1, colors::WHITE, colors::BLACK, &health); - ctx.print_color(50, 2, colors::WHITE, colors::BLACK, &mana); - ctx.print_color(50, 3, colors::WHITE, colors::BLACK, &xp); - ctx.draw_bar_horizontal( - 64, - 1, + draw_batch.print_color( + Point::new(50, 1), + &health, + ColorPair::new(colors::WHITE, colors::BLACK), + ); + draw_batch.print_color( + Point::new(50, 2), + &mana, + ColorPair::new(colors::WHITE, colors::BLACK), + ); + draw_batch.print_color( + Point::new(50, 3), + &xp, + ColorPair::new(colors::WHITE, colors::BLACK), + ); + draw_batch.bar_horizontal( + Point::new(64, 1), 14, player_pools.hit_points.current, player_pools.hit_points.max, - colors::RED, - colors::BLACK, + ColorPair::new(colors::RED, colors::BLACK), ); - ctx.draw_bar_horizontal( - 64, - 2, + draw_batch.bar_horizontal( + Point::new(64, 2), 14, player_pools.mana.current, player_pools.mana.max, - colors::BLUE, - colors::BLACK, + ColorPair::new(colors::BLUE, colors::BLACK), ); let xp_level_start = (player_pools.level - 1) * 1000; - ctx.draw_bar_horizontal( - 64, - 3, + draw_batch.bar_horizontal( + Point::new(64, 3), 14, player_pools.xp - xp_level_start, 1000, - colors::GOLD, - colors::BLACK, + ColorPair::new(colors::GOLD, colors::BLACK), ); +} - // Attributes +fn draw_attributes(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity) { let attributes = ecs.read_storage::(); let attr = attributes.get(*player_entity).unwrap(); - draw_attribute("Might:", &attr.might, 4, ctx); - draw_attribute("Quickness:", &attr.quickness, 5, ctx); - draw_attribute("Fitness:", &attr.fitness, 6, ctx); - draw_attribute("Intelligence:", &attr.intelligence, 7, ctx); + draw_attribute("Might:", &attr.might, 4, draw_batch); + draw_attribute("Quickness:", &attr.quickness, 5, draw_batch); + draw_attribute("Fitness:", &attr.fitness, 6, draw_batch); + draw_attribute("Intelligence:", &attr.intelligence, 7, draw_batch); +} - // Initiative and weight - ctx.print_color( - 50, - 9, - colors::WHITE, - colors::BLACK, +fn initiative_weight(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity) { + let attributes = ecs.read_storage::(); + let attr = attributes.get(*player_entity).unwrap(); + let pools = ecs.read_storage::(); + let player_pools = pools.get(*player_entity).unwrap(); + draw_batch.print_color( + Point::new(50, 9), &format!( "{:.0} lbs ({} lbs max)", player_pools.total_weight, (attr.might.base + attr.might.modifiers) * 15 ), + ColorPair::new(colors::WHITE, colors::BLACK), ); - ctx.print_color( - 50, - 10, - colors::WHITE, - colors::BLACK, + draw_batch.print_color( + Point::new(50, 10), &format!( "Initiative Penalty: {:.0}", player_pools.total_initiative_penalty ), + ColorPair::new(colors::WHITE, colors::BLACK), ); - ctx.print_color( - 50, - 11, - colors::GOLD, - colors::BLACK, + draw_batch.print_color( + Point::new(50, 11), &format!("Gold: {:.1}", player_pools.gold), + ColorPair::new(colors::GOLD, colors::BLACK), ); +} - // Equipped +fn equipped(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity) -> i32 { let mut y = 13; let entities = ecs.entities(); let equipped = ecs.read_storage::(); @@ -130,7 +213,11 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { for (entity, equipped_by) in (&entities, &equipped).join() { if equipped_by.owner == *player_entity { let name = get_item_display_name(ecs, entity); - ctx.print_color(50, y, get_item_color(ecs, entity), colors::BLACK, &name); + draw_batch.print_color( + Point::new(50, y), + &name, + ColorPair::new(get_item_color(ecs, entity), colors::BLACK), + ); y += 1; if let Some(weapon) = weapon.get(entity) { @@ -165,65 +252,95 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { weapon_info += &format!(" (range: {}, F to fire, V cycle targets)", range); } weapon_info += " ├"; - ctx.print_color(3, 45, colors::YELLOW, colors::BLACK, &weapon_info); + draw_batch.print_color( + Point::new(3, 45), + &weapon_info, + ColorPair::new(colors::YELLOW, colors::BLACK), + ); } } } - // Consumables + y +} + +fn consumables(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity, mut y: i32) -> i32 { y += 1; + let entities = ecs.entities(); let consumables = ecs.read_storage::(); let backpack = ecs.read_storage::(); let mut index = 1; for (entity, carried_by, _consumable) in (&entities, &backpack, &consumables).join() { if carried_by.owner == *player_entity && index < 10 { - ctx.print_color(50, y, colors::YELLOW, colors::BLACK, &format!("↑{}", index)); - ctx.print_color( - 53, - y, - get_item_color(ecs, entity), - colors::BLACK, + draw_batch.print_color( + Point::new(50, y), + &format!("↑{}", index), + ColorPair::new(colors::YELLOW, colors::BLACK), + ); + draw_batch.print_color( + Point::new(53, y), &get_item_display_name(ecs, entity), + ColorPair::new(get_item_color(ecs, entity), colors::BLACK), ); y += 1; index += 1; } } - // Spells + y +} + +fn spells(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity, mut y: i32) -> i32 { y += 1; let known_spells_storage = ecs.read_storage::(); let known_spells = &known_spells_storage.get(*player_entity).unwrap().spells; let mut index = 1; for spell in known_spells.iter() { - ctx.print_color(50, y, colors::CYAN, colors::BLACK, &format!("^{}", index)); - ctx.print_color( - 53, - y, - colors::CYAN, - colors::BLACK, + draw_batch.print_color( + Point::new(50, y), + &format!("^{}", index), + ColorPair::new(colors::CYAN, colors::BLACK), + ); + draw_batch.print_color( + Point::new(53, y), &format!("{} ({})", spell.display_name, spell.mana_cost), + ColorPair::new(colors::CYAN, colors::BLACK), ); index += 1; y += 1; } - // Status - y = 44; + y +} + +fn status(ecs: &World, draw_batch: &mut DrawBatch, player_entity: &Entity) { + let mut y = 44; let hunger = ecs.read_storage::(); let hc = hunger.get(*player_entity).unwrap(); match hc.state { HungerState::WellFed => { - ctx.print_color(50, y, colors::GREEN, colors::BLACK, "Well Fed"); + draw_batch.print_color( + Point::new(50, y), + "Well Fed", + ColorPair::new(colors::GREEN, colors::BLACK), + ); y -= 1; } HungerState::Normal => {} HungerState::Hungry => { - ctx.print_color(50, y, colors::ORANGE, colors::BLACK, "Hungry"); + draw_batch.print_color( + Point::new(50, y), + "Hungry", + ColorPair::new(colors::ORANGE, colors::BLACK), + ); y -= 1; } HungerState::Starving => { - ctx.print_color(50, y, colors::RED, colors::BLACK, "Starving"); + draw_batch.print_color( + Point::new(50, y), + "Starving", + ColorPair::new(colors::RED, colors::BLACK), + ); y -= 1; } } @@ -232,45 +349,39 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { let names = ecs.read_storage::(); for (status, duration, name) in (&statuses, &durations, &names).join() { if status.target == *player_entity { - ctx.print_color( - 50, - y, - colors::RED, - colors::BLACK, + draw_batch.print_color( + Point::new(50, y), &format!("{} ({})", name.name, duration.turns), + ColorPair::new(colors::RED, colors::BLACK), ); y -= 1; } } +} + +pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { + let mut draw_batch = DrawBatch::new(); + let player_entity = ecs.fetch::(); + + box_framework(&mut draw_batch); + map_label(ecs, &mut draw_batch); + draw_stats(ecs, &mut draw_batch, &player_entity); + draw_attributes(ecs, &mut draw_batch, &player_entity); + initiative_weight(ecs, &mut draw_batch, &player_entity); + + let mut y = equipped(ecs, &mut draw_batch, &player_entity); + y += consumables(ecs, &mut draw_batch, &player_entity, y); + + spells(ecs, &mut draw_batch, &player_entity, y); + status(ecs, &mut draw_batch, &player_entity); - // Draw the log gamelog::print_log( &mut ::rltk::BACKEND_INTERNAL.lock().consoles[1].console, Point::new(1, 23), ); - draw_tooltips(ecs, ctx); -} - -fn draw_attribute(name: &str, attribute: &Attribute, y: i32, ctx: &mut Rltk) { - ctx.print_color(50, y, colors::ATTR_GRAY, colors::BLACK, name); - - let color = match attribute.modifiers.cmp(&0) { - Ordering::Less => colors::RED, - Ordering::Equal => colors::WHITE, - Ordering::Greater => colors::GREEN, - }; - - ctx.print_color( - 67, - y, - color, - colors::BLACK, - &format!("{}", attribute.base + attribute.modifiers), - ); - ctx.print_color(73, y, color, colors::BLACK, &format!("{}", attribute.bonus)); - - if attribute.bonus > 0 { - ctx.set(72, y, color, colors::BLACK, rltk::to_cp437('+')); - } + + draw_batch + .submit(5000) + .expect("Failed to batch draw hud interface"); }