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(Copy, 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(Copy, 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
82                            .melee_constructor
83                            .create_melee(precision_mult, tool_stats),
84                    );
85                } else if self.timer < self.static_data.swing_duration {
86                    // Swings
87                    if let CharacterState::RiposteMelee(c) = &mut update.character {
88                        c.timer = tick_attack_or_default(data, self.timer, None);
89                    }
90                } else {
91                    // Transitions to recover section of stage
92                    if let CharacterState::RiposteMelee(c) = &mut update.character {
93                        c.timer = Duration::default();
94                        c.stage_section = StageSection::Recover
95                    }
96                }
97            },
98            StageSection::Recover => {
99                if let CharacterState::RiposteMelee(c) = &mut update.character {
100                    let recover_duration = if c.whiffed {
101                        self.static_data.whiffed_recover_duration
102                    } else {
103                        self.static_data.recover_duration
104                    };
105                    if self.timer < recover_duration {
106                        // Recovery
107                        c.timer = tick_attack_or_default(
108                            data,
109                            self.timer,
110                            Some(data.stats.recovery_speed_modifier),
111                        );
112                    } else {
113                        // Done
114                        end_melee_ability(data, &mut update);
115                    }
116                }
117            },
118            _ => {
119                // If it somehow ends up in an incorrect stage section
120                end_melee_ability(data, &mut update);
121            },
122        }
123
124        update
125    }
126}