mirror of https://git.sr.ht/~garritfra/midgard
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.5 KiB
124 lines
3.5 KiB
use crate::crypto; |
|
use crate::traits::Render; |
|
use crate::State; |
|
use rltk::prelude::*; |
|
use rltk::Point; |
|
use rltk::RandomNumberGenerator; |
|
use std::fmt::Display; |
|
|
|
pub type Chunk = Vec<TileType>; |
|
|
|
#[derive(PartialEq, Copy, Clone, Debug)] |
|
pub enum TileType { |
|
Wall, |
|
Floor, |
|
} |
|
|
|
impl Display for TileType { |
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { |
|
match self { |
|
Self::Floor => f.write_str("Floor"), |
|
Self::Wall => f.write_str("Wall"), |
|
} |
|
} |
|
} |
|
|
|
impl Render for Chunk { |
|
fn render(&mut self, gs: &mut State, ctx: &mut rltk::Rltk) { |
|
// We'll use batched drawing |
|
let mut draw_batch = DrawBatch::new(); |
|
|
|
// Set all tiles to not visible |
|
for v in gs.visible.iter_mut() { |
|
*v = false; |
|
} |
|
|
|
// Obtain the player's visible tile set, and apply it |
|
let player_position = gs.index_to_point2d(gs.player_position); |
|
let fov = rltk::field_of_view_set(player_position, 8, gs); |
|
|
|
// Note that the steps above would generally not be run every frame! |
|
for idx in fov.iter() { |
|
let point = gs.point2d_to_index(*idx); |
|
gs.visible[point] = true; |
|
} |
|
|
|
// Clear the screen |
|
draw_batch.cls(); |
|
|
|
// Iterate the map array, incrementing coordinates as we go. |
|
let mut y = 0; |
|
let mut x = 0; |
|
for (i, tile) in gs.view.iter().enumerate() { |
|
// Render a tile depending upon the tile type; now we check visibility as well! |
|
let mut fg; |
|
let mut glyph = "."; |
|
|
|
match tile { |
|
TileType::Floor => { |
|
fg = RGB::from_f32(0.5, 0.5, 0.0); |
|
} |
|
TileType::Wall => { |
|
fg = RGB::from_f32(0.0, 1.0, 0.0); |
|
glyph = "#"; |
|
} |
|
} |
|
if !gs.visible[i] { |
|
fg = fg.to_greyscale(); |
|
} |
|
|
|
draw_batch.print_color( |
|
Point::new(x, y), |
|
glyph, |
|
ColorPair::new(fg, RGB::from_f32(0., 0., 0.)), |
|
); |
|
|
|
// Move the coordinates |
|
x += 1; |
|
if x > 79 { |
|
x = 0; |
|
y += 1; |
|
} |
|
} |
|
|
|
// Display selected object below the screen |
|
let selected_object_text = match gs.selected_object { |
|
Some(obj) => format!("{}", obj), |
|
None => "".to_string(), |
|
}; |
|
draw_batch.print_color( |
|
Point::new(0, 51), |
|
selected_object_text, |
|
ColorPair::new(RGB::from_f32(1.0, 1.0, 0.0), RGB::from_f32(0., 0., 0.)), |
|
); |
|
|
|
// Render the player @ symbol |
|
let ppos = gs.index_to_point2d(gs.player_position); |
|
draw_batch.print_color( |
|
Point::new(ppos.x, ppos.y), |
|
"@", |
|
ColorPair::new(RGB::from_f32(1.0, 1.0, 0.0), RGB::from_f32(0., 0., 0.)), |
|
); |
|
|
|
draw_batch.submit(0).expect("Batch error"); |
|
render_draw_buffer(ctx).expect("Render error"); |
|
} |
|
} |
|
|
|
pub fn new_chunk(seed: u64, pos: Point) -> Chunk { |
|
let mut map = vec![TileType::Floor; 80 * 50]; |
|
let count = map.len(); |
|
|
|
let pos_hash = crypto::hash_to_number(pos); |
|
|
|
// Feed seed and world position into random generator. |
|
// There might be a better way to do this, but I think this works for now. |
|
let mut rng = RandomNumberGenerator::seeded(seed.max(pos_hash) - seed.min(pos_hash)); |
|
|
|
// Place obstacles |
|
for _ in 0..20 { |
|
map[rng.range(0, count)] = TileType::Wall; |
|
} |
|
|
|
map |
|
}
|
|
|