Color to terminal

This commit is contained in:
2024-05-20 22:32:09 +02:00
parent fd23efdb29
commit 59e840cc25
4 changed files with 85 additions and 33 deletions

View File

@@ -1,4 +1,7 @@
use super::{entities::{Action, Direction, Entity}, floor::Floor}; use super::{
entities::{Action, Direction, Entity},
floor::Floor,
};
use dyn_clone::{clone_trait_object, DynClone}; use dyn_clone::{clone_trait_object, DynClone};
use rand::Rng; use rand::Rng;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -45,7 +48,7 @@ impl Cell {
match self { match self {
Cell::Entance => ' ', Cell::Entance => ' ',
Cell::Exit => '¤', Cell::Exit => '¤',
Cell::Special(_) => '§', Cell::Special(effect) => effect.as_char(),
Cell::Wall => '█', Cell::Wall => '█',
Cell::Empty => ' ', Cell::Empty => ' ',
} }
@@ -82,6 +85,10 @@ pub trait Effect: DynClone + core::fmt::Debug {
/// Tramite l'entità si può anche accedere al piano dove si trova per /// Tramite l'entità si può anche accedere al piano dove si trova per
/// poter modificare eventualmente qualcosa. /// poter modificare eventualmente qualcosa.
fn apply_to(&self, entity: &mut Entity, floor: &mut Floor); fn apply_to(&self, entity: &mut Entity, floor: &mut Floor);
/// Ritorna un carattere che rappresenta l'effetto.
fn as_char(&self) -> char {
'?'
}
} }
clone_trait_object!(Effect); clone_trait_object!(Effect);
@@ -99,6 +106,13 @@ impl Effect for InstantDamage {
fn apply_to(&self, entity: &mut Entity, _floor: &mut Floor) { fn apply_to(&self, entity: &mut Entity, _floor: &mut Floor) {
entity.apply_damage(self.0); entity.apply_damage(self.0);
} }
fn as_char(&self) -> char {
if self.0 <= 0 {
'+'
} else {
'-'
}
}
} }
/// Permettere di infliggere lo stato di confuzione ad una entità.\ /// Permettere di infliggere lo stato di confuzione ad una entità.\

View File

@@ -89,7 +89,7 @@ impl Default for Config {
priority: 1, priority: 1,
}, },
ConfigEffect { ConfigEffect {
effect: Box::new(InstantDamage(-20)), effect: Box::new(InstantDamage(-10)),
floors: 0..255, floors: 0..255,
priority: 1, priority: 1,
}, },

View File

@@ -138,6 +138,16 @@ impl Entity {
self.health self.health
} }
/// Restituisce il valore della vita massima dell'entità.\
pub fn get_health_max(&self) -> i32 {
self.health_max
}
/// Restituisce il valore del nome dell'entità.\
pub fn get_name(&self) -> &String {
&self.name
}
/// Applica il valore inserito come danno alla vita.\ /// Applica il valore inserito come danno alla vita.\
/// Nel caso in cui il danno sia negativo allora verrà interpretato come cura.\ /// Nel caso in cui il danno sia negativo allora verrà interpretato come cura.\
/// Nel caso in cui la vita sia negativa la logica sarà inversa.\ /// Nel caso in cui la vita sia negativa la logica sarà inversa.\
@@ -176,6 +186,10 @@ impl Entity {
} }
self.compute_effects(floor); self.compute_effects(floor);
if !self.is_alive() {
self.behavior.you_died(floor.get_limited_view_floor(self));
return false
}
true true
} }

View File

