veloren_common/states/
roll.rs1use crate::{
2 comp::{
3 CharacterState, StateUpdate,
4 buff::{BuffChange, BuffKind},
5 character_state::{AttackFilters, OutputEvents},
6 },
7 event::BuffEvent,
8 states::{
9 behavior::{CharacterBehavior, JoinData},
10 utils::*,
11 },
12 util::Dir,
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 movement_duration: Duration,
24 pub recover_duration: Duration,
26 pub roll_strength: f32,
28 pub attack_immunities: AttackFilters,
30 pub ability_info: AbilityInfo,
32 pub was_cancel: bool,
34}
35
36#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
37pub struct Data {
38 pub static_data: StaticData,
41 pub timer: Duration,
43 pub stage_section: StageSection,
45 pub was_wielded: bool,
47 pub prev_aimed_dir: Option<Dir>,
49 pub is_sneaking: bool,
51}
52
53impl CharacterBehavior for Data {
54 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
55 let mut update = StateUpdate::from(data);
56
57 update.should_strafe = false;
59
60 handle_orientation(data, &mut update, 2.5, None);
62
63 match self.stage_section {
64 StageSection::Buildup => {
65 handle_move(data, &mut update, 0.3);
66 if self.timer < self.static_data.buildup_duration {
67 update.character = CharacterState::Roll(Data {
69 timer: tick_attack_or_default(data, self.timer, None),
70 ..*self
71 });
72 } else {
73 output_events.emit_server(BuffEvent {
75 entity: data.entity,
76 buff_change: BuffChange::RemoveByKind(BuffKind::Burning),
77 });
78 update.character = CharacterState::Roll(Data {
80 timer: Duration::default(),
81 stage_section: StageSection::Movement,
82 ..*self
83 });
84 }
85 },
86 StageSection::Movement => {
87 handle_forced_movement(
89 data,
90 &mut update,
91 ForcedMovement::Forward(
92 self.static_data.roll_strength
93 * ((1.0
94 - self.timer.as_secs_f32()
95 / self.static_data.movement_duration.as_secs_f32())
96 / 2.0
97 + 0.25),
98 ),
99 );
100
101 if self.timer < self.static_data.movement_duration {
102 update.character = CharacterState::Roll(Data {
104 timer: tick_attack_or_default(data, self.timer, None),
105 ..*self
106 });
107 } else {
108 update.character = CharacterState::Roll(Data {
110 timer: Duration::default(),
111 stage_section: StageSection::Recover,
112 ..*self
113 });
114 }
115 },
116 StageSection::Recover => {
117 handle_move(data, &mut update, 1.0);
118 if self.timer < self.static_data.recover_duration
120 && !handle_jump(data, output_events, &mut update, 1.5)
121 {
122 update.character = CharacterState::Roll(Data {
124 timer: tick_attack_or_default(
125 data,
126 self.timer,
127 Some(data.stats.recovery_speed_modifier),
128 ),
129 ..*self
130 });
131 } else {
132 end_ability(data, &mut update);
134 }
135 },
136 _ => {
137 end_ability(data, &mut update);
139 },
140 }
141
142 update
143 }
144}