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 ability_info: AbilityInfo,
35}
36
37#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
38pub struct Data {
39 pub static_data: StaticData,
42 pub auto_charge: bool,
45 pub timer: Duration,
47 pub stage_section: StageSection,
49}
50
51impl CharacterBehavior for Data {
52 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
53 let mut update = StateUpdate::from(data);
54
55 handle_move(data, &mut update, 0.1);
56
57 let create_melee = |charge_frac: f32| {
58 let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
59 let tool_stats = get_tool_stats(data, self.static_data.ability_info);
60 self.static_data
61 .melee_constructor
62 .clone()
63 .handle_scaling(charge_frac)
64 .create_melee(precision_mult, tool_stats, self.static_data.ability_info)
65 };
66
67 match self.stage_section {
68 StageSection::Buildup => {
69 if self.timer < self.static_data.buildup_duration {
70 handle_orientation(data, &mut update, 1.0, None);
71 if let CharacterState::DashMelee(c) = &mut update.character {
73 c.timer = tick_attack_or_default(data, self.timer, None);
74 }
75 } else {
76 if let CharacterState::DashMelee(c) = &mut update.character {
78 c.auto_charge =
79 !input_is_pressed(data, self.static_data.ability_info.input)
80 || self.static_data.auto_charge;
81 c.timer = Duration::default();
82 c.stage_section = StageSection::Charge;
83 }
84 }
85 },
86 StageSection::Charge => {
87 if self.timer < self.static_data.charge_duration
88 && (input_is_pressed(data, self.static_data.ability_info.input)
89 || self.auto_charge)
90 && update.energy.current() >= 0.0
91 {
92 let charge_frac = (self.timer.as_secs_f32()
94 / self.static_data.charge_duration.as_secs_f32())
95 .min(1.0);
96
97 handle_orientation(data, &mut update, self.static_data.ori_modifier, None);
98 handle_forced_movement(
99 data,
100 &mut update,
101 ForcedMovement::Forward(
102 self.static_data.forward_speed * charge_frac.sqrt(),
103 ),
104 );
105
106 if let Some(melee) = data.melee_attack {
109 if !melee.applied {
110 if let CharacterState::DashMelee(c) = &mut update.character {
112 c.timer = tick_attack_or_default(data, self.timer, None);
113 }
114 } else if melee.hit_count == 0 {
115 data.updater.insert(data.entity, create_melee(charge_frac));
117 if let CharacterState::DashMelee(c) = &mut update.character {
118 c.timer = tick_attack_or_default(data, self.timer, None);
119 }
120 } else {
121 if let CharacterState::DashMelee(c) = &mut update.character {
123 c.timer = Duration::default();
124 c.stage_section = StageSection::Action;
125 }
126 }
127 } else {
128 data.updater.insert(data.entity, create_melee(charge_frac));
130
131 if let CharacterState::DashMelee(c) = &mut update.character {
132 c.timer = tick_attack_or_default(data, self.timer, None);
133 }
134 }
135
136 update
138 .energy
139 .change_by(-self.static_data.energy_drain * data.dt.0);
140 } else {
141 if let CharacterState::DashMelee(c) = &mut update.character {
143 c.timer = Duration::default();
144 c.stage_section = StageSection::Action;
145 }
146 }
147 },
148 StageSection::Action => {
149 if self.timer < self.static_data.swing_duration {
150 if let CharacterState::DashMelee(c) = &mut update.character {
152 c.timer = tick_attack_or_default(data, self.timer, None);
153 }
154 } else {
155 if let CharacterState::DashMelee(c) = &mut update.character {
157 c.timer = Duration::default();
158 c.stage_section = StageSection::Recover;
159 }
160 }
161 },
162 StageSection::Recover => {
163 if self.timer < self.static_data.recover_duration {
164 if let CharacterState::DashMelee(c) = &mut update.character {
166 c.timer = tick_attack_or_default(
167 data,
168 self.timer,
169 Some(data.stats.recovery_speed_modifier),
170 );
171 }
172 } else {
173 end_melee_ability(data, &mut update);
175 }
176 },
177 _ => {
178 end_melee_ability(data, &mut update);
180 },
181 }
182
183 handle_interrupts(data, &mut update, output_events);
185
186 update
187 }
188}