feat: added puncture and penetrate
This commit is contained in:
parent
451efd2bb7
commit
6c3c50689a
4 changed files with 104 additions and 59 deletions
|
|
@ -62,6 +62,10 @@ pub enum WeaponBonusType {
|
|||
// Attack nullification types
|
||||
Homerun,
|
||||
Parry,
|
||||
|
||||
// Armour mitigation
|
||||
Puncture,
|
||||
Penetrate,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
|
|
@ -183,6 +187,12 @@ impl BonusPartDamageBonus {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Component)]
|
||||
pub enum ArmourBypassBonus {
|
||||
Puncture { chance: f32 },
|
||||
Penetrate { mitigation: f32 },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Component, Display)]
|
||||
#[cfg_attr(feature = "json", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "json", serde(rename_all = "snake_case"))]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use proxisim_models::bundle::{
|
||||
armour::{ArmourBodyPart, ArmourBodyParts},
|
||||
bonus::DamageMitigationBonus,
|
||||
bonus::{ArmourBypassBonus, DamageMitigationBonus},
|
||||
player::{
|
||||
Attacker, BodyPart, ChooseWeapon, CombatTurns, Current, CurrentTarget, Defeated, Defender,
|
||||
FightEndType, Health, PartDamageBonus, Player, PlayerStrategy, Weapons,
|
||||
|
|
@ -188,10 +188,11 @@ pub fn use_damaging_weapon(
|
|||
),
|
||||
(With<CurrentTarget>, Without<Current>),
|
||||
>,
|
||||
(armour_q, damage_q, mut mitigation_q): (
|
||||
(armour_q, damage_q, mut mitigation_q, bypass_q): (
|
||||
Query<&ArmourBodyPart>,
|
||||
Query<(Entity, &DeferredDamage)>,
|
||||
Query<Option<&mut DamageMitigationBonus>>,
|
||||
Query<(&ArmourBypassBonus)>,
|
||||
),
|
||||
(damage_proc_q, part_bonus_q): (Query<&DamageProcEffect>, Query<&PartDamageBonus>),
|
||||
(mut ammo_q, mut temp_q): (
|
||||
|
|
@ -368,8 +369,8 @@ pub fn use_damaging_weapon(
|
|||
metrics.increment_counter(Some(weapon), "hit", 1);
|
||||
|
||||
let armour_parts = armour_q.get(armour_parts.0[body_part.into()]).unwrap();
|
||||
let piece = rng.sample(armour_parts);
|
||||
let armour_mitigation = piece.map_or(0.0, |p| p.armour_value);
|
||||
let mut piece = rng.sample(armour_parts);
|
||||
let mut armour_mitigation = piece.map_or(0.0, |p| p.armour_value);
|
||||
|
||||
// NOTE: Proxima's simulator seems to have the damage spread be between 95% and 105%,
|
||||
// but from my brief tests it seems that 100% to 110% lines up better, at least for h2h.
|
||||
|
|
@ -384,9 +385,25 @@ pub fn use_damaging_weapon(
|
|||
}
|
||||
}
|
||||
|
||||
let bonus_mitigation = match piece {
|
||||
Some(piece) => {
|
||||
if let Some(mut mitigation) = mitigation_q.get_mut(piece.armour).unwrap() {
|
||||
let bonus_mitigation = 'block: {
|
||||
match piece {
|
||||
Some(part) => {
|
||||
for bypass in bypass_q.iter_many(children) {
|
||||
match bypass {
|
||||
ArmourBypassBonus::Penetrate { mitigation } => {
|
||||
armour_mitigation *= 1.0 - mitigation;
|
||||
}
|
||||
ArmourBypassBonus::Puncture { chance } => {
|
||||
if *chance >= 1.0 || rng.random_bool(*chance as f64) {
|
||||
armour_mitigation = 0.0;
|
||||
piece = None;
|
||||
break 'block 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut mitigation) = mitigation_q.get_mut(part.armour).unwrap() {
|
||||
match mitigation.as_mut() {
|
||||
DamageMitigationBonus::Impregnable { mitigation }
|
||||
if *slot == WeaponSlot::Melee =>
|
||||
|
|
@ -413,7 +430,7 @@ pub fn use_damaging_weapon(
|
|||
}
|
||||
}
|
||||
DamageMitigationBonus::Kinetokinesis { mitigation } => {
|
||||
commands.entity(piece.armour).insert(
|
||||
commands.entity(part.armour).insert(
|
||||
DamageMitigationBonus::ActiveKinetokinesis {
|
||||
mitigation: *mitigation,
|
||||
remaining_turns: 10,
|
||||
|
|
@ -428,7 +445,7 @@ pub fn use_damaging_weapon(
|
|||
*remaining_turns -= 1;
|
||||
|
||||
if *remaining_turns == 0 {
|
||||
commands.entity(piece.armour).insert(
|
||||
commands.entity(part.armour).insert(
|
||||
DamageMitigationBonus::Kinetokinesis {
|
||||
mitigation: *mitigation,
|
||||
},
|
||||
|
|
@ -444,6 +461,7 @@ pub fn use_damaging_weapon(
|
|||
}
|
||||
}
|
||||
None => 0.0,
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: special ammo
|
||||
|
|
@ -503,7 +521,7 @@ pub fn use_damaging_weapon(
|
|||
bonus.spawn(target, &mut effects, &mut rng.0);
|
||||
}
|
||||
}
|
||||
DamageProcEffect::DamageOverTimer { value, kind } => {
|
||||
DamageProcEffect::DamageOverTime { value, kind } => {
|
||||
let chance = (value / 100.0) as f64;
|
||||
if chance > 1.0 || rng.random_bool(chance) {
|
||||
match kind {
|
||||
|
|
@ -562,8 +580,8 @@ pub fn use_damaging_weapon(
|
|||
}
|
||||
}
|
||||
|
||||
// Technically only douple tap and blindfire have this condition, but we can run into with
|
||||
// invalid bonus/weapon combinations without checking this for all bonuses
|
||||
// Technically only douple tap and blindfire have this condition, but we can run into
|
||||
// panics with invalid bonus/weapon combinations without checking this for all bonuses
|
||||
if ammo.as_ref().is_some_and(|(a, _, _)| a.0 == 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -679,5 +697,7 @@ pub(crate) fn configure(stages: &mut Stages) {
|
|||
.before(change_roles),
|
||||
);
|
||||
stages.post_fight.add_systems(record_post_fight_stats);
|
||||
stages.restore.add_systems(restore_initial_state);
|
||||
stages
|
||||
.restore
|
||||
.add_systems((restore_initial_state, restore_health));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use proxisim_models::bundle::{
|
||||
bonus::{BonusPartDamageBonus, BonusValue, WeaponBonusType},
|
||||
bonus::{ArmourBypassBonus, BonusPartDamageBonus, BonusValue, WeaponBonusType},
|
||||
player::PartDamageBonus,
|
||||
stat::{
|
||||
AdditiveBonus, AmmoControl, Clips, CritRate, DamageBonus, SimpleStatBonus,
|
||||
|
|
@ -431,12 +431,27 @@ pub(crate) fn prepare_bonuses(
|
|||
WeaponBonusType::Bleed => {
|
||||
commands
|
||||
.entity(weapon.parent())
|
||||
.with_child(DamageProcEffect::DamageOverTimer {
|
||||
.with_child(DamageProcEffect::DamageOverTime {
|
||||
value: value.0,
|
||||
kind: DamageOverTimeType::Bleed,
|
||||
});
|
||||
}
|
||||
|
||||
WeaponBonusType::Puncture => {
|
||||
commands
|
||||
.entity(weapon.parent())
|
||||
.with_child(ArmourBypassBonus::Puncture {
|
||||
chance: value.0 / 100.0,
|
||||
});
|
||||
}
|
||||
WeaponBonusType::Penetrate => {
|
||||
commands
|
||||
.entity(weapon.parent())
|
||||
.with_child(ArmourBypassBonus::Penetrate {
|
||||
mitigation: value.0 / 100.0,
|
||||
});
|
||||
}
|
||||
|
||||
val => unimplemented!("{val:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ pub enum DamageProcEffect {
|
|||
value: f32,
|
||||
bonus: SelfStatusEffect,
|
||||
},
|
||||
DamageOverTimer {
|
||||
DamageOverTime {
|
||||
value: f32,
|
||||
kind: DamageOverTimeType,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue