use crate::entities::tee::{Tee, TeeCore, TEE_PROXIMITY};
use crate::ids::PlayerUid;
use crate::state::tee_order::TeeOrder;
use slotmap::SecondaryMap;
use vek::num_traits::clamp;
use vek::Vec2;
#[derive(Debug)]
pub struct Tees<T> {
tees: SecondaryMap<PlayerUid, T>,
}
impl<T> Tees<T> {
pub(super) fn new() -> Self {
Self {
tees: Default::default(),
}
}
pub(super) fn reset(&mut self) {
self.tees.clear();
}
}
impl<T> Tees<T> {
pub(super) fn add_tee(&mut self, tee_uid: PlayerUid, tee: T) {
self.tees.insert(tee_uid, tee);
}
pub(super) fn remove_tee(&mut self, tee_uid: PlayerUid) -> Option<T> {
self.tees.remove(tee_uid)
}
pub(crate) fn get_tee(&self, tee_uid: PlayerUid) -> Option<&T> {
self.tees.get(tee_uid)
}
pub(crate) fn get_tee_mut(&mut self, tee_uid: PlayerUid) -> Option<&mut T> {
self.tees.get_mut(tee_uid)
}
pub(crate) fn get_tees_mut<const N: usize>(
&mut self,
tee_uids: [PlayerUid; N],
) -> Option<[&mut T; N]> {
self.tees.get_disjoint_mut(tee_uids)
}
}
impl Tees<Tee> {
pub(crate) fn reset_hook(&mut self, tee_uid: PlayerUid) {
for tee in self.tees.values_mut() {
tee.reset_hook(tee_uid);
}
}
}
pub fn closest_point_on_line(
line: (Vec2<f32>, Vec2<f32>),
target_point: Vec2<f32>,
) -> Option<Vec2<f32>> {
let ab = line.1 - line.0;
let squared_magnitude_ab = ab.dot(ab);
if squared_magnitude_ab > 0.0 {
let ap = target_point - line.0;
let ap_dot_ab = ap.dot(ab);
let t = ap_dot_ab / squared_magnitude_ab;
Some(line.0 + ab * clamp(t, 0.0, 1.0))
} else {
None
}
}
impl Tees<TeeCore> {
pub fn intersect_tees(
&self,
tee_order: &TeeOrder,
ignore: Option<PlayerUid>,
from: Vec2<f32>,
to: Vec2<f32>,
radius: f32,
) -> Option<(PlayerUid, Vec2<f32>)> {
let mut closest_len = from.distance(to) * 100.0;
let mut explosion = None;
for (tee_uid, tee) in tee_order.spawn_order().tees(self) {
if ignore.map(|tid| tid == tee_uid).unwrap_or(false) || tee.is_solo() {
continue;
}
if let Some(intersect_pos) = closest_point_on_line((from, to), tee.pos()) {
let len = tee.pos().distance(intersect_pos);
if len < TEE_PROXIMITY + radius {
let len = from.distance(intersect_pos);
if len < closest_len {
explosion = Some((tee_uid, intersect_pos));
closest_len = len;
}
}
}
}
explosion
}
}