mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Updates from review
This commit is contained in:
parent
5c401215cf
commit
81cfb26059
@ -2,7 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.25,
|
||||
recover_duration: 0.2,
|
||||
max_angle: 60.0,
|
||||
block_strength: 0.5,
|
||||
block_strength: 1.0,
|
||||
parry_window: (
|
||||
buildup: true,
|
||||
recover: false,
|
||||
@ -10,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 5,
|
||||
energy_regen: 2.5,
|
||||
can_hold: true,
|
||||
can_use_block_priority: true,
|
||||
blocked_attacks: (
|
||||
melee: true,
|
||||
projectiles: false,
|
||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.25,
|
||||
recover_duration: 0.2,
|
||||
max_angle: 60.0,
|
||||
block_strength: 0.5,
|
||||
block_strength: 1.0,
|
||||
parry_window: (
|
||||
buildup: true,
|
||||
recover: false,
|
||||
@ -10,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 5,
|
||||
energy_regen: 2.5,
|
||||
can_hold: true,
|
||||
can_use_block_priority: true,
|
||||
blocked_attacks: (
|
||||
melee: true,
|
||||
projectiles: false,
|
||||
|
@ -2,6 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.25,
|
||||
recover_duration: 0.25,
|
||||
max_angle: 90.0,
|
||||
block_strength: 1.0,
|
||||
parry_window: (
|
||||
buildup: false,
|
||||
recover: false,
|
||||
@ -9,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 0,
|
||||
energy_regen: 0,
|
||||
can_hold: true,
|
||||
can_use_block_priority: true,
|
||||
blocked_attacks: (
|
||||
melee: true,
|
||||
projectiles: true,
|
||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.45,
|
||||
recover_duration: 0.2,
|
||||
max_angle: 90.0,
|
||||
block_strength: 0.8,
|
||||
block_strength: 1.0,
|
||||
parry_window: (
|
||||
buildup: true,
|
||||
recover: false,
|
||||
@ -10,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 5.0,
|
||||
energy_regen: 5.0,
|
||||
can_hold: true,
|
||||
can_use_block_priority: true,
|
||||
blocked_attacks: (
|
||||
melee: true,
|
||||
projectiles: true,
|
||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.25,
|
||||
recover_duration: 0.2,
|
||||
max_angle: 60.0,
|
||||
block_strength: 0.5,
|
||||
block_strength: 1.0,
|
||||
parry_window: (
|
||||
buildup: true,
|
||||
recover: false,
|
||||
@ -10,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 5,
|
||||
energy_regen: 2.5,
|
||||
can_hold: true,
|
||||
can_use_block_priority: true,
|
||||
blocked_attacks: (
|
||||
melee: true,
|
||||
projectiles: false,
|
||||
|
@ -2,6 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.4,
|
||||
recover_duration: 0.2,
|
||||
max_angle: 45.0,
|
||||
block_strength: 1.0,
|
||||
parry_window: (
|
||||
buildup: true,
|
||||
recover: false,
|
||||
@ -9,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 2.5,
|
||||
energy_regen: 17.5,
|
||||
can_hold: false,
|
||||
can_use_block_priority: false,
|
||||
blocked_attacks: (
|
||||
melee: false,
|
||||
projectiles: true,
|
||||
|
@ -2,7 +2,7 @@ BasicBlock(
|
||||
buildup_duration: 0.4,
|
||||
recover_duration: 0.15,
|
||||
max_angle: 60.0,
|
||||
block_strength: 0.75,
|
||||
block_strength: 1.1,
|
||||
parry_window: (
|
||||
buildup: true,
|
||||
recover: false,
|
||||
@ -10,6 +10,7 @@ BasicBlock(
|
||||
energy_cost: 2.5,
|
||||
energy_regen: 17.5,
|
||||
can_hold: true,
|
||||
can_use_block_priority: true,
|
||||
blocked_attacks: (
|
||||
melee: true,
|
||||
projectiles: false,
|
||||
|
@ -20,7 +20,7 @@ use crate::{
|
||||
},
|
||||
outcome::Outcome,
|
||||
resources::{Secs, Time},
|
||||
states::utils::{HandInfo, StageSection},
|
||||
states::utils::StageSection,
|
||||
uid::{IdMaps, Uid},
|
||||
util::Dir,
|
||||
};
|
||||
@ -58,6 +58,8 @@ pub const MAX_HEADSHOT_PRECISION: f32 = 1.0;
|
||||
pub const MAX_TOP_HEADSHOT_PRECISION: f32 = 0.5;
|
||||
pub const MAX_BEAM_DUR_PRECISION: f32 = 0.25;
|
||||
pub const MAX_MELEE_POISE_PRECISION: f32 = 0.5;
|
||||
pub const MAX_BLOCK_POISE_COST: f32 = 25.0;
|
||||
pub const PARRY_BONUS_MULTIPLIER: f32 = 2.0;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AttackerInfo<'a> {
|
||||
@ -140,7 +142,7 @@ impl Attack {
|
||||
|
||||
pub fn effects(&self) -> impl Iterator<Item = &AttackEffect> { self.effects.iter() }
|
||||
|
||||
pub fn compute_block_damage_reduction(
|
||||
pub fn compute_block_damage_decrement(
|
||||
attacker: Option<&AttackerInfo>,
|
||||
target: &TargetInfo,
|
||||
source: AttackSource,
|
||||
@ -152,27 +154,24 @@ impl Attack {
|
||||
mut emit_outcome: impl FnMut(Outcome),
|
||||
) -> f32 {
|
||||
if damage.value > 0.0 {
|
||||
let poise_reduction = 1.0
|
||||
- (Poise::compute_poise_damage_reduction(
|
||||
target.inventory,
|
||||
msm,
|
||||
target.char_state,
|
||||
target.stats,
|
||||
));
|
||||
if let (Some(char_state), Some(ori), Some(inventory), Some(stats)) = (
|
||||
target.char_state,
|
||||
target.ori,
|
||||
target.inventory,
|
||||
target.stats,
|
||||
) {
|
||||
if ori.look_vec().angle_between(-dir.with_z(0.0)) < char_state.block_angle() {
|
||||
let poise = stats.original_body.base_poise() as f32 / 4.0;
|
||||
if let (Some(char_state), Some(ori), Some(inventory)) =
|
||||
(target.char_state, target.ori, target.inventory)
|
||||
{
|
||||
let block_strength = block_strength(inventory, char_state);
|
||||
if ori.look_vec().angle_between(-dir.with_z(0.0)) < char_state.block_angle()
|
||||
&& block_strength > 0.0
|
||||
{
|
||||
if char_state.is_parry(source) {
|
||||
let block_strength =
|
||||
f32::max(1.0, block_strength(inventory, char_state) * 2.0);
|
||||
let poise_cost =
|
||||
(damage.value.min(block_strength) * poise * poise_reduction)
|
||||
/ block_strength;
|
||||
let final_block_strength = block_strength * PARRY_BONUS_MULTIPLIER;
|
||||
let poise_change = Poise::apply_poise_reduction(
|
||||
(damage.value.min(final_block_strength) * MAX_BLOCK_POISE_COST)
|
||||
/ final_block_strength,
|
||||
target.inventory,
|
||||
msm,
|
||||
target.char_state,
|
||||
target.stats,
|
||||
);
|
||||
|
||||
emit_outcome(Outcome::Block {
|
||||
parry: true,
|
||||
pos: target.pos,
|
||||
@ -186,19 +185,24 @@ impl Attack {
|
||||
emit(ServerEvent::PoiseChange {
|
||||
entity: target.entity,
|
||||
change: PoiseChange {
|
||||
amount: -poise_cost,
|
||||
amount: -poise_change,
|
||||
impulse: *dir,
|
||||
by: attacker.map(|x| (*x).into()),
|
||||
cause: Some(damage.source),
|
||||
time,
|
||||
},
|
||||
});
|
||||
damage.value.min(block_strength)
|
||||
damage.value.min(final_block_strength)
|
||||
} else if char_state.is_block(source) {
|
||||
let block_strength = f32::max(1.0, block_strength(inventory, char_state));
|
||||
let poise_cost =
|
||||
(damage.value.min(block_strength) * poise * poise_reduction)
|
||||
/ block_strength;
|
||||
let final_block_strength = block_strength;
|
||||
let poise_change = Poise::apply_poise_reduction(
|
||||
(damage.value.min(final_block_strength) * MAX_BLOCK_POISE_COST)
|
||||
/ final_block_strength,
|
||||
target.inventory,
|
||||
msm,
|
||||
target.char_state,
|
||||
target.stats,
|
||||
);
|
||||
emit_outcome(Outcome::Block {
|
||||
parry: false,
|
||||
pos: target.pos,
|
||||
@ -207,29 +211,7 @@ impl Attack {
|
||||
emit(ServerEvent::PoiseChange {
|
||||
entity: target.entity,
|
||||
change: PoiseChange {
|
||||
amount: -poise_cost,
|
||||
impulse: *dir,
|
||||
by: attacker.map(|x| (*x).into()),
|
||||
cause: Some(damage.source),
|
||||
time,
|
||||
},
|
||||
});
|
||||
damage.value.min(block_strength)
|
||||
} else if char_state.is_half_block(source) {
|
||||
let block_strength =
|
||||
f32::max(1.0, block_strength(inventory, char_state) / 2.0);
|
||||
let poise_cost =
|
||||
(damage.value.min(block_strength) * poise * poise_reduction)
|
||||
/ block_strength;
|
||||
emit_outcome(Outcome::Block {
|
||||
parry: false,
|
||||
pos: target.pos,
|
||||
uid: target.uid,
|
||||
});
|
||||
emit(ServerEvent::PoiseChange {
|
||||
entity: target.entity,
|
||||
change: PoiseChange {
|
||||
amount: -poise_cost,
|
||||
amount: -poise_change,
|
||||
impulse: *dir,
|
||||
by: attacker.map(|x| (*x).into()),
|
||||
cause: Some(damage.source),
|
||||
@ -251,7 +233,7 @@ impl Attack {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_armor_damage_reduction(
|
||||
pub fn compute_damage_reduction(
|
||||
attacker: Option<&AttackerInfo>,
|
||||
target: &TargetInfo,
|
||||
damage: Damage,
|
||||
@ -337,14 +319,10 @@ impl Attack {
|
||||
let damage_instance = damage.instance + damage_instance_offset;
|
||||
is_applied = true;
|
||||
|
||||
let armor_damage_reduction = Attack::compute_armor_damage_reduction(
|
||||
attacker.as_ref(),
|
||||
target,
|
||||
damage.damage,
|
||||
msm,
|
||||
);
|
||||
let damage_reduction =
|
||||
Attack::compute_damage_reduction(attacker.as_ref(), target, damage.damage, msm);
|
||||
|
||||
let block_damage_reduction = Attack::compute_block_damage_reduction(
|
||||
let block_damage_decrement = Attack::compute_block_damage_decrement(
|
||||
attacker.as_ref(),
|
||||
target,
|
||||
attack_source,
|
||||
@ -357,8 +335,8 @@ impl Attack {
|
||||
);
|
||||
|
||||
let change = damage.damage.calculate_health_change(
|
||||
armor_damage_reduction,
|
||||
block_damage_reduction,
|
||||
damage_reduction,
|
||||
block_damage_decrement,
|
||||
attacker.map(|x| x.into()),
|
||||
precision_mult,
|
||||
self.precision_multiplier,
|
||||
@ -408,8 +386,8 @@ impl Attack {
|
||||
// of damage that was reduced by target's protection
|
||||
// Damage reduction should never equal 1 here as otherwise the check above
|
||||
// that health change amount is greater than 0 would fail.
|
||||
let reduced_damage = applied_damage * armor_damage_reduction
|
||||
/ (1.0 - armor_damage_reduction);
|
||||
let reduced_damage =
|
||||
applied_damage * damage_reduction / (1.0 - damage_reduction);
|
||||
let poise = reduced_damage
|
||||
* CRUSHING_POISE_FRACTION
|
||||
* attacker
|
||||
@ -1127,8 +1105,8 @@ impl Damage {
|
||||
|
||||
pub fn calculate_health_change(
|
||||
self,
|
||||
armor_damage_reduction: f32,
|
||||
block_damage_reduction: f32,
|
||||
damage_reduction: f32,
|
||||
block_damage_decrement: f32,
|
||||
damage_contributor: Option<DamageContributor>,
|
||||
precision_mult: Option<f32>,
|
||||
precision_power: f32,
|
||||
@ -1147,9 +1125,9 @@ impl Damage {
|
||||
// Precise hit
|
||||
damage += precise_damage;
|
||||
// Block
|
||||
damage -= block_damage_reduction;
|
||||
damage -= block_damage_decrement;
|
||||
// Armor
|
||||
damage *= 1.0 - armor_damage_reduction;
|
||||
damage *= 1.0 - damage_reduction;
|
||||
|
||||
HealthChange {
|
||||
amount: -damage,
|
||||
@ -1162,7 +1140,7 @@ impl Damage {
|
||||
},
|
||||
DamageSource::Falling => {
|
||||
// Armor
|
||||
if (armor_damage_reduction - 1.0).abs() < f32::EPSILON {
|
||||
if (damage_reduction - 1.0).abs() < f32::EPSILON {
|
||||
damage = 0.0;
|
||||
}
|
||||
HealthChange {
|
||||
@ -1586,23 +1564,22 @@ pub fn precision_mult_from_flank(attack_dir: Vec3<f32>, target_ori: Option<&Ori>
|
||||
}
|
||||
|
||||
pub fn block_strength(inventory: &Inventory, char_state: &CharacterState) -> f32 {
|
||||
fn get_equip_slot(hand: Option<HandInfo>) -> EquipSlot {
|
||||
match hand {
|
||||
Some(HandInfo::OffHand) => EquipSlot::ActiveOffhand,
|
||||
_ => EquipSlot::ActiveMainhand,
|
||||
let equip_slot = if let CharacterState::BasicBlock(data) = char_state {
|
||||
if data.static_data.can_use_block_priority {
|
||||
get_block_equip_slot_by_priority(Some(inventory))
|
||||
} else {
|
||||
get_block_equip_slot_by_tool(Some(inventory), data.static_data.ability_info.tool)
|
||||
}
|
||||
}
|
||||
|
||||
let equip_slot = match char_state {
|
||||
CharacterState::BasicBlock(data) => get_equip_slot(data.static_data.ability_info.hand),
|
||||
CharacterState::RiposteMelee(data) => get_equip_slot(data.static_data.ability_info.hand),
|
||||
CharacterState::ComboMelee2(data) => get_equip_slot(data.static_data.ability_info.hand),
|
||||
_ => EquipSlot::ActiveMainhand,
|
||||
} else {
|
||||
get_block_equip_slot_by_tool(
|
||||
Some(inventory),
|
||||
char_state.ability_info().and_then(|t| t.tool),
|
||||
)
|
||||
};
|
||||
|
||||
inventory
|
||||
.equipped(equip_slot)
|
||||
.map_or(0.0, |item| match &*item.kind() {
|
||||
.map(|item| match &*item.kind() {
|
||||
ItemKind::Tool(tool) => {
|
||||
tool.stats(item.stats_durability_multiplier())
|
||||
.block_strength
|
||||
@ -1610,17 +1587,103 @@ pub fn block_strength(inventory: &Inventory, char_state: &CharacterState) -> f32
|
||||
},
|
||||
_ => 0.0,
|
||||
})
|
||||
.map_or(0.0, |weapon_block_strength| match char_state {
|
||||
CharacterState::BasicBlock(data) => {
|
||||
weapon_block_strength * data.static_data.block_strength
|
||||
},
|
||||
CharacterState::ComboMelee2(data) => {
|
||||
let capabilities = data.static_data.ability_info.ability_meta.capabilities;
|
||||
|
||||
if capabilities.contains(Capability::PARRIES)
|
||||
|| capabilities.contains(Capability::PARRIES_MELEE)
|
||||
{
|
||||
return weapon_block_strength;
|
||||
}
|
||||
|
||||
if capabilities.contains(Capability::BLOCKS) {
|
||||
return weapon_block_strength * 0.5;
|
||||
}
|
||||
|
||||
0.0
|
||||
},
|
||||
CharacterState::RiposteMelee(_) => weapon_block_strength,
|
||||
CharacterState::Idle(_)
|
||||
| CharacterState::Climb(_)
|
||||
| CharacterState::Sit
|
||||
| CharacterState::Dance
|
||||
| CharacterState::Talk
|
||||
| CharacterState::Glide(_)
|
||||
| CharacterState::GlideWield(_)
|
||||
| CharacterState::Stunned(_)
|
||||
| CharacterState::Equipping(_)
|
||||
| CharacterState::Wielding(_)
|
||||
| CharacterState::Roll(_)
|
||||
| CharacterState::BasicMelee(_)
|
||||
| CharacterState::BasicRanged(_)
|
||||
| CharacterState::Boost(_)
|
||||
| CharacterState::DashMelee(_)
|
||||
| CharacterState::ComboMeleeDeprecated(_)
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::LeapShockwave(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
| CharacterState::ChargedMelee(_)
|
||||
| CharacterState::RepeaterRanged(_)
|
||||
| CharacterState::Shockwave(_)
|
||||
| CharacterState::BasicBeam(_)
|
||||
| CharacterState::BasicAura(_)
|
||||
| CharacterState::Blink(_)
|
||||
| CharacterState::BasicSummon(_)
|
||||
| CharacterState::SelfBuff(_)
|
||||
| CharacterState::SpriteSummon(_)
|
||||
| CharacterState::UseItem(_)
|
||||
| CharacterState::SpriteInteract(_)
|
||||
| CharacterState::Wallrun(_)
|
||||
| CharacterState::Skate(_)
|
||||
| CharacterState::Music(_)
|
||||
| CharacterState::FinisherMelee(_)
|
||||
| CharacterState::DiveMelee(_)
|
||||
| CharacterState::RapidMelee(_) => 0.0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_block_equip_slot(inventory: Option<&Inventory>) -> EquipSlot {
|
||||
pub fn get_block_equip_slot_by_priority(inventory: Option<&Inventory>) -> EquipSlot {
|
||||
inventory
|
||||
.and_then(|inv| inv.equipped(EquipSlot::ActiveOffhand))
|
||||
.and_then(|item| match &*item.kind() {
|
||||
ItemKind::Tool(tool) => Some(tool.kind),
|
||||
_ => None,
|
||||
})
|
||||
.map_or(EquipSlot::ActiveMainhand, |item| match item {
|
||||
ToolKind::Shield => EquipSlot::ActiveOffhand,
|
||||
_ => EquipSlot::ActiveMainhand,
|
||||
})
|
||||
.map(get_weapon_kinds)
|
||||
.map_or(
|
||||
EquipSlot::ActiveOffhand,
|
||||
|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::ActiveOffhand,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_block_equip_slot_by_tool(
|
||||
inventory: Option<&Inventory>,
|
||||
tool_kind: Option<ToolKind>,
|
||||
) -> EquipSlot {
|
||||
inventory
|
||||
.map(get_weapon_kinds)
|
||||
.map_or(
|
||||
EquipSlot::ActiveOffhand,
|
||||
|weapon_kinds| match weapon_kinds {
|
||||
(mainhand, Some(_)) => {
|
||||
if mainhand == tool_kind {
|
||||
EquipSlot::ActiveMainhand
|
||||
} else {
|
||||
EquipSlot::ActiveOffhand
|
||||
}
|
||||
},
|
||||
(Some(_), None) => EquipSlot::ActiveMainhand,
|
||||
(None, None) => EquipSlot::ActiveOffhand,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ impl ActiveAbilities {
|
||||
|
||||
match ability {
|
||||
Ability::ToolGuard => {
|
||||
let equip_slot = combat::get_block_equip_slot(inv);
|
||||
let equip_slot = combat::get_block_equip_slot_by_priority(inv);
|
||||
ability_set(equip_slot)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
@ -205,7 +205,7 @@ impl ActiveAbilities {
|
||||
})
|
||||
.map(|(ability, i)| (scale_ability(ability, equip_slot), true, spec_ability(i)))
|
||||
.or_else(|| {
|
||||
ability_set(EquipSlot::ActiveOffhand)
|
||||
ability_set(EquipSlot::ActiveMainhand)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.guard(Some(skill_set), context)
|
||||
@ -213,7 +213,7 @@ impl ActiveAbilities {
|
||||
})
|
||||
.map(|(ability, i)| {
|
||||
(
|
||||
scale_ability(ability, EquipSlot::ActiveOffhand),
|
||||
scale_ability(ability, EquipSlot::ActiveMainhand),
|
||||
false,
|
||||
spec_ability(i),
|
||||
)
|
||||
@ -393,7 +393,7 @@ impl Ability {
|
||||
};
|
||||
|
||||
match self {
|
||||
Ability::ToolGuard => ability_set(combat::get_block_equip_slot(inv))
|
||||
Ability::ToolGuard => ability_set(combat::get_block_equip_slot_by_priority(inv))
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.guard(skillset, context)
|
||||
@ -406,7 +406,7 @@ impl Ability {
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
|
||||
ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
||||
abilities
|
||||
.guard(skillset, context)
|
||||
.map(|a| a.0.id.as_str())
|
||||
@ -521,10 +521,10 @@ impl SpecifiedAbility {
|
||||
ability_set(EquipSlot::ActiveMainhand)
|
||||
.map(|abilities| ability_id(self, &abilities.secondary))
|
||||
}),
|
||||
Ability::ToolGuard => ability_set(combat::get_block_equip_slot(inv))
|
||||
Ability::ToolGuard => ability_set(combat::get_block_equip_slot_by_priority(inv))
|
||||
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a)))
|
||||
.or_else(|| {
|
||||
ability_set(EquipSlot::ActiveOffhand)
|
||||
ability_set(EquipSlot::ActiveMainhand)
|
||||
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a)))
|
||||
}),
|
||||
Ability::SpeciesMovement => None, // TODO: Make not None
|
||||
@ -756,6 +756,7 @@ pub enum CharacterAbility {
|
||||
energy_cost: f32,
|
||||
energy_regen: f32,
|
||||
can_hold: bool,
|
||||
can_use_block_priority: bool,
|
||||
blocked_attacks: AttackFilters,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
@ -1282,6 +1283,7 @@ impl CharacterAbility {
|
||||
ref mut energy_cost,
|
||||
energy_regen: _,
|
||||
can_hold: _,
|
||||
can_use_block_priority: _,
|
||||
blocked_attacks: _,
|
||||
meta: _,
|
||||
} => {
|
||||
@ -2346,6 +2348,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
energy_cost,
|
||||
energy_regen,
|
||||
can_hold,
|
||||
can_use_block_priority,
|
||||
blocked_attacks,
|
||||
meta: _,
|
||||
} => CharacterState::BasicBlock(basic_block::Data {
|
||||
@ -2358,6 +2361,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
energy_cost: *energy_cost,
|
||||
energy_regen: *energy_regen,
|
||||
can_hold: *can_hold,
|
||||
can_use_block_priority: *can_use_block_priority,
|
||||
blocked_attacks: *blocked_attacks,
|
||||
ability_info,
|
||||
},
|
||||
@ -3000,6 +3004,8 @@ bitflags::bitflags! {
|
||||
#[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
|
||||
pub struct Capability: u8 {
|
||||
// The ability will parry all blockable attacks in the buildup portion
|
||||
const PARRIES = 0b01000000;
|
||||
// There used to be a capability here, to keep ordering the same below this is now a placeholder
|
||||
const PLACEHOLDER = 0b00000001;
|
||||
// Allows blocking to interrupt the ability at any point
|
||||
@ -3012,8 +3018,6 @@ bitflags::bitflags! {
|
||||
const KNOCKBACK_RESISTANT = 0b00010000;
|
||||
// The ability will parry melee attacks in the buildup portion
|
||||
const PARRIES_MELEE = 0b00100000;
|
||||
// The ability will parry all blockable attacks in the buildup portion
|
||||
const PARRIES = 0b01000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,25 +352,62 @@ impl CharacterState {
|
||||
match self {
|
||||
CharacterState::BasicBlock(data) => {
|
||||
data.static_data.blocked_attacks.applies(attack_source)
|
||||
&& matches!(
|
||||
self.stage_section(),
|
||||
Some(StageSection::Buildup | StageSection::Action),
|
||||
)
|
||||
},
|
||||
_ => false,
|
||||
CharacterState::ComboMelee2(data) => {
|
||||
data.static_data
|
||||
.ability_info
|
||||
.ability_meta
|
||||
.capabilities
|
||||
.contains(Capability::BLOCKS)
|
||||
&& matches!(
|
||||
self.stage_section(),
|
||||
Some(StageSection::Buildup | StageSection::Action),
|
||||
)
|
||||
},
|
||||
CharacterState::Idle(_)
|
||||
| CharacterState::Climb(_)
|
||||
| CharacterState::Sit
|
||||
| CharacterState::Dance
|
||||
| CharacterState::Talk
|
||||
| CharacterState::Glide(_)
|
||||
| CharacterState::GlideWield(_)
|
||||
| CharacterState::Stunned(_)
|
||||
| CharacterState::Equipping(_)
|
||||
| CharacterState::Wielding(_)
|
||||
| CharacterState::Roll(_)
|
||||
| CharacterState::BasicMelee(_)
|
||||
| CharacterState::BasicRanged(_)
|
||||
| CharacterState::Boost(_)
|
||||
| CharacterState::DashMelee(_)
|
||||
| CharacterState::ComboMeleeDeprecated(_)
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::LeapShockwave(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
| CharacterState::ChargedMelee(_)
|
||||
| CharacterState::RepeaterRanged(_)
|
||||
| CharacterState::Shockwave(_)
|
||||
| CharacterState::BasicBeam(_)
|
||||
| CharacterState::BasicAura(_)
|
||||
| CharacterState::Blink(_)
|
||||
| CharacterState::BasicSummon(_)
|
||||
| CharacterState::SelfBuff(_)
|
||||
| CharacterState::SpriteSummon(_)
|
||||
| CharacterState::UseItem(_)
|
||||
| CharacterState::SpriteInteract(_)
|
||||
| CharacterState::Wallrun(_)
|
||||
| CharacterState::Skate(_)
|
||||
| CharacterState::Music(_)
|
||||
| CharacterState::FinisherMelee(_)
|
||||
| CharacterState::DiveMelee(_)
|
||||
| CharacterState::RiposteMelee(_)
|
||||
| CharacterState::RapidMelee(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_half_block(&self, attack_source: AttackSource) -> bool {
|
||||
matches!(attack_source, AttackSource::Melee)
|
||||
&& self
|
||||
.ability_info()
|
||||
.map(|a| a.ability_meta.capabilities)
|
||||
.map_or(false, |c| {
|
||||
c.contains(Capability::BLOCKS)
|
||||
&& matches!(
|
||||
self.stage_section(),
|
||||
Some(StageSection::Buildup | StageSection::Action)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// In radians
|
||||
pub fn block_angle(&self) -> f32 {
|
||||
match self {
|
||||
|
@ -97,6 +97,28 @@ impl ToolKind {
|
||||
| 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)]
|
||||
|
@ -25,7 +25,7 @@ pub struct StaticData {
|
||||
pub recover_duration: Duration,
|
||||
/// Max angle (45.0 will give you a 90.0 angle window)
|
||||
pub max_angle: f32,
|
||||
/// What percentage incoming damage is reduced by
|
||||
/// What percentage of block strength is effective
|
||||
pub block_strength: f32,
|
||||
/// What durations are considered a parry
|
||||
pub parry_window: ParryWindow,
|
||||
@ -37,6 +37,8 @@ pub struct StaticData {
|
||||
pub energy_regen: f32,
|
||||
/// Whether block can be held
|
||||
pub can_hold: bool,
|
||||
/// Whether can choose higher priority weapon block
|
||||
pub can_use_block_priority: bool,
|
||||
/// What kinds of attacks the block applies to
|
||||
pub blocked_attacks: AttackFilters,
|
||||
}
|
||||
|
@ -685,7 +685,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
// Block Strength
|
||||
stat_text(
|
||||
format!(
|
||||
"{} : {:+.0}",
|
||||
"{} : {:.1}",
|
||||
i18n.get_msg("common-stats-block_strength"),
|
||||
stats.block_strength * 10.0
|
||||
),
|
||||
@ -1215,13 +1215,13 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
// Block Strength
|
||||
let block_str_text = if is_primary {
|
||||
format!(
|
||||
"{} : {:.0}",
|
||||
"{} : {:.1}",
|
||||
i18n.get_msg("common-stats-block_strength"),
|
||||
stats.block_strength * 10.0
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{} : x{:.2}",
|
||||
"{} : {:.2}",
|
||||
i18n.get_msg("common-stats-block_strength"),
|
||||
stats.block_strength
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user