@@ -1,7 +1,7 @@
use self::{ use self::{
cell::Cell, cell::Cell,
config::Config, config::Config,
entities::{Action, Behavior, Direction}, entities::{Action, Behavior, Direction, Entity},
floor::FloorView, floor::FloorView,
game::Dungeon, game::Dungeon,
}; };
@@ -60,60 +60,84 @@ pub fn run_console(player: String, seed: u64) {
} }
} }
/// Implementazione di una possibile interfaccia console. const COLOR_RESET: &str = "\x1b[0m";
const COLOR_EFFECT: &str = "\x1b[95m";
const COLOR_ENEMY: &str = "\x1b[38;5;1m";
const COLOR_PLAYER: &str = "\x1b[38;5;166m";
const COLOR_PLAYER_HEALTH: &str = "\x1b[31m";
/// Implementazione di una possibile interfaccia console.\
/// Ha fin troppi metodi per far vedere in modo carino il gioco, ma comunque la parte importante
/// è l'implementazione del Behavior.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ConsoleInput; pub struct ConsoleInput;
impl ConsoleInput { impl ConsoleInput {
/// todo!() add docs
fn print_floor(&self, floor: FloorView, other: String) { fn print_floor(&self, floor: FloorView, other: String) {
let mut term = console::Term::stdout(); let mut term = console::Term::stdout();
let _ = term.clear_screen(); let _ = term.clear_screen();
let _ = term.write_fmt(format_args!( let _ = term.write_fmt(format_args!(
"{}{}\n{}\n", "{}Floor lv.{:2} - {}\n{other}\n",
Self::floor_as_string(&floor), Self::floor_as_string(&floor),
floor.entity, floor.floor.get_level(),
other Self::entity_as_string(floor.entity),
)); ));
} }
/// todo!() add docs /// todo!() add docs
fn entity_as_string(entity: &Entity) -> String {
let times = 20;
let health_bar = (entity.get_health() * times) / entity.get_health_max();
let filled = "".repeat(health_bar as usize);
let empty = " ".repeat((times - health_bar) as usize);
format!(
"{}: [{COLOR_PLAYER_HEALTH}{filled}{empty}{COLOR_RESET}] {:4}/{:4}",
entity.get_name(),
entity.get_health(),
entity.get_health_max()
)
}
/// todo!() add docs
fn floor_as_string(floor: &FloorView) -> String { fn floor_as_string(floor: &FloorView) -> String {
let view = 5; let view = 5;
let size = (2 * view) * 3; let size = (2 * view) * 3;
let iter = floor.get_grid(view).flat_map(|iter| { let iter = floor.get_grid(view).map(|iter| {
iter.flat_map(|view| { iter.map(|view| {
if let Some(e) = view.entity { if let Some(e) = view.entity {
return [' ', e.direction.as_char(), ' '].into_iter(); let color = if floor.entity.position == e.position {
COLOR_PLAYER
} else {
COLOR_ENEMY
};
return format!("{} {} {COLOR_RESET}", color, e.direction.as_char());
} }
let ch = view.cell.as_char(); let cell = view.cell.as_char();
match view.cell { match view.cell {
Cell::Wall => [ch, ch, ch], Cell::Special(_) => format!("{COLOR_EFFECT} {cell} {COLOR_RESET}"),
_ => [' ', ch, ' '], Cell::Wall => format!("{cell}{cell}{cell}"),
_ => format!(" {cell} "),
} }
.into_iter()
}) })
.collect()
}); });
Self::box_of(size, iter).collect() Self::box_of(size, iter).collect()
} }
/// todo!() add docs /// todo!() add docs
fn box_of(size: usize, iter: impl Iterator<Item = char>) -> impl Iterator<Item = char> { fn box_of(size: usize, iter: impl Iterator<Item = String>) -> impl Iterator<Item = String> {
std::iter::once('╔') std::iter::once("".to_string())
.chain(std::iter::repeat('═').take(size + 2)) .chain(std::iter::repeat("".to_string()).take(size + 2))
.chain(['╗', '\n'].into_iter()) .chain(std::iter::once("\n".to_string()))
.chain(iter.enumerate().flat_map(move |(i, c)| { .chain(iter.map(|string| {
let modulo = i % size; std::iter::once("".to_string())
if modulo == 0 { .chain(std::iter::once(string))
vec!['║', ' ', c] .chain(std::iter::once("\n".to_string()))
} else if modulo == size - 1 { .collect()
vec![c, ' ', '║', '\n']
} else {
vec![c]
}
.into_iter()
})) }))
.chain(std::iter::once('╚')) .chain(std::iter::once("".to_string()))
.chain(std::iter::repeat('═').take(size + 2)) .chain(std::iter::repeat("".to_string()).take(size + 2))
.chain(['╝', '\n'].into_iter()) .chain(std::iter::once("\n".to_string()))
} }
} }
#[typetag::serde] #[typetag::serde]