Skip to content
13 changes: 12 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -271,6 +271,17 @@ pub fn get_weapon_ttk(_overshield: f64) -> Result<JsValue, JsValue> {
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<JsEDR, JsValue> {
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")]
Expand Down
89 changes: 89 additions & 0 deletions src/perks/exotic_perks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ pub fn exotic_perks() {
weapon_scale: true,
crit_scale: false,
combatant_scale: true,
..Default::default()
}
}),
);
Expand Down Expand Up @@ -313,6 +314,7 @@ pub fn exotic_perks() {
weapon_scale: true,
crit_scale: false,
combatant_scale: true,
..Default::default()
}
}),
);
Expand Down Expand Up @@ -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()
// }),
// );
}
2 changes: 2 additions & 0 deletions src/perks/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -187,6 +188,7 @@ impl Default for ExtraDamageResponse {
weapon_scale: false,
crit_scale: false,
combatant_scale: false,
explosive_percent: 0.0,
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/perks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ pub enum Perks {
MarkovChain = 2814973067,
MementoMori = 647617635,
AgersScepterCatalyst = 970163821,
MarkofTheDevourer = 1863355414,
SoulDevourer = 2921090754,
ToxicOverload = 4015745376,

//energy exotic
LagragianSight = 2881100038,
Expand Down Expand Up @@ -431,6 +434,9 @@ pub enum Perks {
ColdFusion = 1036269296,
BlackHole = 3905543891,
TemporalUnlimiter = 806917387,
PoisonArrows = 2186532310,
ChargeShot = 1656957541,
Penance = 1185480639,

//heavy exotic
ReignHavoc = 4148158229,
Expand All @@ -443,7 +449,6 @@ pub enum Perks {
TractorCannon = 1210807262,
MarksmanSights = 1408087975,


#[num_enum(default)]
Ignore = 69420,
}
Expand Down
7 changes: 7 additions & 0 deletions src/perks/perk_options_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ fn hash_to_perk_option_data(_hash: u32) -> Option<PerkOptionData> {
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)),
Expand Down
7 changes: 5 additions & 2 deletions src/perks/year_1_perks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}),
);
Expand Down
27 changes: 27 additions & 0 deletions src/types/js_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -115,6 +116,32 @@ impl From<AmmoResponse> 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<EDR> 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 {
Expand Down
9 changes: 9 additions & 0 deletions src/types/rs_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
77 changes: 72 additions & 5 deletions src/weapons/stat_calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ 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,
},
Perks,
},
types::rs_types::{
AmmoFormula, AmmoResponse, FiringResponse, HandlingFormula, HandlingResponse, RangeFormula,
RangeResponse, ReloadFormula, ReloadResponse,
RangeResponse, ReloadFormula, ReloadResponse, EDR,
},
Perk,
};

impl ReloadFormula {
Expand Down Expand Up @@ -597,3 +598,69 @@ impl Weapon {
buffer
}
}

impl Weapon {
pub fn get_edr(
&self,
_calc_input: Option<CalculationInput>,
_cached_data: Option<&mut HashMap<String, f64>>,
_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<ExtraDamageResponse>;

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*/
};
}
}
10 changes: 8 additions & 2 deletions src/weapons/ttk_calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -94,6 +94,12 @@ pub fn calc_ttk(_weapon: &Weapon, _overshield: f64) -> Vec<ResillienceSummary> {
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)
Expand Down