use crate::map::MapTrait;
use crate::tileset::TilesetTrait;
use super::collision::CollisionProvider;
use super::npc_movement::{npc_in_front_of_player, NpcRuntimeState};
use super::player_movement::direction_delta;
use super::types::{Direction, MapData};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InteractionResult {
NoTarget,
Talk { npc_index: u8, text_id: u8 },
AlreadyDefeated { npc_index: u8, text_id: u8 },
}
pub fn try_interact<M: MapTrait, T: TilesetTrait, Mus>(
npcs: &[NpcRuntimeState],
player_x: u16,
player_y: u16,
facing: Direction,
map: Option<&MapData<M, T, Mus>>,
provider: &impl CollisionProvider<T>,
) -> InteractionResult {
let npc = match npc_in_front_of_player(npcs, player_x, player_y, facing, map, provider) {
Some(n) => n,
None => return InteractionResult::NoTarget,
};
if npc.defeated {
return InteractionResult::AlreadyDefeated {
npc_index: npc.npc_index,
text_id: npc.text_id,
};
}
InteractionResult::Talk {
npc_index: npc.npc_index,
text_id: npc.text_id,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LineOfSightResult {
pub npc_index: u8,
pub distance: u8,
}
pub fn check_line_of_sight(
npcs: &[NpcRuntimeState],
player_x: u16,
player_y: u16,
) -> Option<LineOfSightResult> {
for npc in npcs {
if !npc.visible || npc.defeated || npc.range == 0 {
continue;
}
let (dx, dy) = direction_delta(npc.facing);
let mut check_x = npc.x as i32;
let mut check_y = npc.y as i32;
for dist in 1..=npc.range {
check_x += dx as i32;
check_y += dy as i32;
if check_x < 0 || check_y < 0 {
break;
}
if check_x as u16 == player_x && check_y as u16 == player_y {
return Some(LineOfSightResult {
npc_index: npc.npc_index,
distance: dist,
});
}
}
}
None
}
pub fn mark_defeated(npcs: &mut [NpcRuntimeState], npc_index: u8) {
if let Some(npc) = npcs.iter_mut().find(|n| n.npc_index == npc_index) {
npc.defeated = true;
}
}
pub fn check_sign_interaction(
signs: &[(u8, u8, u8)],
player_x: u16,
player_y: u16,
facing: Direction,
) -> Option<u8> {
let (dx, dy) = direction_delta(facing);
let target_x = (player_x as i32 + dx as i32) as u8;
let target_y = (player_y as i32 + dy as i32) as u8;
signs
.iter()
.find(|&&(sx, sy, _)| sx == target_x && sy == target_y)
.map(|&(_, _, text_id)| text_id)
}