generated from GarandPLG/rust-flake-template
7c9e3d28f0
- Change `get_tasks` to return `&VecDeque<Tasks>` instead of a formatted `String`. - Introduce `get_tasks_formatted` for display purposes. - Update `MinerUnit`, `Unit` trait, `Units` enum, and its `Option` implementation accordingly. - Add `EMPTY_TASKS` lazy static for handling empty task lists. - Adjust `BoardState` to use the new task API (commented out conditional).
323 lines
11 KiB
Rust
323 lines
11 KiB
Rust
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<Vec<CellWidget>>,
|
|
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<CellWidget>> = 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<CellWidget> = 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<Units> = 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);
|
|
}
|
|
}
|
|
}
|