mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Nerasw/defensive stance tweaks
This commit is contained in:
parent
769f341795
commit
e72a8f2fcc
16
CHANGELOG.md
16
CHANGELOG.md
@ -8,10 +8,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Esperanto translation
|
||||||
|
- Item quantity sort in player inventory.
|
||||||
|
- Using Block('Alt' by default) in Defensive Stance now feels stronger
|
||||||
- Recipe for twigs from wooden logs
|
- Recipe for twigs from wooden logs
|
||||||
- First version of multisalvage that allows to obtain more than one piece of material from salvage
|
- First version of multisalvage that allows to obtain more than one piece of material from salvage
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- Plugins now target wasm32-unknown-wasi and all wasm cfgs are gone
|
||||||
|
- Slightly reduced quantities of ingredients needed to craft cooked foods
|
||||||
|
- Improved and cleaned loot tables for T1 and T2 dungeons as well as large cave monsters (Good bye, Bowls and Stones!)
|
||||||
|
- Defensive Fell Strike's dmg raised
|
||||||
|
- Defensive Cascade's more effective against parried foes
|
||||||
|
- Defensive Riposte's buildup duration raised a bit
|
||||||
|
- Capabilities of strikes to parry & block now more reliable
|
||||||
|
- Defensive Disengage now more responsive and can block melee
|
||||||
|
- Deflect no longer parry melee hits
|
||||||
|
|
||||||
- Made helmets, necklaces, rings, twig armors and some gliders salvageable
|
- Made helmets, necklaces, rings, twig armors and some gliders salvageable
|
||||||
- Tweaked stats on some foods so they generally increase a tiny bit more HP
|
- Tweaked stats on some foods so they generally increase a tiny bit more HP
|
||||||
- Reduced idle time after consumption from 5 to 4 seconds
|
- Reduced idle time after consumption from 5 to 4 seconds
|
||||||
|
@ -3,6 +3,13 @@
|
|||||||
// A set of abilities is a primary, a secondary, and a vec of all extra abilities
|
// A set of abilities is a primary, a secondary, and a vec of all extra abilities
|
||||||
({
|
({
|
||||||
Tool(Sword): (
|
Tool(Sword): (
|
||||||
|
guard: Some(Contextualized(
|
||||||
|
pseudo_id: "veloren.core.pseudo_abilities.sword.guard",
|
||||||
|
abilities: [
|
||||||
|
([Stance(Sword(Defensive))], (None, "common.abilities.sword.defensive_guard")),
|
||||||
|
([], (None, "common.abilities.sword.basic_guard")),
|
||||||
|
],
|
||||||
|
)),
|
||||||
primary: Contextualized(
|
primary: Contextualized(
|
||||||
pseudo_id: "veloren.core.pseudo_abilities.sword.double_slash",
|
pseudo_id: "veloren.core.pseudo_abilities.sword.double_slash",
|
||||||
abilities: [
|
abilities: [
|
||||||
@ -136,6 +143,7 @@
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Tool(Axe): (
|
Tool(Axe): (
|
||||||
|
guard: Some(Simple(None, "common.abilities.axe.basic_guard")),
|
||||||
primary: Simple(None, "common.abilities.axe.doublestrike"),
|
primary: Simple(None, "common.abilities.axe.doublestrike"),
|
||||||
secondary: Simple(None, "common.abilities.axe.spin"),
|
secondary: Simple(None, "common.abilities.axe.spin"),
|
||||||
abilities: [
|
abilities: [
|
||||||
@ -143,6 +151,7 @@
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Tool(Hammer): (
|
Tool(Hammer): (
|
||||||
|
guard: Some(Simple(None, "common.abilities.hammer.basic_guard")),
|
||||||
primary: Simple(None, "common.abilities.hammer.singlestrike"),
|
primary: Simple(None, "common.abilities.hammer.singlestrike"),
|
||||||
secondary: Simple(None, "common.abilities.hammer.charged"),
|
secondary: Simple(None, "common.abilities.hammer.charged"),
|
||||||
abilities: [
|
abilities: [
|
||||||
|
21
assets/common/abilities/axe/basic_guard.ron
Normal file
21
assets/common/abilities/axe/basic_guard.ron
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
BasicBlock(
|
||||||
|
buildup_duration: 0.25,
|
||||||
|
recover_duration: 0.2,
|
||||||
|
max_angle: 60.0,
|
||||||
|
block_strength: 0.5,
|
||||||
|
parry_window: (
|
||||||
|
buildup: true,
|
||||||
|
recover: false,
|
||||||
|
),
|
||||||
|
energy_cost: 5,
|
||||||
|
energy_regen: 2.5,
|
||||||
|
can_hold: true,
|
||||||
|
blocked_attacks: (
|
||||||
|
melee: true,
|
||||||
|
projectiles: false,
|
||||||
|
beams: false,
|
||||||
|
ground_shockwaves: false,
|
||||||
|
air_shockwaves: false,
|
||||||
|
explosions: false,
|
||||||
|
),
|
||||||
|
)
|
21
assets/common/abilities/hammer/basic_guard.ron
Normal file
21
assets/common/abilities/hammer/basic_guard.ron
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
BasicBlock(
|
||||||
|
buildup_duration: 0.25,
|
||||||
|
recover_duration: 0.2,
|
||||||
|
max_angle: 60.0,
|
||||||
|
block_strength: 0.5,
|
||||||
|
parry_window: (
|
||||||
|
buildup: true,
|
||||||
|
recover: false,
|
||||||
|
),
|
||||||
|
energy_cost: 5,
|
||||||
|
energy_regen: 2.5,
|
||||||
|
can_hold: true,
|
||||||
|
blocked_attacks: (
|
||||||
|
melee: true,
|
||||||
|
projectiles: false,
|
||||||
|
beams: false,
|
||||||
|
ground_shockwaves: false,
|
||||||
|
air_shockwaves: false,
|
||||||
|
explosions: false,
|
||||||
|
),
|
||||||
|
)
|
@ -8,6 +8,7 @@ BasicBlock(
|
|||||||
recover: false,
|
recover: false,
|
||||||
),
|
),
|
||||||
energy_cost: 0.0,
|
energy_cost: 0.0,
|
||||||
|
energy_regen: 0.0,
|
||||||
can_hold: true,
|
can_hold: true,
|
||||||
blocked_attacks: (
|
blocked_attacks: (
|
||||||
melee: true,
|
melee: true,
|
||||||
|
21
assets/common/abilities/sword/basic_guard.ron
Normal file
21
assets/common/abilities/sword/basic_guard.ron
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
BasicBlock(
|
||||||
|
buildup_duration: 0.25,
|
||||||
|
recover_duration: 0.2,
|
||||||
|
max_angle: 60.0,
|
||||||
|
block_strength: 0.5,
|
||||||
|
parry_window: (
|
||||||
|
buildup: true,
|
||||||
|
recover: false,
|
||||||
|
),
|
||||||
|
energy_cost: 5,
|
||||||
|
energy_regen: 2.5,
|
||||||
|
can_hold: true,
|
||||||
|
blocked_attacks: (
|
||||||
|
melee: true,
|
||||||
|
projectiles: false,
|
||||||
|
beams: false,
|
||||||
|
ground_shockwaves: false,
|
||||||
|
air_shockwaves: false,
|
||||||
|
explosions: false,
|
||||||
|
),
|
||||||
|
)
|
@ -10,7 +10,7 @@ ComboMelee2(
|
|||||||
),
|
),
|
||||||
range: 4.0,
|
range: 4.0,
|
||||||
angle: 15.0,
|
angle: 15.0,
|
||||||
damage_effect: Some(BuffsVulnerable(0.5, Parried)),
|
damage_effect: Some(BuffsVulnerable(0.6, Parried)),
|
||||||
),
|
),
|
||||||
buildup_duration: 0.4,
|
buildup_duration: 0.4,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
@ -21,7 +21,7 @@ ComboMelee2(
|
|||||||
],
|
],
|
||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("BUILDUP_PARRIES"),
|
capabilities: ("PARRIES"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -21,7 +21,7 @@ ComboMelee2(
|
|||||||
],
|
],
|
||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("BUILDUP_PARRIES"),
|
capabilities: ("PARRIES"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -40,7 +40,7 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 2.5,
|
energy_cost_per_strike: 2.5,
|
||||||
auto_progress: true,
|
auto_progress: true,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("BUILDUP_PARRIES"),
|
capabilities: ("PARRIES"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -1,18 +1,19 @@
|
|||||||
BasicBlock(
|
BasicBlock(
|
||||||
buildup_duration: 0.25,
|
buildup_duration: 0.4,
|
||||||
recover_duration: 0.15,
|
recover_duration: 0.2,
|
||||||
max_angle: 45.0,
|
max_angle: 45.0,
|
||||||
block_strength: 0.75,
|
block_strength: 0.75,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: true,
|
recover: false,
|
||||||
),
|
),
|
||||||
energy_cost: 0,
|
energy_cost: 2.5,
|
||||||
|
energy_regen: 17.5,
|
||||||
can_hold: false,
|
can_hold: false,
|
||||||
blocked_attacks: (
|
blocked_attacks: (
|
||||||
melee: true,
|
melee: false,
|
||||||
projectiles: true,
|
projectiles: true,
|
||||||
beams: false,
|
beams: true,
|
||||||
ground_shockwaves: false,
|
ground_shockwaves: false,
|
||||||
air_shockwaves: false,
|
air_shockwaves: false,
|
||||||
explosions: false,
|
explosions: false,
|
||||||
|
@ -11,13 +11,13 @@ ComboMelee2(
|
|||||||
range: 6.0,
|
range: 6.0,
|
||||||
angle: 45.0,
|
angle: 45.0,
|
||||||
),
|
),
|
||||||
buildup_duration: 0.1,
|
buildup_duration: 0.05,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
hit_timing: 0.6,
|
hit_timing: 0.6,
|
||||||
recover_duration: 0.4,
|
recover_duration: 0.3,
|
||||||
movement: (
|
movement: (
|
||||||
buildup: None,
|
buildup: None,
|
||||||
swing: None,
|
swing: Some(Reverse(2)),
|
||||||
recover: Some(Reverse(1.5)),
|
recover: Some(Reverse(1.5)),
|
||||||
),
|
),
|
||||||
ori_modifier: 0.6,
|
ori_modifier: 0.6,
|
||||||
@ -26,5 +26,6 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 0,
|
energy_cost_per_strike: 0,
|
||||||
meta: (
|
meta: (
|
||||||
init_event: Some(EnterStance(Sword(Defensive))),
|
init_event: Some(EnterStance(Sword(Defensive))),
|
||||||
|
capabilities: ("BLOCKS"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -37,7 +37,7 @@ ComboMelee2(
|
|||||||
],
|
],
|
||||||
energy_cost_per_strike: 0,
|
energy_cost_per_strike: 0,
|
||||||
meta: (
|
meta: (
|
||||||
// Blocks melee attacks at 50% strength
|
// Blocks melee attacks at 50% strength during buildup_duration & swing_duration
|
||||||
capabilities: ("BUILDUP_BLOCKS"),
|
capabilities: ("BLOCKS"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -22,7 +22,7 @@ ComboMelee2(
|
|||||||
],
|
],
|
||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("BUILDUP_PARRIES"),
|
capabilities: ("PARRIES"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -3,7 +3,7 @@ ComboMelee2(
|
|||||||
(
|
(
|
||||||
melee_constructor: (
|
melee_constructor: (
|
||||||
kind: Slash(
|
kind: Slash(
|
||||||
damage: 15,
|
damage: 20,
|
||||||
poise: 5,
|
poise: 5,
|
||||||
knockback: 0,
|
knockback: 0,
|
||||||
energy_regen: 0,
|
energy_regen: 0,
|
||||||
@ -21,7 +21,7 @@ ComboMelee2(
|
|||||||
],
|
],
|
||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("BUILDUP_PARRIES"),
|
capabilities: ("PARRIES"),
|
||||||
),
|
),
|
||||||
)
|
)
|
24
assets/common/abilities/sword/defensive_guard.ron
Normal file
24
assets/common/abilities/sword/defensive_guard.ron
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
BasicBlock(
|
||||||
|
buildup_duration: 0.4,
|
||||||
|
recover_duration: 0.15,
|
||||||
|
max_angle: 60.0,
|
||||||
|
block_strength: 0.75,
|
||||||
|
parry_window: (
|
||||||
|
buildup: true,
|
||||||
|
recover: false,
|
||||||
|
),
|
||||||
|
energy_cost: 2.5,
|
||||||
|
energy_regen: 17.5,
|
||||||
|
can_hold: true,
|
||||||
|
blocked_attacks: (
|
||||||
|
melee: true,
|
||||||
|
projectiles: false,
|
||||||
|
beams: false,
|
||||||
|
ground_shockwaves: false,
|
||||||
|
air_shockwaves: false,
|
||||||
|
explosions: false,
|
||||||
|
),
|
||||||
|
meta: (
|
||||||
|
requirements: (stance: Some(Sword(Defensive))),
|
||||||
|
),
|
||||||
|
)
|
@ -1,6 +1,6 @@
|
|||||||
RiposteMelee(
|
RiposteMelee(
|
||||||
energy_cost: 5,
|
energy_cost: 5,
|
||||||
buildup_duration: 0.3,
|
buildup_duration: 0.4,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
melee_constructor: (
|
melee_constructor: (
|
||||||
|
@ -26,7 +26,7 @@ ComboMelee2(
|
|||||||
],
|
],
|
||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("BUILDUP_PARRIES"),
|
capabilities: ("PARRIES"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -9,7 +9,7 @@ ChargedMelee(
|
|||||||
energy_regen: 0,
|
energy_regen: 0,
|
||||||
),
|
),
|
||||||
scaled: Some(Stab(
|
scaled: Some(Stab(
|
||||||
damage: 10,
|
damage: 12,
|
||||||
poise: 5,
|
poise: 5,
|
||||||
knockback: 0,
|
knockback: 0,
|
||||||
energy_regen: 15,
|
energy_regen: 15,
|
||||||
|
@ -148,6 +148,7 @@ impl Attack {
|
|||||||
emit(ServerEvent::ParryHook {
|
emit(ServerEvent::ParryHook {
|
||||||
defender: target.entity,
|
defender: target.entity,
|
||||||
attacker: attacker.map(|a| a.entity),
|
attacker: attacker.map(|a| a.entity),
|
||||||
|
source,
|
||||||
});
|
});
|
||||||
1.0
|
1.0
|
||||||
} else if let Some(block_strength) = char_state.block_strength(source) {
|
} else if let Some(block_strength) = char_state.block_strength(source) {
|
||||||
|
@ -42,6 +42,7 @@ pub type AuxiliaryKey = (Option<ToolKind>, Option<ToolKind>);
|
|||||||
// considerations.
|
// considerations.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct ActiveAbilities {
|
pub struct ActiveAbilities {
|
||||||
|
pub guard: GuardAbility,
|
||||||
pub primary: PrimaryAbility,
|
pub primary: PrimaryAbility,
|
||||||
pub secondary: SecondaryAbility,
|
pub secondary: SecondaryAbility,
|
||||||
pub movement: MovementAbility,
|
pub movement: MovementAbility,
|
||||||
@ -55,6 +56,7 @@ impl Component for ActiveAbilities {
|
|||||||
impl Default for ActiveAbilities {
|
impl Default for ActiveAbilities {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
guard: GuardAbility::Tool,
|
||||||
primary: PrimaryAbility::Tool,
|
primary: PrimaryAbility::Tool,
|
||||||
secondary: SecondaryAbility::Tool,
|
secondary: SecondaryAbility::Tool,
|
||||||
movement: MovementAbility::Species,
|
movement: MovementAbility::Species,
|
||||||
@ -123,6 +125,7 @@ impl ActiveAbilities {
|
|||||||
skill_set: Option<&SkillSet>,
|
skill_set: Option<&SkillSet>,
|
||||||
) -> Ability {
|
) -> Ability {
|
||||||
match input {
|
match input {
|
||||||
|
AbilityInput::Guard => self.guard.into(),
|
||||||
AbilityInput::Primary => self.primary.into(),
|
AbilityInput::Primary => self.primary.into(),
|
||||||
AbilityInput::Secondary => self.secondary.into(),
|
AbilityInput::Secondary => self.secondary.into(),
|
||||||
AbilityInput::Movement => self.movement.into(),
|
AbilityInput::Movement => self.movement.into(),
|
||||||
@ -165,6 +168,22 @@ impl ActiveAbilities {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match ability {
|
match ability {
|
||||||
|
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
|
||||||
|
.and_then(|abilities| {
|
||||||
|
abilities
|
||||||
|
.guard(Some(skill_set), contexts)
|
||||||
|
.map(|a| a.ability.clone())
|
||||||
|
})
|
||||||
|
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), true))
|
||||||
|
.or_else(|| {
|
||||||
|
ability_set(EquipSlot::ActiveOffhand)
|
||||||
|
.and_then(|abilities| {
|
||||||
|
abilities
|
||||||
|
.secondary(Some(skill_set), contexts)
|
||||||
|
.map(|a| a.ability.clone())
|
||||||
|
})
|
||||||
|
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), false))
|
||||||
|
}),
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
||||||
.and_then(|abilities| {
|
.and_then(|abilities| {
|
||||||
abilities
|
abilities
|
||||||
@ -250,6 +269,7 @@ impl ActiveAbilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum AbilityInput {
|
pub enum AbilityInput {
|
||||||
|
Guard,
|
||||||
Primary,
|
Primary,
|
||||||
Secondary,
|
Secondary,
|
||||||
Movement,
|
Movement,
|
||||||
@ -258,6 +278,7 @@ pub enum AbilityInput {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
pub enum Ability {
|
pub enum Ability {
|
||||||
|
ToolGuard,
|
||||||
ToolPrimary,
|
ToolPrimary,
|
||||||
ToolSecondary,
|
ToolSecondary,
|
||||||
SpeciesMovement,
|
SpeciesMovement,
|
||||||
@ -293,6 +314,31 @@ impl Ability {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
|
||||||
|
.and_then(|abilities| {
|
||||||
|
abilities
|
||||||
|
.guard(skillset, contexts)
|
||||||
|
.map(|a| a.id.as_str())
|
||||||
|
.or_else(|| {
|
||||||
|
abilities
|
||||||
|
.guard
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|g| contextual_id(Some(g)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
|
||||||
|
abilities
|
||||||
|
.guard(skillset, contexts)
|
||||||
|
.map(|a| a.id.as_str())
|
||||||
|
.or_else(|| {
|
||||||
|
abilities
|
||||||
|
.guard
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|g| contextual_id(Some(g)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
||||||
abilities
|
abilities
|
||||||
.primary(skillset, contexts)
|
.primary(skillset, contexts)
|
||||||
@ -335,6 +381,20 @@ impl Ability {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
||||||
|
pub enum GuardAbility {
|
||||||
|
Tool,
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GuardAbility> for Ability {
|
||||||
|
fn from(guard: GuardAbility) -> Self {
|
||||||
|
match guard {
|
||||||
|
GuardAbility::Tool => Ability::ToolGuard,
|
||||||
|
GuardAbility::Empty => Ability::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
||||||
pub enum PrimaryAbility {
|
pub enum PrimaryAbility {
|
||||||
@ -550,6 +610,7 @@ pub enum CharacterAbility {
|
|||||||
block_strength: f32,
|
block_strength: f32,
|
||||||
parry_window: basic_block::ParryWindow,
|
parry_window: basic_block::ParryWindow,
|
||||||
energy_cost: f32,
|
energy_cost: f32,
|
||||||
|
energy_regen: f32,
|
||||||
can_hold: bool,
|
can_hold: bool,
|
||||||
blocked_attacks: AttackFilters,
|
blocked_attacks: AttackFilters,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -967,30 +1028,6 @@ impl CharacterAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_block() -> CharacterAbility {
|
|
||||||
CharacterAbility::BasicBlock {
|
|
||||||
buildup_duration: 0.25,
|
|
||||||
recover_duration: 0.2,
|
|
||||||
max_angle: 60.0,
|
|
||||||
block_strength: 0.5,
|
|
||||||
parry_window: basic_block::ParryWindow {
|
|
||||||
buildup: true,
|
|
||||||
recover: false,
|
|
||||||
},
|
|
||||||
energy_cost: 2.5,
|
|
||||||
can_hold: true,
|
|
||||||
blocked_attacks: AttackFilters {
|
|
||||||
melee: true,
|
|
||||||
projectiles: false,
|
|
||||||
ground_shockwaves: false,
|
|
||||||
air_shockwaves: false,
|
|
||||||
beams: false,
|
|
||||||
explosions: false,
|
|
||||||
},
|
|
||||||
meta: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn adjusted_by_stats(mut self, stats: Stats) -> Self {
|
pub fn adjusted_by_stats(mut self, stats: Stats) -> Self {
|
||||||
use CharacterAbility::*;
|
use CharacterAbility::*;
|
||||||
@ -1090,6 +1127,7 @@ impl CharacterAbility {
|
|||||||
block_strength: _,
|
block_strength: _,
|
||||||
parry_window: _,
|
parry_window: _,
|
||||||
ref mut energy_cost,
|
ref mut energy_cost,
|
||||||
|
energy_regen: _,
|
||||||
can_hold: _,
|
can_hold: _,
|
||||||
blocked_attacks: _,
|
blocked_attacks: _,
|
||||||
meta: _,
|
meta: _,
|
||||||
@ -2247,6 +2285,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
block_strength,
|
block_strength,
|
||||||
parry_window,
|
parry_window,
|
||||||
energy_cost,
|
energy_cost,
|
||||||
|
energy_regen,
|
||||||
can_hold,
|
can_hold,
|
||||||
blocked_attacks,
|
blocked_attacks,
|
||||||
meta: _,
|
meta: _,
|
||||||
@ -2258,6 +2297,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
block_strength: *block_strength,
|
block_strength: *block_strength,
|
||||||
parry_window: *parry_window,
|
parry_window: *parry_window,
|
||||||
energy_cost: *energy_cost,
|
energy_cost: *energy_cost,
|
||||||
|
energy_regen: *energy_regen,
|
||||||
can_hold: *can_hold,
|
can_hold: *can_hold,
|
||||||
blocked_attacks: *blocked_attacks,
|
blocked_attacks: *blocked_attacks,
|
||||||
ability_info,
|
ability_info,
|
||||||
@ -2910,13 +2950,13 @@ bitflags::bitflags! {
|
|||||||
// Allows blocking to interrupt the ability at any point
|
// Allows blocking to interrupt the ability at any point
|
||||||
const BLOCK_INTERRUPT = 0b00000010;
|
const BLOCK_INTERRUPT = 0b00000010;
|
||||||
// When the ability is in the buildup section, it counts as a block with 50% DR
|
// When the ability is in the buildup section, it counts as a block with 50% DR
|
||||||
const BUILDUP_BLOCKS = 0b00000100;
|
const BLOCKS = 0b00000100;
|
||||||
// When in the ability, an entity only receives half as much poise damage
|
// When in the ability, an entity only receives half as much poise damage
|
||||||
const POISE_RESISTANT = 0b00001000;
|
const POISE_RESISTANT = 0b00001000;
|
||||||
// WHen in the ability, an entity only receives half as much knockback
|
// WHen in the ability, an entity only receives half as much knockback
|
||||||
const KNOCKBACK_RESISTANT = 0b00010000;
|
const KNOCKBACK_RESISTANT = 0b00010000;
|
||||||
// The ability will parry melee attacks in the buildup portion
|
// The ability will parry melee attacks in the buildup portion
|
||||||
const BUILDUP_PARRIES = 0b00100000;
|
const PARRIES = 0b00100000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,8 +289,11 @@ impl CharacterState {
|
|||||||
.map(|a| a.ability_meta)
|
.map(|a| a.ability_meta)
|
||||||
.map(|m| m.capabilities)
|
.map(|m| m.capabilities)
|
||||||
{
|
{
|
||||||
(capabilities.contains(Capability::BUILDUP_BLOCKS)
|
(capabilities.contains(Capability::BLOCKS)
|
||||||
&& matches!(self.stage_section(), Some(StageSection::Buildup)))
|
&& matches!(
|
||||||
|
self.stage_section(),
|
||||||
|
Some(StageSection::Buildup | StageSection::Action)
|
||||||
|
))
|
||||||
.then_some(0.5)
|
.then_some(0.5)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -320,13 +323,20 @@ impl CharacterState {
|
|||||||
.ability_info()
|
.ability_info()
|
||||||
.map(|a| a.ability_meta.capabilities)
|
.map(|a| a.ability_meta.capabilities)
|
||||||
.map_or(false, |c| {
|
.map_or(false, |c| {
|
||||||
c.contains(Capability::BUILDUP_PARRIES)
|
c.contains(Capability::PARRIES)
|
||||||
&& matches!(self.stage_section(), Some(StageSection::Buildup))
|
&& matches!(
|
||||||
|
self.stage_section(),
|
||||||
|
Some(StageSection::Buildup | StageSection::Action)
|
||||||
|
)
|
||||||
});
|
});
|
||||||
let from_state = match self {
|
let from_state = match self {
|
||||||
CharacterState::BasicBlock(c) => c.is_parry(attack_source),
|
CharacterState::BasicBlock(c) => c.is_parry(attack_source),
|
||||||
CharacterState::RiposteMelee(c) => {
|
CharacterState::RiposteMelee(c) => {
|
||||||
melee && matches!(c.stage_section, StageSection::Buildup)
|
melee
|
||||||
|
&& matches!(
|
||||||
|
c.stage_section,
|
||||||
|
StageSection::Buildup | StageSection::Action
|
||||||
|
)
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
@ -215,11 +215,12 @@ impl From<InputKind> for Option<ability::AbilityInput> {
|
|||||||
fn from(input: InputKind) -> Option<ability::AbilityInput> {
|
fn from(input: InputKind) -> Option<ability::AbilityInput> {
|
||||||
use ability::AbilityInput;
|
use ability::AbilityInput;
|
||||||
match input {
|
match input {
|
||||||
|
InputKind::Block => Some(AbilityInput::Guard),
|
||||||
InputKind::Primary => Some(AbilityInput::Primary),
|
InputKind::Primary => Some(AbilityInput::Primary),
|
||||||
InputKind::Secondary => Some(AbilityInput::Secondary),
|
InputKind::Secondary => Some(AbilityInput::Secondary),
|
||||||
InputKind::Roll => Some(AbilityInput::Movement),
|
InputKind::Roll => Some(AbilityInput::Movement),
|
||||||
InputKind::Ability(index) => Some(AbilityInput::Auxiliary(index)),
|
InputKind::Ability(index) => Some(AbilityInput::Auxiliary(index)),
|
||||||
InputKind::Jump | InputKind::Fly | InputKind::Block => None,
|
InputKind::Jump | InputKind::Fly => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,6 +294,7 @@ impl Tool {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct AbilitySet<T> {
|
pub struct AbilitySet<T> {
|
||||||
|
pub guard: Option<AbilityKind<T>>,
|
||||||
pub primary: AbilityKind<T>,
|
pub primary: AbilityKind<T>,
|
||||||
pub secondary: AbilityKind<T>,
|
pub secondary: AbilityKind<T>,
|
||||||
pub abilities: Vec<AbilityKind<T>>,
|
pub abilities: Vec<AbilityKind<T>>,
|
||||||
@ -422,6 +423,7 @@ impl AbilitySet<AbilityItem> {
|
|||||||
impl<T> AbilitySet<T> {
|
impl<T> AbilitySet<T> {
|
||||||
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> AbilitySet<U> {
|
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> AbilitySet<U> {
|
||||||
AbilitySet {
|
AbilitySet {
|
||||||
|
guard: self.guard.map(|g| g.map(&mut f)),
|
||||||
primary: self.primary.map(&mut f),
|
primary: self.primary.map(&mut f),
|
||||||
secondary: self.secondary.map(&mut f),
|
secondary: self.secondary.map(&mut f),
|
||||||
abilities: self.abilities.into_iter().map(|x| x.map(&mut f)).collect(),
|
abilities: self.abilities.into_iter().map(|x| x.map(&mut f)).collect(),
|
||||||
@ -430,12 +432,19 @@ impl<T> AbilitySet<T> {
|
|||||||
|
|
||||||
pub fn map_ref<U, F: FnMut(&T) -> U>(&self, mut f: F) -> AbilitySet<U> {
|
pub fn map_ref<U, F: FnMut(&T) -> U>(&self, mut f: F) -> AbilitySet<U> {
|
||||||
AbilitySet {
|
AbilitySet {
|
||||||
|
guard: self.guard.as_ref().map(|g| g.map_ref(&mut f)),
|
||||||
primary: self.primary.map_ref(&mut f),
|
primary: self.primary.map_ref(&mut f),
|
||||||
secondary: self.secondary.map_ref(&mut f),
|
secondary: self.secondary.map_ref(&mut f),
|
||||||
abilities: self.abilities.iter().map(|x| x.map_ref(&mut f)).collect(),
|
abilities: self.abilities.iter().map(|x| x.map_ref(&mut f)).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn guard(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> {
|
||||||
|
self.guard
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|g| g.ability(skillset, contexts))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn primary(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> {
|
pub fn primary(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> {
|
||||||
self.primary.ability(skillset, contexts)
|
self.primary.ability(skillset, contexts)
|
||||||
}
|
}
|
||||||
@ -463,6 +472,7 @@ impl<T> AbilitySet<T> {
|
|||||||
impl Default for AbilitySet<AbilityItem> {
|
impl Default for AbilitySet<AbilityItem> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
AbilitySet {
|
AbilitySet {
|
||||||
|
guard: None,
|
||||||
primary: AbilityKind::Simple(None, AbilityItem {
|
primary: AbilityKind::Simple(None, AbilityItem {
|
||||||
id: String::new(),
|
id: String::new(),
|
||||||
ability: CharacterAbility::default(),
|
ability: CharacterAbility::default(),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
|
combat::AttackSource,
|
||||||
comp::{
|
comp::{
|
||||||
self,
|
self,
|
||||||
agent::Sound,
|
agent::Sound,
|
||||||
@ -261,6 +262,7 @@ pub enum ServerEvent {
|
|||||||
ParryHook {
|
ParryHook {
|
||||||
defender: EcsEntity,
|
defender: EcsEntity,
|
||||||
attacker: Option<EcsEntity>,
|
attacker: Option<EcsEntity>,
|
||||||
|
source: AttackSource,
|
||||||
},
|
},
|
||||||
RequestSiteInfo {
|
RequestSiteInfo {
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
|
@ -33,6 +33,8 @@ pub struct StaticData {
|
|||||||
pub ability_info: AbilityInfo,
|
pub ability_info: AbilityInfo,
|
||||||
/// Energy consumed to initiate the block
|
/// Energy consumed to initiate the block
|
||||||
pub energy_cost: f32,
|
pub energy_cost: f32,
|
||||||
|
/// Energy recovered upon successful parry
|
||||||
|
pub energy_regen: f32,
|
||||||
/// Whether block can be held
|
/// Whether block can be held
|
||||||
pub can_hold: bool,
|
pub can_hold: bool,
|
||||||
/// What kinds of attacks the block applies to
|
/// What kinds of attacks the block applies to
|
||||||
|
@ -14,8 +14,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
quadruped_low, quadruped_medium, quadruped_small, ship,
|
quadruped_low, quadruped_medium, quadruped_small, ship,
|
||||||
skills::{Skill, SwimSkill, SKILL_MODIFIERS},
|
skills::{Skill, SwimSkill, SKILL_MODIFIERS},
|
||||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
theropod, Body, CharacterState, Density, InputAttr, InputKind, InventoryAction, Melee,
|
||||||
InventoryAction, Melee, StateUpdate,
|
StateUpdate,
|
||||||
},
|
},
|
||||||
consts::{FRIC_GROUND, GRAVITY, MAX_PICKUP_RANGE},
|
consts::{FRIC_GROUND, GRAVITY, MAX_PICKUP_RANGE},
|
||||||
event::{LocalEvent, ServerEvent},
|
event::{LocalEvent, ServerEvent},
|
||||||
@ -1247,15 +1247,16 @@ pub fn handle_input(
|
|||||||
input: InputKind,
|
input: InputKind,
|
||||||
) {
|
) {
|
||||||
match input {
|
match input {
|
||||||
InputKind::Primary | InputKind::Secondary | InputKind::Ability(_) | InputKind::Roll => {
|
InputKind::Primary
|
||||||
|
| InputKind::Secondary
|
||||||
|
| InputKind::Ability(_)
|
||||||
|
| InputKind::Block
|
||||||
|
| InputKind::Roll => {
|
||||||
handle_ability(data, update, output_events, input);
|
handle_ability(data, update, output_events, input);
|
||||||
},
|
},
|
||||||
InputKind::Jump => {
|
InputKind::Jump => {
|
||||||
handle_jump(data, output_events, update, 1.0);
|
handle_jump(data, output_events, update, 1.0);
|
||||||
},
|
},
|
||||||
InputKind::Block => {
|
|
||||||
handle_block_input(data, update);
|
|
||||||
},
|
|
||||||
InputKind::Fly => {},
|
InputKind::Fly => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1271,30 +1272,6 @@ pub fn attempt_input(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that player can block, then attempts to block
|
|
||||||
pub fn handle_block_input(data: &JoinData<'_>, update: &mut StateUpdate) -> bool {
|
|
||||||
let can_block = |equip_slot| matches!(unwrap_tool_data(data, equip_slot), Some((kind, _)) if kind.can_block());
|
|
||||||
let hands = get_hands(data);
|
|
||||||
if input_is_pressed(data, InputKind::Block)
|
|
||||||
&& (can_block(EquipSlot::ActiveMainhand)
|
|
||||||
|| (hands.0.is_none() && can_block(EquipSlot::ActiveOffhand)))
|
|
||||||
{
|
|
||||||
let ability = CharacterAbility::default_block();
|
|
||||||
if ability.requirements_paid(data, update) {
|
|
||||||
update.character = CharacterState::from((
|
|
||||||
&ability,
|
|
||||||
AbilityInfo::from_input(data, false, InputKind::Block, Default::default()),
|
|
||||||
data,
|
|
||||||
));
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether an interrupt occurred
|
/// Returns whether an interrupt occurred
|
||||||
pub fn handle_interrupts(
|
pub fn handle_interrupts(
|
||||||
data: &JoinData,
|
data: &JoinData,
|
||||||
@ -1314,8 +1291,8 @@ pub fn handle_interrupts(
|
|||||||
});
|
});
|
||||||
if can_dodge && input_is_pressed(data, InputKind::Roll) {
|
if can_dodge && input_is_pressed(data, InputKind::Roll) {
|
||||||
handle_ability(data, update, output_events, InputKind::Roll)
|
handle_ability(data, update, output_events, InputKind::Roll)
|
||||||
} else if can_block {
|
} else if can_block && input_is_pressed(data, InputKind::Block) {
|
||||||
handle_block_input(data, update)
|
handle_ability(data, update, output_events, InputKind::Block)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use crate::{
|
|||||||
use authc::Uuid;
|
use authc::Uuid;
|
||||||
use common::{
|
use common::{
|
||||||
combat,
|
combat,
|
||||||
combat::DamageContributor,
|
combat::{AttackSource, DamageContributor},
|
||||||
comp::{
|
comp::{
|
||||||
self, aura, buff,
|
self, aura, buff,
|
||||||
chat::{KillSource, KillType},
|
chat::{KillSource, KillType},
|
||||||
@ -1361,7 +1361,12 @@ pub fn handle_combo_change(server: &Server, entity: EcsEntity, change: i32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<EcsEntity>) {
|
pub fn handle_parry_hook(
|
||||||
|
server: &Server,
|
||||||
|
defender: EcsEntity,
|
||||||
|
attacker: Option<EcsEntity>,
|
||||||
|
source: AttackSource,
|
||||||
|
) {
|
||||||
let ecs = &server.state.ecs();
|
let ecs = &server.state.ecs();
|
||||||
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
||||||
// Reset character state of defender
|
// Reset character state of defender
|
||||||
@ -1379,7 +1384,7 @@ pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<
|
|||||||
// Refund half the energy of entering the block for a successful parry
|
// Refund half the energy of entering the block for a successful parry
|
||||||
server_eventbus.emit_now(ServerEvent::EnergyChange {
|
server_eventbus.emit_now(ServerEvent::EnergyChange {
|
||||||
entity: defender,
|
entity: defender,
|
||||||
change: c.static_data.energy_cost / 2.0,
|
change: c.static_data.energy_regen,
|
||||||
});
|
});
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
@ -1391,7 +1396,7 @@ pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(attacker) = attacker {
|
if let Some(attacker) = attacker && matches!(source, AttackSource::Melee){
|
||||||
// When attacker is parried, add the parried debuff for 2 seconds, which slows
|
// When attacker is parried, add the parried debuff for 2 seconds, which slows
|
||||||
// them
|
// them
|
||||||
let data = buff::BuffData::new(1.0, Some(Secs(2.0)), None);
|
let data = buff::BuffData::new(1.0, Some(Secs(2.0)), None);
|
||||||
|
@ -237,9 +237,11 @@ impl Server {
|
|||||||
ServerEvent::ComboChange { entity, change } => {
|
ServerEvent::ComboChange { entity, change } => {
|
||||||
handle_combo_change(self, entity, change)
|
handle_combo_change(self, entity, change)
|
||||||
},
|
},
|
||||||
ServerEvent::ParryHook { defender, attacker } => {
|
ServerEvent::ParryHook {
|
||||||
handle_parry_hook(self, defender, attacker)
|
defender,
|
||||||
},
|
attacker,
|
||||||
|
source,
|
||||||
|
} => handle_parry_hook(self, defender, attacker, source),
|
||||||
ServerEvent::RequestSiteInfo { entity, id } => handle_site_info(self, entity, id),
|
ServerEvent::RequestSiteInfo { entity, id } => handle_site_info(self, entity, id),
|
||||||
ServerEvent::MineBlock { entity, pos, tool } => {
|
ServerEvent::MineBlock { entity, pos, tool } => {
|
||||||
handle_mine_block(self, entity, pos, tool)
|
handle_mine_block(self, entity, pos, tool)
|
||||||
|
@ -51,7 +51,11 @@ impl Animation for BlockAnimation {
|
|||||||
next.second.orientation = Quaternion::rotation_z(0.0);
|
next.second.orientation = Quaternion::rotation_z(0.0);
|
||||||
|
|
||||||
match ability_id {
|
match ability_id {
|
||||||
None => {
|
None
|
||||||
|
| Some("common.abilities.sword.basic_guard")
|
||||||
|
| Some("common.abilities.axe.basic_guard")
|
||||||
|
| Some("common.abilities.hammer.basic_guard")
|
||||||
|
| Some("common.abilities.sword.defensive_guard") => {
|
||||||
let speed = Vec2::<f32>::from(velocity).magnitude();
|
let speed = Vec2::<f32>::from(velocity).magnitude();
|
||||||
|
|
||||||
let (movement1base, move2, movement3) = match stage_section {
|
let (movement1base, move2, movement3) = match stage_section {
|
||||||
|
Loading…
Reference in New Issue
Block a user