1use crate::{
2 combat,
3 comp::{CharacterState, MeleeConstructor, StateUpdate, character_state::OutputEvents},
4 event::LocalEvent,
5 outcome::Outcome,
6 states::{
7 behavior::{CharacterBehavior, JoinData},
8 utils::{StageSection, *},
9 },
10};
11use serde::{Deserialize, Serialize};
12use std::time::Duration;
13
14#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
16pub struct StaticData {
17 pub movement_duration: Duration,
19 pub buildup_duration: Duration,
21 pub swing_duration: Duration,
23 pub recover_duration: Duration,
25 pub melee_constructor: MeleeConstructor,
27 pub specifier: Option<FrontendSpecifier>,
29 pub forward_leap_strength: f32,
31 pub vertical_leap_strength: f32,
33 pub ability_info: AbilityInfo,
35}
36
37#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
38pub struct Data {
39 pub static_data: StaticData,
42 pub timer: Duration,
44 pub stage_section: StageSection,
46 pub exhausted: bool,
48}
49
50impl CharacterBehavior for Data {
51 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
52 let mut update = StateUpdate::from(data);
53
54 handle_orientation(data, &mut update, 1.0, None);
55 handle_move(data, &mut update, 0.3);
56 handle_jump(data, output_events, &mut update, 1.0);
57
58 match self.stage_section {
59 StageSection::Buildup => {
61 if self.timer < self.static_data.buildup_duration {
63 if let CharacterState::LeapMelee(c) = &mut update.character {
64 c.timer = tick_attack_or_default(data, self.timer, None);
65 }
66 } else {
67 if let CharacterState::LeapMelee(c) = &mut update.character {
69 c.timer = Duration::default();
70 c.stage_section = StageSection::Movement
71 }
72
73 match self.static_data.specifier {
75 Some(FrontendSpecifier::LeapWhoosh) => {
76 output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Whoosh {
77 pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
78 }));
79 },
80 Some(FrontendSpecifier::LeapSwoosh) => {
81 output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Swoosh {
82 pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
83 }));
84 },
85 _ => {},
86 };
87 }
88 },
89 StageSection::Movement => {
90 if self.timer < self.static_data.movement_duration {
91 let progress = 1.0
93 - self.timer.as_secs_f32()
94 / self.static_data.movement_duration.as_secs_f32();
95 handle_forced_movement(data, &mut update, ForcedMovement::Leap {
96 vertical: self.static_data.vertical_leap_strength,
97 forward: self.static_data.forward_leap_strength,
98 progress,
99 direction: MovementDirection::Look,
100 });
101
102 if let CharacterState::LeapMelee(c) = &mut update.character {
107 c.timer = tick_attack_or_default(data, self.timer, None);
108 }
109 } else if data.physics.on_ground.is_some() | data.physics.in_liquid().is_some() {
110 if let CharacterState::LeapMelee(c) = &mut update.character {
112 c.timer = Duration::default();
113 c.stage_section = StageSection::Action;
114 }
115 }
116 },
117 StageSection::Action => {
118 if self.timer < self.static_data.swing_duration {
119 if let CharacterState::LeapMelee(c) = &mut update.character {
121 c.timer = tick_attack_or_default(data, self.timer, None);
122 }
123 } else {
124 if let CharacterState::LeapMelee(c) = &mut update.character {
126 c.timer = Duration::default();
127 c.stage_section = StageSection::Recover;
128 }
129 }
130 },
131 StageSection::Recover => {
132 if !self.exhausted {
133 let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
134
135 data.updater.insert(
136 data.entity,
137 self.static_data
138 .melee_constructor
139 .clone()
140 .create_melee(precision_mult, self.static_data.ability_info),
141 );
142
143 if let CharacterState::LeapMelee(c) = &mut update.character {
144 c.timer = tick_attack_or_default(data, self.timer, None);
145 c.exhausted = true;
146 }
147 } else if self.timer < self.static_data.recover_duration {
148 if let CharacterState::LeapMelee(c) = &mut update.character {
150 c.timer = tick_attack_or_default(data, self.timer, None);
151 }
152 } else {
153 end_melee_ability(data, &mut update);
155 }
156 },
157 _ => {
158 end_melee_ability(data, &mut update);
160 },
161 }
162
163 handle_interrupts(data, &mut update, output_events);
165
166 update
167 }
168}
169
170#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
171pub enum FrontendSpecifier {
172 LeapWhoosh,
173 LeapSwoosh,
174}