mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added precision
This commit is contained in:
parent
62464dbe11
commit
d3b3bca621
@ -86,7 +86,6 @@ common-rand_name = Выпадковае імя
|
||||
common-stats-combat_rating = БР
|
||||
common-stats-power = Моц
|
||||
common-stats-speed = Хуткасць
|
||||
common-stats-crit_chance = Крыт. шанец
|
||||
common-stats-crit_mult = Крыт. множнік
|
||||
common-stats-armor = Браня
|
||||
common-stats-poise_res = Супраціўленне аглушэнню
|
||||
|
@ -86,7 +86,6 @@ common-rand_name = Nom Aleatori
|
||||
common-stats-combat_rating = PC
|
||||
common-stats-power = Potència
|
||||
common-stats-speed = Velocitat
|
||||
common-stats-crit_chance = Probabilitat de Crític
|
||||
common-stats-crit_mult = Multiplicador de Crític
|
||||
common-stats-armor = Armadura
|
||||
common-stats-poise_res = Resistència a l'Atordiment
|
||||
|
@ -83,7 +83,6 @@ common-rand_name = Náhodné jméno
|
||||
common-stats-combat_rating = CR
|
||||
common-stats-power = Síla
|
||||
common-stats-speed = Rychlost
|
||||
common-stats-crit_chance = Kritická šance
|
||||
common-stats-crit_mult = Krit Násobek
|
||||
common-stats-armor = Zbroj
|
||||
common-stats-poise_res = Odolnost omráčení
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = Schnelligkeit
|
||||
common-stats-range = Reichweite
|
||||
common-stats-energy_efficiency = Ausdauereffizienz
|
||||
common-stats-buff_strength = Buff/Debuff Stärke
|
||||
common-stats-crit_chance = Krit. Trefferchance
|
||||
common-stats-crit_mult = Krit. Multiplikator
|
||||
common-stats-armor = Rüstung
|
||||
common-stats-poise_res = Betäubungsresistenz
|
||||
|
@ -97,7 +97,6 @@ common-stats-effect-power = Effect Power
|
||||
common-stats-range = Range
|
||||
common-stats-energy_efficiency = Energy Efficiency
|
||||
common-stats-buff_strength = Buff/Debuff Strength
|
||||
common-stats-crit_chance = Crit Chance
|
||||
common-stats-crit_mult = Crit Mult
|
||||
common-stats-armor = Armor
|
||||
common-stats-poise_res = Stun Res
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = Velocidad
|
||||
common-stats-range = Rango
|
||||
common-stats-energy_efficiency = Eficiencia de energía
|
||||
common-stats-buff_strength = Fuerza de Mejora/Debilitación
|
||||
common-stats-crit_chance = Probabilidad de Crítico
|
||||
common-stats-crit_mult = Multiplicador de Crítico
|
||||
common-stats-armor = Armadura
|
||||
common-stats-poise_res = Resistencia al aturdimiento
|
||||
|
@ -94,7 +94,6 @@ common-stats-effect-power = Potencia de estados alterados
|
||||
common-stats-range = Rango
|
||||
common-stats-energy_efficiency = Eficiencia de aguante
|
||||
common-stats-buff_strength = Potencia de estados beneficiosos
|
||||
common-stats-crit_chance = Probabilidad de daño crítico
|
||||
common-stats-crit_mult = Multiplicador de crítico
|
||||
common-stats-armor = Armadura
|
||||
common-stats-poise_res = Resistencia al aturdimiento
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = Abiadura
|
||||
common-stats-range = Maila
|
||||
common-stats-energy_efficiency = Energia eraginkortasuna
|
||||
common-stats-buff_strength = Buff/Debuff indarra
|
||||
common-stats-crit_chance = Kritiko probabilitatea
|
||||
common-stats-crit_mult = Kritiko biderkatzailea
|
||||
common-stats-armor = Armadura
|
||||
common-stats-poise_res = Orekarako gaitasuna
|
||||
|
@ -95,7 +95,6 @@ common-stats-speed = Vitesse
|
||||
common-stats-range = Portée
|
||||
common-stats-energy_efficiency = Efficacité du coût d'Endurance
|
||||
common-stats-buff_strength = Montant de l'augmentation
|
||||
common-stats-crit_chance = Chance de Crit
|
||||
common-stats-crit_mult = Multiplicateur de Crit
|
||||
common-stats-armor = Armure
|
||||
common-stats-poise_res = Résistance à l'étourdissement
|
||||
|
@ -81,7 +81,6 @@ common-rand_name = Véletlenszerű név
|
||||
common-stats-combat_rating = KÉ
|
||||
common-stats-power = Erő
|
||||
common-stats-speed = Gyorsaság
|
||||
common-stats-crit_chance = Kritikus találat esélye
|
||||
common-stats-crit_mult = Kritikus találat szorzója
|
||||
common-stats-armor = Páncélzat
|
||||
common-stats-poise_res = Megszédíthetőség
|
||||
|
@ -97,7 +97,6 @@ common-stats-effect-power = Potenza effetto
|
||||
common-stats-range = Intervallo
|
||||
common-stats-energy_efficiency = Efficienza energia
|
||||
common-stats-buff_strength = Quantità di aumento/diminuzione
|
||||
common-stats-crit_chance = Probabilità di critico
|
||||
common-stats-crit_mult = Moltiplicatore del critico
|
||||
common-stats-armor = Armatura
|
||||
common-stats-poise_res = Resistenza allo stordimento
|
||||
|
@ -77,7 +77,6 @@ common-rand_appearance = ランダムに見た目を選択
|
||||
common-rand_name = ランダムに名前を選ぶ
|
||||
common-stats-power = Power
|
||||
common-stats-speed = Speed
|
||||
common-stats-crit_chance = Crit Chance
|
||||
common-stats-crit_mult = Crit Mult
|
||||
common-stats-armor = Armor
|
||||
common-stats-poise_res = Poise res
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = 속도
|
||||
common-stats-range = 사거리
|
||||
common-stats-energy_efficiency = 기력 효율
|
||||
common-stats-buff_strength = 힘 버프/디버프
|
||||
common-stats-crit_chance = 치명타 확률
|
||||
common-stats-crit_mult = 치명타 배수
|
||||
common-stats-armor = 방어력
|
||||
common-stats-poise_res = 기절 저항
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = Prędkość
|
||||
common-stats-range = Zasięg
|
||||
common-stats-energy_efficiency = Efektywność Energii
|
||||
common-stats-buff_strength = Siła Efektów Wzmacniających
|
||||
common-stats-crit_chance = % na cios kryt.
|
||||
common-stats-crit_mult = Mnożnik ciosu kryt.
|
||||
common-stats-armor = Obrona
|
||||
common-stats-poise_res = Odp. na ogłuszenie
|
||||
|
@ -96,7 +96,6 @@ common-stats-effect-power = Poder de Efeito
|
||||
common-stats-range = Alcance
|
||||
common-stats-energy_efficiency = Eficiência Energética
|
||||
common-stats-buff_strength = Buff/Debuff de força
|
||||
common-stats-crit_chance = Chance de Crítico
|
||||
common-stats-crit_mult = Multiplicador de Crítico
|
||||
common-stats-armor = Armadura
|
||||
common-stats-poise_res = Resistência a Atordoamento
|
||||
|
@ -90,7 +90,6 @@ common-stats-speed = Viteză
|
||||
common-stats-range = Distanță
|
||||
common-stats-energy_efficiency = Eficiența energiei
|
||||
common-stats-buff_strength = Buff/Debuff Strength
|
||||
common-stats-crit_chance = Șansă Crit
|
||||
common-stats-crit_mult = Multiplicator Crit
|
||||
common-stats-armor = Armură
|
||||
common-stats-poise_res = Stun Res
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = Скорость
|
||||
common-stats-range = Дистанция
|
||||
common-stats-energy_efficiency = Энергоэффективность
|
||||
common-stats-buff_strength = Увеличение силы
|
||||
common-stats-crit_chance = Шанс крита
|
||||
common-stats-crit_mult = Множитель крита
|
||||
common-stats-armor = Броня
|
||||
common-stats-poise_res = Оглушение
|
||||
|
@ -83,7 +83,6 @@ common-rand_name = Насумично име
|
||||
common-stats-combat_rating = CR
|
||||
common-stats-power = Снага
|
||||
common-stats-speed = Брзина
|
||||
common-stats-crit_chance = Крит Шанса
|
||||
common-stats-crit_mult = Мулти Крит
|
||||
common-stats-armor = Оклоп
|
||||
common-stats-poise_res = Отпорност на Омаму
|
||||
|
@ -97,7 +97,6 @@ common-stats-effect-power = Effektstyrka
|
||||
common-stats-range = Räckvidd
|
||||
common-stats-energy_efficiency = Energieffektivitet
|
||||
common-stats-buff_strength = Buff/Debuff-styrka
|
||||
common-stats-crit_chance = Kritisk chans
|
||||
common-stats-crit_mult = Kritisk multi
|
||||
common-stats-armor = Rustning
|
||||
common-stats-poise_res = Motståndskraft
|
||||
|
@ -93,7 +93,6 @@ common-stats-speed = ความเร็ว
|
||||
common-stats-range = ระยะโจมตี
|
||||
common-stats-energy_efficiency = ประสิทธิภาพพลังงาน
|
||||
common-stats-buff_strength = เสริมพลังความแข็งแกร่ง
|
||||
common-stats-crit_chance = โอกาสคริติคอล
|
||||
common-stats-crit_mult = ความรุนแรงคริติคอล
|
||||
common-stats-armor = เกราะ
|
||||
common-stats-poise_res = ความคงทน
|
||||
|
@ -83,7 +83,6 @@ common-rand_appearance = Rastgele görünüm
|
||||
common-stats-combat_rating = DP
|
||||
common-stats-power = Güç
|
||||
common-stats-speed = Hız
|
||||
common-stats-crit_chance = Kritik Şansı
|
||||
common-stats-crit_mult = Kritik Çarpanı
|
||||
common-stats-armor = Zırh
|
||||
common-stats-energy_max = Maksimum Enerji
|
||||
|
@ -97,7 +97,6 @@ common-stats-effect-power = Сила ефекту
|
||||
common-stats-range = Дистанція
|
||||
common-stats-energy_efficiency = Енергоощадливість
|
||||
common-stats-buff_strength = Сила бафу/дебафу
|
||||
common-stats-crit_chance = Крит. шанс
|
||||
common-stats-crit_mult = Крит. множник
|
||||
common-stats-armor = Броня
|
||||
common-stats-poise_res = Супротив приголомшенню
|
||||
|
@ -81,7 +81,6 @@ common-rand_name = Tên ngẫu nhiên
|
||||
common-stats-combat_rating = CR
|
||||
common-stats-power = Sức Mạnh
|
||||
common-stats-speed = Tốc Độ
|
||||
common-stats-crit_chance = Tỉ Lệ Chí Mạng
|
||||
common-stats-armor = Giáp
|
||||
common-stats-energy_max = Năng Lượng Tối Đa
|
||||
common-stats-energy_reward = Thưởng Năng Lượng
|
||||
|
@ -95,7 +95,6 @@ common-stats-effect-power = 效果威力
|
||||
common-stats-range = 范围
|
||||
common-stats-energy_efficiency = 耐力消耗
|
||||
common-stats-buff_strength = 增幅
|
||||
common-stats-crit_chance = 暴击率
|
||||
common-stats-crit_mult = 暴击倍率
|
||||
common-stats-armor = 护甲
|
||||
common-stats-poise_res = 韧性
|
||||
|
@ -44,6 +44,12 @@ pub enum AttackSource {
|
||||
Explosion,
|
||||
}
|
||||
|
||||
pub const FULL_FLANK_ANGLE: f32 = std::f32::consts::PI / 4.0;
|
||||
pub const PARTIAL_FLANK_ANGLE: f32 = std::f32::consts::PI * 3.0 / 4.0;
|
||||
// NOTE: Do we want to change this to be a configurable parameter on body?
|
||||
pub const PROJECTILE_HEADSHOT_PROPORTION: f32 = 0.1;
|
||||
pub const BEAM_DURATION_PRECISION: f32 = 2.5;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AttackerInfo<'a> {
|
||||
pub entity: EcsEntity,
|
||||
@ -73,6 +79,7 @@ pub struct AttackOptions {
|
||||
pub target_dodging: bool,
|
||||
pub may_harm: bool,
|
||||
pub target_group: GroupTarget,
|
||||
pub precision_mult: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)] // TODO: Yeet clone derive
|
||||
@ -202,6 +209,7 @@ impl Attack {
|
||||
target_dodging,
|
||||
may_harm,
|
||||
target_group,
|
||||
precision_mult,
|
||||
} = options;
|
||||
|
||||
// target == OutOfGroup is basic heuristic that this
|
||||
@ -217,7 +225,10 @@ impl Attack {
|
||||
matches!(attack_effect.target, Some(GroupTarget::OutOfGroup))
|
||||
&& (target_dodging || !may_harm)
|
||||
};
|
||||
let is_crit = false;
|
||||
let precision_mult = attacker
|
||||
.and_then(|a| a.stats)
|
||||
.and_then(|s| s.precision_multiplier_override)
|
||||
.or(precision_mult);
|
||||
let mut is_applied = false;
|
||||
let mut accumulated_damage = 0.0;
|
||||
let damage_modifier = attacker
|
||||
@ -244,7 +255,7 @@ impl Attack {
|
||||
let change = damage.damage.calculate_health_change(
|
||||
damage_reduction,
|
||||
attacker.map(|x| x.into()),
|
||||
is_crit,
|
||||
precision_mult,
|
||||
self.crit_multiplier,
|
||||
strength_modifier * damage_modifier,
|
||||
time,
|
||||
@ -273,7 +284,7 @@ impl Attack {
|
||||
by: attacker.map(|x| x.into()),
|
||||
cause: Some(damage.damage.source),
|
||||
time,
|
||||
crit: is_crit,
|
||||
crit: precision_mult.is_some(),
|
||||
instance: damage_instance,
|
||||
};
|
||||
emit(ServerEvent::HealthChange {
|
||||
@ -324,7 +335,7 @@ impl Attack {
|
||||
by: attacker.map(|x| x.into()),
|
||||
cause: Some(damage.damage.source),
|
||||
instance: damage_instance,
|
||||
crit: is_crit,
|
||||
crit: precision_mult.is_some(),
|
||||
time,
|
||||
};
|
||||
emit(ServerEvent::HealthChange {
|
||||
@ -1014,18 +1025,14 @@ impl Damage {
|
||||
self,
|
||||
damage_reduction: f32,
|
||||
damage_contributor: Option<DamageContributor>,
|
||||
is_crit: bool,
|
||||
precision_mult: Option<f32>,
|
||||
crit_mult: f32,
|
||||
damage_modifier: f32,
|
||||
time: Time,
|
||||
instance: u64,
|
||||
) -> HealthChange {
|
||||
let mut damage = self.value * damage_modifier;
|
||||
let critdamage = if is_crit {
|
||||
damage * (crit_mult - 1.0)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let critdamage = damage * precision_mult.unwrap_or(0.0) * (crit_mult - 1.0);
|
||||
match self.source {
|
||||
DamageSource::Melee
|
||||
| DamageSource::Projectile
|
||||
@ -1042,7 +1049,7 @@ impl Damage {
|
||||
by: damage_contributor,
|
||||
cause: Some(self.source),
|
||||
time,
|
||||
crit: is_crit,
|
||||
crit: precision_mult.is_some(),
|
||||
instance,
|
||||
}
|
||||
},
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{combat::Attack, resources::Secs};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage, Entity as EcsEntity};
|
||||
use vek::*;
|
||||
@ -14,6 +15,16 @@ pub struct Beam {
|
||||
pub bezier: QuadraticBezier3<f32>,
|
||||
#[serde(skip)]
|
||||
pub hit_entities: Vec<EcsEntity>,
|
||||
#[serde(skip)]
|
||||
pub hit_durations: HashMap<EcsEntity, u32>,
|
||||
}
|
||||
|
||||
impl Beam {
|
||||
pub fn hit_entities_and_durations(
|
||||
&mut self,
|
||||
) -> (&Vec<EcsEntity>, &mut HashMap<EcsEntity, u32>) {
|
||||
(&self.hit_entities, &mut self.hit_durations)
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Beam {
|
||||
|
@ -333,10 +333,7 @@ impl BuffKind {
|
||||
BuffKind::Hastened => vec![
|
||||
BuffEffect::MovementSpeed(1.0 + data.strength),
|
||||
BuffEffect::AttackSpeed(1.0 + data.strength),
|
||||
BuffEffect::CriticalChance {
|
||||
kind: ModifierKind::Multiplicative,
|
||||
val: 0.0,
|
||||
},
|
||||
BuffEffect::PrecisionOverride(0.0),
|
||||
],
|
||||
BuffKind::Fortitude => vec![
|
||||
BuffEffect::PoiseReduction(nn_scaling(data.strength)),
|
||||
@ -388,10 +385,7 @@ impl BuffKind {
|
||||
AttackEffect::new(None, CombatEffect::Lifesteal(data.strength))
|
||||
.with_requirement(CombatRequirement::TargetHasBuff(BuffKind::Bleeding)),
|
||||
)],
|
||||
BuffKind::ImminentCritical => vec![BuffEffect::CriticalChance {
|
||||
kind: ModifierKind::Additive,
|
||||
val: 1.0,
|
||||
}],
|
||||
BuffKind::ImminentCritical => vec![BuffEffect::PrecisionOverride(1.0)],
|
||||
BuffKind::Fury => vec![BuffEffect::AttackEffect(
|
||||
AttackEffect::new(None, CombatEffect::Combo(data.strength.round() as i32))
|
||||
.with_requirement(CombatRequirement::AnyDamage),
|
||||
@ -558,11 +552,8 @@ pub enum BuffEffect {
|
||||
},
|
||||
/// Modifier to the amount of damage dealt with attacks
|
||||
AttackDamage(f32),
|
||||
/// Multiplies crit chance of attacks
|
||||
CriticalChance {
|
||||
kind: ModifierKind,
|
||||
val: f32,
|
||||
},
|
||||
/// Overrides the precision multiplier applied to an attack
|
||||
PrecisionOverride(f32),
|
||||
/// Changes body.
|
||||
BodyChange(Body),
|
||||
BuffImmunity(BuffKind),
|
||||
|
@ -134,7 +134,7 @@ impl PoiseState {
|
||||
}
|
||||
|
||||
/// Returns the multiplier on poise damage to health damage for when the
|
||||
/// target is in a poise state
|
||||
/// target is in a poise state, also is used for precision
|
||||
pub fn damage_multiplier(&self) -> f32 {
|
||||
match self {
|
||||
Self::Interrupted => 0.1,
|
||||
|
@ -63,7 +63,7 @@ pub struct Stats {
|
||||
pub max_energy_modifiers: StatsModifier,
|
||||
pub poise_damage_modifier: f32,
|
||||
pub attack_damage_modifier: f32,
|
||||
pub crit_chance_modifier: StatsModifier,
|
||||
pub precision_multiplier_override: Option<f32>,
|
||||
pub swim_speed_modifier: f32,
|
||||
/// This adds effects to any attacks that the entity makes
|
||||
pub effects_on_attack: Vec<AttackEffect>,
|
||||
@ -90,7 +90,7 @@ impl Stats {
|
||||
max_energy_modifiers: StatsModifier::default(),
|
||||
poise_damage_modifier: 1.0,
|
||||
attack_damage_modifier: 1.0,
|
||||
crit_chance_modifier: StatsModifier::default(),
|
||||
precision_multiplier_override: None,
|
||||
swim_speed_modifier: 1.0,
|
||||
effects_on_attack: Vec::new(),
|
||||
mitigations_penetration: 0.0,
|
||||
|
@ -17,6 +17,7 @@ use crate::{
|
||||
terrain::Block,
|
||||
util::Dir,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
@ -132,6 +133,7 @@ impl CharacterBehavior for Data {
|
||||
duration: self.static_data.beam_duration,
|
||||
tick_dur: Secs(1.0 / self.static_data.tick_rate as f64),
|
||||
hit_entities: Vec::new(),
|
||||
hit_durations: HashMap::new(),
|
||||
specifier: self.static_data.specifier,
|
||||
bezier: QuadraticBezier3 {
|
||||
start: data.pos.0,
|
||||
|
@ -73,6 +73,11 @@ impl<'a> System<'a> for Sys {
|
||||
.for_each(|(pos, ori, char_state, mut beam)| {
|
||||
// Clear hit entities list if list should be cleared
|
||||
if read_data.time.0 % beam.tick_dur.0 < read_data.dt.0 as f64 {
|
||||
let (hit_entities, hit_durations) = beam.hit_entities_and_durations();
|
||||
hit_durations.retain(|e, _| hit_entities.contains(e));
|
||||
for entity in hit_entities {
|
||||
*hit_durations.entry(*entity).or_insert(0) += 1;
|
||||
}
|
||||
beam.hit_entities.clear();
|
||||
}
|
||||
// Update start, end, and control positions of beam bezier
|
||||
@ -227,10 +232,45 @@ impl<'a> System<'a> for Sys {
|
||||
Some(entity),
|
||||
target,
|
||||
);
|
||||
|
||||
let precision_from_flank = {
|
||||
let beam_dir = beam.bezier.ctrl - beam.bezier.start;
|
||||
let angle = target_info.ori.map_or(std::f32::consts::PI, |t_ori| {
|
||||
t_ori.look_dir().angle_between(beam_dir)
|
||||
});
|
||||
if angle < combat::FULL_FLANK_ANGLE {
|
||||
Some(1.0)
|
||||
} else if angle < combat::PARTIAL_FLANK_ANGLE {
|
||||
Some(0.5)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let precision_from_time = {
|
||||
if let Some(ticks) = beam.hit_durations.get(&target) {
|
||||
let dur = *ticks as f32 * beam.tick_dur.0 as f32;
|
||||
let mult =
|
||||
(dur / combat::BEAM_DURATION_PRECISION).clamp(0.0, 1.0);
|
||||
Some(mult)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Is there a more idiomatic way to do this (taking the max of 2
|
||||
// options)?
|
||||
let precision_mult = precision_from_flank
|
||||
.map(|flank| {
|
||||
precision_from_time.map_or(flank, |head: f32| head.max(flank))
|
||||
})
|
||||
.or(precision_from_time);
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging,
|
||||
may_harm,
|
||||
target_group,
|
||||
precision_mult,
|
||||
};
|
||||
|
||||
beam.attack.apply_attack(
|
||||
|
@ -674,9 +674,12 @@ fn execute_effect(
|
||||
BuffEffect::AttackDamage(dam) => {
|
||||
stat.attack_damage_modifier *= *dam;
|
||||
},
|
||||
BuffEffect::CriticalChance { kind, val } => match kind {
|
||||
ModifierKind::Additive => stat.crit_chance_modifier.add_mod += val,
|
||||
ModifierKind::Multiplicative => stat.crit_chance_modifier.mult_mod *= val,
|
||||
BuffEffect::PrecisionOverride(val) => {
|
||||
// Use lower of precision multiplier overrides
|
||||
stat.precision_multiplier_override = stat
|
||||
.precision_multiplier_override
|
||||
.map(|mult| mult.min(*val))
|
||||
.or(Some(*val));
|
||||
},
|
||||
BuffEffect::BodyChange(b) => {
|
||||
// For when an entity is under the effects of multiple de/buffs that change the
|
||||
|
@ -196,6 +196,8 @@ impl<'a> System<'a> for Sys {
|
||||
stats: read_data.stats.get(attacker),
|
||||
});
|
||||
|
||||
let target_ori = read_data.orientations.get(target);
|
||||
let target_char_state = read_data.char_states.get(target);
|
||||
let target_info = TargetInfo {
|
||||
entity: target,
|
||||
uid: *uid_b,
|
||||
@ -203,8 +205,8 @@ impl<'a> System<'a> for Sys {
|
||||
stats: read_data.stats.get(target),
|
||||
health: read_data.healths.get(target),
|
||||
pos: pos_b.0,
|
||||
ori: read_data.orientations.get(target),
|
||||
char_state: read_data.char_states.get(target),
|
||||
ori: target_ori,
|
||||
char_state: target_char_state,
|
||||
energy: read_data.energies.get(target),
|
||||
buffs: read_data.buffs.get(target),
|
||||
};
|
||||
@ -218,10 +220,39 @@ impl<'a> System<'a> for Sys {
|
||||
target,
|
||||
);
|
||||
|
||||
let precision_from_flank = {
|
||||
let angle = target_ori.map_or(std::f32::consts::PI, |t_ori| {
|
||||
t_ori.look_dir().angle_between(*ori.look_dir())
|
||||
});
|
||||
if angle < combat::FULL_FLANK_ANGLE {
|
||||
Some(1.0)
|
||||
} else if angle < combat::PARTIAL_FLANK_ANGLE {
|
||||
Some(0.5)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let precision_from_poise = {
|
||||
if let Some(CharacterState::Stunned(data)) = target_char_state {
|
||||
Some(data.static_data.poise_state.damage_multiplier())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Is there a more idiomatic way to do this (taking the max of 2 options)?
|
||||
let precision_mult = precision_from_flank
|
||||
.map(|flank| {
|
||||
precision_from_poise.map_or(flank, |head: f32| head.max(flank))
|
||||
})
|
||||
.or(precision_from_poise);
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging,
|
||||
may_harm,
|
||||
target_group,
|
||||
precision_mult,
|
||||
};
|
||||
|
||||
let strength =
|
||||
|
@ -157,6 +157,7 @@ impl<'a> System<'a> for Sys {
|
||||
owner,
|
||||
ori: orientations.get(entity),
|
||||
pos,
|
||||
vel,
|
||||
};
|
||||
|
||||
let target = entity_of(other);
|
||||
@ -247,6 +248,7 @@ struct ProjectileInfo<'a> {
|
||||
owner: Option<EcsEntity>,
|
||||
ori: Option<&'a Ori>,
|
||||
pos: &'a Pos,
|
||||
vel: &'a Vel,
|
||||
}
|
||||
|
||||
struct ProjectileTargetInfo<'a> {
|
||||
@ -343,10 +345,76 @@ fn dispatch_hit(
|
||||
.get(target)
|
||||
.and_then(|cs| cs.attack_immunities())
|
||||
.map_or(false, |i| i.projectiles);
|
||||
|
||||
let precision_from_flank = {
|
||||
let angle = target_info.ori.map_or(std::f32::consts::PI, |t_ori| {
|
||||
t_ori.look_dir().angle_between(*projectile_dir)
|
||||
});
|
||||
if angle < combat::FULL_FLANK_ANGLE {
|
||||
Some(1.0)
|
||||
} else if angle < combat::PARTIAL_FLANK_ANGLE {
|
||||
Some(0.5)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let precision_from_head = {
|
||||
let curr_pos = projectile_info.pos.0;
|
||||
let last_pos = projectile_info.pos.0 - projectile_info.vel.0 * read_data.dt.0;
|
||||
let vel = projectile_info.vel.0;
|
||||
let (target_height, target_radius) = read_data
|
||||
.bodies
|
||||
.get(target)
|
||||
.map_or((0.0, 0.0), |b| (b.height(), b.max_radius()));
|
||||
let head_top_pos = target_pos.with_z(target_pos.z + target_height);
|
||||
let head_bottom_pos = head_top_pos.with_z(
|
||||
head_top_pos.z - target_height * combat::PROJECTILE_HEADSHOT_PROPORTION,
|
||||
);
|
||||
let headshot = if (curr_pos.z < head_bottom_pos.z && last_pos.z < head_bottom_pos.z)
|
||||
|| (curr_pos.z > head_top_pos.z && last_pos.z > head_top_pos.z)
|
||||
{
|
||||
false
|
||||
} else if curr_pos.z > head_top_pos.z
|
||||
|| curr_pos.z < head_bottom_pos.z
|
||||
|| last_pos.z > head_top_pos.z
|
||||
|| last_pos.z < head_bottom_pos.z
|
||||
{
|
||||
let proj_top_intersection = {
|
||||
let t = (head_top_pos.z - last_pos.z) / vel.z;
|
||||
last_pos + vel * t
|
||||
};
|
||||
let proj_bottom_intersection = {
|
||||
let t = (head_bottom_pos.z - last_pos.z) / vel.z;
|
||||
last_pos + vel * t
|
||||
};
|
||||
head_top_pos.distance_squared(proj_top_intersection) < target_radius.powi(2)
|
||||
|| head_bottom_pos.distance_squared(proj_bottom_intersection)
|
||||
< target_radius.powi(2)
|
||||
} else {
|
||||
let trajectory = LineSegment3 {
|
||||
start: last_pos,
|
||||
end: curr_pos,
|
||||
};
|
||||
let head_middle_pos = head_bottom_pos.with_z(
|
||||
head_bottom_pos.z
|
||||
+ target_height * combat::PROJECTILE_HEADSHOT_PROPORTION * 0.5,
|
||||
);
|
||||
trajectory.distance_to_point(head_middle_pos) < target_radius
|
||||
};
|
||||
if headshot { Some(1.0) } else { None }
|
||||
};
|
||||
|
||||
// Is there a more idiomatic way to do this (taking the max of 2 options)?
|
||||
let precision_mult = precision_from_flank
|
||||
.map(|flank| precision_from_head.map_or(flank, |head: f32| head.max(flank)))
|
||||
.or(precision_from_head);
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging,
|
||||
may_harm,
|
||||
target_group: projectile_target_info.target_group,
|
||||
precision_mult,
|
||||
};
|
||||
|
||||
attack.apply_attack(
|
||||
|
@ -234,10 +234,13 @@ impl<'a> System<'a> for Sys {
|
||||
shockwave_owner,
|
||||
target,
|
||||
);
|
||||
// Shockwaves aren't precise, and thus cannot be a precise strike
|
||||
let precision_mult = None;
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging,
|
||||
may_harm,
|
||||
target_group,
|
||||
precision_mult,
|
||||
};
|
||||
|
||||
shockwave.properties.attack.apply_attack(
|
||||
|
@ -670,7 +670,7 @@ pub fn handle_land_on_ground(
|
||||
let change = damage.calculate_health_change(
|
||||
damage_reduction,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
0.0,
|
||||
1.0,
|
||||
*time,
|
||||
@ -1049,10 +1049,13 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
||||
// PvP check
|
||||
let may_harm =
|
||||
combat::may_harm(alignments, players, id_maps, owner_entity, entity_b);
|
||||
// Explosions aren't precise, and thus cannot be a precise strike
|
||||
let precision_mult = None;
|
||||
let attack_options = combat::AttackOptions {
|
||||
target_dodging,
|
||||
may_harm,
|
||||
target_group,
|
||||
precision_mult,
|
||||
};
|
||||
|
||||
let time = server.state.ecs().read_resource::<Time>();
|
||||
|
@ -196,7 +196,7 @@ impl StateExt for State {
|
||||
&msm,
|
||||
),
|
||||
damage_contributor,
|
||||
false,
|
||||
None,
|
||||
0.0,
|
||||
1.0,
|
||||
*time,
|
||||
|
Loading…
Reference in New Issue
Block a user