use crate::app::{ helpers::cells_area_helper, states::{ FocusedCell, Offset, skirmish_states::{ CellSizes, MarkedCells, MoveFocusedCell, Players, ZoomLevel, structures::{BaseBuilding, Ore, Stone, Structures}, tasks::{DiggingTask, Tasks}, units::{MinerUnit, Unit, Units}, }, }, widgets::CellWidget, }; use log::info; use ratatui::layout::Rect; use std::collections::VecDeque; #[derive(Debug, Clone, PartialEq)] pub struct BoardState { cells_area: Rect, pub cell_width: usize, pub cell_height: usize, pub map_width: usize, pub map_height: usize, pub cols: usize, pub rows: usize, pub vertical_offset: Offset, pub horizontal_offset: Offset, pub cells: Vec>, pub zoom_level: ZoomLevel, focused_cell: FocusedCell, pub marked_cells: MarkedCells, } impl BoardState { pub fn new( area: &Rect, map_width: usize, map_height: usize, zoom_level: ZoomLevel, side_panel: bool, ) -> Self { let cells_area: Rect = cells_area_helper(area, side_panel); let cell_width: usize = zoom_level.get_cell_size(CellSizes::Width); let cell_height: usize = zoom_level.get_cell_size(CellSizes::Height); let cols: usize = (cells_area.width / cell_width as u16) as usize; let rows: usize = (cells_area.height / cell_height as u16) as usize; let v_max_offset: usize = Self::max_offset(map_height, rows); let h_max_offset: usize = Self::max_offset(map_width, cols); let vertical_offset: Offset = Offset::new( Some((map_height - rows as usize + 1) / 2), Some(v_max_offset), ); let horizontal_offset: Offset = Offset::new(None, Some(h_max_offset)); let focused_cell: FocusedCell = FocusedCell::new((map_height) / 2, 3, map_height, map_width); let mut cells: Vec> = Vec::new(); let player_base_coords: (usize, usize) = ((map_height) / 2, 2); let enemy_base_coords: (usize, usize) = ((map_height) / 2, map_width - 3); for row in 0..map_height { let mut rows: Vec = Vec::new(); for col in 0..map_width { let selected: bool = row == focused_cell.get_row() && col == focused_cell.get_col(); let player_base: bool = row == player_base_coords.0 && col == player_base_coords.1; let player_ore: bool = row == player_base_coords.0 && col == player_base_coords.1 - 1; let enemy_base: bool = row == enemy_base_coords.0 && col == enemy_base_coords.1; let enemy_ore: bool = row == enemy_base_coords.0 && col == enemy_base_coords.1 + 1; let structure: Structures = if player_base { Structures::Base(BaseBuilding::new(Players::Player)) } else if enemy_base { Structures::Base(BaseBuilding::new(Players::Enemy)) } else if player_ore { Structures::Ore(Ore::new(Players::Player, 1)) } else if enemy_ore { Structures::Ore(Ore::new(Players::Enemy, 1)) } else { Structures::Stone(Stone::new()) }; let unit: Option = if player_base { Some(Units::Miner(MinerUnit::new( Players::Player, player_base_coords, ))) } else if enemy_base { Some(Units::Miner(MinerUnit::new( Players::Enemy, enemy_base_coords, ))) } else { None }; rows.push(CellWidget::new( row, col, zoom_level, selected, structure, unit, )); } cells.push(rows); } let marked_cells: MarkedCells = MarkedCells::new(); Self { cells_area, cell_width, cell_height, map_width, map_height, cols, rows, vertical_offset, horizontal_offset, cells, zoom_level, focused_cell, marked_cells, } } pub fn get_ref_cell(&self, row: usize, col: usize) -> &CellWidget { &self.cells[row][col] } fn get_mut_cell(&mut self, row: usize, col: usize) -> &mut CellWidget { &mut self.cells[row][col] } pub fn get_marked_cells_widgets(&self) -> VecDeque<&CellWidget> { self.marked_cells .marked_cells .iter() .map(move |&(row, col)| &self.cells[row][col]) .collect() } pub fn get_marked_cells(&self) -> VecDeque<(usize, usize)> { self.marked_cells.marked_cells.clone() } pub fn toggle_marking(&mut self) { self.marked_cells.marking_cells = !self.marked_cells.marking_cells; if self.marked_cells.marking_cells { self.start_marking_cells(); } else { self.clear_marked_cells(); } } pub fn set_marked_cell(&mut self, new_cell: (usize, usize)) { let cell: &mut CellWidget = self.get_mut_cell(new_cell.0, new_cell.1); if !cell.get_marked() { cell.set_marked(true); } self.marked_cells .marked_cells .push_back((new_cell.0, new_cell.1)); info!("{:?}", self.marked_cells); } pub fn undo_marked_cell(&mut self) { if self.marked_cells.marked_cells.len() < 2 { return; } let old: (usize, usize) = self.marked_cells.marked_cells[self.marked_cells.marked_cells.len() - 1]; let new: (usize, usize) = self.marked_cells.marked_cells[self.marked_cells.marked_cells.len() - 2]; let old_is_unique: bool = self .marked_cells .marked_cells .iter() .filter(|x| **x == old) .count() == 1; let old_cell: &mut CellWidget = self.get_mut_cell(old.0, old.1).set_selected(false); if old_is_unique { old_cell.set_marked(false); } self.get_mut_cell(new.0, new.1).set_selected(true); self.marked_cells.marked_cells.pop_back(); self.focused_cell.set_focused_cell(new); } pub fn start_marking_cells(&mut self) { let row: usize = self.focused_cell.get_row(); let col: usize = self.focused_cell.get_col(); let cell: &mut CellWidget = self.get_mut_cell(row, col); cell.set_marked(true); self.marked_cells.selected_unit = cell.get_option_unit(); self.marked_cells.marked_cells.push_back((row, col)); } pub fn clear_marked_cells(&mut self) { for (row, col) in self.marked_cells.marked_cells.clone() { self.get_mut_cell(row, col).set_marked(false); } let (row, col) = self.marked_cells.selected_unit.get_coords(); // if !self.marked_cells.marked_cells.len() == 1 { let task: Tasks = Tasks::Digging(DiggingTask::new(self.marked_cells.marked_cells.clone())); self.get_mut_cell(row, col) .get_mut_option_unit() .set_task(task); // } self.marked_cells.selected_unit = None; self.marked_cells.marked_cells.clear(); } fn max_offset(map_size: usize, size: usize) -> usize { if map_size > size { map_size - size } else { 0 } } pub fn get_focused_cell(&self) -> &FocusedCell { &self.focused_cell } pub fn is_focused_cell_visible(&self) -> bool { let vertical_offset: usize = self.vertical_offset.get_value(); let horizontal_offset: usize = self.horizontal_offset.get_value(); let row: usize = self.focused_cell.get_row(); let col: usize = self.focused_cell.get_col(); if 0usize.saturating_add(vertical_offset) > row || row >= self.rows.saturating_add(vertical_offset) { return false; } if 0usize.saturating_add(horizontal_offset) > col || col >= self.cols.saturating_add(horizontal_offset) { return false; } true } pub fn change_resize(&mut self, area: &Rect, side_panel: bool) { self.cells_area = cells_area_helper(area, side_panel); self.cols = (self.cells_area.width / self.cell_width as u16) as usize; self.rows = (self.cells_area.height / self.cell_height as u16) as usize; let v_max_offset: usize = Self::max_offset(self.map_height, self.rows); let h_max_offset: usize = Self::max_offset(self.map_width, self.cols); self.horizontal_offset = Offset::new(Some(self.horizontal_offset.get_value()), Some(h_max_offset)); self.vertical_offset = Offset::new(Some(self.vertical_offset.get_value()), Some(v_max_offset)); } pub fn change_zoom(&mut self, new_zoom_level: ZoomLevel) { self.zoom_level = new_zoom_level; self.cell_width = new_zoom_level.get_cell_size(CellSizes::Width); self.cell_height = new_zoom_level.get_cell_size(CellSizes::Height); self.cols = (self.cells_area.width / self.cell_width as u16) as usize; self.rows = (self.cells_area.height / self.cell_height as u16) as usize; let v_max_offset: usize = Self::max_offset(self.map_height, self.rows); let h_max_offset: usize = Self::max_offset(self.map_width, self.cols); self.vertical_offset = Offset::new(Some(self.vertical_offset.get_value()), Some(v_max_offset)); self.horizontal_offset = Offset::new(Some(self.horizontal_offset.get_value()), Some(h_max_offset)); self.focused_cell = FocusedCell::new( self.focused_cell.get_row(), self.focused_cell.get_col(), self.map_height, self.map_width, ); for row in 0..self.map_height { for col in 0..self.map_width { self.get_mut_cell(row, col).set_zoom_level(new_zoom_level); } } } pub fn change_focused_cell(&mut self, direction: MoveFocusedCell) { let old_cell: (usize, usize) = (self.focused_cell.get_row(), self.focused_cell.get_col()); let new_cell: (usize, usize) = self.focused_cell.move_focused_cell(direction); self.get_mut_cell(old_cell.0, old_cell.1) .set_selected(false); self.get_mut_cell(new_cell.0, new_cell.1).set_selected(true); if self.marked_cells.marking_cells { self.set_marked_cell(new_cell); } } }