1use crate::{
2 combat,
3 comp::{
4 CharacterState, MeleeConstructor, StateUpdate, character_state::OutputEvents,
5 tool::ToolKind,
6 },
7 event::LocalEvent,
8 outcome::Outcome,
9 states::{
10 behavior::{CharacterBehavior, JoinData},
11 utils::*,
12 },
13};
14use serde::{Deserialize, Serialize};
15use std::time::Duration;
16
17#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
19pub struct StaticData {
20 pub buildup_duration: Duration,
22 pub swing_duration: Duration,
24 pub recover_duration: Duration,
26 pub hit_timing: f32,
28 pub melee_constructor: MeleeConstructor,
30 pub ori_modifier: f32,
32 pub frontend_specifier: Option<FrontendSpecifier>,
35 pub ability_info: AbilityInfo,
37}
38
39#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
40pub struct Data {
41 pub static_data: StaticData,
44 pub timer: Duration,
46 pub stage_section: StageSection,
48 pub exhausted: bool,
50}
51
52impl CharacterBehavior for Data {
53 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
54 let mut update = StateUpdate::from(data);
55
56 handle_orientation(data, &mut update, self.static_data.ori_modifier, None);
57 handle_move(data, &mut update, 0.7);
58 handle_jump(data, output_events, &mut update, 1.0);
59
60 match self.stage_section {
61 StageSection::Buildup => {
62 if self.timer < self.static_data.buildup_duration {
63 update.character = CharacterState::BasicMelee(Data {
65 timer: tick_attack_or_default(data, self.timer, None),
66 ..*self
67 });
68 } else {
69 update.character = CharacterState::BasicMelee(Data {
71 timer: Duration::default(),
72 stage_section: StageSection::Action,
73 ..*self
74 });
75 }
76 },
77 StageSection::Action => {
78 if !self.exhausted
79 && self.timer.as_secs_f32()
80 >= self.static_data.swing_duration.as_secs_f32()
81 * self.static_data.hit_timing
82 {
83 update.character = CharacterState::BasicMelee(Data {
84 timer: tick_attack_or_default(data, self.timer, None),
85 exhausted: true,
86 ..*self
87 });
88
89 let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
90 let tool_stats = get_tool_stats(data, self.static_data.ability_info);
91
92 data.updater.insert(
93 data.entity,
94 self.static_data
95 .melee_constructor
96 .create_melee(precision_mult, tool_stats)
97 .with_block_breaking(
98 data.inputs
99 .break_block_pos
100 .map(|p| {
101 (
102 p.map(|e| e.floor() as i32),
103 self.static_data.ability_info.tool,
104 )
105 })
106 .filter(|(_, tool)| {
107 matches!(tool, Some(ToolKind::Pick | ToolKind::Shovel))
108 }),
109 ),
110 );
111 if self.static_data.ability_info.tool == Some(ToolKind::Shovel) {
113 output_events.emit_local(LocalEvent::CreateOutcome(Outcome::GroundDig {
114 pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
115 }));
116 }
117 } else if self.timer < self.static_data.swing_duration {
118 update.character = CharacterState::BasicMelee(Data {
120 timer: tick_attack_or_default(data, self.timer, None),
121 ..*self
122 });
123 } else {
124 update.character = CharacterState::BasicMelee(Data {
126 timer: Duration::default(),
127 stage_section: StageSection::Recover,
128 ..*self
129 });
130 }
131 },
132 StageSection::Recover => {
133 if self.timer < self.static_data.recover_duration {
134 update.character = CharacterState::BasicMelee(Data {
136 timer: tick_attack_or_default(
137 data,
138 self.timer,
139 Some(data.stats.recovery_speed_modifier),
140 ),
141 ..*self
142 });
143 } else {
144 if input_is_pressed(data, self.static_data.ability_info.input) {
146 reset_state(self, data, output_events, &mut update);
147 } else {
148 end_melee_ability(data, &mut update);
149 }
150 }
151 },
152 _ => {
153 end_melee_ability(data, &mut update);
155 },
156 }
157
158 handle_interrupts(data, &mut update, output_events);
160
161 update
162 }
163}
164
165fn reset_state(
166 data: &Data,
167 join: &JoinData,
168 output_events: &mut OutputEvents,
169 update: &mut StateUpdate,
170) {
171 handle_input(
172 join,
173 output_events,
174 update,
175 data.static_data.ability_info.input,
176 );
177}
178
179#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
180pub enum FrontendSpecifier {
181 FlameTornado,
182}