mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added capability for attacks to be interrupted by dodging or blocking
This commit is contained in:
parent
c09e858cba
commit
057b1a4ad6
@ -55,5 +55,11 @@ ComboMelee2(
|
||||
ori_modifier: 0.6,
|
||||
),
|
||||
],
|
||||
meta: Some(Sword(Balanced)),
|
||||
meta: (
|
||||
kind: Some(Sword(Balanced)),
|
||||
capabilities: (
|
||||
// Roll
|
||||
bits: 0b00000001,
|
||||
),
|
||||
),
|
||||
)
|
@ -14,5 +14,11 @@ BasicMelee(
|
||||
range: 5.0,
|
||||
angle: 10.0,
|
||||
),
|
||||
meta: Some(Sword(Balanced)),
|
||||
meta: (
|
||||
kind: Some(Sword(Balanced)),
|
||||
capabilities: (
|
||||
// Block
|
||||
bits: 0b00000010,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -419,7 +419,8 @@ pub enum CharacterAbility {
|
||||
recover_duration: f32,
|
||||
melee_constructor: MeleeConstructor,
|
||||
ori_modifier: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
BasicRanged {
|
||||
energy_cost: f32,
|
||||
@ -431,7 +432,8 @@ pub enum CharacterAbility {
|
||||
projectile_speed: f32,
|
||||
num_projectiles: u32,
|
||||
projectile_spread: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
RepeaterRanged {
|
||||
energy_cost: f32,
|
||||
@ -444,14 +446,16 @@ pub enum CharacterAbility {
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_speed: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
Boost {
|
||||
movement_duration: f32,
|
||||
only_up: bool,
|
||||
speed: f32,
|
||||
max_exit_velocity: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
DashMelee {
|
||||
energy_cost: f32,
|
||||
@ -464,7 +468,8 @@ pub enum CharacterAbility {
|
||||
melee_constructor: MeleeConstructor,
|
||||
ori_modifier: f32,
|
||||
charge_through: bool,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
BasicBlock {
|
||||
buildup_duration: f32,
|
||||
@ -472,7 +477,8 @@ pub enum CharacterAbility {
|
||||
max_angle: f32,
|
||||
block_strength: f32,
|
||||
energy_cost: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
Roll {
|
||||
energy_cost: f32,
|
||||
@ -481,7 +487,8 @@ pub enum CharacterAbility {
|
||||
recover_duration: f32,
|
||||
roll_strength: f32,
|
||||
immune_melee: bool,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
ComboMelee {
|
||||
stage_data: Vec<combo_melee::Stage<f32>>,
|
||||
@ -492,11 +499,13 @@ pub enum CharacterAbility {
|
||||
max_speed_increase: f32,
|
||||
scales_from_combo: u32,
|
||||
ori_modifier: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
ComboMelee2 {
|
||||
strikes: Vec<combo_melee2::Strike<f32>>,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: f32,
|
||||
@ -507,7 +516,8 @@ pub enum CharacterAbility {
|
||||
melee_constructor: MeleeConstructor,
|
||||
forward_leap_strength: f32,
|
||||
vertical_leap_strength: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
SpinMelee {
|
||||
buildup_duration: f32,
|
||||
@ -520,7 +530,8 @@ pub enum CharacterAbility {
|
||||
num_spins: u32,
|
||||
specifier: Option<spin_melee::FrontendSpecifier>,
|
||||
melee_constructor: MeleeConstructor,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
ChargedMelee {
|
||||
energy_cost: f32,
|
||||
@ -531,7 +542,8 @@ pub enum CharacterAbility {
|
||||
recover_duration: f32,
|
||||
melee_constructor: MeleeConstructor,
|
||||
specifier: Option<charged_melee::FrontendSpecifier>,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
ChargedRanged {
|
||||
energy_cost: f32,
|
||||
@ -550,7 +562,8 @@ pub enum CharacterAbility {
|
||||
initial_projectile_speed: f32,
|
||||
scaled_projectile_speed: f32,
|
||||
move_speed: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
Shockwave {
|
||||
energy_cost: f32,
|
||||
@ -569,7 +582,8 @@ pub enum CharacterAbility {
|
||||
damage_kind: DamageKind,
|
||||
specifier: comp::shockwave::FrontendSpecifier,
|
||||
damage_effect: Option<CombatEffect>,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
BasicBeam {
|
||||
buildup_duration: f32,
|
||||
@ -584,7 +598,8 @@ pub enum CharacterAbility {
|
||||
energy_drain: f32,
|
||||
ori_rate: f32,
|
||||
specifier: beam::FrontendSpecifier,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
BasicAura {
|
||||
buildup_duration: f32,
|
||||
@ -597,13 +612,15 @@ pub enum CharacterAbility {
|
||||
energy_cost: f32,
|
||||
scales_with_combo: bool,
|
||||
specifier: Option<aura::Specifier>,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
Blink {
|
||||
buildup_duration: f32,
|
||||
recover_duration: f32,
|
||||
max_range: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
BasicSummon {
|
||||
buildup_duration: f32,
|
||||
@ -613,7 +630,8 @@ pub enum CharacterAbility {
|
||||
summon_distance: (f32, f32),
|
||||
summon_info: basic_summon::SummonInfo,
|
||||
duration: Option<Duration>,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
SelfBuff {
|
||||
buildup_duration: f32,
|
||||
@ -623,7 +641,8 @@ pub enum CharacterAbility {
|
||||
buff_strength: f32,
|
||||
buff_duration: Option<f32>,
|
||||
energy_cost: f32,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
SpriteSummon {
|
||||
buildup_duration: f32,
|
||||
@ -632,7 +651,8 @@ pub enum CharacterAbility {
|
||||
sprite: SpriteKind,
|
||||
summon_distance: (f32, f32),
|
||||
sparseness: f64,
|
||||
meta: Option<AbilityMeta>,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
Music {
|
||||
play_duration: f32,
|
||||
@ -661,7 +681,7 @@ impl Default for CharacterAbility {
|
||||
damage_effect: None,
|
||||
},
|
||||
ori_modifier: 1.0,
|
||||
meta: None,
|
||||
meta: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -728,7 +748,7 @@ impl CharacterAbility {
|
||||
recover_duration: 0.125,
|
||||
roll_strength: 2.0,
|
||||
immune_melee: true,
|
||||
meta: None,
|
||||
meta: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -739,7 +759,7 @@ impl CharacterAbility {
|
||||
max_angle: 60.0,
|
||||
block_strength: 0.5,
|
||||
energy_cost: 2.5,
|
||||
meta: None,
|
||||
meta: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1165,7 +1185,7 @@ impl CharacterAbility {
|
||||
}
|
||||
|
||||
// TODO: Maybe consider making CharacterAbility a struct at some point?
|
||||
pub fn ability_meta(&self) -> Option<AbilityMeta> {
|
||||
pub fn ability_meta(&self) -> AbilityMeta {
|
||||
use CharacterAbility::*;
|
||||
match self {
|
||||
BasicMelee { meta, .. }
|
||||
@ -1194,8 +1214,8 @@ impl CharacterAbility {
|
||||
#[must_use]
|
||||
pub fn contextualize(mut self, data: &JoinData) -> Self {
|
||||
if let Some(ability_info) = data.character.ability_info() {
|
||||
if let Some(AbilityMeta::Sword(old_stance)) = ability_info.ability_meta {
|
||||
if matches!(self.ability_meta(), Some(AbilityMeta::Sword(new_stance)) if old_stance == new_stance)
|
||||
if let Some(AbilityKind::Sword(old_stance)) = ability_info.ability_meta.kind {
|
||||
if matches!(self.ability_meta().kind, Some(AbilityKind::Sword(new_stance)) if old_stance == new_stance)
|
||||
{
|
||||
const ENERGY_REDUCTION: f32 = 0.75;
|
||||
use CharacterAbility::*;
|
||||
@ -2266,7 +2286,25 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum AbilityMeta {
|
||||
pub struct AbilityMeta {
|
||||
pub kind: Option<AbilityKind>,
|
||||
#[serde(default)]
|
||||
pub capabilities: InterruptCapability,
|
||||
}
|
||||
|
||||
impl Default for AbilityMeta {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
kind: None,
|
||||
capabilities: InterruptCapability::NONE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only extend this if it is needed to control certain functionality of
|
||||
// abilities
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum AbilityKind {
|
||||
Sword(SwordStance),
|
||||
}
|
||||
|
||||
@ -2283,3 +2321,12 @@ pub enum SwordStance {
|
||||
Reaching,
|
||||
AirSlash,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct InterruptCapability: u8 {
|
||||
const NONE = 0b00000000;
|
||||
const ROLL = 0b00000001;
|
||||
const BLOCK = 0b00000010;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.7);
|
||||
handle_dodge_interrupt(data, &mut update, Some(InputKind::Primary));
|
||||
handle_interrupts(data, &mut update, Some(InputKind::Primary));
|
||||
|
||||
let strike_data =
|
||||
self.static_data.strikes[self.completed_strikes % self.static_data.strikes.len()];
|
||||
|
@ -245,7 +245,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_dodge_interrupt(data, &mut update, None);
|
||||
handle_interrupts(data, &mut update, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
astar::Astar,
|
||||
combat,
|
||||
comp::{
|
||||
ability::AbilityMeta,
|
||||
ability::{AbilityMeta, InterruptCapability},
|
||||
arthropod, biped_large, biped_small,
|
||||
character_state::OutputEvents,
|
||||
inventory::slot::{ArmorSlot, EquipSlot, Slot},
|
||||
@ -1007,7 +1007,7 @@ pub fn handle_block_input(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||
if ability.requirements_paid(data, update) {
|
||||
update.character = CharacterState::from((
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, false, InputKind::Block, None),
|
||||
AbilityInfo::from_input(data, false, InputKind::Block, Default::default()),
|
||||
data,
|
||||
));
|
||||
}
|
||||
@ -1022,7 +1022,7 @@ pub fn handle_dodge_input(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||
if ability.requirements_paid(data, update) {
|
||||
update.character = CharacterState::from((
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll, None),
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll, Default::default()),
|
||||
data,
|
||||
));
|
||||
if let CharacterState::Roll(roll) = &mut update.character {
|
||||
@ -1042,10 +1042,11 @@ pub fn handle_dodge_input(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains logic for dodge interrupt
|
||||
pub fn handle_dodge_interrupt(
|
||||
pub fn handle_interrupts(
|
||||
data: &JoinData,
|
||||
update: &mut StateUpdate,
|
||||
// Used when an input other than the one that activated the ability being pressed should block
|
||||
// an interrupt
|
||||
input_override: Option<InputKind>,
|
||||
) {
|
||||
// Check that the input used to enter current character state (if there was one)
|
||||
@ -1054,15 +1055,29 @@ pub fn handle_dodge_interrupt(
|
||||
.or_else(|| data.character.ability_info().map(|a| a.input))
|
||||
.map_or(true, |input| !input_is_pressed(data, input))
|
||||
{
|
||||
// If there is a stage section, only roll during
|
||||
if data
|
||||
.character
|
||||
.stage_section()
|
||||
.map_or(true, |stage_section| {
|
||||
matches!(stage_section, StageSection::Buildup)
|
||||
})
|
||||
{
|
||||
let can_dodge = {
|
||||
let in_buildup = data
|
||||
.character
|
||||
.stage_section()
|
||||
.map_or(true, |stage_section| {
|
||||
matches!(stage_section, StageSection::Buildup)
|
||||
});
|
||||
let interruptible = data.character.ability_info().map_or(false, |info| {
|
||||
info.ability_meta
|
||||
.capabilities
|
||||
.contains(InterruptCapability::ROLL)
|
||||
});
|
||||
in_buildup || interruptible
|
||||
};
|
||||
let can_block = data.character.ability_info().map_or(false, |info| {
|
||||
info.ability_meta
|
||||
.capabilities
|
||||
.contains(InterruptCapability::BLOCK)
|
||||
});
|
||||
if can_dodge {
|
||||
handle_dodge_input(data, update);
|
||||
} else if can_block {
|
||||
handle_block_input(data, update);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1234,7 +1249,7 @@ pub struct AbilityInfo {
|
||||
pub hand: Option<HandInfo>,
|
||||
pub input: InputKind,
|
||||
pub input_attr: Option<InputAttr>,
|
||||
pub ability_meta: Option<AbilityMeta>,
|
||||
pub ability_meta: AbilityMeta,
|
||||
}
|
||||
|
||||
impl AbilityInfo {
|
||||
@ -1242,7 +1257,7 @@ impl AbilityInfo {
|
||||
data: &JoinData<'_>,
|
||||
from_offhand: bool,
|
||||
input: InputKind,
|
||||
ability_meta: Option<AbilityMeta>,
|
||||
ability_meta: AbilityMeta,
|
||||
) -> Self {
|
||||
let tool_data = if from_offhand {
|
||||
unwrap_tool_data(data, EquipSlot::ActiveOffhand)
|
||||
|
Loading…
Reference in New Issue
Block a user