fixed first round effect and migrated logging

This commit is contained in:
TotallyNot 2024-01-08 19:37:48 +01:00
parent b45d04b872
commit e7d6b74aab
10 changed files with 539 additions and 222 deletions

View file

@ -9,9 +9,9 @@ use crate::{
log,
log::Logger,
metrics::Metrics,
passives::{Education, FactionUpgrades, Merits},
passives::{EducationPartDamageBonus, FactionUpgrades, Merits},
weapon::{
bonus::MultiTurnBonus,
bonus::{BonusPartDamageBonus, MultiTurnBonus},
temp::{NonTargeted, Uses},
Ammo, DamageProcEffect, DamageStat, NeedsReload, RateOfFire, TurnTriggeredEffect, Usable,
Weapon, WeaponSlot,
@ -172,6 +172,24 @@ pub enum FightEndType {
Loss,
}
#[derive(Component)]
pub enum PartDamageBonus {
Education(EducationPartDamageBonus),
WeaponBonus {
value: f32,
bonus: BonusPartDamageBonus,
},
}
impl PartDamageBonus {
pub fn dmg_bonus(&self, part: BodyPart) -> Option<f32> {
match self {
Self::Education(edu) => edu.dmg_bonus(part),
Self::WeaponBonus { value, bonus } => bonus.dmg_bonus(part, *value),
}
}
}
#[derive(Bundle)]
pub struct PlayerBundle {
pub name: Name,
@ -341,7 +359,6 @@ pub fn use_damaging_weapon(
&SimpleStatEffective<CritRate>,
&SimpleStatEffective<WeaponAccuracy>,
&SimpleStatEffective<DamageBonus>,
&Education,
Has<Attacker>,
),
(With<Player>, With<Current>),
@ -357,7 +374,7 @@ pub fn use_damaging_weapon(
With<CurrentTarget>,
>,
armour_q: Query<&armour::ArmourBodyPart>,
damage_proc_q: Query<&DamageProcEffect>,
(damage_proc_q, part_bonus_q): (Query<&DamageProcEffect>, Query<&PartDamageBonus>),
(mut ammo_q, mut temp_q): (
Query<(
&mut Ammo,
@ -367,18 +384,19 @@ pub fn use_damaging_weapon(
)>,
Query<&mut Uses>,
),
(mut logger, mut commands, dmg_spread, metrics): (
(mut logger, mut commands, dmg_spread, metrics, mut effects): (
Logger,
Commands,
Local<DamageSpread>,
Res<Metrics>,
Effects,
),
) {
let Ok((weapon, w_dmg, acc, dmg_bonus, crit, children, non_targeted)) = weapon_q.get_single()
else {
return;
};
let (player, player_spd, player_str, player_crit, acc_bonus, p_dmg_bonus, edu, attacker) =
let (player, player_spd, player_str, player_crit, acc_bonus, p_dmg_bonus, attacker) =
player_q.single();
let (target, target_dex, target_def, armour_parts, mut health) = target_q.single_mut();
@ -457,6 +475,7 @@ pub fn use_damaging_weapon(
actor: player,
recipient: target,
rounds: rounds,
hit_chance: hit_chance,
});
metrics.increment_counter(player, "miss", 1);
metrics.increment_counter(weapon, "miss", 1);
@ -494,13 +513,17 @@ pub fn use_damaging_weapon(
let piece = rng.sample(armour_parts);
let armour_mitigation = piece.map_or(0.0, |p| p.armour_value);
// NOTE: The beta distribution is defined on [0,1], so we rescale here
// 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.
// It might be better to revivisit this detail later down the line and run more tests.
let dmg_spread = rng.sample(dmg_spread.0) / 10.0 + 1.0;
let mut dmg_bonus = dmg_bonus + p_dmg_bonus;
if edu.bio2380 && body_part == BodyPart::Throat {
dmg_bonus.value += 0.10;
for part_bonus in part_bonus_q.iter_many(children.get()) {
if let Some(bonus) = part_bonus.dmg_bonus(body_part) {
dmg_bonus.value += bonus;
}
}
// TODO: special ammo
@ -519,11 +542,13 @@ pub fn use_damaging_weapon(
if dmg > 0 {
for effect in damage_proc_q.iter_many(children.get()) {
match effect {
DamageProcEffect::MultiTurn { value, bonus }
if multi_attack_proc.is_none() =>
{
if rng.gen_bool((*value / 100.0) as f64) {
match *effect {
DamageProcEffect::MultiTurn { value, bonus } => {
if multi_attack_proc.is_some() {
continue;
}
let chance = (value / 100.0) as f64;
if chance > 1.0 || rng.gen_bool(chance) {
match bonus {
MultiTurnBonus::Blindfire => {
multi_attack_proc = Some(MultiAttack::Blindfire)
@ -545,7 +570,18 @@ pub fn use_damaging_weapon(
metrics.increment_counter(weapon, bonus.counter_label(), 1);
}
}
_ => (),
DamageProcEffect::SelfEffect { value, bonus } => {
let chance = (value / 100.0) as f64;
if chance > 1.0 || rng.gen_bool(chance) {
bonus.spawn(player, &mut effects);
}
}
DamageProcEffect::OpponentEffect { value, bonus } => {
let chance = (value / 100.0) as f64;
if chance > 1.0 || rng.gen_bool(chance) {
bonus.spawn(target, &mut effects, &mut rng.0);
}
}
}
}
}
@ -561,6 +597,7 @@ pub fn use_damaging_weapon(
part: %body_part,
part_mult: mult,
dmg: dmg,
rounds: rounds,
health_before: health_before,
health_after: health.value,
dmg_spread: dmg_spread,
@ -584,7 +621,7 @@ pub fn use_damaging_weapon(
FightEndType::Victory
} else {
FightEndType::Loss
}
},
});
metrics.increment_counter(player, "victory", 1);
}
@ -613,7 +650,7 @@ pub fn use_damaging_weapon(
}
pub fn check_stalemate(
current_q: Query<(Entity, &CombatTurns, Option<&Attacker>), (With<Current>, With<Player>)>,
current_q: Query<(Entity, &CombatTurns, Has<Attacker>), (With<Current>, With<Player>)>,
target_q: Query<Entity, With<CurrentTarget>>,
other_attackers_q: Query<(), (With<Attacker>, Without<Current>)>,
mut state: ResMut<FightStatus>,
@ -622,14 +659,14 @@ pub fn check_stalemate(
metrics: Res<Metrics>,
) {
let (current, current_turns, attacker) = current_q.single();
if *state == FightStatus::Ongoing && current_turns.0 >= 25 && attacker.is_some() {
if *state == FightStatus::Ongoing && current_turns.0 >= 25 && attacker {
commands.entity(current).insert(Defeated);
let target = target_q.single();
log!(logger, "fight_end", {
actor: current,
recipient: target,
fight_end_type: %FightEndType::Stalemate
fight_end_type: %FightEndType::Stalemate,
});
metrics.increment_counter(current, "stalemate", 1);