diff --git a/models/src/bundle/bonus.rs b/models/src/bundle/bonus.rs index a7793e3..8a290ae 100644 --- a/models/src/bundle/bonus.rs +++ b/models/src/bundle/bonus.rs @@ -66,6 +66,10 @@ pub enum WeaponBonusType { // Armour mitigation Puncture, Penetrate, + + // Misc + Execute, + Deadly, } #[derive(Component)] diff --git a/src/defender.json b/src/defender.json index 530e51e..4c74f16 100644 --- a/src/defender.json +++ b/src/defender.json @@ -1,22 +1,24 @@ { "level": 100, - "name": "Evil Pyrit", + "name": "Lynaikitsu", "stats": { - "str": 1415286156, - "spd": 1344108854, - "def": 1425974550, - "dex": 2182078916 + "str": 8910798, + "spd": 9802681, + "def": 3132400125, + "dex": 787 }, "strategy": { "type": "in_order", - "order": [], + "order": [ + "primary" + ], "reload": false }, "education": { "bio2350": true, "bio2380": true, "bio2410": true, - "cbt2790": true, + "cbt2790": false, "cbt2820": true, "cbt2830": true, "cbt2840": true, @@ -25,41 +27,41 @@ "cbt2125": true, "gen2116": true, "gen2119": true, - "haf2104": true, - "haf2105": true, - "haf2106": true, - "haf2107": true, - "haf2108": true, - "haf2109": true, + "haf2104": false, + "haf2105": false, + "haf2106": false, + "haf2107": false, + "haf2108": false, + "haf2109": false, "his2160": true, "his2170": true, - "mth2240": true, - "mth2250": true, - "mth2260": true, - "mth2320": true, + "mth2240": false, + "mth2250": false, + "mth2260": false, + "mth2320": false, "mth2310": true, "mth3330": true, - "psy2640": true, - "psy2650": true, - "psy2660": true, - "psy2670": true, - "def2710": true, - "def2730": true, - "def2740": true, - "def2750": true, - "def2760": true, + "psy2640": false, + "psy2650": false, + "psy2660": false, + "psy2670": false, + "def2710": false, + "def2730": false, + "def2740": false, + "def2750": false, + "def2760": false, "def3770": true, "spt2480": true, - "spt2490": true, - "spt2500": true + "spt2490": false, + "spt2500": false }, "merits": { "life": 10, "crits": 10, - "brawn": 10, - "protection": 10, - "sharpness": 10, - "evasion": 10, + "brawn": 0, + "protection": 0, + "sharpness": 0, + "evasion": 0, "heavy_artillery_mastery": 0, "machine_gun_mastery": 0, "rifle_mastery": 5, @@ -85,13 +87,137 @@ "weapons": { "primary": null, "secondary": null, - "melee": null + "melee": null, + "temporary": null }, "armour": { - "helmet": null, - "body": null, - "pants": null, - "gloves": null, - "boots": null + "helmet": { + "slot": "head", + "id": 680, + "name": "EOD Helmet", + "base_armour": 55, + "armour": 55, + "coverage": { + "body": 10.220000267028809, + "heart": 0, + "stomach": 0, + "chest": 0, + "arm": 0, + "groin": 0, + "leg": 0, + "throat": 42.900001525878906, + "hand": 0, + "foot": 0, + "head": 100 + }, + "immunities": [ + "concussion_grenade", + "pepper_spray" + ], + "bonus": { + "kind": "impassable", + "value": 0 + } + }, + "body": { + "slot": "body", + "id": 681, + "name": "EOD Apron", + "base_armour": 55, + "armour": 55, + "coverage": { + "body": 55.2400016784668, + "heart": 100, + "stomach": 100, + "chest": 100, + "arm": 100, + "groin": 100, + "leg": 17.579999923706055, + "throat": 100, + "hand": 16.8799991607666, + "foot": 0, + "head": 4.679999828338623 + }, + "immunities": [], + "bonus": { + "kind": "impassable", + "value": 0 + } + }, + "pants": { + "slot": "legs", + "id": 682, + "name": "EOD Pants", + "base_armour": 55, + "armour": 55, + "coverage": { + "body": 26.010000228881836, + "heart": 0, + "stomach": 23.940000534057617, + "chest": 0, + "arm": 0, + "groin": 100, + "leg": 100, + "throat": 0, + "hand": 0, + "foot": 20.1299991607666, + "head": 0 + }, + "immunities": [], + "bonus": { + "kind": "impassable", + "value": 0 + } + }, + "gloves": { + "slot": "hands", + "id": 684, + "name": "EOD Gloves", + "base_armour": 55, + "armour": 55, + "coverage": { + "body": 14.369999885559082, + "heart": 0, + "stomach": 0, + "chest": 0, + "arm": 0.5, + "groin": 0, + "leg": 0, + "throat": 0, + "hand": 100, + "foot": 0, + "head": 0 + }, + "immunities": [], + "bonus": { + "kind": "impassable", + "value": 0 + } + }, + "boots": { + "slot": "feet", + "id": 683, + "name": "EOD Boots", + "base_armour": 55, + "armour": 55, + "coverage": { + "body": 15.170000076293945, + "heart": 0, + "stomach": 0, + "chest": 0, + "arm": 0, + "groin": 0, + "leg": 6.190000057220459, + "throat": 0, + "hand": 0, + "foot": 100, + "head": 0 + }, + "immunities": [], + "bonus": { + "kind": "impassable", + "value": 0 + } + } } } diff --git a/src/player/mod.rs b/src/player/mod.rs index a6d8bba..d4ab2ab 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -192,7 +192,7 @@ pub fn use_damaging_weapon( Query<&ArmourBodyPart>, Query<(Entity, &DeferredDamage)>, Query>, - Query<(&ArmourBypassBonus)>, + Query<&ArmourBypassBonus>, ), (damage_proc_q, part_bonus_q): (Query<&DamageProcEffect>, Query<&PartDamageBonus>), (mut ammo_q, mut temp_q): ( @@ -245,6 +245,7 @@ pub fn use_damaging_weapon( commands.entity(instance).despawn(); if p_health.0 == 0 { + commands.entity(player).insert(Defeated); log!(logger, "fight_end", { actor: target, recipient: player, @@ -466,7 +467,7 @@ pub fn use_damaging_weapon( // TODO: special ammo - let dmg = dmg_intrinsic + let mut dmg = dmg_intrinsic * w_dmg.0 * (1.0 + dmg_bonus.value) * (1.0 - armour_mitigation) @@ -474,12 +475,12 @@ pub fn use_damaging_weapon( * (1.0 - bonus_mitigation) * mult * dmg_spread; - let dmg = dmg.round() as u32; + let mut dmg_i = dmg.round() as u32; - metrics.record_histogram(Some(player), "dmg", dmg); - metrics.record_histogram(Some(weapon), "dmg", dmg); + metrics.record_histogram(Some(player), "dmg", dmg_i); + metrics.record_histogram(Some(weapon), "dmg", dmg_i); - if dmg > 0 { + if dmg_i > 0 { for effect in damage_proc_q.iter_many(children) { match *effect { DamageProcEffect::MultiTurn { value, bonus } => { @@ -528,18 +529,54 @@ pub fn use_damaging_weapon( DamageOverTimeType::Bleed => { commands .entity(target) - .insert(DamageOverTime::::new(dmg)); + .insert(DamageOverTime::::new(dmg_i)); } } } } + DamageProcEffect::Deadly { chance } => { + if chance >= 1.0 || rng.random_bool(chance as f64) { + dmg = dmg_intrinsic + * w_dmg.0 + * (1.0 + dmg_bonus.value + 5.0) + * (1.0 - armour_mitigation) + * (1.0 - def_mitigation) + * (1.0 - bonus_mitigation) + * mult + * dmg_spread; + dmg_i = dmg.round() as u32; + } + } + DamageProcEffect::Execute { cutoff } => { + if health.0 as f32 / target_max_health.value as f32 <= cutoff { + commands.entity(target).insert(Defeated); + let health_before = health.0; + health.0 = 0; + log!(logger, "executed", { + actor: player, + recipient: target, + health_before, + }); + log!(logger, "fight_end", { + actor: player, + recipient: target, + fight_end_type: %if attacker { + FightEndType::Victory + } else { + FightEndType::Loss + }, + }); + metrics.increment_counter(Some(player), "victory", 1); + return; + } + } } } } let health_before = health.0; - health.0 = health.0.saturating_sub(dmg as u16); + health.0 = health.0.saturating_sub(dmg_i as u16); log!(logger, "hit_target", { actor: player, @@ -551,7 +588,7 @@ pub fn use_damaging_weapon( rounds, health_before: health_before, health_after: health.0, - dmg, + dmg: dmg_i, dmg_spread, dmg_intrinsic, dmg_weapon: w_dmg.0, diff --git a/src/weapon/bonus.rs b/src/weapon/bonus.rs index d4a4361..6a466ce 100644 --- a/src/weapon/bonus.rs +++ b/src/weapon/bonus.rs @@ -452,6 +452,21 @@ pub(crate) fn prepare_bonuses( }); } + WeaponBonusType::Deadly => { + commands + .entity(weapon.parent()) + .with_child(DamageProcEffect::Deadly { + chance: value.0 / 100.0, + }); + } + WeaponBonusType::Execute => { + commands + .entity(weapon.parent()) + .with_child(DamageProcEffect::Execute { + cutoff: value.0 / 100.0, + }); + } + val => unimplemented!("{val:?}"), } } diff --git a/src/weapon/mod.rs b/src/weapon/mod.rs index 2f66730..7530881 100644 --- a/src/weapon/mod.rs +++ b/src/weapon/mod.rs @@ -149,6 +149,7 @@ pub enum DamageProcEffect { value: f32, bonus: OpponentStatusEffect, }, + SelfEffect { value: f32, bonus: SelfStatusEffect, @@ -157,6 +158,13 @@ pub enum DamageProcEffect { value: f32, kind: DamageOverTimeType, }, + + Execute { + cutoff: f32, + }, + Deadly { + chance: f32, + }, } fn apply_passives(