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 mut melee = self
64 .static_data
65 .melee_constructor
66 .clone()
67 .handle_scaling(charge_frac)
68 .create_melee(precision_mult, self.static_data.ability_info);
69 if self.static_data.charge_through {
70 melee.sustained = true;
71 }
72 melee
73 };
74
75 match self.stage_section {
76 StageSection::Buildup => {
77 if self.timer < self.static_data.buildup_duration {
78 handle_orientation(data, &mut update, 1.0, None);
79 if let CharacterState::DashMelee(c) = &mut update.character {
81 c.timer = tick_attack_or_default(data, self.timer, None);
82 }
83 } else {
84 if let CharacterState::DashMelee(c) = &mut update.character {
86 c.auto_charge =
87 !input_is_pressed(data, self.static_data.ability_info.input)
88 || self.static_data.auto_charge;
89 c.timer = Duration::default();
90 c.stage_section = StageSection::Charge;
91 }
92 }
93 },
94 StageSection::Charge => {
95 if self.timer < self.static_data.charge_duration
96 && (input_is_pressed(data, self.static_data.ability_info.input)
97 || self.auto_charge)
98 && update.energy.current() >= 0.0
99 {
100 let charge_frac = (self.timer.as_secs_f32()
102 / self.static_data.charge_duration.as_secs_f32())
103 .min(1.0);
104
105 handle_orientation(data, &mut update, self.static_data.ori_modifier, None);
106 handle_forced_movement(
107 data,
108 &mut update,
109 ForcedMovement::Forward(
110 self.static_data.forward_speed * charge_frac.sqrt(),
111 ),
112 );
113
114 if let Some(melee) = data.melee_attack {
117 if melee.sustained || !melee.applied {
118 if let CharacterState::DashMelee(c) = &mut update.character {
120 c.timer = tick_attack_or_default(data, self.timer, None);
121 }
122 } else if melee.hit_entities.is_empty() {
123 data.updater.insert(data.entity, create_melee(charge_frac));
125 if let CharacterState::DashMelee(c) = &mut update.character {
126 c.timer = tick_attack_or_default(data, self.timer, None);
127 }
128 } else {
129 if let CharacterState::DashMelee(c) = &mut update.character {
131 c.timer = Duration::default();
132 c.stage_section = StageSection::Action;
133 }
134 }
135 } else {
136 data.updater.insert(data.entity, create_melee(charge_frac));
138
139 if let CharacterState::DashMelee(c) = &mut update.character {
140 c.timer = tick_attack_or_default(data, self.timer, None);
141 }
142 }
143
144 update
146 .energy
147 .change_by(-self.static_data.energy_drain * data.dt.0);
148 } else {
149 if let CharacterState::DashMelee(c) = &mut update.character {
151 c.timer = Duration::default();
152 c.stage_section = StageSection::Action;
153 }
154 }
155 },
156 StageSection::Action => {
157 if self.timer < self.static_data.swing_duration {
158 if let CharacterState::DashMelee(c) = &mut update.character {
160 c.timer = tick_attack_or_default(data, self.timer, None);
161 }
162 } else {
163 if let CharacterState::DashMelee(c) = &mut update.character {
165 c.timer = Duration::default();
166 c.stage_section = StageSection::Recover;
167 }
168 }
169 },
170 StageSection::Recover => {
171 if self.timer < self.static_data.recover_duration {
172 if let CharacterState::DashMelee(c) = &mut update.character {
174 c.timer = tick_attack_or_default(data, self.timer, None);
175 }
176 } else {
177 end_melee_ability(data, &mut update);
179 }
180 },
181 _ => {
182 end_melee_ability(data, &mut update);
184 },
185 }
186
187 handle_interrupts(data, &mut update, output_events);
189
190 update
191 }
192}
193
194#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
195pub enum FrontendSpecifier {
196 FireDash,
197}