added log! macro
This commit is contained in:
parent
86f9333aec
commit
b45d04b872
5 changed files with 140 additions and 522 deletions
|
|
@ -1,5 +1,4 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use macros::LogMessage;
|
||||
use rand::Rng as _;
|
||||
use strum::Display;
|
||||
|
||||
|
|
@ -7,6 +6,7 @@ use crate::{
|
|||
armour,
|
||||
effect::Effects,
|
||||
hierarchy::Children,
|
||||
log,
|
||||
log::Logger,
|
||||
metrics::Metrics,
|
||||
passives::{Education, FactionUpgrades, Merits},
|
||||
|
|
@ -165,18 +165,6 @@ impl std::fmt::Display for BodyPart {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct InitiateHit {
|
||||
pub body_part: BodyPart,
|
||||
pub weapon: Entity,
|
||||
pub rounds: Option<u16>,
|
||||
pub dmg: f32,
|
||||
pub dmg_bonus_weapon: f32,
|
||||
pub dmg_bonus_player: f32,
|
||||
pub hit_chance: f32,
|
||||
pub crit_rate: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Display)]
|
||||
pub enum FightEndType {
|
||||
Victory,
|
||||
|
|
@ -184,16 +172,6 @@ pub enum FightEndType {
|
|||
Loss,
|
||||
}
|
||||
|
||||
#[derive(LogMessage)]
|
||||
struct FightEnd {
|
||||
#[log(player)]
|
||||
actor: Entity,
|
||||
#[log(player)]
|
||||
recipient: Entity,
|
||||
#[log(display)]
|
||||
fight_end_type: FightEndType,
|
||||
}
|
||||
|
||||
#[derive(Bundle)]
|
||||
pub struct PlayerBundle {
|
||||
pub name: Name,
|
||||
|
|
@ -338,164 +316,6 @@ impl FromWorld for DamageSpread {
|
|||
}
|
||||
}
|
||||
|
||||
fn receive_hit(
|
||||
(mut rng, spread): (ResMut<crate::Rng>, Local<DamageSpread>),
|
||||
mut hit_init_events: EventReader<InitiateHit>,
|
||||
current_q: Query<
|
||||
(
|
||||
Entity,
|
||||
&Education,
|
||||
Option<&Attacker>,
|
||||
&EffectiveStat<Strength>,
|
||||
),
|
||||
(With<Current>, With<Player>),
|
||||
>,
|
||||
mut target_q: Query<
|
||||
(
|
||||
Entity,
|
||||
&mut SimpleStatEffective<Health>,
|
||||
&armour::ArmourBodyParts,
|
||||
&EffectiveStat<Defence>,
|
||||
),
|
||||
With<CurrentTarget>,
|
||||
>,
|
||||
armour_q: Query<&armour::ArmourBodyPart>,
|
||||
(mut commands, mut logger): (Commands, Logger),
|
||||
metrics: Res<Metrics>,
|
||||
) {
|
||||
#[derive(LogMessage)]
|
||||
struct HitTarget {
|
||||
#[log(player)]
|
||||
actor: Entity,
|
||||
#[log(player)]
|
||||
recipient: Entity,
|
||||
#[log(weapon)]
|
||||
weapon: Entity,
|
||||
|
||||
#[log(display)]
|
||||
part: BodyPart,
|
||||
part_mult: f32,
|
||||
rounds: Option<u16>,
|
||||
|
||||
dmg: u32,
|
||||
health_before: u16,
|
||||
health_after: u16,
|
||||
|
||||
dmg_intrinsic: f32,
|
||||
dmg_spread: f32,
|
||||
|
||||
armour_mitigation: f32,
|
||||
def_mitigation: f32,
|
||||
|
||||
weapon_dmg: f32,
|
||||
bonus_dmg: f32,
|
||||
hit_chance: f32,
|
||||
|
||||
crit_rate: u16,
|
||||
}
|
||||
|
||||
if hit_init_events.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (target, mut health, body_parts, target_def) = target_q.single_mut();
|
||||
let (current, edu, attacker, current_str) = current_q.single();
|
||||
|
||||
let def_str_ratio = (target_def.value / current_str.value).clamp(1.0 / 32.0, 14.0);
|
||||
let def_mitigation = if def_str_ratio < 1.0 {
|
||||
0.5 * def_str_ratio.log(32.0) + 0.5
|
||||
} else {
|
||||
0.5 * def_str_ratio.log(14.0) + 0.5
|
||||
};
|
||||
|
||||
let dmg_intrinsic = 7.0 * (current_str.value / 10.0).log10().powi(2)
|
||||
+ 27.0 * (current_str.value / 10.0).log10()
|
||||
+ 30.0;
|
||||
|
||||
for event in hit_init_events.read() {
|
||||
let mult = match event.body_part {
|
||||
BodyPart::Head | BodyPart::Heart | BodyPart::Throat => {
|
||||
metrics.increment_counter(current, "crit", 1);
|
||||
metrics.increment_counter(event.weapon, "crit", 1);
|
||||
1.0
|
||||
}
|
||||
BodyPart::LeftHand | BodyPart::RightHand | BodyPart::LeftFoot | BodyPart::RightFoot => {
|
||||
0.2
|
||||
}
|
||||
BodyPart::LeftArm | BodyPart::RightArm | BodyPart::LeftLeg | BodyPart::RightLeg => {
|
||||
1.0 / 3.5
|
||||
}
|
||||
BodyPart::Groin | BodyPart::Stomach | BodyPart::Chest => 1.0 / 1.75,
|
||||
};
|
||||
|
||||
metrics.increment_counter(current, "hit", 1);
|
||||
metrics.increment_counter(event.weapon, "hit", 1);
|
||||
|
||||
let armour_parts = armour_q.get(body_parts.0[event.body_part.into()]).unwrap();
|
||||
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
|
||||
let dmg_spread = rng.sample(spread.0) / 10.0 + 1.0;
|
||||
|
||||
let mut dmg_bonus = event.dmg_bonus_weapon + event.dmg_bonus_player;
|
||||
|
||||
if edu.bio2380 && event.body_part == BodyPart::Throat {
|
||||
dmg_bonus += 0.10;
|
||||
}
|
||||
|
||||
let dmg = dmg_intrinsic
|
||||
* event.dmg
|
||||
* dmg_bonus
|
||||
* (1.0 - armour_mitigation)
|
||||
* (1.0 - def_mitigation)
|
||||
* mult
|
||||
* dmg_spread;
|
||||
let dmg = dmg.round() as u32;
|
||||
|
||||
metrics.record_histogram(current, "dmg", dmg);
|
||||
metrics.record_histogram(event.weapon, "dmg", dmg);
|
||||
|
||||
let health_before = health.value;
|
||||
|
||||
health.value = health.value.saturating_sub(dmg as u16);
|
||||
|
||||
logger.log(|| HitTarget {
|
||||
actor: current,
|
||||
recipient: target,
|
||||
weapon: event.weapon,
|
||||
part: event.body_part,
|
||||
part_mult: mult,
|
||||
rounds: event.rounds,
|
||||
dmg,
|
||||
health_before,
|
||||
health_after: health.value,
|
||||
dmg_spread,
|
||||
dmg_intrinsic,
|
||||
armour_mitigation,
|
||||
def_mitigation,
|
||||
weapon_dmg: event.dmg,
|
||||
bonus_dmg: dmg_bonus,
|
||||
hit_chance: event.hit_chance,
|
||||
crit_rate: event.crit_rate,
|
||||
});
|
||||
|
||||
if health.value == 0 {
|
||||
commands.entity(target).insert(Defeated);
|
||||
logger.log(|| FightEnd {
|
||||
actor: current,
|
||||
recipient: target,
|
||||
fight_end_type: if attacker.is_some() {
|
||||
FightEndType::Victory
|
||||
} else {
|
||||
FightEndType::Loss
|
||||
},
|
||||
});
|
||||
metrics.increment_counter(current, "victory", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: unfortunately this function can't really be split into smaller parts due to the existence
|
||||
// of multi turn bonuses
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
|
@ -554,48 +374,6 @@ pub fn use_damaging_weapon(
|
|||
Res<Metrics>,
|
||||
),
|
||||
) {
|
||||
#[derive(LogMessage)]
|
||||
pub struct MissTarget {
|
||||
#[log(player)]
|
||||
pub actor: Entity,
|
||||
#[log(player)]
|
||||
pub recipient: Entity,
|
||||
#[log(weapon)]
|
||||
pub weapon: Entity,
|
||||
pub rounds: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(LogMessage)]
|
||||
struct HitTarget {
|
||||
#[log(player)]
|
||||
actor: Entity,
|
||||
#[log(player)]
|
||||
recipient: Entity,
|
||||
#[log(weapon)]
|
||||
weapon: Entity,
|
||||
|
||||
#[log(display)]
|
||||
part: BodyPart,
|
||||
part_mult: f32,
|
||||
rounds: Option<u16>,
|
||||
|
||||
dmg: u32,
|
||||
health_before: u16,
|
||||
health_after: u16,
|
||||
|
||||
dmg_intrinsic: f32,
|
||||
dmg_spread: f32,
|
||||
|
||||
armour_mitigation: f32,
|
||||
def_mitigation: f32,
|
||||
|
||||
weapon_dmg: f32,
|
||||
bonus_dmg: f32,
|
||||
hit_chance: f32,
|
||||
|
||||
crit_rate: u16,
|
||||
}
|
||||
|
||||
let Ok((weapon, w_dmg, acc, dmg_bonus, crit, children, non_targeted)) = weapon_q.get_single()
|
||||
else {
|
||||
return;
|
||||
|
|
@ -674,11 +452,11 @@ pub fn use_damaging_weapon(
|
|||
};
|
||||
|
||||
if hit_chance <= 1.0 && !rng.gen_bool(hit_chance as f64) {
|
||||
logger.log(|| MissTarget {
|
||||
weapon,
|
||||
log!(logger, "miss_target", {
|
||||
weapon: weapon,
|
||||
actor: player,
|
||||
recipient: target,
|
||||
rounds,
|
||||
rounds: rounds,
|
||||
});
|
||||
metrics.increment_counter(player, "miss", 1);
|
||||
metrics.increment_counter(weapon, "miss", 1);
|
||||
|
|
@ -745,7 +523,7 @@ pub fn use_damaging_weapon(
|
|||
DamageProcEffect::MultiTurn { value, bonus }
|
||||
if multi_attack_proc.is_none() =>
|
||||
{
|
||||
if rng.gen_bool(*value as f64) {
|
||||
if rng.gen_bool((*value / 100.0) as f64) {
|
||||
match bonus {
|
||||
MultiTurnBonus::Blindfire => {
|
||||
multi_attack_proc = Some(MultiAttack::Blindfire)
|
||||
|
|
@ -763,6 +541,8 @@ pub fn use_damaging_weapon(
|
|||
Some(MultiAttack::DoubleTap { first_shot: true })
|
||||
}
|
||||
};
|
||||
metrics.increment_counter(player, bonus.counter_label(), 1);
|
||||
metrics.increment_counter(weapon, bonus.counter_label(), 1);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
@ -774,23 +554,22 @@ pub fn use_damaging_weapon(
|
|||
|
||||
health.value = health.value.saturating_sub(dmg as u16);
|
||||
|
||||
logger.log(|| HitTarget {
|
||||
log!(logger, "hit_target", {
|
||||
actor: player,
|
||||
recipient: target,
|
||||
weapon,
|
||||
part: body_part,
|
||||
weapon: weapon,
|
||||
part: %body_part,
|
||||
part_mult: mult,
|
||||
rounds,
|
||||
dmg,
|
||||
health_before,
|
||||
dmg: dmg,
|
||||
health_before: health_before,
|
||||
health_after: health.value,
|
||||
dmg_spread,
|
||||
dmg_intrinsic,
|
||||
armour_mitigation,
|
||||
def_mitigation,
|
||||
dmg_spread: dmg_spread,
|
||||
dmg_intrinsic: dmg_intrinsic,
|
||||
armour_mitigation: armour_mitigation,
|
||||
def_mitigation: def_mitigation,
|
||||
weapon_dmg: w_dmg.0,
|
||||
bonus_dmg: dmg_bonus.value,
|
||||
hit_chance,
|
||||
hit_chance: hit_chance,
|
||||
crit_rate: crit.value,
|
||||
});
|
||||
|
||||
|
|
@ -798,14 +577,14 @@ pub fn use_damaging_weapon(
|
|||
defeated = true;
|
||||
|
||||
commands.entity(target).insert(Defeated);
|
||||
logger.log(|| FightEnd {
|
||||
log!(logger, "fight_end", {
|
||||
actor: player,
|
||||
recipient: target,
|
||||
fight_end_type: if attacker {
|
||||
fight_end_type: %if attacker {
|
||||
FightEndType::Victory
|
||||
} else {
|
||||
FightEndType::Loss
|
||||
},
|
||||
}
|
||||
});
|
||||
metrics.increment_counter(player, "victory", 1);
|
||||
}
|
||||
|
|
@ -846,12 +625,12 @@ pub fn check_stalemate(
|
|||
if *state == FightStatus::Ongoing && current_turns.0 >= 25 && attacker.is_some() {
|
||||
commands.entity(current).insert(Defeated);
|
||||
let target = target_q.single();
|
||||
logger.log(|| FightEnd {
|
||||
|
||||
log!(logger, "fight_end", {
|
||||
actor: current,
|
||||
recipient: target,
|
||||
fight_end_type: FightEndType::Stalemate,
|
||||
fight_end_type: %FightEndType::Stalemate
|
||||
});
|
||||
|
||||
metrics.increment_counter(current, "stalemate", 1);
|
||||
|
||||
if other_attackers_q.is_empty() {
|
||||
|
|
@ -898,7 +677,6 @@ pub(crate) fn configure(stages: &mut Stages) {
|
|||
status_effect::configure(stages);
|
||||
|
||||
stages.add_event::<ChooseWeapon>();
|
||||
stages.add_event::<InitiateHit>();
|
||||
stages.equip.add_systems(designate_first);
|
||||
stages.pre_fight.add_systems(derive_max_health);
|
||||
stages.pre_turn.add_systems(pick_action);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue