veloren_common/states/
basic_block.rs1use super::utils::*;
2use crate::{
3 combat::AttackSource,
4 comp::{
5 CharacterState, StateUpdate,
6 character_state::{AttackFilters, OutputEvents},
7 },
8 states::behavior::{CharacterBehavior, JoinData},
9};
10use serde::{Deserialize, Serialize};
11use std::time::Duration;
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
14pub struct ParryWindow {
15 pub buildup: bool,
16 pub recover: bool,
17}
18
19#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
21pub struct StaticData {
22 pub buildup_duration: Duration,
24 pub recover_duration: Duration,
26 pub max_angle: f32,
28 pub block_strength: f32,
31 pub parry_window: ParryWindow,
33 pub ability_info: AbilityInfo,
35 pub energy_cost: f32,
37 pub energy_regen: f32,
39 pub can_hold: bool,
41 pub blocked_attacks: AttackFilters,
43}
44
45#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
46pub struct Data {
47 pub static_data: StaticData,
50 pub timer: Duration,
52 pub stage_section: StageSection,
54 pub is_parry: bool,
56}
57
58impl CharacterBehavior for Data {
59 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
60 let mut update = StateUpdate::from(data);
61
62 handle_orientation(data, &mut update, 1.0, None);
63 handle_move(data, &mut update, 0.4);
64
65 match self.stage_section {
66 StageSection::Buildup => {
67 if self.timer < self.static_data.buildup_duration {
68 update.character = CharacterState::BasicBlock(Data {
70 timer: tick_attack_or_default(data, self.timer, None),
71 ..*self
72 });
73 } else {
74 update.character = CharacterState::BasicBlock(Data {
76 timer: Duration::default(),
77 stage_section: if self.static_data.can_hold {
78 StageSection::Action
79 } else {
80 StageSection::Recover
81 },
82 ..*self
83 });
84 }
85 },
86 StageSection::Action => {
87 if self.static_data.can_hold
88 && input_is_pressed(data, self.static_data.ability_info.input)
89 {
90 update.character = CharacterState::BasicBlock(Data {
92 timer: tick_attack_or_default(data, self.timer, None),
93 ..*self
94 });
95 } else {
96 update.character = CharacterState::BasicBlock(Data {
98 timer: Duration::default(),
99 stage_section: StageSection::Recover,
100 ..*self
101 });
102 }
103 },
104 StageSection::Recover => {
105 if (self.static_data.parry_window.recover || !self.is_parry)
106 && self.timer < self.static_data.recover_duration
107 {
108 update.character = CharacterState::BasicBlock(Data {
110 timer: tick_attack_or_default(
111 data,
112 self.timer,
113 Some(data.stats.recovery_speed_modifier),
114 ),
115 ..*self
116 });
117 } else {
118 end_ability(data, &mut update);
120 }
121 },
122 _ => {
123 end_ability(data, &mut update);
125 },
126 }
127
128 handle_interrupts(data, &mut update, output_events);
130
131 update
132 }
133}
134
135impl Data {
136 pub fn is_parry(&self, attack: AttackSource) -> bool {
137 let could_block = self.static_data.blocked_attacks.applies(attack);
138 let timed = match self.stage_section {
139 StageSection::Buildup => self.static_data.parry_window.buildup,
140 StageSection::Recover => self.static_data.parry_window.recover,
141 _ => false,
142 };
143 could_block && timed
144 }
145}