use bevy::prelude::*;
use crate::flowfields::{
fields::{
Field, FieldCell,
integration_field::{
INT_BITS_GOAL, INT_BITS_IMPASSABLE, INT_BITS_LOS, INT_BITS_PORTAL,
INT_FILTER_BITS_COST, IntegrationField,
},
},
portal::PortalWindow,
route::RouteStep,
utilities::{CompassDir, FIELD_RESOLUTION},
};
const BITS_NORTH: u8 = 0b0000_0001;
const BITS_EAST: u8 = 0b0000_0010;
const BITS_SOUTH: u8 = 0b0000_0100;
const BITS_WEST: u8 = 0b0000_1000;
const BITS_NORTH_EAST: u8 = 0b0000_0011;
const BITS_SOUTH_EAST: u8 = 0b0000_0110;
const BITS_SOUTH_WEST: u8 = 0b0000_1100;
const BITS_NORTH_WEST: u8 = 0b0000_1001;
const BITS_DEFAULT: u8 = 0b0000_0000;
const BITS_PATHABLE: u8 = 0b0001_0000;
const BITS_HAS_LOS: u8 = 0b0010_0000;
const BITS_GOAL: u8 = 0b0100_0000;
const BITS_PORTAL_GOAL: u8 = 0b1000_0000;
const BITS_IMPASSABLE: u8 = 0b1110_0000;
#[allow(dead_code)] const BITS_FLAG_FILTER: u8 = 0b1111_0000;
const BITS_COST_FILTER: u8 = 0b0000_1111;
pub fn convert_compass_dir_to_bits_dir(compass_dir: &CompassDir) -> u8 {
match compass_dir {
CompassDir::North => BITS_NORTH,
CompassDir::East => BITS_EAST,
CompassDir::South => BITS_SOUTH,
CompassDir::West => BITS_WEST,
CompassDir::NorthEast => BITS_NORTH_EAST,
CompassDir::SouthEast => BITS_SOUTH_EAST,
CompassDir::SouthWest => BITS_SOUTH_WEST,
CompassDir::NorthWest => BITS_NORTH_WEST,
CompassDir::Zero => BITS_IMPASSABLE,
}
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Reflect)]
pub struct FlowField {
#[cfg_attr(feature = "serde", serde(with = "serde_big_array::BigArray"))]
field: [u8; FIELD_RESOLUTION * FIELD_RESOLUTION],
}
impl Default for FlowField {
fn default() -> Self {
FlowField {
field: [BITS_DEFAULT; FIELD_RESOLUTION * FIELD_RESOLUTION],
}
}
}
impl Field<u8> for FlowField {
fn get(&self) -> &[u8; FIELD_RESOLUTION * FIELD_RESOLUTION] {
&self.field
}
fn get_field_cell_value(&self, field_cell: FieldCell) -> u8 {
self.field[field_cell.as_1d_index()]
}
fn set_field_cell_value(&mut self, value: u8, field_cell: FieldCell) {
self.field[field_cell.as_1d_index()] = value;
}
}
impl FlowField {
pub fn new(
route_step: &RouteStep,
int_field: &IntegrationField,
prev_int_field: Option<&IntegrationField>,
) -> FlowField {
let mut flowfield = FlowField::default();
set_starting_flags(&mut flowfield, int_field);
if let Some(window) = route_step.portal() {
if let Some(neighbour_int) = prev_int_field {
optimise_portal_direction(&mut flowfield, neighbour_int, window);
} else {
set_portal_direction(&mut flowfield, window);
}
}
flowfield
}
pub fn build(&mut self, int_field: &IntegrationField) {
for (cell_index, flow_value) in self.field.iter_mut().enumerate() {
calculate_flow_cell(cell_index, flow_value, int_field);
}
}
pub fn is_pathable(&self, field_cell: &FieldCell) -> bool {
self.field[field_cell.as_1d_index()] & BITS_PATHABLE == BITS_PATHABLE
}
pub fn is_goal(&self, field_cell: &FieldCell) -> bool {
self.field[field_cell.as_1d_index()] & BITS_GOAL == BITS_GOAL
&& self.is_pathable(field_cell)
}
pub fn is_portal_goal(&self, field_cell: &FieldCell) -> bool {
self.field[field_cell.as_1d_index()] & BITS_PORTAL_GOAL == BITS_PORTAL_GOAL
&& self.is_pathable(field_cell)
}
pub fn has_los(&self, field_cell: &FieldCell) -> bool {
self.field[field_cell.as_1d_index()] & BITS_HAS_LOS == BITS_HAS_LOS
&& self.is_pathable(field_cell)
}
#[cfg(feature = "2d")]
pub fn get_2d_dir(&self, field_cell: &FieldCell) -> Option<Vec2> {
let cell_value = self.field[field_cell.as_1d_index()];
let bit_dir = cell_value & BITS_COST_FILTER;
match bit_dir {
BITS_NORTH => Some(Vec2::new(0.0, 1.0)),
BITS_EAST => Some(Vec2::new(1.0, 0.0)),
BITS_SOUTH => Some(Vec2::new(0.0, -1.0)),
BITS_WEST => Some(Vec2::new(-1.0, 0.0)),
BITS_NORTH_EAST => Some(Vec2::new(1.0, 1.0)),
BITS_SOUTH_EAST => Some(Vec2::new(1.0, -1.0)),
BITS_SOUTH_WEST => Some(Vec2::new(-1.0, -1.0)),
BITS_NORTH_WEST => Some(Vec2::new(-1.0, 1.0)),
BITS_DEFAULT => {
None
}
_ => {
warn!(
"First 4 bits of cell are not recognised directions: {}, bits {}",
field_cell, bit_dir
);
None
}
}
}
#[cfg(feature = "3d")]
pub fn get_3d_dir(&self, field_cell: &FieldCell) -> Option<Vec3> {
let cell_value = self.field[field_cell.as_1d_index()];
let bit_dir = cell_value & BITS_COST_FILTER;
match bit_dir {
BITS_NORTH => Some(Vec3::new(0.0, 0.0, -1.0)),
BITS_EAST => Some(Vec3::new(1.0, 0.0, 0.0)),
BITS_SOUTH => Some(Vec3::new(0.0, 0.0, 1.0)),
BITS_WEST => Some(Vec3::new(-1.0, 0.0, 0.0)),
BITS_NORTH_EAST => Some(Vec3::new(1.0, 0.0, -1.0)),
BITS_SOUTH_EAST => Some(Vec3::new(1.0, 0.0, 1.0)),
BITS_SOUTH_WEST => Some(Vec3::new(-1.0, 0.0, 1.0)),
BITS_NORTH_WEST => Some(Vec3::new(-1.0, 0.0, -1.0)),
BITS_DEFAULT => {
None
}
_ => {
debug!(
"First 4 bits of cell are not recognised directions: {}, bits {}",
field_cell, bit_dir
);
None
}
}
}
}
fn set_starting_flags(flowfield: &mut FlowField, int_field: &IntegrationField) {
for (i, value) in int_field.get().iter().enumerate() {
if value & INT_BITS_GOAL == INT_BITS_GOAL {
flowfield.field[i] |= BITS_GOAL;
flowfield.field[i] |= BITS_PATHABLE;
flowfield.field[i] |= BITS_HAS_LOS;
} else if value & INT_BITS_PORTAL == INT_BITS_PORTAL {
flowfield.field[i] |= BITS_PORTAL_GOAL;
flowfield.field[i] |= BITS_PATHABLE;
} else if value & INT_BITS_LOS == INT_BITS_LOS {
flowfield.field[i] |= BITS_HAS_LOS;
flowfield.field[i] |= BITS_PATHABLE;
} else if value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE {
flowfield.field[i] |= BITS_IMPASSABLE;
}
}
}
fn set_portal_direction(flowfield: &mut FlowField, window: &PortalWindow) {
let this_boundary = window.get_boundary();
let dir_bits = convert_compass_dir_to_bits_dir(this_boundary);
for cell_index in window.get_all_window_cells().iter() {
flowfield.field[*cell_index] |= dir_bits;
}
}
fn optimise_portal_direction(
flowfield: &mut FlowField,
prev_int_field: &IntegrationField,
this_window: &PortalWindow,
) {
let this_boundary = this_window.get_boundary();
let this_cells = this_window.get_all_window_cells();
if this_cells.len() == 1 {
let dir_bits = convert_compass_dir_to_bits_dir(this_boundary);
flowfield.field[this_cells[0]] |= dir_bits;
return;
}
let adjacent_values = match this_boundary {
CompassDir::North => {
let mut values = vec![];
for this_cell in this_cells.iter() {
let fc = FieldCell::from_index(*this_cell);
let adj_cell = FieldCell::new(fc.column, 9);
values.push(prev_int_field.get_field_cell_value(adj_cell) & INT_FILTER_BITS_COST);
}
values
}
CompassDir::East => {
let mut values = vec![];
for this_cell in this_cells.iter() {
let fc = FieldCell::from_index(*this_cell);
let adj_cell = FieldCell::new(0, fc.row);
values.push(prev_int_field.get_field_cell_value(adj_cell) & INT_FILTER_BITS_COST);
}
values
}
CompassDir::South => {
let mut values = vec![];
for this_cell in this_cells.iter() {
let fc = FieldCell::from_index(*this_cell);
let adj_cell = FieldCell::new(fc.column, 0);
values.push(prev_int_field.get_field_cell_value(adj_cell) & INT_FILTER_BITS_COST);
}
values
}
CompassDir::West => {
let mut values = vec![];
for this_cell in this_cells.iter() {
let fc = FieldCell::from_index(*this_cell);
let adj_cell = FieldCell::new(9, fc.row);
values.push(prev_int_field.get_field_cell_value(adj_cell) & INT_FILTER_BITS_COST);
}
values
}
_ => panic!(
"Invalid compass dir {} used for optimising flow portal direction",
this_boundary
),
};
match this_boundary {
CompassDir::North => {
for (i, this_cell) in this_cells.iter().enumerate() {
if i == 0 {
let n_value = adjacent_values[i];
let ne_value = adjacent_values[i + 1];
if n_value <= ne_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::North);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthEast);
flowfield.field[*this_cell] |= dir_bits;
}
} else if i == this_cells.len() - 1 {
let n_value = adjacent_values[i];
let nw_value = adjacent_values[i - 1];
if n_value <= nw_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::North);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthWest);
flowfield.field[*this_cell] |= dir_bits;
}
} else {
let nw_value = adjacent_values[i - 1];
let n_value = adjacent_values[i];
let ne_value = adjacent_values[i + 1];
if n_value <= nw_value && n_value <= ne_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::North);
flowfield.field[*this_cell] |= dir_bits;
} else if nw_value <= n_value && nw_value <= ne_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthWest);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthEast);
flowfield.field[*this_cell] |= dir_bits;
}
}
}
}
CompassDir::East => {
for (i, this_cell) in this_cells.iter().enumerate() {
if i == 0 {
let e_value = adjacent_values[i];
let se_value = adjacent_values[i + 1];
if e_value <= se_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::East);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthEast);
flowfield.field[*this_cell] |= dir_bits;
}
} else if i == this_cells.len() - 1 {
let e_value = adjacent_values[i];
let ne_value = adjacent_values[i - 1];
if e_value <= ne_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::East);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthEast);
flowfield.field[*this_cell] |= dir_bits;
}
} else {
let ne_value = adjacent_values[i - 1];
let e_value = adjacent_values[i];
let se_value = adjacent_values[i + 1];
if e_value <= ne_value && e_value <= se_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::East);
flowfield.field[*this_cell] |= dir_bits;
} else if ne_value <= e_value && ne_value <= se_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthEast);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthEast);
flowfield.field[*this_cell] |= dir_bits;
}
}
}
}
CompassDir::South => {
for (i, this_cell) in this_cells.iter().enumerate() {
if i == 0 {
let s_value = adjacent_values[i];
let se_value = adjacent_values[i + 1];
if s_value <= se_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::South);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthEast);
flowfield.field[*this_cell] |= dir_bits;
}
} else if i == this_cells.len() - 1 {
let s_value = adjacent_values[i];
let sw_value = adjacent_values[i - 1];
if s_value <= sw_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::South);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthWest);
flowfield.field[*this_cell] |= dir_bits;
}
} else {
let sw_value = adjacent_values[i - 1];
let s_value = adjacent_values[i];
let se_value = adjacent_values[i + 1];
if s_value <= sw_value && s_value <= se_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::South);
flowfield.field[*this_cell] |= dir_bits;
} else if sw_value <= s_value && sw_value <= se_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthWest);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthEast);
flowfield.field[*this_cell] |= dir_bits;
}
}
}
}
CompassDir::West => {
for (i, this_cell) in this_cells.iter().enumerate() {
if i == 0 {
let w_value = adjacent_values[i];
let sw_value = adjacent_values[i + 1];
if w_value <= sw_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::West);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthWest);
flowfield.field[*this_cell] |= dir_bits;
}
} else if i == this_cells.len() - 1 {
let w_value = adjacent_values[i];
let nw_value = adjacent_values[i - 1];
if w_value <= nw_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::West);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthWest);
flowfield.field[*this_cell] |= dir_bits;
}
} else {
let nw_value = adjacent_values[i - 1];
let w_value = adjacent_values[i];
let sw_value = adjacent_values[i + 1];
if w_value <= nw_value && w_value <= sw_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::West);
flowfield.field[*this_cell] |= dir_bits;
} else if nw_value <= w_value && nw_value <= sw_value {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::NorthWest);
flowfield.field[*this_cell] |= dir_bits;
} else {
let dir_bits = convert_compass_dir_to_bits_dir(&CompassDir::SouthWest);
flowfield.field[*this_cell] |= dir_bits;
}
}
}
}
_ => panic!(
"Invalid compass dir {} used for optimising flow portal direction",
this_boundary
),
}
}
fn calculate_flow_cell(cell_index: usize, flow_value: &mut u8, int_field: &IntegrationField) {
if *flow_value & BITS_IMPASSABLE == BITS_IMPASSABLE
|| *flow_value & BITS_PATHABLE == BITS_PATHABLE
{
return;
}
let this_cell = FieldCell::from_index(cell_index);
let n_compass_dirs = CompassDir::get_all_cell_neighbours_with_compass_dir(this_cell);
let mut goal_dir: Option<CompassDir> = None;
let mut best_dir: Option<(CompassDir, u32)> = None;
for (compass_dir, n_cell) in n_compass_dirs.iter() {
let n_int_value = int_field.get_field_cell_value(*n_cell);
if n_int_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE {
continue;
}
match compass_dir {
CompassDir::NorthEast => {
if let Some(north_this) = this_cell.get_in_compass_direction(&CompassDir::North, 1)
&& let Some(east_this) =
this_cell.get_in_compass_direction(&CompassDir::East, 1)
{
let north_this_value = int_field.get_field_cell_value(north_this);
let east_this_value = int_field.get_field_cell_value(east_this);
if north_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
&& east_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
{
continue;
}
}
}
CompassDir::SouthEast => {
if let Some(south_this) = this_cell.get_in_compass_direction(&CompassDir::South, 1)
&& let Some(east_this) =
this_cell.get_in_compass_direction(&CompassDir::East, 1)
{
let south_this_value = int_field.get_field_cell_value(south_this);
let east_this_value = int_field.get_field_cell_value(east_this);
if south_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
&& east_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
{
continue;
}
}
}
CompassDir::SouthWest => {
if let Some(south_this) = this_cell.get_in_compass_direction(&CompassDir::South, 1)
&& let Some(west_this) =
this_cell.get_in_compass_direction(&CompassDir::West, 1)
{
let south_this_value = int_field.get_field_cell_value(south_this);
let west_this_value = int_field.get_field_cell_value(west_this);
if south_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
&& west_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
{
continue;
}
}
}
CompassDir::NorthWest => {
if let Some(north_this) = this_cell.get_in_compass_direction(&CompassDir::North, 1)
&& let Some(west_this) =
this_cell.get_in_compass_direction(&CompassDir::West, 1)
{
let north_this_value = int_field.get_field_cell_value(north_this);
let west_this_value = int_field.get_field_cell_value(west_this);
if north_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
&& west_this_value & INT_BITS_IMPASSABLE == INT_BITS_IMPASSABLE
{
continue;
}
}
}
_ => {
}
}
if n_int_value & INT_BITS_GOAL == INT_BITS_GOAL
|| n_int_value & INT_BITS_PORTAL == INT_BITS_PORTAL
{
goal_dir = Some(*compass_dir);
break;
}
if n_int_value & INT_FILTER_BITS_COST == 65535 {
*flow_value |= BITS_IMPASSABLE;
break;
}
if let Some((o, v)) = &mut best_dir {
if n_int_value & INT_FILTER_BITS_COST < *v {
*v = n_int_value & INT_FILTER_BITS_COST;
*o = *compass_dir;
}
} else {
best_dir = Some((*compass_dir, n_int_value & INT_FILTER_BITS_COST));
}
}
if let Some(dir) = goal_dir {
let bits = convert_compass_dir_to_bits_dir(&dir);
*flow_value |= bits;
*flow_value |= BITS_PATHABLE;
} else if let Some((dir, _)) = best_dir {
let bits = convert_compass_dir_to_bits_dir(&dir);
*flow_value |= bits;
*flow_value |= BITS_PATHABLE;
} else {
*flow_value |= BITS_IMPASSABLE;
}
}
pub fn is_pathable(cell_value: u8) -> bool {
cell_value & BITS_PATHABLE == BITS_PATHABLE
}
pub fn is_goal(cell_value: u8) -> bool {
cell_value & BITS_GOAL == BITS_GOAL && is_pathable(cell_value)
}
pub fn is_portal_goal(cell_value: u8) -> bool {
cell_value & BITS_PORTAL_GOAL == BITS_PORTAL_GOAL && is_pathable(cell_value)
}
pub fn has_line_of_sight(cell_value: u8) -> bool {
cell_value & BITS_HAS_LOS == BITS_HAS_LOS && is_pathable(cell_value)
}
pub fn is_wall(cell_value: u8) -> bool {
cell_value & BITS_IMPASSABLE == BITS_IMPASSABLE && !is_pathable(cell_value)
}
pub fn get_compass_dir_from_bits(cell_value: u8) -> CompassDir {
let dir = cell_value & BITS_COST_FILTER;
match dir {
BITS_NORTH => CompassDir::North,
BITS_EAST => CompassDir::East,
BITS_SOUTH => CompassDir::South,
BITS_WEST => CompassDir::West,
BITS_NORTH_EAST => CompassDir::NorthEast,
BITS_SOUTH_EAST => CompassDir::SouthEast,
BITS_SOUTH_WEST => CompassDir::SouthWest,
BITS_NORTH_WEST => CompassDir::NorthWest,
BITS_DEFAULT => CompassDir::Zero,
_ => CompassDir::Zero, }
}
#[cfg(test)]
mod tests {
use crate::flowfields::{fields::cost_field::CostField, sectors::SectorID};
use super::*;
#[test]
fn default_init() {
let flow_field = FlowField::default();
let v = flow_field.get_field_cell_value(FieldCell::new(0, 0));
assert_eq!(BITS_DEFAULT, v);
}
#[test]
fn starting_flags() {
let mut costfield = CostField::default();
costfield.set_field_cell_value(255, FieldCell::new(3, 5));
costfield.set_field_cell_value(255, FieldCell::new(4, 5));
costfield.set_field_cell_value(255, FieldCell::new(5, 5));
costfield.set_field_cell_value(255, FieldCell::new(2, 9));
costfield.set_field_cell_value(255, FieldCell::new(6, 9));
let sector = SectorID::new(1, 1);
let goal = 84;
let portal = None;
let route_step = RouteStep::new(§or, goal, portal);
let int_field = IntegrationField::init(&costfield, &route_step);
let mut flowfield = FlowField::default();
set_starting_flags(&mut flowfield, &int_field);
let r_c = FieldCell::new(2, 9);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_IMPASSABLE == BITS_IMPASSABLE);
let r_c = FieldCell::new(4, 8);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_GOAL == BITS_GOAL);
let r_c = FieldCell::new(4, 7);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_HAS_LOS == BITS_HAS_LOS);
}
#[test]
fn portal_dir_north() {
let prev_costfield = CostField::default();
let prev_sector = SectorID::new(1, 0);
let prev_goal = 25;
let prev_portal = None;
let prev_route_step = RouteStep::new(&prev_sector, prev_goal, prev_portal);
let mut prev_int_field = IntegrationField::init(&prev_costfield, &prev_route_step);
prev_int_field.build(&prev_costfield);
let costfield = CostField::default();
let sector = SectorID::new(1, 1);
let goal = 0;
let portal = Some(PortalWindow::new(
FieldCell::new(0, 0),
FieldCell::new(0, 0),
CompassDir::North,
));
let route_step = RouteStep::new(§or, goal, portal);
let int_field = IntegrationField::init(&costfield, &route_step);
let flowfield = FlowField::new(&route_step, &int_field, Some(&prev_int_field));
let r_c = flowfield.field[0];
assert!(r_c & BITS_NORTH == BITS_NORTH)
}
#[test]
fn flags_after_build() {
let mut costfield = CostField::default();
costfield.set_field_cell_value(255, FieldCell::new(3, 5));
costfield.set_field_cell_value(255, FieldCell::new(4, 5));
costfield.set_field_cell_value(255, FieldCell::new(5, 5));
costfield.set_field_cell_value(255, FieldCell::new(2, 9));
costfield.set_field_cell_value(255, FieldCell::new(6, 9));
let sector = SectorID::new(1, 1);
let goal = 84;
let portal = None;
let route_step = RouteStep::new(§or, goal, portal);
let int_field = IntegrationField::init(&costfield, &route_step);
let mut flowfield = FlowField::new(&route_step, &int_field, None);
flowfield.build(&int_field);
let r_c = FieldCell::new(2, 9);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_IMPASSABLE == BITS_IMPASSABLE);
let r_c = FieldCell::new(3, 7);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_PATHABLE == BITS_PATHABLE);
let r_c = FieldCell::new(4, 8);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_GOAL == BITS_GOAL);
let r_c = FieldCell::new(4, 7);
let r = flowfield.get_field_cell_value(r_c);
println!(
"{} :: flags: {:#010b}, cost: {:#010b}",
r_c,
r & BITS_FLAG_FILTER,
r & BITS_COST_FILTER
);
assert!(r & BITS_HAS_LOS == BITS_HAS_LOS);
}
}