mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'danielkenji83/block-based-on-poise' into 'master'
Block based on poise See merge request veloren/veloren!4283
This commit is contained in:
commit
94f6c3350c
@ -90,6 +90,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Balance changes; Smoother entity progression consisting of larger variety in (effective) health pools, dps, entity flee_health alterations, and minor weight distribution changes for entity spawns.
|
- Balance changes; Smoother entity progression consisting of larger variety in (effective) health pools, dps, entity flee_health alterations, and minor weight distribution changes for entity spawns.
|
||||||
- Made power of weapon tiers scale non-linearly.
|
- Made power of weapon tiers scale non-linearly.
|
||||||
- Sword Changes; Pommel Strike has been nerfed -> increased energy cost, increased _durations, and decreased poise damage. Heavy Sweep has been nerfed -> decreased poise damage and stun vulnerability damage. Pillar Thrust has been altered -> decreased maximum base damage with an increase in stun vulnerability damage.
|
- Sword Changes; Pommel Strike has been nerfed -> increased energy cost, increased _durations, and decreased poise damage. Heavy Sweep has been nerfed -> decreased poise damage and stun vulnerability damage. Pillar Thrust has been altered -> decreased maximum base damage with an increase in stun vulnerability damage.
|
||||||
|
- Weapons block are based on poise
|
||||||
|
- Wooden Shield recipe
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Medium and large potions from all loot tables
|
- Medium and large potions from all loot tables
|
||||||
|
@ -351,8 +351,9 @@
|
|||||||
abilities: [],
|
abilities: [],
|
||||||
),
|
),
|
||||||
Tool(Shield): (
|
Tool(Shield): (
|
||||||
primary: Simple(None, "common.abilities.shield.tempbasic"),
|
guard: Some(Simple(None, "common.abilities.shield.basic_guard")),
|
||||||
secondary: Simple(None, "common.abilities.shield.block"),
|
primary: Simple(None, "common.abilities.shield.singlestrike"),
|
||||||
|
secondary: Simple(None, "common.abilities.shield.power_guard"),
|
||||||
abilities: [],
|
abilities: [],
|
||||||
),
|
),
|
||||||
Custom("Stone Golem"): (
|
Custom("Stone Golem"): (
|
||||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
|||||||
buildup_duration: 0.25,
|
buildup_duration: 0.25,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
max_angle: 60.0,
|
max_angle: 60.0,
|
||||||
block_strength: 0.5,
|
block_strength: 5.0,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: false,
|
recover: false,
|
||||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
|||||||
buildup_duration: 0.25,
|
buildup_duration: 0.25,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
max_angle: 60.0,
|
max_angle: 60.0,
|
||||||
block_strength: 0.5,
|
block_strength: 5.0,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: false,
|
recover: false,
|
||||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
|||||||
buildup_duration: 0.25,
|
buildup_duration: 0.25,
|
||||||
recover_duration: 0.25,
|
recover_duration: 0.25,
|
||||||
max_angle: 90.0,
|
max_angle: 90.0,
|
||||||
block_strength: 0.5,
|
block_strength: 5.0,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: false,
|
buildup: false,
|
||||||
recover: false,
|
recover: false,
|
||||||
|
@ -3,6 +3,7 @@ RiposteMelee(
|
|||||||
buildup_duration: 0.7,
|
buildup_duration: 0.7,
|
||||||
swing_duration: 0.3,
|
swing_duration: 0.3,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
|
block_strength: 5.0,
|
||||||
melee_constructor: (
|
melee_constructor: (
|
||||||
kind: Slash(
|
kind: Slash(
|
||||||
damage: 30,
|
damage: 30,
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
BasicBlock(
|
BasicBlock(
|
||||||
buildup_duration: 0.1,
|
buildup_duration: 0.45,
|
||||||
recover_duration: 0.1,
|
recover_duration: 0.2,
|
||||||
max_angle: 90.0,
|
max_angle: 90.0,
|
||||||
block_strength: 0.8,
|
block_strength: 10.0,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: false,
|
recover: false,
|
||||||
),
|
),
|
||||||
energy_cost: 0.0,
|
energy_cost: 5.0,
|
||||||
energy_regen: 0.0,
|
energy_regen: 2.5,
|
||||||
can_hold: true,
|
can_hold: true,
|
||||||
blocked_attacks: (
|
blocked_attacks: (
|
||||||
melee: true,
|
melee: true,
|
21
assets/common/abilities/shield/power_guard.ron
Normal file
21
assets/common/abilities/shield/power_guard.ron
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
BasicBlock(
|
||||||
|
buildup_duration: 0.5,
|
||||||
|
recover_duration: 0.25,
|
||||||
|
max_angle: 90.0,
|
||||||
|
block_strength: 15.0,
|
||||||
|
parry_window: (
|
||||||
|
buildup: true,
|
||||||
|
recover: false,
|
||||||
|
),
|
||||||
|
energy_cost: 15.0,
|
||||||
|
energy_regen: 2.5,
|
||||||
|
can_hold: true,
|
||||||
|
blocked_attacks: (
|
||||||
|
melee: true,
|
||||||
|
projectiles: true,
|
||||||
|
beams: true,
|
||||||
|
ground_shockwaves: false,
|
||||||
|
air_shockwaves: true,
|
||||||
|
explosions: true,
|
||||||
|
),
|
||||||
|
)
|
32
assets/common/abilities/shield/singlestrike.ron
Normal file
32
assets/common/abilities/shield/singlestrike.ron
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
ComboMelee2(
|
||||||
|
strikes: [
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Bash(
|
||||||
|
damage: 6,
|
||||||
|
poise: 5,
|
||||||
|
knockback: 0,
|
||||||
|
energy_regen: 5,
|
||||||
|
),
|
||||||
|
range: 1.5,
|
||||||
|
angle: 45.0,
|
||||||
|
damage_effect: Some(BuffsVulnerable(0.5, Parried)),
|
||||||
|
),
|
||||||
|
buildup_duration: 0.15,
|
||||||
|
swing_duration: 0.2,
|
||||||
|
hit_timing: 0.1,
|
||||||
|
recover_duration: 0.15,
|
||||||
|
ori_modifier: 0.1,
|
||||||
|
movement: (
|
||||||
|
buildup: Some(Forward(0.1)),
|
||||||
|
swing: None,
|
||||||
|
recover: None,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
energy_cost_per_strike: 0,
|
||||||
|
meta: (
|
||||||
|
// The ability will parry all blockable attacks in the buildup portion
|
||||||
|
capabilities: ("PARRIES"),
|
||||||
|
),
|
||||||
|
)
|
@ -1,18 +0,0 @@
|
|||||||
BasicMelee(
|
|
||||||
energy_cost: 0,
|
|
||||||
buildup_duration: 0.1,
|
|
||||||
swing_duration: 0.1,
|
|
||||||
hit_timing: 0.0,
|
|
||||||
recover_duration: 0.3,
|
|
||||||
melee_constructor: (
|
|
||||||
kind: Bash(
|
|
||||||
damage: 4.0,
|
|
||||||
poise: 0.0,
|
|
||||||
knockback: 0.0,
|
|
||||||
energy_regen: 0.0,
|
|
||||||
),
|
|
||||||
range: 3.0,
|
|
||||||
angle: 90.0,
|
|
||||||
),
|
|
||||||
ori_modifier: 1.0,
|
|
||||||
)
|
|
@ -2,7 +2,7 @@ BasicBlock(
|
|||||||
buildup_duration: 0.25,
|
buildup_duration: 0.25,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
max_angle: 60.0,
|
max_angle: 60.0,
|
||||||
block_strength: 0.5,
|
block_strength: 5.0,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: false,
|
recover: false,
|
||||||
|
@ -22,6 +22,6 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup & swing portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("PARRIES"),
|
capabilities: ("PARRIES_MELEE"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -22,6 +22,6 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup & swing portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("PARRIES"),
|
capabilities: ("PARRIES_MELEE"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -41,6 +41,6 @@ ComboMelee2(
|
|||||||
auto_progress: true,
|
auto_progress: true,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup & swing portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("PARRIES"),
|
capabilities: ("PARRIES_MELEE"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -2,7 +2,7 @@ BasicBlock(
|
|||||||
buildup_duration: 0.4,
|
buildup_duration: 0.4,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
max_angle: 45.0,
|
max_angle: 45.0,
|
||||||
block_strength: 0.75,
|
block_strength: 7.5,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: false,
|
recover: false,
|
||||||
|
@ -23,6 +23,6 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup & swing portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("PARRIES"),
|
capabilities: ("PARRIES_MELEE"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -22,6 +22,6 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup & swing portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("PARRIES"),
|
capabilities: ("PARRIES_MELEE"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -2,7 +2,7 @@ BasicBlock(
|
|||||||
buildup_duration: 0.4,
|
buildup_duration: 0.4,
|
||||||
recover_duration: 0.15,
|
recover_duration: 0.15,
|
||||||
max_angle: 60.0,
|
max_angle: 60.0,
|
||||||
block_strength: 0.75,
|
block_strength: 7.5,
|
||||||
parry_window: (
|
parry_window: (
|
||||||
buildup: true,
|
buildup: true,
|
||||||
recover: false,
|
recover: false,
|
||||||
|
@ -3,6 +3,7 @@ RiposteMelee(
|
|||||||
buildup_duration: 0.4,
|
buildup_duration: 0.4,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.2,
|
recover_duration: 0.2,
|
||||||
|
block_strength: 5.0,
|
||||||
melee_constructor: (
|
melee_constructor: (
|
||||||
kind: Slash(
|
kind: Slash(
|
||||||
damage: 18,
|
damage: 18,
|
||||||
|
@ -27,6 +27,6 @@ ComboMelee2(
|
|||||||
energy_cost_per_strike: 5,
|
energy_cost_per_strike: 5,
|
||||||
meta: (
|
meta: (
|
||||||
// The ability will parry melee attacks in the buildup & swing portion
|
// The ability will parry melee attacks in the buildup & swing portion
|
||||||
capabilities: ("PARRIES"),
|
capabilities: ("PARRIES_MELEE"),
|
||||||
),
|
),
|
||||||
)
|
)
|
@ -708,6 +708,9 @@
|
|||||||
Simple(
|
Simple(
|
||||||
"common.items.weapons.shield.shield_1",
|
"common.items.weapons.shield.shield_1",
|
||||||
): "weapon-shield-wood-0",
|
): "weapon-shield-wood-0",
|
||||||
|
Simple(
|
||||||
|
"common.items.weapons.shield.starter_shield",
|
||||||
|
): "weapon-shield-starter",
|
||||||
Simple(
|
Simple(
|
||||||
"common.items.weapons.dagger.basic_0",
|
"common.items.weapons.dagger.basic_0",
|
||||||
): "weapon-dagger-dagger_basic-0",
|
): "weapon-dagger-dagger_basic-0",
|
||||||
|
20
assets/common/items/weapons/shield/starter_shield.ron
Normal file
20
assets/common/items/weapons/shield/starter_shield.ron
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
ItemDef(
|
||||||
|
legacy_name: "Wooden Shield",
|
||||||
|
legacy_description: "May not withstand fire",
|
||||||
|
kind: Tool((
|
||||||
|
kind: Shield,
|
||||||
|
hands: One,
|
||||||
|
stats: (
|
||||||
|
equip_time_secs: 0.3,
|
||||||
|
power: 0.5,
|
||||||
|
effect_power: 1.0,
|
||||||
|
speed: 1.0,
|
||||||
|
range: 1.0,
|
||||||
|
energy_efficiency: 1.0,
|
||||||
|
buff_strength: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
quality: Common,
|
||||||
|
tags: [],
|
||||||
|
ability_spec: None,
|
||||||
|
)
|
@ -5,4 +5,5 @@
|
|||||||
(1.0, Item("common.items.weapons.axe.starter_axe")),
|
(1.0, Item("common.items.weapons.axe.starter_axe")),
|
||||||
(1.0, Item("common.items.weapons.staff.starter_staff")),
|
(1.0, Item("common.items.weapons.staff.starter_staff")),
|
||||||
(1.0, Item("common.items.weapons.sceptre.starter_sceptre")),
|
(1.0, Item("common.items.weapons.sceptre.starter_sceptre")),
|
||||||
|
(1.0, Item("common.items.weapons.shield.starter_shield")),
|
||||||
]
|
]
|
@ -2357,4 +2357,12 @@
|
|||||||
],
|
],
|
||||||
craft_sprite: Some(Cauldron),
|
craft_sprite: Some(Cauldron),
|
||||||
),
|
),
|
||||||
|
"shield": (
|
||||||
|
output: ("common.items.weapons.shield.starter_shield", 1),
|
||||||
|
inputs: [
|
||||||
|
(Item("common.items.log.wood"), 5, false),
|
||||||
|
(Item("common.items.crafting_ing.leather.leather_strips"), 2, false)
|
||||||
|
],
|
||||||
|
craft_sprite: Some(CraftingBench),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ recipes: {
|
|||||||
ItemDefId("common.items.weapons.staff.starter_staff"): ( inputs: [], ),
|
ItemDefId("common.items.weapons.staff.starter_staff"): ( inputs: [], ),
|
||||||
ItemDefId("common.items.weapons.sceptre.starter_sceptre"): ( inputs: [], ),
|
ItemDefId("common.items.weapons.sceptre.starter_sceptre"): ( inputs: [], ),
|
||||||
ItemDefId("common.items.weapons.sword_1h.starter"): ( inputs: [], ),
|
ItemDefId("common.items.weapons.sword_1h.starter"): ( inputs: [], ),
|
||||||
|
ItemDefId("common.items.weapons.shield.starter_shield"): ( inputs: [], ),
|
||||||
ModularWeapon(material: "common.items.mineral.ingot.bronze"): (
|
ModularWeapon(material: "common.items.mineral.ingot.bronze"): (
|
||||||
inputs: [
|
inputs: [
|
||||||
(Item("common.items.mineral.ingot.bronze"), 1),
|
(Item("common.items.mineral.ingot.bronze"), 1),
|
||||||
|
@ -954,7 +954,7 @@
|
|||||||
threshold: 0.5,
|
threshold: 0.5,
|
||||||
subtitle: "subtitle-unwield_shield",
|
subtitle: "subtitle-unwield_shield",
|
||||||
),
|
),
|
||||||
Attack(BasicMelee(Action), Shield): (
|
Attack(ComboMelee2(Action), Shield): (
|
||||||
files: [
|
files: [
|
||||||
"voxygen.audio.sfx.abilities.swing",
|
"voxygen.audio.sfx.abilities.swing",
|
||||||
],
|
],
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
weapon-shield-wood-0 = A Tattered Targe
|
weapon-shield-wood-0 = A Tattered Targe
|
||||||
.desc = Should withstand a few more hits, hopefully...
|
.desc = Should withstand a few more hits, hopefully...
|
||||||
|
|
||||||
|
weapon-shield-starter = Wooden Shield
|
||||||
|
.desc = May not withstand fire
|
||||||
|
|
||||||
weapon-dagger-dagger_basic-0 = Suspicious Paper Knife
|
weapon-dagger-dagger_basic-0 = Suspicious Paper Knife
|
||||||
.desc = Opens letters quickly.
|
.desc = Opens letters quickly.
|
||||||
|
|
||||||
|
@ -1554,7 +1554,11 @@
|
|||||||
// Shields
|
// Shields
|
||||||
Simple("common.items.weapons.shield.shield_1"): VoxTrans(
|
Simple("common.items.weapons.shield.shield_1"): VoxTrans(
|
||||||
"voxel.weapon.shield.wood-0",
|
"voxel.weapon.shield.wood-0",
|
||||||
(0.0, 0.0, 0.0), (-90.0, 90.0, 0.0), 2.4,
|
(0.0, 0.0, 0.0), (-135.0, 90.0, 0.0), 1.0,
|
||||||
|
),
|
||||||
|
Simple("common.items.weapons.shield.starter_shield"): VoxTrans(
|
||||||
|
"voxel.weapon.shield.wood-1",
|
||||||
|
(0.0, 0.0, 0.0), (-135.0, 90.0, 0.0), 1.0,
|
||||||
),
|
),
|
||||||
// Lanterns
|
// Lanterns
|
||||||
Simple("common.items.lantern.black_0"): VoxTrans(
|
Simple("common.items.lantern.black_0"): VoxTrans(
|
||||||
|
@ -899,7 +899,11 @@
|
|||||||
),
|
),
|
||||||
// Shields
|
// Shields
|
||||||
Tool("common.items.weapons.shield.shield_1"): (
|
Tool("common.items.weapons.shield.shield_1"): (
|
||||||
vox_spec: ("weapon.shield.wood-0", (-2.5, -5.5, -5.5)),
|
vox_spec: ("weapon.shield.wood-0", (-2.5, -7.5, -5.5)),
|
||||||
|
color: None
|
||||||
|
),
|
||||||
|
Tool("common.items.weapons.shield.starter_shield"): (
|
||||||
|
vox_spec: ("weapon.shield.wood-1", (-3.5, -7.5, -5.5)),
|
||||||
color: None
|
color: None
|
||||||
),
|
),
|
||||||
// Bows
|
// Bows
|
||||||
|
@ -376,6 +376,7 @@
|
|||||||
Simple("common.items.weapons.dagger.cultist_0"): "voxel.weapon.dagger.dagger_cult-0",
|
Simple("common.items.weapons.dagger.cultist_0"): "voxel.weapon.dagger.dagger_cult-0",
|
||||||
// Shields
|
// Shields
|
||||||
Simple("common.items.weapons.shield.shield_1"): "voxel.weapon.shield.wood-0",
|
Simple("common.items.weapons.shield.shield_1"): "voxel.weapon.shield.wood-0",
|
||||||
|
Simple("common.items.weapons.shield.starter_shield"): "voxel.weapon.shield.wood-1",
|
||||||
// Lanterns
|
// Lanterns
|
||||||
Simple("common.items.lantern.black_0"): "voxel.lantern.black-0",
|
Simple("common.items.lantern.black_0"): "voxel.lantern.black-0",
|
||||||
Simple("common.items.lantern.green_0"): "voxel.lantern.green-0",
|
Simple("common.items.lantern.green_0"): "voxel.lantern.green-0",
|
||||||
|
BIN
assets/voxygen/voxel/weapon/shield/wood-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/weapon/shield/wood-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -58,6 +58,9 @@ pub const MAX_HEADSHOT_PRECISION: f32 = 1.0;
|
|||||||
pub const MAX_TOP_HEADSHOT_PRECISION: f32 = 0.5;
|
pub const MAX_TOP_HEADSHOT_PRECISION: f32 = 0.5;
|
||||||
pub const MAX_BEAM_DUR_PRECISION: f32 = 0.25;
|
pub const MAX_BEAM_DUR_PRECISION: f32 = 0.25;
|
||||||
pub const MAX_MELEE_POISE_PRECISION: f32 = 0.5;
|
pub const MAX_MELEE_POISE_PRECISION: f32 = 0.5;
|
||||||
|
pub const MAX_BLOCK_POISE_COST: f32 = 50.0;
|
||||||
|
pub const PARRY_BONUS_MULTIPLIER: f32 = 2.0;
|
||||||
|
pub const FALLBACK_BLOCK_STRENGTH: f32 = 5.0;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct AttackerInfo<'a> {
|
pub struct AttackerInfo<'a> {
|
||||||
@ -140,15 +143,84 @@ impl Attack {
|
|||||||
|
|
||||||
pub fn effects(&self) -> impl Iterator<Item = &AttackEffect> { self.effects.iter() }
|
pub fn effects(&self) -> impl Iterator<Item = &AttackEffect> { self.effects.iter() }
|
||||||
|
|
||||||
pub fn compute_damage_reduction(
|
pub fn compute_block_damage_decrement(
|
||||||
attacker: Option<&AttackerInfo>,
|
attacker: Option<&AttackerInfo>,
|
||||||
|
damage_reduction: f32,
|
||||||
target: &TargetInfo,
|
target: &TargetInfo,
|
||||||
source: AttackSource,
|
source: AttackSource,
|
||||||
dir: Dir,
|
dir: Dir,
|
||||||
damage: Damage,
|
damage: Damage,
|
||||||
msm: &MaterialStatManifest,
|
msm: &MaterialStatManifest,
|
||||||
emitters: &mut impl EmitExt<ParryHookEvent>,
|
time: Time,
|
||||||
|
emitters: &mut (impl EmitExt<ParryHookEvent> + EmitExt<PoiseChangeEvent>),
|
||||||
mut emit_outcome: impl FnMut(Outcome),
|
mut emit_outcome: impl FnMut(Outcome),
|
||||||
|
) -> f32 {
|
||||||
|
if damage.value > 0.0 {
|
||||||
|
if let (Some(char_state), Some(ori), Some(inventory)) =
|
||||||
|
(target.char_state, target.ori, target.inventory)
|
||||||
|
{
|
||||||
|
let is_parry = char_state.is_parry(source);
|
||||||
|
let is_block = char_state.is_block(source);
|
||||||
|
let damage_value = damage.value * (1.0 - damage_reduction);
|
||||||
|
let mut block_strength = block_strength(inventory, char_state);
|
||||||
|
|
||||||
|
if ori.look_vec().angle_between(-dir.with_z(0.0)) < char_state.block_angle()
|
||||||
|
&& (is_parry || is_block)
|
||||||
|
&& block_strength > 0.0
|
||||||
|
{
|
||||||
|
if is_parry {
|
||||||
|
block_strength *= PARRY_BONUS_MULTIPLIER;
|
||||||
|
|
||||||
|
emitters.emit(ParryHookEvent {
|
||||||
|
defender: target.entity,
|
||||||
|
attacker: attacker.map(|a| a.entity),
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let poise_cost =
|
||||||
|
(damage_value / block_strength).min(1.0) * MAX_BLOCK_POISE_COST;
|
||||||
|
|
||||||
|
let poise_change = Poise::apply_poise_reduction(
|
||||||
|
poise_cost,
|
||||||
|
target.inventory,
|
||||||
|
msm,
|
||||||
|
target.char_state,
|
||||||
|
target.stats,
|
||||||
|
);
|
||||||
|
|
||||||
|
emit_outcome(Outcome::Block {
|
||||||
|
parry: is_parry,
|
||||||
|
pos: target.pos,
|
||||||
|
uid: target.uid,
|
||||||
|
});
|
||||||
|
emitters.emit(PoiseChangeEvent {
|
||||||
|
entity: target.entity,
|
||||||
|
change: PoiseChange {
|
||||||
|
amount: -poise_change,
|
||||||
|
impulse: *dir,
|
||||||
|
by: attacker.map(|x| (*x).into()),
|
||||||
|
cause: Some(damage.source),
|
||||||
|
time,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
block_strength
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_damage_reduction(
|
||||||
|
attacker: Option<&AttackerInfo>,
|
||||||
|
target: &TargetInfo,
|
||||||
|
damage: Damage,
|
||||||
|
msm: &MaterialStatManifest,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
if damage.value > 0.0 {
|
if damage.value > 0.0 {
|
||||||
let attacker_penetration = attacker
|
let attacker_penetration = attacker
|
||||||
@ -157,39 +229,7 @@ impl Attack {
|
|||||||
.clamp(0.0, 1.0);
|
.clamp(0.0, 1.0);
|
||||||
let raw_damage_reduction =
|
let raw_damage_reduction =
|
||||||
Damage::compute_damage_reduction(Some(damage), target.inventory, target.stats, msm);
|
Damage::compute_damage_reduction(Some(damage), target.inventory, target.stats, msm);
|
||||||
let damage_reduction = (1.0 - attacker_penetration) * raw_damage_reduction;
|
(1.0 - attacker_penetration) * raw_damage_reduction
|
||||||
let block_reduction =
|
|
||||||
if let (Some(char_state), Some(ori)) = (target.char_state, target.ori) {
|
|
||||||
if ori.look_vec().angle_between(-dir.with_z(0.0)) < char_state.block_angle() {
|
|
||||||
if char_state.is_parry(source) {
|
|
||||||
emit_outcome(Outcome::Block {
|
|
||||||
parry: true,
|
|
||||||
pos: target.pos,
|
|
||||||
uid: target.uid,
|
|
||||||
});
|
|
||||||
emitters.emit(ParryHookEvent {
|
|
||||||
defender: target.entity,
|
|
||||||
attacker: attacker.map(|a| a.entity),
|
|
||||||
source,
|
|
||||||
});
|
|
||||||
1.0
|
|
||||||
} else if let Some(block_strength) = char_state.block_strength(source) {
|
|
||||||
emit_outcome(Outcome::Block {
|
|
||||||
parry: false,
|
|
||||||
pos: target.pos,
|
|
||||||
uid: target.uid,
|
|
||||||
});
|
|
||||||
block_strength
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
1.0 - (1.0 - damage_reduction) * (1.0 - block_reduction)
|
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
}
|
}
|
||||||
@ -260,18 +300,26 @@ impl Attack {
|
|||||||
{
|
{
|
||||||
let damage_instance = damage.instance + damage_instance_offset;
|
let damage_instance = damage.instance + damage_instance_offset;
|
||||||
is_applied = true;
|
is_applied = true;
|
||||||
let damage_reduction = Attack::compute_damage_reduction(
|
|
||||||
|
let damage_reduction =
|
||||||
|
Attack::compute_damage_reduction(attacker.as_ref(), target, damage.damage, msm);
|
||||||
|
|
||||||
|
let block_damage_decrement = Attack::compute_block_damage_decrement(
|
||||||
attacker.as_ref(),
|
attacker.as_ref(),
|
||||||
|
damage_reduction,
|
||||||
target,
|
target,
|
||||||
attack_source,
|
attack_source,
|
||||||
dir,
|
dir,
|
||||||
damage.damage,
|
damage.damage,
|
||||||
msm,
|
msm,
|
||||||
|
time,
|
||||||
emitters,
|
emitters,
|
||||||
&mut emit_outcome,
|
&mut emit_outcome,
|
||||||
);
|
);
|
||||||
|
|
||||||
let change = damage.damage.calculate_health_change(
|
let change = damage.damage.calculate_health_change(
|
||||||
damage_reduction,
|
damage_reduction,
|
||||||
|
block_damage_decrement,
|
||||||
attacker.map(|x| x.into()),
|
attacker.map(|x| x.into()),
|
||||||
precision_mult,
|
precision_mult,
|
||||||
self.precision_multiplier,
|
self.precision_multiplier,
|
||||||
@ -1046,6 +1094,7 @@ impl Damage {
|
|||||||
pub fn calculate_health_change(
|
pub fn calculate_health_change(
|
||||||
self,
|
self,
|
||||||
damage_reduction: f32,
|
damage_reduction: f32,
|
||||||
|
block_damage_decrement: f32,
|
||||||
damage_contributor: Option<DamageContributor>,
|
damage_contributor: Option<DamageContributor>,
|
||||||
precision_mult: Option<f32>,
|
precision_mult: Option<f32>,
|
||||||
precision_power: f32,
|
precision_power: f32,
|
||||||
@ -1065,6 +1114,8 @@ impl Damage {
|
|||||||
damage += precise_damage;
|
damage += precise_damage;
|
||||||
// Armor
|
// Armor
|
||||||
damage *= 1.0 - damage_reduction;
|
damage *= 1.0 - damage_reduction;
|
||||||
|
// Block
|
||||||
|
damage = f32::max(damage - block_damage_decrement, 0.0);
|
||||||
|
|
||||||
HealthChange {
|
HealthChange {
|
||||||
amount: -damage,
|
amount: -damage,
|
||||||
@ -1496,3 +1547,55 @@ pub fn precision_mult_from_flank(attack_dir: Vec3<f32>, target_ori: Option<&Ori>
|
|||||||
Some(_) | None => None,
|
Some(_) | None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block_strength(inventory: &Inventory, char_state: &CharacterState) -> f32 {
|
||||||
|
match char_state {
|
||||||
|
CharacterState::BasicBlock(data) => data.static_data.block_strength,
|
||||||
|
CharacterState::RiposteMelee(data) => data.static_data.block_strength,
|
||||||
|
_ => char_state
|
||||||
|
.ability_info()
|
||||||
|
.map(|ability| (ability.ability_meta.capabilities, ability.hand))
|
||||||
|
.map(|(capabilities, hand)| {
|
||||||
|
(
|
||||||
|
if capabilities.contains(Capability::PARRIES)
|
||||||
|
|| capabilities.contains(Capability::PARRIES_MELEE)
|
||||||
|
|| capabilities.contains(Capability::BLOCKS)
|
||||||
|
{
|
||||||
|
FALLBACK_BLOCK_STRENGTH
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
},
|
||||||
|
hand.and_then(|hand| inventory.equipped(hand.to_equip_slot()))
|
||||||
|
.map_or(1.0, |item| match &*item.kind() {
|
||||||
|
ItemKind::Tool(tool) => {
|
||||||
|
tool.stats(item.stats_durability_multiplier()).power
|
||||||
|
},
|
||||||
|
_ => 1.0,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_or(0.0, |(capability_strength, tool_block_strength)| {
|
||||||
|
capability_strength * tool_block_strength
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_equip_slot_by_block_priority(inventory: Option<&Inventory>) -> EquipSlot {
|
||||||
|
inventory
|
||||||
|
.map(get_weapon_kinds)
|
||||||
|
.map_or(
|
||||||
|
EquipSlot::ActiveMainhand,
|
||||||
|
|weapon_kinds| match weapon_kinds {
|
||||||
|
(Some(mainhand), Some(offhand)) => {
|
||||||
|
if mainhand.block_priority() >= offhand.block_priority() {
|
||||||
|
EquipSlot::ActiveMainhand
|
||||||
|
} else {
|
||||||
|
EquipSlot::ActiveOffhand
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Some(_), None) => EquipSlot::ActiveMainhand,
|
||||||
|
(None, Some(_)) => EquipSlot::ActiveOffhand,
|
||||||
|
(None, None) => EquipSlot::ActiveMainhand,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -195,34 +195,22 @@ impl ActiveAbilities {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match ability {
|
match ability {
|
||||||
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
|
Ability::ToolGuard => {
|
||||||
.and_then(|abilities| {
|
let equip_slot = combat::get_equip_slot_by_block_priority(inv);
|
||||||
abilities
|
ability_set(equip_slot)
|
||||||
.guard(Some(skill_set), context)
|
.and_then(|abilities| {
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
abilities
|
||||||
})
|
.guard(Some(skill_set), context)
|
||||||
.map(|(ability, i)| {
|
.map(|(a, i)| (a.ability.clone(), i))
|
||||||
(
|
})
|
||||||
scale_ability(ability, EquipSlot::ActiveMainhand),
|
.map(|(ability, i)| {
|
||||||
true,
|
(
|
||||||
spec_ability(i),
|
scale_ability(ability, equip_slot),
|
||||||
)
|
matches!(equip_slot, EquipSlot::ActiveOffhand),
|
||||||
})
|
spec_ability(i),
|
||||||
.or_else(|| {
|
)
|
||||||
ability_set(EquipSlot::ActiveOffhand)
|
})
|
||||||
.and_then(|abilities| {
|
},
|
||||||
abilities
|
|
||||||
.guard(Some(skill_set), context)
|
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
|
||||||
})
|
|
||||||
.map(|(ability, i)| {
|
|
||||||
(
|
|
||||||
scale_ability(ability, EquipSlot::ActiveOffhand),
|
|
||||||
false,
|
|
||||||
spec_ability(i),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
||||||
.and_then(|abilities| {
|
.and_then(|abilities| {
|
||||||
abilities
|
abilities
|
||||||
@ -396,7 +384,7 @@ impl Ability {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
|
Ability::ToolGuard => ability_set(combat::get_equip_slot_by_block_priority(inv))
|
||||||
.and_then(|abilities| {
|
.and_then(|abilities| {
|
||||||
abilities
|
abilities
|
||||||
.guard(skillset, context)
|
.guard(skillset, context)
|
||||||
@ -407,19 +395,6 @@ impl Ability {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|g| contextual_id(Some(g)))
|
.and_then(|g| contextual_id(Some(g)))
|
||||||
})
|
})
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.guard(skillset, context)
|
|
||||||
.map(|a| a.0.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
|
||||||
@ -524,12 +499,8 @@ impl SpecifiedAbility {
|
|||||||
ability_set(EquipSlot::ActiveMainhand)
|
ability_set(EquipSlot::ActiveMainhand)
|
||||||
.map(|abilities| ability_id(self, &abilities.secondary))
|
.map(|abilities| ability_id(self, &abilities.secondary))
|
||||||
}),
|
}),
|
||||||
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
|
Ability::ToolGuard => ability_set(combat::get_equip_slot_by_block_priority(inv))
|
||||||
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a)))
|
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a))),
|
||||||
.or_else(|| {
|
|
||||||
ability_set(EquipSlot::ActiveOffhand)
|
|
||||||
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a)))
|
|
||||||
}),
|
|
||||||
Ability::SpeciesMovement => None, // TODO: Make not None
|
Ability::SpeciesMovement => None, // TODO: Make not None
|
||||||
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
|
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
|
||||||
.and_then(|abilities| abilities.abilities.get(index).map(|a| ability_id(self, a))),
|
.and_then(|abilities| abilities.abilities.get(index).map(|a| ability_id(self, a))),
|
||||||
@ -1006,6 +977,7 @@ pub enum CharacterAbility {
|
|||||||
buildup_duration: f32,
|
buildup_duration: f32,
|
||||||
swing_duration: f32,
|
swing_duration: f32,
|
||||||
recover_duration: f32,
|
recover_duration: f32,
|
||||||
|
block_strength: f32,
|
||||||
melee_constructor: MeleeConstructor,
|
melee_constructor: MeleeConstructor,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
meta: AbilityMeta,
|
meta: AbilityMeta,
|
||||||
@ -1279,8 +1251,7 @@ impl CharacterAbility {
|
|||||||
ref mut recover_duration,
|
ref mut recover_duration,
|
||||||
// Do we want angle to be adjusted by range?
|
// Do we want angle to be adjusted by range?
|
||||||
max_angle: _,
|
max_angle: _,
|
||||||
// Block strength explicitly not modified by power, that will be a separate stat
|
ref mut block_strength,
|
||||||
block_strength: _,
|
|
||||||
parry_window: _,
|
parry_window: _,
|
||||||
ref mut energy_cost,
|
ref mut energy_cost,
|
||||||
energy_regen: _,
|
energy_regen: _,
|
||||||
@ -1291,6 +1262,7 @@ impl CharacterAbility {
|
|||||||
*buildup_duration /= stats.speed;
|
*buildup_duration /= stats.speed;
|
||||||
*recover_duration /= stats.speed;
|
*recover_duration /= stats.speed;
|
||||||
*energy_cost /= stats.energy_efficiency;
|
*energy_cost /= stats.energy_efficiency;
|
||||||
|
*block_strength *= stats.power;
|
||||||
},
|
},
|
||||||
Roll {
|
Roll {
|
||||||
ref mut energy_cost,
|
ref mut energy_cost,
|
||||||
@ -1660,6 +1632,7 @@ impl CharacterAbility {
|
|||||||
ref mut buildup_duration,
|
ref mut buildup_duration,
|
||||||
ref mut swing_duration,
|
ref mut swing_duration,
|
||||||
ref mut recover_duration,
|
ref mut recover_duration,
|
||||||
|
ref mut block_strength,
|
||||||
ref mut melee_constructor,
|
ref mut melee_constructor,
|
||||||
meta: _,
|
meta: _,
|
||||||
} => {
|
} => {
|
||||||
@ -1667,6 +1640,7 @@ impl CharacterAbility {
|
|||||||
*swing_duration /= stats.speed;
|
*swing_duration /= stats.speed;
|
||||||
*recover_duration /= stats.speed;
|
*recover_duration /= stats.speed;
|
||||||
*energy_cost /= stats.energy_efficiency;
|
*energy_cost /= stats.energy_efficiency;
|
||||||
|
*block_strength *= stats.power;
|
||||||
*melee_constructor = melee_constructor.adjusted_by_stats(stats);
|
*melee_constructor = melee_constructor.adjusted_by_stats(stats);
|
||||||
},
|
},
|
||||||
RapidMelee {
|
RapidMelee {
|
||||||
@ -2914,6 +2888,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
buildup_duration,
|
buildup_duration,
|
||||||
swing_duration,
|
swing_duration,
|
||||||
recover_duration,
|
recover_duration,
|
||||||
|
block_strength,
|
||||||
melee_constructor,
|
melee_constructor,
|
||||||
meta: _,
|
meta: _,
|
||||||
} => CharacterState::RiposteMelee(riposte_melee::Data {
|
} => CharacterState::RiposteMelee(riposte_melee::Data {
|
||||||
@ -2921,6 +2896,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
swing_duration: Duration::from_secs_f32(*swing_duration),
|
swing_duration: Duration::from_secs_f32(*swing_duration),
|
||||||
recover_duration: Duration::from_secs_f32(*recover_duration),
|
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||||
|
block_strength: *block_strength,
|
||||||
melee_constructor: *melee_constructor,
|
melee_constructor: *melee_constructor,
|
||||||
ability_info,
|
ability_info,
|
||||||
},
|
},
|
||||||
@ -3003,18 +2979,18 @@ bitflags::bitflags! {
|
|||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||||
// If more are ever needed, first check if any not used anymore, as some were only used in intermediary stages so may be free
|
// If more are ever needed, first check if any not used anymore, as some were only used in intermediary stages so may be free
|
||||||
pub struct Capability: u8 {
|
pub struct Capability: u8 {
|
||||||
// There used to be a capability here, to keep ordering the same below this is now a placeholder
|
// The ability will parry all blockable attacks in the buildup portion
|
||||||
const PLACEHOLDER = 0b00000001;
|
const PARRIES = 0b00000001;
|
||||||
// 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
|
// The ability will block melee attacks in the buildup portion
|
||||||
const 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 PARRIES = 0b00100000;
|
const PARRIES_MELEE = 0b00100000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,53 +308,36 @@ impl CharacterState {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block_strength(&self, attack_source: AttackSource) -> Option<f32> {
|
|
||||||
let from_capability = if let AttackSource::Melee = attack_source {
|
|
||||||
if let Some(capabilities) = self
|
|
||||||
.ability_info()
|
|
||||||
.map(|a| a.ability_meta)
|
|
||||||
.map(|m| m.capabilities)
|
|
||||||
{
|
|
||||||
(capabilities.contains(Capability::BLOCKS)
|
|
||||||
&& matches!(
|
|
||||||
self.stage_section(),
|
|
||||||
Some(StageSection::Buildup | StageSection::Action)
|
|
||||||
))
|
|
||||||
.then_some(0.5)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let from_state = match self {
|
|
||||||
CharacterState::BasicBlock(c) => c
|
|
||||||
.static_data
|
|
||||||
.blocked_attacks
|
|
||||||
.applies(attack_source)
|
|
||||||
.then_some(c.static_data.block_strength),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
match (from_capability, from_state) {
|
|
||||||
(Some(a), Some(b)) => Some(a.max(b)),
|
|
||||||
(Some(a), None) | (None, Some(a)) => Some(a),
|
|
||||||
(None, None) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_parry(&self, attack_source: AttackSource) -> bool {
|
pub fn is_parry(&self, attack_source: AttackSource) -> bool {
|
||||||
let melee = matches!(attack_source, AttackSource::Melee);
|
let melee = matches!(attack_source, AttackSource::Melee);
|
||||||
let from_capability = melee
|
let from_capability_melee = melee
|
||||||
&& self
|
&& self
|
||||||
.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::PARRIES)
|
c.contains(Capability::PARRIES_MELEE)
|
||||||
&& matches!(
|
&& matches!(
|
||||||
self.stage_section(),
|
self.stage_section(),
|
||||||
Some(StageSection::Buildup | StageSection::Action)
|
Some(StageSection::Buildup | StageSection::Action)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
let from_capability = matches!(
|
||||||
|
attack_source,
|
||||||
|
AttackSource::Melee
|
||||||
|
| AttackSource::Projectile
|
||||||
|
| AttackSource::Beam
|
||||||
|
| AttackSource::AirShockwave
|
||||||
|
| AttackSource::Explosion
|
||||||
|
) && self
|
||||||
|
.ability_info()
|
||||||
|
.map(|a| a.ability_meta.capabilities)
|
||||||
|
.map_or(false, |c| {
|
||||||
|
c.contains(Capability::PARRIES)
|
||||||
|
&& 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) => {
|
||||||
@ -366,7 +349,30 @@ impl CharacterState {
|
|||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
from_capability || from_state
|
from_capability_melee || from_capability || from_state
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_block(&self, attack_source: AttackSource) -> bool {
|
||||||
|
match self {
|
||||||
|
CharacterState::BasicBlock(data) => {
|
||||||
|
data.static_data.blocked_attacks.applies(attack_source)
|
||||||
|
&& matches!(
|
||||||
|
self.stage_section(),
|
||||||
|
Some(StageSection::Buildup | StageSection::Action)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => self
|
||||||
|
.ability_info()
|
||||||
|
.map(|ability| ability.ability_meta.capabilities)
|
||||||
|
.map_or(false, |capabilities| {
|
||||||
|
capabilities.contains(Capability::BLOCKS)
|
||||||
|
&& matches!(
|
||||||
|
self.stage_section(),
|
||||||
|
Some(StageSection::Buildup | StageSection::Action)
|
||||||
|
)
|
||||||
|
&& matches!(attack_source, AttackSource::Melee)
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In radians
|
/// In radians
|
||||||
|
@ -97,6 +97,28 @@ impl ToolKind {
|
|||||||
| ToolKind::Dagger
|
| ToolKind::Dagger
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block_priority(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
ToolKind::Debug => 0,
|
||||||
|
ToolKind::Blowgun => 1,
|
||||||
|
ToolKind::Bow => 2,
|
||||||
|
ToolKind::Staff => 3,
|
||||||
|
ToolKind::Sceptre => 4,
|
||||||
|
ToolKind::Empty => 5,
|
||||||
|
ToolKind::Natural => 6,
|
||||||
|
ToolKind::Instrument => 7,
|
||||||
|
ToolKind::Farming => 8,
|
||||||
|
ToolKind::Shovel => 9,
|
||||||
|
ToolKind::Pick => 10,
|
||||||
|
ToolKind::Dagger => 11,
|
||||||
|
ToolKind::Spear => 12,
|
||||||
|
ToolKind::Hammer => 13,
|
||||||
|
ToolKind::Axe => 14,
|
||||||
|
ToolKind::Sword => 15,
|
||||||
|
ToolKind::Shield => 16,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
@ -25,7 +25,8 @@ pub struct StaticData {
|
|||||||
pub recover_duration: Duration,
|
pub recover_duration: Duration,
|
||||||
/// Max angle (45.0 will give you a 90.0 angle window)
|
/// Max angle (45.0 will give you a 90.0 angle window)
|
||||||
pub max_angle: f32,
|
pub max_angle: f32,
|
||||||
/// What percentage incoming damage is reduced by
|
/// Base value that incoming damage is reduced by and converted to poise
|
||||||
|
/// damage
|
||||||
pub block_strength: f32,
|
pub block_strength: f32,
|
||||||
/// What durations are considered a parry
|
/// What durations are considered a parry
|
||||||
pub parry_window: ParryWindow,
|
pub parry_window: ParryWindow,
|
||||||
|
@ -18,6 +18,9 @@ pub struct StaticData {
|
|||||||
pub swing_duration: Duration,
|
pub swing_duration: Duration,
|
||||||
/// How long the state has until exiting
|
/// How long the state has until exiting
|
||||||
pub recover_duration: Duration,
|
pub recover_duration: Duration,
|
||||||
|
/// Base value that incoming damage is reduced by and converted to poise
|
||||||
|
/// damage
|
||||||
|
pub block_strength: f32,
|
||||||
/// Used to construct the Melee attack
|
/// Used to construct the Melee attack
|
||||||
pub melee_constructor: MeleeConstructor,
|
pub melee_constructor: MeleeConstructor,
|
||||||
/// What key is used to press ability
|
/// What key is used to press ability
|
||||||
|
@ -1411,10 +1411,7 @@ pub fn get_hands(data: &JoinData<'_>) -> (Option<Hands>, Option<Hands>) {
|
|||||||
|
|
||||||
pub fn get_tool_stats(data: &JoinData<'_>, ai: AbilityInfo) -> tool::Stats {
|
pub fn get_tool_stats(data: &JoinData<'_>, ai: AbilityInfo) -> tool::Stats {
|
||||||
ai.hand
|
ai.hand
|
||||||
.map(|hand| match hand {
|
.map(|hand| hand.to_equip_slot())
|
||||||
HandInfo::TwoHanded | HandInfo::MainHand => EquipSlot::ActiveMainhand,
|
|
||||||
HandInfo::OffHand => EquipSlot::ActiveOffhand,
|
|
||||||
})
|
|
||||||
.and_then(|slot| data.inventory.and_then(|inv| inv.equipped(slot)))
|
.and_then(|slot| data.inventory.and_then(|inv| inv.equipped(slot)))
|
||||||
.and_then(|item| {
|
.and_then(|item| {
|
||||||
if let ItemKind::Tool(tool) = &*item.kind() {
|
if let ItemKind::Tool(tool) = &*item.kind() {
|
||||||
@ -1616,6 +1613,13 @@ impl HandInfo {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_equip_slot(&self) -> EquipSlot {
|
||||||
|
match self {
|
||||||
|
HandInfo::TwoHanded | HandInfo::MainHand => EquipSlot::ActiveMainhand,
|
||||||
|
HandInfo::OffHand => EquipSlot::ActiveOffhand,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn leave_stance(data: &JoinData<'_>, output_events: &mut OutputEvents) {
|
pub fn leave_stance(data: &JoinData<'_>, output_events: &mut OutputEvents) {
|
||||||
|
@ -819,6 +819,7 @@ impl ServerEvent for LandOnGroundEvent {
|
|||||||
);
|
);
|
||||||
let change = damage.calculate_health_change(
|
let change = damage.calculate_health_change(
|
||||||
damage_reduction,
|
damage_reduction,
|
||||||
|
0.0,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
@ -1401,6 +1402,7 @@ pub fn emit_effect_events(
|
|||||||
common::effect::Effect::Damage(damage) => {
|
common::effect::Effect::Damage(damage) => {
|
||||||
let change = damage.calculate_health_change(
|
let change = damage.calculate_health_change(
|
||||||
combat::Damage::compute_damage_reduction(Some(damage), inventory, stats, msm),
|
combat::Damage::compute_damage_reduction(Some(damage), inventory, stats, msm),
|
||||||
|
0.0,
|
||||||
damage_contributor,
|
damage_contributor,
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
@ -1677,7 +1679,7 @@ impl ServerEvent for ParryHookEvent {
|
|||||||
entity: ev.defender,
|
entity: ev.defender,
|
||||||
change: c.static_data.energy_regen,
|
change: c.static_data.energy_regen,
|
||||||
});
|
});
|
||||||
true
|
false
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
@ -202,6 +202,7 @@ impl StateExt for State {
|
|||||||
stats.get(entity),
|
stats.get(entity),
|
||||||
&msm,
|
&msm,
|
||||||
),
|
),
|
||||||
|
0.0,
|
||||||
damage_contributor,
|
damage_contributor,
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -55,7 +55,9 @@ impl Animation for BlockAnimation {
|
|||||||
| Some("common.abilities.sword.basic_guard")
|
| Some("common.abilities.sword.basic_guard")
|
||||||
| Some("common.abilities.axe.basic_guard")
|
| Some("common.abilities.axe.basic_guard")
|
||||||
| Some("common.abilities.hammer.basic_guard")
|
| Some("common.abilities.hammer.basic_guard")
|
||||||
| Some("common.abilities.sword.defensive_guard") => {
|
| Some("common.abilities.sword.defensive_guard")
|
||||||
|
| Some("common.abilities.shield.basic_guard")
|
||||||
|
| Some("common.abilities.shield.power_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 {
|
||||||
@ -215,53 +217,95 @@ impl Animation for BlockAnimation {
|
|||||||
* Quaternion::rotation_y(0.6)
|
* Quaternion::rotation_y(0.6)
|
||||||
* Quaternion::rotation_z(0.0);
|
* Quaternion::rotation_z(0.0);
|
||||||
},
|
},
|
||||||
|
Some(ToolKind::Shield) => {
|
||||||
|
next.control.position = Vec3::new(2.0, 9.0, 8.0);
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_x(0.25) * Quaternion::rotation_z(-1.5);
|
||||||
|
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0)
|
||||||
|
* Quaternion::rotation_y(PI / 2.0);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
((Some(Hands::One), Some(Hands::One)), _, Some(ToolKind::Shield)) => {
|
||||||
|
next.control_r.position = Vec3::new(-1.5, 8.0, 4.0 + move1 * 3.0);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(0.25)
|
||||||
|
* Quaternion::rotation_y(0.0)
|
||||||
|
* Quaternion::rotation_z(1.5);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, -2.0, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.control_l.position = Vec3::new(-9.0, -5.0, 0.0);
|
||||||
|
next.control_l.orientation =
|
||||||
|
Quaternion::rotation_x(-1.75) * Quaternion::rotation_y(-0.3);
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -0.5, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
},
|
||||||
|
((Some(Hands::One), _), Some(ToolKind::Shield), _) => {
|
||||||
|
next.control_l.position = Vec3::new(1.5, 8.0, 4.0 + move1 * 3.0);
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(0.25)
|
||||||
|
* Quaternion::rotation_y(0.0)
|
||||||
|
* Quaternion::rotation_z(-1.5);
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.control_r.position = Vec3::new(9.0, -5.0, 0.0);
|
||||||
|
next.control_r.orientation =
|
||||||
|
Quaternion::rotation_x(-1.75) * Quaternion::rotation_y(0.3);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, -0.5, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
},
|
||||||
|
((Some(Hands::One), _), _, _) => {
|
||||||
|
match hands {
|
||||||
|
(Some(Hands::One), _) => {
|
||||||
|
next.control_l.position =
|
||||||
|
Vec3::new(-7.0, 8.0 + move1 * 3.0, 2.0 + move1 * 3.0);
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(-0.3)
|
||||||
|
* Quaternion::rotation_y(move1 * 1.0);
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -0.5, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0)
|
||||||
|
},
|
||||||
|
(_, _) => {},
|
||||||
|
};
|
||||||
|
match hands {
|
||||||
|
(None | Some(Hands::One), Some(Hands::One)) => {
|
||||||
|
next.control_r.position =
|
||||||
|
Vec3::new(7.0, 8.0 + move1 * 3.0, 2.0 + move1 * 3.0);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(-0.3)
|
||||||
|
* Quaternion::rotation_y(move1 * -1.0);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, -0.5, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0)
|
||||||
|
},
|
||||||
|
(_, _) => {},
|
||||||
|
};
|
||||||
|
match hands {
|
||||||
|
(None, None) | (None, Some(Hands::One)) => {
|
||||||
|
next.hand_l.position = Vec3::new(-4.5, 8.0, 5.0);
|
||||||
|
next.hand_l.orientation =
|
||||||
|
Quaternion::rotation_x(1.9) * Quaternion::rotation_y(-0.5)
|
||||||
|
},
|
||||||
|
(_, _) => {},
|
||||||
|
};
|
||||||
|
match hands {
|
||||||
|
(None, None) | (Some(Hands::One), None) => {
|
||||||
|
next.hand_r.position = Vec3::new(4.5, 8.0, 5.0);
|
||||||
|
next.hand_r.orientation =
|
||||||
|
Quaternion::rotation_x(1.9) * Quaternion::rotation_y(0.5)
|
||||||
|
},
|
||||||
|
(_, _) => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let (None, Some(Hands::Two)) = hands {
|
||||||
|
next.second = next.main;
|
||||||
|
}
|
||||||
|
},
|
||||||
((_, _), _, _) => {},
|
((_, _), _, _) => {},
|
||||||
};
|
};
|
||||||
match hands {
|
|
||||||
(Some(Hands::One), _) => {
|
|
||||||
next.control_l.position =
|
|
||||||
Vec3::new(-7.0, 8.0 + move1 * 3.0, 2.0 + move1 * 3.0);
|
|
||||||
next.control_l.orientation =
|
|
||||||
Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(move1 * 1.0);
|
|
||||||
next.hand_l.position = Vec3::new(0.0, -0.5, 0.0);
|
|
||||||
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0)
|
|
||||||
},
|
|
||||||
(_, _) => {},
|
|
||||||
};
|
|
||||||
match hands {
|
|
||||||
(None | Some(Hands::One), Some(Hands::One)) => {
|
|
||||||
next.control_r.position =
|
|
||||||
Vec3::new(7.0, 8.0 + move1 * 3.0, 2.0 + move1 * 3.0);
|
|
||||||
next.control_r.orientation =
|
|
||||||
Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(move1 * -1.0);
|
|
||||||
next.hand_r.position = Vec3::new(0.0, -0.5, 0.0);
|
|
||||||
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0)
|
|
||||||
},
|
|
||||||
(_, _) => {},
|
|
||||||
};
|
|
||||||
match hands {
|
|
||||||
(None, None) | (None, Some(Hands::One)) => {
|
|
||||||
next.hand_l.position = Vec3::new(-4.5, 8.0, 5.0);
|
|
||||||
next.hand_l.orientation =
|
|
||||||
Quaternion::rotation_x(1.9) * Quaternion::rotation_y(-0.5)
|
|
||||||
},
|
|
||||||
(_, _) => {},
|
|
||||||
};
|
|
||||||
match hands {
|
|
||||||
(None, None) | (Some(Hands::One), None) => {
|
|
||||||
next.hand_r.position = Vec3::new(4.5, 8.0, 5.0);
|
|
||||||
next.hand_r.orientation =
|
|
||||||
Quaternion::rotation_x(1.9) * Quaternion::rotation_y(0.5)
|
|
||||||
},
|
|
||||||
(_, _) => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
if let (None, Some(Hands::Two)) = hands {
|
|
||||||
next.second = next.main;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Some("common.abilities.sword.defensive_deflect") => {
|
Some("common.abilities.sword.defensive_deflect") => {
|
||||||
let (move1, move2, move3) = match stage_section {
|
let (move1, move2, move3) = match stage_section {
|
||||||
|
@ -2,7 +2,7 @@ use super::{
|
|||||||
super::{vek::*, Animation},
|
super::{vek::*, Animation},
|
||||||
CharacterSkeleton, SkeletonAttr,
|
CharacterSkeleton, SkeletonAttr,
|
||||||
};
|
};
|
||||||
use common::states::utils::{AbilityInfo, StageSection};
|
use common::states::utils::{AbilityInfo, HandInfo, StageSection};
|
||||||
use core::f32::consts::{PI, TAU};
|
use core::f32::consts::{PI, TAU};
|
||||||
|
|
||||||
pub struct ComboAnimation;
|
pub struct ComboAnimation;
|
||||||
@ -1133,6 +1133,81 @@ impl Animation for ComboAnimation {
|
|||||||
next.control.orientation.rotate_x(move2 * -1.2);
|
next.control.orientation.rotate_x(move2 * -1.2);
|
||||||
next.control.position += Vec3::new(move2 * 8.0, 0.0, 0.0);
|
next.control.position += Vec3::new(move2 * 8.0, 0.0, 0.0);
|
||||||
},
|
},
|
||||||
|
Some("common.abilities.shield.singlestrike") => {
|
||||||
|
let move1 = if strike == current_strike {
|
||||||
|
match stage_section {
|
||||||
|
Some(StageSection::Buildup) => anim_time,
|
||||||
|
Some(StageSection::Action) => 1.0,
|
||||||
|
Some(StageSection::Recover) => 1.0,
|
||||||
|
_ => 0.0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
let move1 = move1 * multi_strike_pullback;
|
||||||
|
|
||||||
|
if let Some(ability_info) = _ability_info {
|
||||||
|
match ability_info.hand {
|
||||||
|
Some(HandInfo::TwoHanded) => {
|
||||||
|
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.chest.orientation = Quaternion::rotation_z(move1 * -0.3);
|
||||||
|
next.torso.orientation = Quaternion::rotation_z(move1 * -1.0);
|
||||||
|
next.head.orientation = Quaternion::rotation_z(move1 * 0.75);
|
||||||
|
next.head.position = Vec3::new(0.5, s_a.head.0 + 0.5, s_a.head.1);
|
||||||
|
|
||||||
|
next.control.position = Vec3::new(move1 * -10.0, 6.0, move1 * 6.0);
|
||||||
|
next.control.orientation = Quaternion::rotation_z(-0.25);
|
||||||
|
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0)
|
||||||
|
* Quaternion::rotation_y(PI / 2.0);
|
||||||
|
},
|
||||||
|
Some(HandInfo::MainHand) => {
|
||||||
|
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.chest.orientation = Quaternion::rotation_z(move1 * -0.3);
|
||||||
|
next.torso.orientation = Quaternion::rotation_z(move1 * -1.2);
|
||||||
|
next.head.orientation = Quaternion::rotation_z(move1 * 0.75);
|
||||||
|
next.head.position = Vec3::new(0.5, s_a.head.0 + 0.5, s_a.head.1);
|
||||||
|
|
||||||
|
next.control_l.position =
|
||||||
|
Vec3::new(move1 * -12.0, 4.0, move1 * 6.0);
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(move1 * 0.0)
|
||||||
|
* Quaternion::rotation_y(0.0)
|
||||||
|
* Quaternion::rotation_z(-0.25);
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -1.5, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.control_r.position = Vec3::new(9.0, -1.0, 0.0);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(-1.75);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.5, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
},
|
||||||
|
Some(HandInfo::OffHand) => {
|
||||||
|
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.chest.orientation = Quaternion::rotation_z(move1 * 0.3);
|
||||||
|
next.torso.orientation = Quaternion::rotation_z(move1 * 1.2);
|
||||||
|
next.head.orientation = Quaternion::rotation_z(move1 * -0.75);
|
||||||
|
next.head.position = Vec3::new(-0.5, s_a.head.0 + -0.5, s_a.head.1);
|
||||||
|
|
||||||
|
next.control_r.position = Vec3::new(move1 * 12.0, 4.0, move1 * 6.0);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(move1 * 0.0)
|
||||||
|
* Quaternion::rotation_y(0.0)
|
||||||
|
* Quaternion::rotation_z(0.25);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, -1.5, 0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.control_l.position = Vec3::new(-9.0, -1.0, 0.0);
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(-1.75);
|
||||||
|
next.hand_l.position = Vec3::new(0.0, 0.5, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,6 +360,11 @@ impl CharacterSkeleton {
|
|||||||
self.main.orientation =
|
self.main.orientation =
|
||||||
Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(PI / 2.0);
|
Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(PI / 2.0);
|
||||||
},
|
},
|
||||||
|
Some(ToolKind::Shield) => {
|
||||||
|
self.main.position = Vec3::new(-2.0, -3.0 - self.back_carry_offset, 1.0);
|
||||||
|
self.main.orientation =
|
||||||
|
Quaternion::rotation_y(-0.75) * Quaternion::rotation_z(PI / 2.0);
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
self.main.position = Vec3::new(-7.0, -5.0 - self.back_carry_offset, 15.0);
|
self.main.position = Vec3::new(-7.0, -5.0 - self.back_carry_offset, 15.0);
|
||||||
self.main.orientation =
|
self.main.orientation =
|
||||||
@ -382,7 +387,7 @@ impl CharacterSkeleton {
|
|||||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
|
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
|
||||||
},
|
},
|
||||||
Some(ToolKind::Shield) => {
|
Some(ToolKind::Shield) => {
|
||||||
self.main.position = Vec3::new(-0.0, -4.0 - self.back_carry_offset, 3.0);
|
self.main.position = Vec3::new(-2.0, -4.0 - self.back_carry_offset, 3.0);
|
||||||
self.main.orientation =
|
self.main.orientation =
|
||||||
Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
|
Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
|
||||||
},
|
},
|
||||||
@ -403,7 +408,7 @@ impl CharacterSkeleton {
|
|||||||
Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(-PI / 2.0);
|
Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(-PI / 2.0);
|
||||||
},
|
},
|
||||||
Some(ToolKind::Shield) => {
|
Some(ToolKind::Shield) => {
|
||||||
self.second.position = Vec3::new(0.0, -4.0 - self.back_carry_offset, 3.0);
|
self.second.position = Vec3::new(1.5, -4.0 - self.back_carry_offset, 3.0);
|
||||||
self.second.orientation =
|
self.second.orientation =
|
||||||
Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
|
Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
|
||||||
},
|
},
|
||||||
|
@ -167,6 +167,18 @@ impl Animation for RollAnimation {
|
|||||||
|
|
||||||
next.control.position = Vec3::new(-11.0, 1.8, 4.0);
|
next.control.position = Vec3::new(-11.0, 1.8, 4.0);
|
||||||
},
|
},
|
||||||
|
Some(ToolKind::Shield) => {
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -1.5, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.hand_r.orientation =
|
||||||
|
Quaternion::rotation_x(PI / 2.0) * Quaternion::rotation_y(2.0);
|
||||||
|
|
||||||
|
next.control.position = Vec3::new(0.0, 7.0, 4.0);
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(-1.25);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
(_, _) => {},
|
(_, _) => {},
|
||||||
|
@ -497,6 +497,18 @@ impl Animation for WieldAnimation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Some(ToolKind::Shield) => {
|
||||||
|
next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.hand_r.orientation =
|
||||||
|
Quaternion::rotation_x(PI / 2.0) * Quaternion::rotation_y(2.0);
|
||||||
|
|
||||||
|
next.control.position = Vec3::new(0.0, 7.0, 4.0);
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(-1.25);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
((_, _), _, _) => {},
|
((_, _), _, _) => {},
|
||||||
|
@ -145,7 +145,12 @@ impl CombatEventMapper {
|
|||||||
previous_state: &PreviousEntityState,
|
previous_state: &PreviousEntityState,
|
||||||
inventory: &Inventory,
|
inventory: &Inventory,
|
||||||
) -> SfxEvent {
|
) -> SfxEvent {
|
||||||
if let Some(item) = inventory.equipped(EquipSlot::ActiveMainhand) {
|
let equip_slot = character_state
|
||||||
|
.ability_info()
|
||||||
|
.and_then(|ability| ability.hand)
|
||||||
|
.map_or(EquipSlot::ActiveMainhand, |hand| hand.to_equip_slot());
|
||||||
|
|
||||||
|
if let Some(item) = inventory.equipped(equip_slot) {
|
||||||
if let ItemKind::Tool(data) = &*item.kind() {
|
if let ItemKind::Tool(data) = &*item.kind() {
|
||||||
if character_state.is_attack() {
|
if character_state.is_attack() {
|
||||||
return SfxEvent::Attack(
|
return SfxEvent::Attack(
|
||||||
|
@ -1131,6 +1131,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
RecipeKind::Component(ToolKind::Bow) => self.imgs.icon_log,
|
RecipeKind::Component(ToolKind::Bow) => self.imgs.icon_log,
|
||||||
RecipeKind::Component(ToolKind::Staff) => self.imgs.icon_log,
|
RecipeKind::Component(ToolKind::Staff) => self.imgs.icon_log,
|
||||||
RecipeKind::Component(ToolKind::Sceptre) => self.imgs.icon_log,
|
RecipeKind::Component(ToolKind::Sceptre) => self.imgs.icon_log,
|
||||||
|
RecipeKind::Component(ToolKind::Shield) => self.imgs.icon_ingot,
|
||||||
_ => self.imgs.not_found,
|
_ => self.imgs.not_found,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -563,8 +563,8 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
|
|||||||
"common.abilities.sceptre.healingaura" => imgs.skill_sceptre_heal,
|
"common.abilities.sceptre.healingaura" => imgs.skill_sceptre_heal,
|
||||||
"common.abilities.sceptre.wardingaura" => imgs.skill_sceptre_aura,
|
"common.abilities.sceptre.wardingaura" => imgs.skill_sceptre_aura,
|
||||||
// Shield
|
// Shield
|
||||||
"common.abilities.shield.tempbasic" => imgs.onehshield_m1,
|
"common.abilities.shield.singlestrike" => imgs.onehshield_m1,
|
||||||
"common.abilities.shield.block" => imgs.onehshield_m2,
|
"common.abilities.shield.power_guard" => imgs.onehshield_m1,
|
||||||
// Dagger
|
// Dagger
|
||||||
"common.abilities.dagger.tempbasic" => imgs.onehdagger_m1,
|
"common.abilities.dagger.tempbasic" => imgs.onehdagger_m1,
|
||||||
// Pickaxe
|
// Pickaxe
|
||||||
|
Loading…
Reference in New Issue
Block a user