use crate::rsmod::collision::collision::CollisionFlagMap;
use crate::rsmod::collision_flag::CollisionFlag;
use crate::rsmod::line::Line;
pub unsafe fn has_line_of_sight(
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,
) -> bool {
return rayCastLine(
flags,
y,
src_x,
src_z,
dest_x,
dest_z,
src_width,
src_height,
dest_width,
dest_height,
Line::SIGHT_BLOCKED_WEST | extra_flag,
Line::SIGHT_BLOCKED_EAST | extra_flag,
Line::SIGHT_BLOCKED_SOUTH | extra_flag,
Line::SIGHT_BLOCKED_NORTH | extra_flag,
CollisionFlag::LOC as u32 | extra_flag,
CollisionFlag::LOC_PROJ_BLOCKER as u32 | extra_flag,
true,
);
}
#[inline(always)]
pub unsafe fn has_line_of_walk(
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,
) -> bool {
return rayCastLine(
flags,
y,
src_x,
src_z,
dest_x,
dest_z,
src_width,
src_height,
dest_width,
dest_height,
Line::WALK_BLOCKED_WEST | extra_flag,
Line::WALK_BLOCKED_EAST | extra_flag,
Line::WALK_BLOCKED_SOUTH | extra_flag,
Line::WALK_BLOCKED_NORTH | extra_flag,
CollisionFlag::LOC as u32 | extra_flag,
CollisionFlag::LOC_PROJ_BLOCKER as u32 | extra_flag,
false,
);
}
#[inline(always)]
unsafe fn rayCastLine(
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,
flag_west: u32,
flag_east: u32,
flag_south: u32,
flag_north: u32,
flag_loc: u32,
flag_proj: u32,
los: bool,
) -> bool {
let start_x: i32 = Line::coordinate(src_x, dest_x, src_width);
let start_z: i32 = Line::coordinate(src_z, dest_z, src_height);
let end_x: i32 = Line::coordinate(dest_x, src_x, dest_width);
let end_z: i32 = Line::coordinate(dest_z, src_z, dest_height);
if start_x == end_x && start_z == end_z {
return true;
}
if los && flags.is_flagged(start_x, start_z, y, flag_loc) {
return false;
}
let delta_x: i32 = end_x - start_x;
let delta_z: i32 = end_z - start_z;
let absolute_delta_x: i32 = delta_x.abs();
let absolute_delta_z: i32 = delta_z.abs();
let travel_east: bool = delta_x >= 0;
let travel_north: bool = delta_z >= 0;
let mut x_flags: u32 = if travel_east { flag_west } else { flag_east };
let mut z_flags: u32 = if travel_north { flag_south } else { flag_north };
if absolute_delta_x > absolute_delta_z {
let offset_x: i32 = if travel_east { 1 } else { -1 };
let offset_z: i32 = if travel_north { 0 } else { -1 };
let mut scaled_z: i32 = Line::scale_up(start_z) + Line::HALF_TILE + offset_z;
let tangent: i32 = Line::scale_up(delta_z) / absolute_delta_x;
let mut curr_x: i32 = start_x;
while curr_x != end_x {
curr_x += offset_x;
let curr_z: i32 = Line::scale_down(scaled_z);
if los && curr_x == end_x && curr_z == end_z {
x_flags &= !flag_proj;
}
if flags.is_flagged(curr_x, curr_z, y, x_flags) {
return false;
}
scaled_z += tangent;
let nextZ: i32 = Line::scale_down(scaled_z);
if los && curr_x == end_x && nextZ == end_z {
z_flags &= !flag_proj;
}
if nextZ != curr_z && flags.is_flagged(curr_x, nextZ, y, z_flags) {
return false;
}
}
} else {
let offset_x: i32 = if travel_east { 0 } else { -1 };
let offset_z: i32 = if travel_north { 1 } else { -1 };
let mut scaled_x: i32 = Line::scale_up(start_x) + Line::HALF_TILE + offset_x;
let tangent: i32 = Line::scale_up(delta_x) / absolute_delta_z;
let mut curr_z: i32 = start_z;
while curr_z != end_z {
curr_z += offset_z;
let curr_x: i32 = Line::scale_down(scaled_x);
if los && curr_x == end_x && curr_z == end_z {
z_flags &= !flag_proj;
}
if flags.is_flagged(curr_x, curr_z, y, z_flags) {
return false;
}
scaled_x += tangent;
let nextX: i32 = Line::scale_down(scaled_x);
if los && nextX == end_x && curr_z == end_z {
x_flags &= !flag_proj;
}
if nextX != curr_x && flags.is_flagged(nextX, curr_z, y, x_flags) {
return false;
}
}
}
return true;
}