diff --git a/src/lib.rs b/src/lib.rs index fd2262e0..804b90a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ mod database { //JavaScript use crate::types::js_types::{ - JsAmmoResponse, JsDifficultyOptions, JsDpsResponse, JsEnemyType, JsFiringResponse, + JsAmmoResponse, JsDifficultyOptions, JsDpsResponse, JsEDR, JsEnemyType, JsFiringResponse, JsHandlingResponse, JsMetaData, JsRangeResponse, JsReloadResponse, JsResillienceSummary, JsStat, }; @@ -271,6 +271,17 @@ pub fn get_weapon_ttk(_overshield: f64) -> Result { Ok(serde_wasm_bindgen::to_value(&js_ttk_data).unwrap()) } +#[wasm_bindgen(js_name = "getExtraDamage")] +pub fn get_weapon_extra_damage(_dynamic_traits: bool, _pvp: bool) -> Result { + let weapon = PERS_DATA.with(|perm_data| perm_data.borrow().weapon.clone()); + if _dynamic_traits { + Ok(weapon + .get_edr(Some(weapon.static_calc_input()), None, _pvp) + .into()) + } else { + Ok(weapon.get_edr(None, None, _pvp).into()) + } +} ///DEPRECATED for now // // #[wasm_bindgen(js_name = "getWeaponDps")] diff --git a/src/perks/exotic_perks.rs b/src/perks/exotic_perks.rs index 55724e07..9dc83749 100644 --- a/src/perks/exotic_perks.rs +++ b/src/perks/exotic_perks.rs @@ -237,6 +237,7 @@ pub fn exotic_perks() { weapon_scale: true, crit_scale: false, combatant_scale: true, + ..Default::default() } }), ); @@ -313,6 +314,7 @@ pub fn exotic_perks() { weapon_scale: true, crit_scale: false, combatant_scale: true, + ..Default::default() } }), ); @@ -1100,4 +1102,91 @@ pub fn exotic_perks() { } }), ); + + add_edr( + Perks::MarkofTheDevourer, + Box::new(|_input: ModifierResponseInput| -> ExtraDamageResponse { + let perks = _input.calc_data.perk_value_map.clone(); + let perk_check = + |hash: Perks| -> bool { matches!(perks.get(&hash.into()), Some(x) if x > &0) }; + let mut buff = 1.0; + if perk_check(Perks::SoulDevourer) { + buff = if _input.pvp { 17.5 } else { 2.0 } + }; + let dmg = if _input.pvp { 0.4 } else { 8.5 }; + ExtraDamageResponse { + additive_damage: dmg * buff, + time_for_additive_damage: 2.05, + times_to_hit: 4, + hit_at_same_time: true, + is_dot: true, + explosive_percent: 0.0, + ..Default::default() + } + }), + ); + + add_edr( + Perks::PoisonArrows, + Box::new(|_input: ModifierResponseInput| -> ExtraDamageResponse { + let dmg = if _input.pvp { 1.876 } else { 29.0 }; + ExtraDamageResponse { + additive_damage: dmg, + time_for_additive_damage: 4.0, + times_to_hit: 8, + hit_at_same_time: true, + is_dot: true, + explosive_percent: 0.0, + ..Default::default() + } + }), + ); + + add_edr( + Perks::ChargeShot, + Box::new(|_input: ModifierResponseInput| -> ExtraDamageResponse { + let dmg = if _input.pvp { 8.0 } else { 0.0 }; //NEED PVE VALUE + ExtraDamageResponse { + additive_damage: dmg, + time_for_additive_damage: 1.75, + times_to_hit: 7, + hit_at_same_time: false, + is_dot: true, + explosive_percent: 0.0, + ..Default::default() + } + }), + ); + + add_edr( + Perks::Penance, + Box::new(|_input: ModifierResponseInput| -> ExtraDamageResponse { + let dmg = if _input.pvp { 520.0 } else { 1060.0 }; + ExtraDamageResponse { + additive_damage: dmg, + time_for_additive_damage: 3.75, + times_to_hit: 1, + hit_at_same_time: true, + is_dot: false, + explosive_percent: 0.0, + ..Default::default() + } + }), + ) + + // add_edr( + // Perks::ToxicOverload, + // Box::new(|_input: ModifierResponseInput| -> ExtraDamageResponse { + // if _input.calc_data.total_shots_hit > 14 { + // let time = if _input.pvp { 0.7 } else { 0.5 }; + // let ticks = if _input.pvp { 0 } else { 19 }; + // let dmg = if _input.pvp { 5.0 } else { 34 }; + // ExtraDamageResponse { + // additive_damage: dmg + (0.077 * _input.calc_data.s), + // time_for_additive_damage: time * ticks, + // } + // } + // ExtraDamageResponse::default() + // }), + // ); } diff --git a/src/perks/lib.rs b/src/perks/lib.rs index c3e9bd8a..57a47e41 100644 --- a/src/perks/lib.rs +++ b/src/perks/lib.rs @@ -174,6 +174,7 @@ pub struct ExtraDamageResponse { pub weapon_scale: bool, pub crit_scale: bool, pub combatant_scale: bool, + pub explosive_percent: f64, } impl Default for ExtraDamageResponse { fn default() -> Self { @@ -187,6 +188,7 @@ impl Default for ExtraDamageResponse { weapon_scale: false, crit_scale: false, combatant_scale: false, + explosive_percent: 0.0, } } } diff --git a/src/perks/mod.rs b/src/perks/mod.rs index 241a7f98..7b1d38f5 100644 --- a/src/perks/mod.rs +++ b/src/perks/mod.rs @@ -403,6 +403,9 @@ pub enum Perks { MarkovChain = 2814973067, MementoMori = 647617635, AgersScepterCatalyst = 970163821, + MarkofTheDevourer = 1863355414, + SoulDevourer = 2921090754, + ToxicOverload = 4015745376, //energy exotic LagragianSight = 2881100038, @@ -431,6 +434,9 @@ pub enum Perks { ColdFusion = 1036269296, BlackHole = 3905543891, TemporalUnlimiter = 806917387, + PoisonArrows = 2186532310, + ChargeShot = 1656957541, + Penance = 1185480639, //heavy exotic ReignHavoc = 4148158229, @@ -443,7 +449,6 @@ pub enum Perks { TractorCannon = 1210807262, MarksmanSights = 1408087975, - #[num_enum(default)] Ignore = 69420, } diff --git a/src/perks/perk_options_handler.rs b/src/perks/perk_options_handler.rs index a58cc22a..ff58b4fd 100644 --- a/src/perks/perk_options_handler.rs +++ b/src/perks/perk_options_handler.rs @@ -347,6 +347,13 @@ fn hash_to_perk_option_data(_hash: u32) -> Option { Perks::BlackHole => Some(PerkOptionData::static_()), Perks::TemporalUnlimiter => Some(PerkOptionData::toggle()), Perks::MarksmanSights => Some(PerkOptionData::static_()), + Perks::MarkofTheDevourer => Some(PerkOptionData::static_()), + Perks::SoulDevourer => Some(PerkOptionData::toggle()), + Perks::ToxicOverload => Some(PerkOptionData::static_()), + Perks::PoisonArrows => Some(PerkOptionData::static_()), + Perks::ChargeShot => Some(PerkOptionData::static_()), + Perks::Penance => Some(PerkOptionData::static_()), + Perks::DexterityMod => Some(PerkOptionData::stacking(3)), Perks::ReserveMod => Some(PerkOptionData::stacking(3)), Perks::LoaderMod => Some(PerkOptionData::stacking(3)), diff --git a/src/perks/year_1_perks.rs b/src/perks/year_1_perks.rs index d9cc8fe0..3c830610 100644 --- a/src/perks/year_1_perks.rs +++ b/src/perks/year_1_perks.rs @@ -694,16 +694,19 @@ pub fn year_1_perks() { add_edr( Perks::ClusterBomb, Box::new(|_input: ModifierResponseInput| -> ExtraDamageResponse { + let dmg = if _input.pvp { 0.0 } else { 51.0 }; //NEED PVP VALUE ExtraDamageResponse { - additive_damage: 350.0 * 0.04, + additive_damage: dmg, combatant_scale: true, crit_scale: false, increment_total_time: false, time_for_additive_damage: 0.8, - times_to_hit: 6, + times_to_hit: 8, weapon_scale: true, hit_at_same_time: true, is_dot: false, + explosive_percent: 1.0, + ..Default::default() } }), ); diff --git a/src/types/js_types.rs b/src/types/js_types.rs index a4e5f0e1..feaa995e 100644 --- a/src/types/js_types.rs +++ b/src/types/js_types.rs @@ -21,6 +21,7 @@ use wasm_bindgen::{ use super::rs_types::{ AmmoFormula, AmmoResponse, DamageMods, DpsResponse, FiringData, FiringResponse, HandlingFormula, HandlingResponse, RangeFormula, RangeResponse, ReloadFormula, ReloadResponse, + EDR, }; #[derive(Debug, Clone, Copy, Serialize)] @@ -115,6 +116,32 @@ impl From for JsAmmoResponse { } } +#[derive(Debug, Clone, Copy, Serialize)] +#[wasm_bindgen(js_name = "ExtraDamageResponse", inspectable)] +pub struct JsEDR { + #[wasm_bindgen(js_name = "firstTick", readonly)] + pub first_tick: f64, + #[wasm_bindgen(js_name = "lastTick", readonly)] + pub last_tick: f64, + #[wasm_bindgen(js_name = "avgTick", readonly)] + pub avg_tick: f64, + #[wasm_bindgen(js_name = "numTicks", readonly)] + pub num_ticks: i32, + #[wasm_bindgen(js_name = "tickDuration", readonly)] + pub tick_duration: f64, +} +impl From for JsEDR { + fn from(edr: EDR) -> Self { + JsEDR { + first_tick: edr.first_tick_damage, + last_tick: edr.last_tick_damage, + avg_tick: edr.avg_tick_damage, + num_ticks: edr.num_ticks, + tick_duration: edr.tick_duration, + } + } +} + #[derive(Debug, Clone, Serialize)] #[wasm_bindgen(js_name = "DpsResponse")] pub struct JsDpsResponse { diff --git a/src/types/rs_types.rs b/src/types/rs_types.rs index e868470e..19c65bcd 100644 --- a/src/types/rs_types.rs +++ b/src/types/rs_types.rs @@ -221,3 +221,12 @@ impl FiringResponse { self.pve_explosion_damage *= _rpl_mult * _gpl_mult * _pve_mult * _combatant_mult; } } + +#[derive(Debug, Clone, Default)] +pub struct EDR { + pub first_tick_damage: f64, + pub avg_tick_damage: f64, + pub last_tick_damage: f64, + pub tick_duration: f64, + pub num_ticks: i32, +} diff --git a/src/weapons/stat_calc.rs b/src/weapons/stat_calc.rs index 15b51335..ba72d396 100644 --- a/src/weapons/stat_calc.rs +++ b/src/weapons/stat_calc.rs @@ -4,11 +4,11 @@ use super::{reserve_calc::calc_reserves, Stat, Weapon}; use crate::{ d2_enums::{MetersPerSecond, Seconds, StatHashes, WeaponType}, perks::{ - get_dmg_modifier, get_explosion_data, get_firing_modifier, get_flinch_modifier, - get_handling_modifier, get_magazine_modifier, get_range_modifier, get_reload_modifier, - get_reserve_modifier, get_velocity_modifier, + get_dmg_modifier, get_explosion_data, get_extra_damage, get_firing_modifier, + get_flinch_modifier, get_handling_modifier, get_magazine_modifier, get_range_modifier, + get_reload_modifier, get_reserve_modifier, get_velocity_modifier, lib::{ - CalculationInput, DamageModifierResponse, FiringModifierResponse, + CalculationInput, DamageModifierResponse, ExtraDamageResponse, FiringModifierResponse, HandlingModifierResponse, InventoryModifierResponse, MagazineModifierResponse, RangeModifierResponse, ReloadModifierResponse, }, @@ -16,8 +16,9 @@ use crate::{ }, types::rs_types::{ AmmoFormula, AmmoResponse, FiringResponse, HandlingFormula, HandlingResponse, RangeFormula, - RangeResponse, ReloadFormula, ReloadResponse, + RangeResponse, ReloadFormula, ReloadResponse, EDR, }, + Perk, }; impl ReloadFormula { @@ -597,3 +598,69 @@ impl Weapon { buffer } } + +impl Weapon { + pub fn get_edr( + &self, + _calc_input: Option, + _cached_data: Option<&mut HashMap>, + _pvp: bool, + ) -> EDR { + let mut default_cached_data = HashMap::new(); + let cached_data = _cached_data.unwrap_or(&mut default_cached_data); + let damage_modifiers: DamageModifierResponse; + let extra_damage: Vec; + + if _calc_input.is_some() { + damage_modifiers = get_dmg_modifier( + self.list_perks(), + &_calc_input.clone().unwrap(), + _pvp, + &mut cached_data.clone(), + ); + + extra_damage = get_extra_damage( + self.list_perks(), + &_calc_input.clone().unwrap(), + _pvp, + &mut cached_data.clone(), + ); + } else { + damage_modifiers = DamageModifierResponse::default(); + extra_damage = vec![ExtraDamageResponse::default()]; + } + + let mut average_tick_damage = 0.0; + let mut average_explosive_percent = 0.0; + // goes thru the vec to find the avg tick damage + for edr in &extra_damage { + average_tick_damage += edr.additive_damage; + average_explosive_percent += edr.explosive_percent; + } + let length = extra_damage.len() - 1; + average_tick_damage /= length as f64 + 1.0; + average_explosive_percent /= length as f64 + 1.0; + + return EDR { + first_tick_damage: (extra_damage[0].additive_damage + * extra_damage[0].explosive_percent + * damage_modifiers.explosive_dmg_scale) + + (extra_damage[0].additive_damage * (1.0 - extra_damage[0].explosive_percent)/* damage_modifiers.impact_dmg_scale*/), + + tick_duration: extra_damage[0].time_for_additive_damage, + + num_ticks: extra_damage[0].times_to_hit, + + last_tick_damage: (extra_damage[length].additive_damage + * extra_damage[length].explosive_percent + * damage_modifiers.explosive_dmg_scale) + + (extra_damage[length].additive_damage + * (1.0 - extra_damage[length].explosive_percent)/* damage_modifiers.impact_dmg_scale*/), + + avg_tick_damage: (average_tick_damage + * average_explosive_percent + * damage_modifiers.explosive_dmg_scale) + + (average_tick_damage * (1.0 - average_explosive_percent)), /*damage_modifiers.impact_dmg_scale*/ + }; + } +} diff --git a/src/weapons/ttk_calc.rs b/src/weapons/ttk_calc.rs index 35f90c43..d594ea03 100644 --- a/src/weapons/ttk_calc.rs +++ b/src/weapons/ttk_calc.rs @@ -5,10 +5,10 @@ use serde::Serialize; use crate::{ d2_enums::WeaponType, logging::extern_log, - perks::{get_dmg_modifier, get_firing_modifier, lib::CalculationInput}, + perks::{get_dmg_modifier, get_firing_modifier, get_extra_damage, lib::CalculationInput}, }; -use super::{FiringData, Weapon}; +use super::{FiringData, Weapon, dps_calc::calc_extra_dmg}; //just to make code cleaner for now fn ceil(x: f64) -> f64 { @@ -94,6 +94,12 @@ pub fn calc_ttk(_weapon: &Weapon, _overshield: f64) -> Vec { true, &mut persistent_data, ); + let extra_damage = get_extra_damage( + _weapon.list_perks().clone(), + &calc_input, + true, + &mut persistent_data, + ); /////////////////////////////// let body_damage = (impact_dmg * dmg_mods.impact_dmg_scale)