veloren_common/states/
riposte_melee.rs

1use 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/// Separated out to condense update portions of character state
13#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
14pub struct StaticData {
15    /// How long until state should deal damage
16    pub buildup_duration: Duration,
17    /// How long the state is swinging for
18    pub swing_duration: Duration,
19    /// How long the state has until exiting
20    pub recover_duration: Duration,
21    /// How long the state has until exiting if the ability missed
22    pub whiffed_recover_duration: Duration,
23    /// Base value that incoming damage is reduced by and converted to poise
24    /// damage
25    pub block_strength: f32,
26    /// Used to construct the Melee attack
27    pub melee_constructor: MeleeConstructor,
28    /// What key is used to press ability
29    pub ability_info: AbilityInfo,
30}
31
32#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
33pub struct Data {
34    /// Struct containing data that does not change over the course of the
35    /// character state
36    pub static_data: StaticData,
37    /// Timer for each stage
38    pub timer: Duration,
39    /// What section the character stage is in
40    pub stage_section: StageSection,
41    /// Whether the attack can deal more damage
42    pub exhausted: bool,
43    /// Whether the riposte whiffed
44    pub whiffed: bool,
45}
46
47impl CharacterBehavior for Data {
48    fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
49        let mut update = StateUpdate::from(data);
50
51        handle_orientation(data, &mut update, 1.0, None);
52        handle_move(data, &mut update, 0.7);
53        handle_jump(data, output_events, &mut update, 1.0);
54        handle_interrupts(data, &mut update, output_events);
55
56        match self.stage_section {
57            StageSection::Buildup => {
58                if let CharacterState::RiposteMelee(c) = &mut update.character {
59                    if self.timer < self.static_data.buildup_duration {
60                        // Build up
61                        c.timer = tick_attack_or_default(data, self.timer, None);
62                    } else {
63                        // If duration finishes with no parry occurring transition to recover
64                        // Transition to action happens in parry hook server event
65                        c.timer = Duration::default();
66                        c.stage_section = StageSection::Recover;
67                    }
68                }
69            },
70            StageSection::Action => {
71                if !self.exhausted {
72                    if let CharacterState::RiposteMelee(c) = &mut update.character {
73                        c.exhausted = true;
74                    }
75
76                    let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
77                    let tool_stats = get_tool_stats(data, self.static_data.ability_info);
78
79                    data.updater.insert(
80                        data.entity,
81                        self.static_data.melee_constructor.clone().create_melee(
82                            precision_mult,
83                            tool_stats,
84                            self.static_data.ability_info,
85                        ),
86                    );
87                } else if self.timer < self.static_data.swing_duration {
88                    // Swings
89                    if let CharacterState::RiposteMelee(c) = &mut update.character {
90                        c.timer = tick_attack_or_default(data, self.timer, None);
91                    }
92                } else {
93                    // Transitions to recover section of stage
94                    if let CharacterState::RiposteMelee(c) = &mut update.character {
95                        c.timer = Duration::default();
96                        c.stage_section = StageSection::Recover
97                    }
98                }
99            },
100            StageSection::Recover => {
101                if let CharacterState::RiposteMelee(c) = &mut update.character {
102                    let recover_duration = if c.whiffed {
103                        self.static_data.whiffed_recover_duration
104                    } else {
105                        self.static_data.recover_duration
106                    };
107                    if self.timer < recover_duration {
108                        // Recovery
109                        c.timer = tick_attack_or_default(
110                            data,
111                            self.timer,
112                            Some(data.stats.recovery_speed_modifier),
113                        );
114                    } else {
115                        // Done
116                        end_melee_ability(data, &mut update);
117                    }
118                }
119            },
120            _ => {
121                // If it somehow ends up in an incorrect stage section
122                end_melee_ability(data, &mut update);
123            },
124        }
125
126        update
127    }
128}