We've got color (finally)!

This commit is contained in:
Alex Bethel 2022-03-03 11:21:32 -07:00
parent daafe3b023
commit c6868a7a01
6 changed files with 124 additions and 32 deletions

21
Cargo.lock generated
View file

@ -108,6 +108,7 @@ dependencies = [
"rand",
"specs",
"specs-derive",
"thiserror",
]
[[package]]
@ -506,6 +507,26 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tuple_utils"
version = "0.3.0"

View file

@ -13,3 +13,4 @@ rand = "0.8.4"
grid = "0.6.0"
float-ord = "0.3.2"
pathfinding = "3"
thiserror = "1"

92
src/io.rs Normal file
View file

@ -0,0 +1,92 @@
//! Pancurses boilerplate code.
use std::process::exit;
use pancurses::{
endwin, has_colors, init_pair, initscr, noecho, start_color, ColorPair, Window, COLORS,
COLOR_PAIRS,
};
use thiserror::Error;
/// Initializes the terminal to accept user input, and creates a new
/// Window.
pub fn init_window() -> Window {
// Create a new window over the terminal.
let window = initscr();
// Enable keypad mode (off by default for historical reasons), so
// we can read special keycodes other than just characters.
window.keypad(true);
// Disable echoing so the user doesn't see flickering in the
// upper-left corner of the screen when they type a character.
noecho();
// // Set up a color palette. TODO
// init_colors().unwrap();
let c = init_colors();
if let Err(e) = c {
endwin();
println!("{}", e);
panic!();
}
window
}
/// Cleans everything up and exits the game.
pub fn quit() -> ! {
endwin();
exit(0)
}
/// The colors on a terminal.
#[allow(unused)]
pub enum Color {
Black = 0,
Red = 1,
Green = 2,
Brown = 3,
Blue = 4,
Magenta = 5,
Cyan = 6,
White = 7,
}
#[derive(Error, Debug)]
enum ColorError {
#[error("colors not supported")]
NoColors,
#[error("too few colors (have {0}, need 8)")]
NotEnoughColors(u32),
#[error("too few color slots (have {0}, need 8)")]
NotEnoughSlots(u32),
}
fn init_colors() -> Result<(), ColorError> {
assert_eq!(start_color(), 0);
if !has_colors() {
Err(ColorError::NoColors)
} else if COLORS() < 8 {
Err(ColorError::NotEnoughColors(COLORS() as _))
} else if COLOR_PAIRS() < 8 {
Err(ColorError::NotEnoughSlots(COLOR_PAIRS() as _))
} else {
for n in 0..8 {
init_pair(n, n, Color::Black as _);
}
Ok(())
}
}
pub fn set_color(win: &Window, c: Color) {
// This gets called for every single character; could be a
// performance bottleneck depending on how ncurses implements it.
if has_colors() {
win.attron(ColorPair(c as _));
}
}

View file

@ -4,10 +4,7 @@ use pancurses::Window;
use rand::Rng;
use specs::prelude::*;
use crate::{
components::{CharRender, Position},
rooms,
};
use crate::{components::{CharRender, Position}, io::{Color, set_color}, rooms};
/// The size of a dungeon level, in tiles.
pub const LEVEL_SIZE: (usize, usize) = (80, 24);
@ -108,6 +105,12 @@ impl DungeonLevel {
for y in 0..LEVEL_SIZE.1 {
win.mv(y as _, 0);
for x in 0..LEVEL_SIZE.0 {
if (x + y) % 2 == 0 {
set_color(win, Color::Cyan);
} else {
set_color(win, Color::Red);
}
win.addch(if filter((x as _, y as _)) {
self.render_tile(x, y)
} else {

View file

@ -1,15 +1,14 @@
use std::process::exit;
use components::{register_all, CharRender, MobAction, Mobile, Player, Position, TurnTaker};
use io::init_window;
use level::DungeonLevel;
use pancurses::{endwin, initscr, noecho, Window};
use player::player_turn;
use rand::thread_rng;
use specs::prelude::*;
use systems::{MobSystem, TimeSystem};
mod components;
mod io;
mod level;
mod player;
mod rooms;
@ -65,27 +64,3 @@ fn main() {
}
}
}
/// Initializes the terminal to accept user input, and creates a new
/// Window.
fn init_window() -> Window {
// Create a new window over the terminal.
let window = initscr();
// Enable keypad mode (off by default for historical reasons), so
// we can read special keycodes other than just characters.
window.keypad(true);
// Disable echoing so the user doesn't see flickering in the
// upper-left corner of the screen when they type a character.
noecho();
window
}
/// Cleans everything up and exits the game.
fn quit() -> ! {
endwin();
exit(0)
}

View file

@ -6,7 +6,7 @@ use specs::prelude::*;
use crate::{
components::{CharRender, MobAction, Mobile, Player, Position},
level::DungeonLevel,
quit,
io::quit,
visibility::{visible, CellVisibility, Lighting},
};