use rand::Rng;
use crate::rsmod::{can_travel, CollisionStrategies, CoordGrid};
use crate::rsmod::collision::collision::CollisionFlagMap;
const DIRECTIONS: [[i32; 2]; 4] = [
[-1, 0], [1, 0], [0, 1], [0, -1], ];
#[inline(always)]
pub unsafe fn find_naive_path(
flags: &CollisionFlagMap,
y: i32,
src_x: i32,
src_z: i32,
dest_x: i32,
dest_z: i32,
src_width: u8,
src_height: u8,
dest_width: u8,
dest_height: u8,
extra_flag: u32,
collision: &CollisionStrategies,
) -> Vec<u32> {
if intersects(
src_x,
src_z,
src_width,
src_height,
dest_x,
dest_z,
dest_width,
dest_height,
) {
return cardinal_destination(y, src_x, src_z);
}
let dest: Vec<u32> = naive_destination(
y,
src_x,
src_z,
src_width as i32,
src_height as i32,
dest_x,
dest_z,
1,
1,
);
let dx: i32 = CoordGrid::from(dest[0]).x() as i32;
let dz: i32 = CoordGrid::from(dest[0]).z() as i32;
if is_diagonal(
dx,
dz,
src_width as i32,
src_height as i32,
dest_x,
dest_z,
dest_width as i32,
dest_height as i32,
) {
return dest;
}
if intersects(
dx,
dz,
src_width,
src_height,
dest_x,
dest_z,
dest_width,
dest_height,
) {
return dest;
}
let mut currX: i32 = dx;
let mut currZ: i32 = dz;
while currX != dest_x && currZ != dest_z {
let dx: i8 = (dest_x - currX).signum() as i8;
let dz: i8 = (dest_z - currZ).signum() as i8;
if can_travel(
flags, y, currX, currZ, dx, dz, src_width, extra_flag, collision,
) {
currX += dx as i32;
currZ += dz as i32;
} else if dx != 0
&& can_travel(
flags, y, currX, currZ, dx, 0, src_width, extra_flag, collision,
)
{
currX += dx as i32;
} else if dz != 0
&& can_travel(
flags, y, currX, currZ, 0, dz, src_width, extra_flag, collision,
)
{
currZ += dz as i32;
} else {
break;
}
}
return vec![CoordGrid::new(y, currX, currZ).packed];
}
#[inline(always)]
fn intersects(
src_x: i32,
src_z: i32,
src_width: u8,
src_height: u8,
dest_x: i32,
dest_z: i32,
dest_width: u8,
dest_height: u8,
) -> bool {
let srcHorizontal: i32 = src_x + src_width as i32;
let srcVertical: i32 = src_z + src_height as i32;
let destHorizontal: i32 = dest_x + dest_width as i32;
let destVertical: i32 = dest_z + dest_height as i32;
return !(dest_x >= srcHorizontal
|| destHorizontal <= src_x
|| dest_z >= srcVertical
|| destVertical <= src_z);
}
#[inline(always)]
fn is_diagonal(
src_x: i32,
src_z: i32,
src_width: i32,
src_height: i32,
dest_x: i32,
dest_z: i32,
dest_width: i32,
dest_height: i32,
) -> bool {
if src_x + src_width == dest_x && src_z + src_height == dest_z {
return true;
}
if src_x - 1 == dest_x + dest_width - 1 && src_z - 1 == dest_z + dest_height - 1 {
return true;
}
if src_x + src_width == dest_x && src_z - 1 == dest_z + dest_height - 1 {
return true;
}
return src_x - 1 == dest_x + dest_width - 1 && src_z + src_height == dest_z;
}
#[inline(always)]
fn cardinal_destination(y: i32, src_x: i32, src_z: i32) -> Vec<u32> {
let direction: [i32; 2] = DIRECTIONS[rand::thread_rng().gen_range(0..DIRECTIONS.len())];
vec![CoordGrid::new(y, src_x + direction[0], src_z + direction[1]).packed]
}
#[inline(always)]
fn naive_destination(
y: i32,
src_x: i32,
src_z: i32,
src_width: i32,
src_height: i32,
dest_x: i32,
dest_z: i32,
dest_width: i32,
dest_height: i32,
) -> Vec<u32> {
let diagonal: i32 = src_x - dest_x + (src_z - dest_z);
let anti: i32 = src_x - dest_x - (src_z - dest_z);
let southwest_clockwise: bool = anti < 0;
let northwest_clockwise: bool = diagonal >= dest_height - 1 - (src_width - 1);
let northeast_clockwise: bool = anti > src_width - src_height;
let southeast_clockwise: bool = diagonal <= dest_width - 1 - (src_height - 1);
return if southwest_clockwise && !northwest_clockwise {
let mut off_z: i32 = 0;
if diagonal >= -src_width {
off_z = coerceAtMost(diagonal + src_width, dest_height - 1);
} else if anti > -src_width {
off_z = -(src_width + anti);
}
vec![CoordGrid::new(y, -src_width + dest_x, off_z + dest_z).packed]
} else if northwest_clockwise && !northeast_clockwise {
let mut off_x: i32 = 0;
if anti >= -dest_height {
off_x = coerceAtMost(anti + dest_height, dest_width - 1);
} else if diagonal < dest_height {
off_x = coerceAtLeast(diagonal - dest_height, -(src_width - 1));
}
vec![CoordGrid::new(y, off_x + dest_x, dest_height + dest_z).packed]
} else if northeast_clockwise && !southeast_clockwise {
let mut off_z: i32 = 0;
if anti <= dest_width {
off_z = dest_height - anti;
} else if diagonal < dest_width {
off_z = coerceAtLeast(diagonal - dest_width, -(src_height - 1));
}
vec![CoordGrid::new(y, dest_width + dest_x, off_z + dest_z).packed]
} else {
if !(southeast_clockwise && !southwest_clockwise) {
return vec![]; }
let mut off_x: i32 = 0;
if diagonal > -src_height {
off_x = coerceAtMost(diagonal + src_height, dest_width - 1);
} else if anti < src_height {
off_x = coerceAtLeast(anti - src_height, -(src_height - 1));
}
vec![CoordGrid::new(y, off_x + dest_x, -src_height + dest_z).packed]
};
}
#[inline(always)]
fn coerceAtMost(value: i32, max: i32) -> i32 {
return if value > max { max } else { value };
}
#[inline(always)]
fn coerceAtLeast(value: i32, min: i32) -> i32 {
return if value < min { min } else { value };
}