steel_core/entity/ai/goal/
squid_random_movement_goal.rs1use std::f32::consts::TAU;
2
3use glam::DVec3;
4use steel_math::trig;
5use steel_utils::Downcast;
6
7use crate::entity::{
8 Entity, LivingEntity, PathfinderMob, SharedEntity,
9 ai::goal::{
10 reduced_tick_delay,
11 selector::{Goal, GoalControls},
12 },
13 entities::SquidEntity,
14};
15
16const NO_ACTION_TIME_LIMIT: i32 = 100;
18const MOVEMENT_CHANGE_INTERVAL: i32 = 50;
20const MOVEMENT_SPEED: f32 = 0.2;
22const MOVEMENT_VERTICAL_BASE: f32 = -0.1;
24
25pub struct SquidRandomMovementGoal;
26
27impl SquidRandomMovementGoal {
28 #[must_use]
29 pub(crate) const fn new() -> Self {
30 Self
31 }
32}
33
34impl Goal for SquidRandomMovementGoal {
35 fn controls(&self) -> GoalControls {
36 GoalControls::EMPTY
37 }
38
39 fn can_use(&mut self, _mob: &dyn PathfinderMob) -> bool {
40 true
41 }
42
43 fn tick(&mut self, mob: &dyn PathfinderMob, _entity: &SharedEntity) {
44 let Some(squid) = mob.downcast_ref::<SquidEntity>() else {
45 tracing::warn!("SquidRandomMovementGoal assigned to non-squid entity");
46 return;
47 };
48
49 if squid.no_action_time() > NO_ACTION_TIME_LIMIT {
50 squid.set_movement_vector(DVec3::ZERO);
51 return;
52 }
53
54 if rand::random_range(0..reduced_tick_delay(MOVEMENT_CHANGE_INTERVAL)) != 0
55 && squid.is_in_water()
56 && squid.has_movement_vector()
57 {
58 return;
59 }
60
61 let angle = rand::random::<f32>() * TAU;
62 let movement = DVec3::new(
63 f64::from(trig::cos(f64::from(angle)) * MOVEMENT_SPEED),
64 f64::from(MOVEMENT_VERTICAL_BASE + rand::random::<f32>() * MOVEMENT_SPEED),
65 f64::from(trig::sin(f64::from(angle)) * MOVEMENT_SPEED),
66 );
67
68 squid.set_movement_vector(movement);
69 }
70}