1use super::super::sqrt;
2use super::emit::round;
3
4#[must_use]
5pub fn toward<const N: usize>(from: [i32; N], to: [i32; N], step: i32) -> [i32; N] {
6 if step <= 0 {
7 return from;
8 }
9 let d: [i64; N] = std::array::from_fn(|i| i64::from(to[i]) - i64::from(from[i]));
10 let dist2: i128 = d.iter().map(|&c| i128::from(c) * i128::from(c)).sum();
11 if dist2 <= i128::from(step) * i128::from(step) {
12 return to;
13 }
14 let scale = f64::from(step) / sqrt(dist2 as f64);
15 std::array::from_fn(|i| from[i].saturating_add(round(d[i] as f64 * scale)))
16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Member<const N: usize> {
21 #[cfg_attr(feature = "serde", serde(with = "super::arr"))]
22 pub pos: [i32; N],
23 #[cfg_attr(feature = "serde", serde(with = "super::arr"))]
24 pub offset: [i32; N],
25 pub limit: Option<i32>,
26}
27
28impl<const N: usize> Member<N> {
29 pub fn slot(&self, leader: [i32; N]) -> [i32; N] {
30 std::array::from_fn(|i| leader[i].saturating_add(self.offset[i]))
31 }
32
33 pub fn slot_scaled(&self, leader: [i32; N], num: i32, den: i32) -> [i32; N] {
34 std::array::from_fn(|i| leader[i].saturating_add(scale(self.offset[i], num, den)))
35 }
36
37 pub fn step(&mut self, leader: [i32; N]) {
38 self.step_scaled(leader, 1, 1);
39 }
40
41 pub fn step_scaled(&mut self, leader: [i32; N], num: i32, den: i32) {
42 let slot = self.slot_scaled(leader, num, den);
43 self.pos = match self.limit {
44 Some(limit) => toward(self.pos, slot, limit),
45 None => slot,
46 };
47 }
48}
49
50pub fn follow<const N: usize>(members: &mut [Member<N>], leader: [i32; N]) {
51 follow_scaled(members, leader, 1, 1);
52}
53
54pub fn follow_scaled<const N: usize>(
55 members: &mut [Member<N>],
56 leader: [i32; N],
57 num: i32,
58 den: i32,
59) {
60 for member in members {
61 member.step_scaled(leader, num, den);
62 }
63}
64
65fn scale(offset: i32, num: i32, den: i32) -> i32 {
66 if den == 0 {
67 return offset;
68 }
69 let (mut p, mut q) = (i64::from(offset) * i64::from(num), i64::from(den));
70 if q < 0 {
71 p = -p;
72 q = -q;
73 }
74 let near = if p >= 0 {
75 (2 * p + q) / (2 * q)
76 } else {
77 -((-2 * p + q) / (2 * q))
78 };
79 near.clamp(i64::from(i32::MIN), i64::from(i32::MAX)) as i32
80}
81
82#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
84pub struct Slow {
85 pub num: u32,
86 pub den: u32,
87 pub ticks: u32,
88}
89
90#[derive(Clone, Debug, PartialEq, Eq, Hash)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92pub struct Mover<const N: usize> {
93 #[cfg_attr(feature = "serde", serde(with = "super::arr"))]
94 pub pos: [i32; N],
95 pub top: i32,
96 stun: u32,
97 slows: Vec<Slow>,
98}
99
100impl<const N: usize> Mover<N> {
101 pub fn new(pos: [i32; N], top: i32) -> Self {
102 Self {
103 pos,
104 top,
105 stun: 0,
106 slows: Vec::new(),
107 }
108 }
109
110 pub fn stun(&mut self, ticks: u32) {
111 self.stun = self.stun.max(ticks);
112 }
113
114 pub fn slow(&mut self, num: u32, den: u32, ticks: u32) {
115 if den == 0 || ticks == 0 {
116 return;
117 }
118 let same =
119 |s: &Slow| u64::from(s.num) * u64::from(den) == u64::from(num) * u64::from(s.den);
120 match self.slows.iter_mut().find(|s| same(s)) {
121 Some(slow) => slow.ticks = slow.ticks.max(ticks),
122 None => self.slows.push(Slow { num, den, ticks }),
123 }
124 }
125
126 pub fn clear_effects(&mut self) {
127 self.stun = 0;
128 self.slows.clear();
129 }
130
131 pub const fn stunned(&self) -> u32 {
132 self.stun
133 }
134
135 pub fn slows(&self) -> &[Slow] {
136 &self.slows
137 }
138
139 pub fn speed(&self) -> i32 {
140 if self.stun > 0 {
141 return 0;
142 }
143 let strongest = self.slows.iter().min_by(|a, b| {
144 (u64::from(a.num) * u64::from(b.den)).cmp(&(u64::from(b.num) * u64::from(a.den)))
145 });
146 match strongest {
147 Some(slow) => {
148 let speed = i64::from(self.top) * i64::from(slow.num) / i64::from(slow.den);
149 speed.clamp(i64::from(i32::MIN), i64::from(i32::MAX)) as i32
150 }
151 None => self.top,
152 }
153 }
154
155 pub fn step(&mut self, target: [i32; N]) -> [i32; N] {
156 self.pos = toward(self.pos, target, self.speed());
157 self.stun = self.stun.saturating_sub(1);
158 for slow in &mut self.slows {
159 slow.ticks -= 1;
160 }
161 self.slows.retain(|slow| slow.ticks > 0);
162 self.pos
163 }
164}