use crate::Textures; use super::tile::*; use raylib::prelude::*; #[derive(Debug, Default, Clone, Copy, PartialEq)] pub struct Pos { pub x: isize, pub y: isize, } impl Pos { pub const fn to_vec(self) -> Vector2 { Vector2 { x: self.x as f32, y: self.y as f32, } } } impl From<(usize, usize)> for Pos { fn from(value: (usize, usize)) -> Self { Self { x: value.0 as isize, y: value.1 as isize, } } } impl From for Pos { fn from(vec: Vector2) -> Self { Self { x: vec.x as isize, y: vec.y as isize, } } } #[derive(Debug, Clone)] pub struct Board { rows: Vec>, width: usize, height: usize, offset_x: isize, offset_y: isize, } impl Board { pub fn parse(source: &str) -> Self { let mut rows = Vec::new(); let mut width = 0; for line in source.lines() { width = width.max(line.len()); let mut tiles = Vec::new(); for char in line.chars() { tiles.push(Tile::from_char(char)); } rows.push(tiles); } for line in &mut rows { line.resize(width, Tile::Blank); } Board::new(rows) } pub fn to_string(&self) -> String { let mut out = String::new(); for row in &self.rows { for tile in row { out.push(tile.to_char()) } out.push('\n'); } out } pub fn new_empty(width: usize, height: usize) -> Self { let rows = vec![vec![Tile::Blank; width]; height]; Self { rows, width, height, offset_x: 0, offset_y: 0, } } pub fn new(rows: Vec>) -> Self { Self { width: rows[0].len(), height: rows.len(), rows, offset_x: 0, offset_y: 0, } } pub fn count_tiles(&self) -> usize { let mut sum = 0; for row in &self.rows { for tile in row { match tile { Tile::Blank | Tile::Block => (), _ => sum += 1, } } } sum } fn transform(&self, p: Pos) -> Pos { Pos { x: p.x + self.offset_x, y: p.y + self.offset_y, } } pub fn pos_in_bounds(&self, p: Pos) -> bool { let p = self.transform(p); self.in_bounds(p) } fn in_bounds(&self, p: Pos) -> bool { p.x >= 0 && p.y >= 0 && p.x < self.width as isize && p.y < self.height as isize } pub fn get(&self, p: Pos) -> Option { let p = self.transform(p); if self.in_bounds(p) { Some(self.rows[p.y as usize][p.x as usize]) } else { None } } pub fn get_or_blank(&self, p: Pos) -> Tile { let p = self.transform(p); if self.in_bounds(p) { self.rows[p.y as usize][p.x as usize] } else { Tile::default() } } pub fn get_mut(&mut self, p: Pos) -> Option<&mut Tile> { let p = self.transform(p); if self.in_bounds(p) { Some(&mut self.rows[p.y as usize][p.x as usize]) } else { None } } pub fn get_blank_mut(&mut self, p: Pos) -> Option<&mut Tile> { let p = self.transform(p); if self.in_bounds(p) { let tile = &mut self.rows[p.y as usize][p.x as usize]; if tile == &Tile::Blank { return Some(tile); } } None } pub fn set(&mut self, p: Pos, tile: Tile) { let p = self.transform(p); if self.in_bounds(p) { self.rows[p.y as usize][p.x as usize] = tile; } } pub fn grow_to_include(&mut self, p: Pos) { let p = self.transform(p); if p.x < 0 { let len = p.x.unsigned_abs(); for row in &mut self.rows { let mut new_row = vec![Tile::Blank; len]; new_row.append(row); *row = new_row; } self.offset_x += len as isize; self.width += len; } else if p.x as usize >= self.width { let new_width = p.x as usize + 1; for row in &mut self.rows { row.resize(new_width, Tile::Blank); } self.width = new_width; } if p.y < 0 { let len = p.y.unsigned_abs(); let mut new_rows = vec![vec![Tile::Blank; self.width]; len]; new_rows.append(&mut self.rows); self.rows = new_rows; self.offset_y += len as isize; self.height += len; } else if p.y as usize > self.height { let new_height = p.y as usize + 1; self.rows.resize(new_height, vec![Tile::Blank; self.width]); self.height = new_height; } } pub fn width(&self) -> usize { self.width } pub fn height(&self) -> usize { self.height } pub fn draw(&self, d: &mut RaylibDrawHandle, textures: &Textures, offset: Vector2, zoom: i32) { let tile_size = 16 << zoom; let start_x = (-offset.x as i32) / tile_size - 1; let tile_width = d.get_screen_width() / tile_size + 2; let start_y = (-offset.y as i32) / tile_size - 1; let tile_height = d.get_screen_height() / tile_size + 2; for x in start_x..(start_x + tile_width) { for y in start_y..(start_y + tile_height) { let tx = (x as isize + self.offset_x) as usize; let ty = (y as isize + self.offset_y) as usize; if self.in_bounds((tx, ty).into()) { let tile = self.rows[ty][tx]; let texname = tile.texture(); if texname == "" { continue; } let texture = textures.get(&texname); let px = x * tile_size + offset.x as i32; let py = y * tile_size + offset.y as i32; d.draw_texture_ex( texture, Vector2::new(px as f32, py as f32), 0.0, (1 << zoom) as f32, Color::WHITE, ); } } } } }