1use crate::proto::{CMsgDotaCombatLogEntry, DotaCombatlogTypes};
2use crate::string_table::StringTable;
3
4#[derive(Clone)]
6pub struct CombatLogEntry<'a> {
7 pub(crate) names: &'a StringTable,
8 pub(crate) log: CMsgDotaCombatLogEntry,
9}
10
11#[derive(thiserror::Error, Debug)]
12pub enum CombatLogError {
13 #[error("No {0} for {1}")]
14 EmptyProperty(String, String),
15 #[error("No {0} for {1}")]
16 EmptyName(String, String),
17}
18
19macro_rules! define_combat_log_getters {
20 ($($name:ident: $type:ty),*) => {
21 $(
22 pub fn $name(&self) -> Result<$type, CombatLogError> {
23 self.log.$name.ok_or_else(|| {
24 CombatLogError::EmptyProperty(stringify!($name).into(), format!("{:?}", self.r#type()))
25 })
26 }
27 )*
28 };
29}
30
31macro_rules! define_name_getter {
32 ($($fn_name:ident: $log_prop:ident),*) => {
33 $(
34 pub fn $fn_name(&self) -> Result<&str, CombatLogError> {
35 self.log.$log_prop
36 .and_then(|id| self.names.items.get(id as usize).map(|name| name.key.as_ref()))
37 .ok_or_else(|| {
38 CombatLogError::EmptyName(stringify!($fn_name).into(), format!("{:?}", self.r#type()))
39 })
40 }
41 )*
42 };
43}
44
45impl<'a> CombatLogEntry<'a> {
46 pub fn r#type(&self) -> DotaCombatlogTypes {
47 self.log.r#type()
48 }
49
50 pub fn assist_players(&self) -> &[i32] {
51 self.log.assist_players.as_slice()
52 }
53
54 define_name_getter! {
55 target_name: target_name,
56 target_source_name: target_source_name,
57 attacker_name: attacker_name,
58 damage_source_name: damage_source_name,
59 inflictor_name: inflictor_name,
60 value_name: value
61 }
62
63 define_combat_log_getters! {
64 value: u32,
65 health: i32,
66 timestamp: f32,
67 stun_duration: f32,
68 slow_duration: f32,
69 ability_level: u32,
70 location_x: f32,
71 location_y: f32,
72 gold_reason: u32,
73 timestamp_raw: f32,
74 modifier_duration: f32,
75 xp_reason: u32,
76 last_hits: u32,
77 attacker_team: u32,
78 target_team: u32,
79 obs_wards_placed: u32,
80 assist_player0: u32,
81 assist_player1: u32,
82 assist_player2: u32,
83 assist_player3: u32,
84 stack_count: u32,
85 hidden_modifier: bool,
86 neutral_camp_type: u32,
87 rune_type: u32,
88 attacker_hero_level: u32,
89 target_hero_level: u32,
90 xpm: u32,
91 gpm: u32,
92 event_location: u32,
93 target_is_self: bool,
94 damage_type: u32,
95 invisibility_modifier: bool,
96 damage_category: u32,
97 networth: u32,
98 building_type: u32,
99 modifier_elapsed_duration: f32,
100 silence_modifier: bool,
101 heal_from_lifesteal: bool,
102 modifier_purged: bool,
103 spell_evaded: bool,
104 motion_controller_modifier: bool,
105 long_range_kill: bool,
106 modifier_purge_ability: u32,
107 modifier_purge_npc: u32,
108 root_modifier: bool,
109 total_unit_death_count: u32,
110 aura_modifier: bool,
111 armor_debuff_modifier: bool,
112 no_physical_damage_modifier: bool,
113 modifier_ability: u32,
114 modifier_hidden: bool,
115 inflictor_is_stolen_ability: bool,
116 kill_eater_event: u32,
117 unit_status_label: u32,
118 spell_generated_attack: bool,
119 is_attacker_illusion: bool,
120 is_attacker_hero: bool,
121 is_target_illusion: bool,
122 is_target_hero: bool,
123 is_visible_radiant: bool,
124 is_visible_dire: bool,
125 is_ability_toggle_on: bool,
126 is_ability_toggle_off: bool,
127 is_heal_save: bool,
128 is_ultimate_ability: bool,
129 uses_charges: bool,
130 will_reincarnate: bool,
131 regenerated_health: f32,
132 neutral_camp_team: u32,
133 at_night_time: bool,
134 is_target_building: bool,
135 attacker_has_scepter: bool
136 }
137}