veloren_common/states/
dash_melee.rs1use crate::{
2 combat,
3 comp::{CharacterState, MeleeConstructor, StateUpdate, character_state::OutputEvents},
4 states::{
5 behavior::{CharacterBehavior, JoinData},
6 utils::*,
7 },
8};
9use serde::{Deserialize, Serialize};
10use std::time::Duration;
11
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
14pub struct StaticData {
15 pub energy_drain: f32,
17 pub forward_speed: f32,
19 pub buildup_duration: Duration,
21 pub charge_duration: Duration,
23 pub swing_duration: Duration,
25 pub recover_duration: Duration,
27 pub melee_constructor: MeleeConstructor,
29 pub ori_modifier: f32,
31 pub auto_charge: bool,
33 pub charge_through: bool,
35 pub ability_info: AbilityInfo,
37 pub frontend_specifier: Option<FrontendSpecifier>,
39}
40
41#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
42pub struct Data {
43 pub static_data: StaticData,
46 pub auto_charge: bool,
49 pub timer: Duration,
51 pub stage_section: StageSection,
53}
54
55impl CharacterBehavior for Data {
56 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
57 let mut update = StateUpdate::from(data);
58
59 handle_move(data, &mut update, 0.1);
60
61 let create_melee = |charge_frac: f32| {
62 let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
63 let tool_stats = get_tool_stats(data, self.static_data.ability_info);
64 let mut melee = self
65 .static_data
66 .melee_constructor
67 .clone()
68 .handle_scaling(charge_frac)
69 .create_melee(precision_mult, tool_stats, self.static_data.ability_info);
70 if self.static_data.charge_through {
71 melee.sustained = true;
72 }
73 melee
74 };
75
76 match self.stage_section {
77 StageSection::Buildup => {
78 if self.timer < self.static_data.buildup_duration {
79 handle_orientation(data, &mut update, 1.0, None);
80 if let CharacterState::DashMelee(c) = &mut update.character {
82 c.timer = tick_attack_or_default(data, self.timer, None);
83 }
84 } else {
85 if let CharacterState::DashMelee(c) = &mut update.character {
87 c.auto_charge =
88 !input_is_pressed(data, self.static_data.ability_info.input)
89 || self.static_data.auto_charge;
90 c.timer = Duration::default();
91 c.stage_section = StageSection::Charge;
92 }
93 }
94 },
95 StageSection::Charge => {
96 if self.timer < self.static_data.charge_duration
97 && (input_is_pressed(data, self.static_data.ability_info.input)
98 || self.auto_charge)
99 && update.energy.current() >= 0.0
100 {
101 let charge_frac = (self.timer.as_secs_f32()
103 / self.static_data.charge_duration.as_secs_f32())
104 .min(1.0);
105
106 handle_orientation(data, &mut update, self.static_data.ori_modifier, None);
107 handle_forced_movement(
108 data,
109 &mut update,
110 ForcedMovement::Forward(
111 self.static_data.forward_speed * charge_frac.sqrt(),
112 ),
113 );
114
115 if let Some(melee) = data.melee_attack {
118 if melee.sustained || !melee.applied {
119 if let CharacterState::DashMelee(c) = &mut update.character {
121 c.timer = tick_attack_or_default(data, self.timer, None);
122 }
123 } else if melee.hit_entities.is_empty() {
124 data.updater.insert(data.entity, create_melee(charge_frac));
126 if let CharacterState::DashMelee(c) = &mut update.character {
127 c.timer = tick_attack_or_default(data, self.timer, None);
128 }
129 } else {
130 if let CharacterState::DashMelee(c) = &mut update.character {
132 c.timer = Duration::default();
133 c.stage_section = StageSection::Action;
134 }
135 }
136 } else {
137 data.updater.insert(data.entity, create_melee(charge_frac));
139
140 if let CharacterState::DashMelee(c) = &mut update.character {
141 c.timer = tick_attack_or_default(data, self.timer, None);
142 }
143 }
144
145 update
147 .energy
148 .change_by(-self.static_data.energy_drain * data.dt.0);
149 } else {
150 if let CharacterState::DashMelee(c) = &mut update.character {
152 c.timer = Duration::default();
153 c.stage_section = StageSection::Action;
154 }
155 }
156 },
157 StageSection::Action => {
158 if self.timer < self.static_data.swing_duration {
159 if let CharacterState::DashMelee(c) = &mut update.character {
161 c.timer = tick_attack_or_default(data, self.timer, None);
162 }
163 } else {
164 if let CharacterState::DashMelee(c) = &mut update.character {
166 c.timer = Duration::default();
167 c.stage_section = StageSection::Recover;
168 }
169 }
170 },
171 StageSection::Recover => {
172 if self.timer < self.static_data.recover_duration {
173 if let CharacterState::DashMelee(c) = &mut update.character {
175 c.timer = tick_attack_or_default(
176 data,
177 self.timer,
178 Some(data.stats.recovery_speed_modifier),
179 );
180 }
181 } else {
182 end_melee_ability(data, &mut update);
184 }
185 },
186 _ => {
187 end_melee_ability(data, &mut update);
189 },
190 }
191
192 handle_interrupts(data, &mut update, output_events);
194
195 update
196 }
197}
198
199#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
200pub enum FrontendSpecifier {
201 FireDash,
202}