Skip to content

Commit

Permalink
[gear] Update role mults for Sikran's Endless Arsenal, Shadowed Essen…
Browse files Browse the repository at this point in the history
…ce, Mad Queen's Mandate, Skyterror's Corrosive Organ (simulationcraft#9484)

* [gear] Fix or add many missing \`role_mult\`s.
* [gear/html] Fix Elemental Focusing Lens multipliers and improve composite base multiplier reporting.
* [gear] Provide a default `role_mult` spell in case none can be found on related spells. Assert if no `desc_vars` exist for the provided effect.
  • Loading branch information
renanthera authored Sep 11, 2024
1 parent 5a6c13e commit c302d41
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 45 deletions.
99 changes: 56 additions & 43 deletions engine/player/unique_gear_thewarwithin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ custom_cb_t primary_food( unsigned id, stat_e stat, size_t primary_idx = 3, bool
auto coeff = effect.player->find_spell( food_coeff_spell_id );

auto buff = create_buff<consumable_buff_t<stat_buff_t>>( effect.player, effect.driver() );

if ( primary_idx )
{
auto _amt = coeff->effectN( primary_idx ).average( effect );
Expand Down Expand Up @@ -578,7 +578,8 @@ void pouch_of_pocket_grenades( special_effect_t& effect )
auto missile = driver->effectN( 1 ).trigger();
auto damage = missile->effectN( 1 ).trigger();
// TODO: determine which coeff is the correct one. assuming driver is correct.
auto amount = driver->effectN( 1 ).average( effect ) * role_mult( effect );
auto amount = driver->effectN( 1 ).average( effect );
auto multiplier = role_mult( effect );

effect.spell_id = driver->id();

Expand All @@ -588,6 +589,8 @@ void pouch_of_pocket_grenades( special_effect_t& effect )
auto grenade = create_proc_action<generic_aoe_proc_t>( "pocket_grenade", effect, damage );
grenade->base_dd_min += amount;
grenade->base_dd_max += amount;
// We cannot use `*=`, as two copies of the embellishment would doubly apply role mult.
grenade->base_multiplier = multiplier;

if ( found )
return;
Expand All @@ -614,7 +617,8 @@ void elemental_focusing_lens( special_effect_t& effect )
if ( !gems.size() )
return;

auto amount = effect.driver()->effectN( 1 ).average( effect ) * role_mult( effect );
auto amount = effect.driver()->effectN( 1 ).average( effect );
auto multiplier = role_mult( effect );

effect.spell_id = effect.trigger()->id();

Expand Down Expand Up @@ -644,6 +648,8 @@ void elemental_focusing_lens( special_effect_t& effect )
auto dam = create_proc_action<generic_proc_t>( fmt::format( "elemental_focusing_lens_{}", name ), effect, id );
dam->base_dd_min += amount;
dam->base_dd_max += amount;
// We cannot use `*=`, as two copies of the embellishment would doubly apply role mult.
dam->base_multiplier = multiplier;
dam->name_str_reporting = util::inverse_tokenize( name );
damages.push_back( dam );
proxy->add_child( dam );
Expand Down Expand Up @@ -813,7 +819,9 @@ void deepening_darkness( special_effect_t& effect )
create_proc_action<generic_aoe_proc_t>( "deepening_darkness", effect, effect.player->find_spell( 446753 ), true );

damage->base_dd_min = damage->base_dd_max =
effect.driver()->effectN( 2 ).average( effect ) * role_mult( effect ) * writhing_mul( effect.player );
effect.driver()->effectN( 2 ).average( effect );
damage->base_multiplier *= role_mult( effect );
damage->base_multiplier *= writhing_mul( effect.player );

auto buff = create_buff<buff_t>( effect.player, effect.player->find_spell( 446743 ) )
->set_expire_callback( [ damage ]( buff_t*, int, timespan_t d ) {
Expand Down Expand Up @@ -992,7 +1000,7 @@ void spymasters_web( special_effect_t& effect )
void execute() override
{
generic_proc_t::execute();

use_buff->expire();
use_buff->trigger( stacking_buff->check() );
stacking_buff->expire();
Expand Down Expand Up @@ -1135,7 +1143,7 @@ void aberrant_spellforge( special_effect_t& effect )
: generic_proc_t( e, "aberrant_shadows", 451866 ), stack( b )
{
base_dd_min = base_dd_max = data->effectN( 1 ).average( e );
base_multiplier *= role_mult( e );
base_multiplier *= role_mult( e.player, e.player->find_spell( 445593 ) );

for ( auto a : player->action_list )
{
Expand Down Expand Up @@ -1272,7 +1280,7 @@ void sikrans_endless_arsenal( special_effect_t& effect )
// setup flourish
auto f_dam = create_proc_action<generic_proc_t>( "surekian_flourish", e, 445434 );
f_dam->base_td = data->effectN( 1 ).average( e ) * f_dam->base_tick_time / f_dam->dot_duration;
f_dam->base_multiplier *= role_mult( e );
f_dam->base_multiplier *= role_mult( e.player, e.player->find_spell( 445434 ) );
add_child( f_dam );

auto f_stance = create_buff<stat_buff_t>( e.player, e.player->find_spell( 447962 ) )
Expand All @@ -1284,8 +1292,8 @@ void sikrans_endless_arsenal( special_effect_t& effect )
// setup decimation
auto d_dam = create_proc_action<generic_aoe_proc_t>( "surekian_decimation", e, 448090 );
// TODO: confirm there is no standard +15% per target up to five
d_dam->base_dd_min = d_dam->base_dd_max = data->effectN( 4 ).average( e ) * role_mult( e );
d_dam->base_multiplier *= role_mult( e );
d_dam->base_dd_min = d_dam->base_dd_max = data->effectN( 4 ).average( e );
d_dam->base_multiplier *= role_mult( e.player, e.player->find_spell( 448090 ) );
add_child( d_dam );

auto d_shield = create_proc_action<generic_proc_t>( "surekian_brutality", e, 448519 );
Expand Down Expand Up @@ -1325,8 +1333,8 @@ void sikrans_endless_arsenal( special_effect_t& effect )
auto b_dam = create_proc_action<generic_aoe_proc_t>( "surekian_barrage", e, 445475 );
// TODO: confirm damage isn't split and has no diminishing returns
b_dam->split_aoe_damage = false;
b_dam->base_dd_min = b_dam->base_dd_max = data->effectN( 6 ).average( e ) * role_mult( e );
b_dam->base_multiplier *= role_mult( e );
b_dam->base_dd_min = b_dam->base_dd_max = data->effectN( 6 ).average( e );
b_dam->base_multiplier *= role_mult( e.player, e.player->find_spell( 445475 ) );
add_child( b_dam );

auto b_speed = create_buff<buff_t>( e.player, e.player->find_spell( 448436 ) )
Expand Down Expand Up @@ -1818,7 +1826,7 @@ void treacherous_transmitter( special_effect_t& effect )
}
}
};

effect.disable_buff();
effect.stat = effect.player->convert_hybrid_stat( STAT_STR_AGI_INT );
effect.execute_action = create_proc_action<cryptic_instructions_t>( "cryptic_instructions", effect );
Expand Down Expand Up @@ -1860,7 +1868,7 @@ void mad_queens_mandate( special_effect_t& effect )
heal_speed( e.trigger()->missile_speed() ),
hp_mul( 0.5 ) // not present in spell data
{
base_dd_min = base_dd_max = data->effectN( 1 ).average( e ) * role_mult( e );
base_dd_min = base_dd_max = data->effectN( 1 ).average( e );
base_multiplier *= role_mult( e );

heal = create_proc_action<generic_heal_t>( "abyssal_gluttony_heal", e, "abyssal_gluttony_heal",
Expand Down Expand Up @@ -2272,7 +2280,7 @@ void skarmorak_shard( special_effect_t& e )
void void_pactstone( special_effect_t& e )
{
auto buff = create_buff<stat_buff_t>( e.player, e.player->find_spell( 450962 ) )
// Will Throw a warning currently, as the mod rating misc_value1 is empty. Does not work in game either.
// Will Throw a warning currently, as the mod rating misc_value1 is empty. Does not work in game either.
->add_stat_from_effect_type( A_MOD_RATING, e.driver()->effectN( 2 ).average( e ) );

auto damage = create_proc_action<generic_aoe_proc_t>( "void_pulse", e, 450960 );
Expand Down Expand Up @@ -2490,7 +2498,7 @@ void opressive_orators_larynx( special_effect_t& e )
{
background = true;
base_dd_min = base_dd_max = equip_driver->effectN( 2 ).average( e );
base_multiplier = role_mult( e );
base_multiplier *= role_mult( e );
}

double composite_da_multiplier( const action_state_t* state ) const override
Expand Down Expand Up @@ -2569,7 +2577,7 @@ void arakara_sacbrood( special_effect_t& e )
{
damage = create_proc_action<generic_proc_t>( "spidersting", e, e.player->find_spell( 452229 ) );
damage->base_td = e.player->find_spell( 443541 )->effectN( 2 ).average( e );
damage->base_multiplier = role_mult( e );
damage->base_multiplier *= role_mult( e.player, e.player->find_spell( 443541 ) );
missile = create_proc_action<generic_proc_t>( "spiderfling", e, e.player->find_spell( 452227 ) );
missile->impact_action = damage;
}
Expand All @@ -2583,7 +2591,7 @@ void arakara_sacbrood( special_effect_t& e )

// In game this buff seems to stack infinitely, while data suggests 1 max stack.
auto spiderling_buff = create_buff<buff_t>( e.player, e.player->find_spell( 452226 ) )
->set_max_stack( 99 );
->set_max_stack( 99 );

auto spiderling = new special_effect_t( e.player );
spiderling->name_str = "spiderling";
Expand Down Expand Up @@ -2624,7 +2632,7 @@ void skyterrors_corrosive_organ( special_effect_t& e )
background = true;
aoe = data().max_targets();
split_aoe_damage = false;
base_dd_min = base_dd_max = equip_driver->effectN( 2 ).average( e ) * role_mult( e );
base_dd_min = base_dd_max = equip_driver->effectN( 2 ).average( e );
base_multiplier *= role_mult( e );
}

Expand Down Expand Up @@ -2925,7 +2933,8 @@ void mereldars_toll( special_effect_t& effect )
target_debuff = e.trigger();

impact_action = create_proc_action<generic_proc_t>( "mereldars_toll_damage", e, e.trigger() );
impact_action->base_dd_min = impact_action->base_dd_max = data->effectN( 2 ).average( e ) * role_mult( e );
impact_action->base_dd_min = impact_action->base_dd_max = data->effectN( 2 ).average( e );
impact_action->base_multiplier *= role_mult( e );
// TODO: confirm 950ms delay in damage
impact_action->travel_delay = e.driver()->effectN( 2 ).misc_value1() * 0.001;
impact_action->stats = stats;
Expand Down Expand Up @@ -3091,7 +3100,7 @@ void signet_of_the_priory( special_effect_t& effect )
effect.disable_buff();
auto signet = debug_cast<signet_of_the_priory_t*>(
create_proc_action<signet_of_the_priory_t>( "signet_of_the_priory", effect, data ) );
effect.execute_action = signet;
effect.execute_action = signet;
effect.stat = STAT_ANY_DPS;

// TODO: determine reasonable default for party buff options
Expand Down Expand Up @@ -3131,9 +3140,10 @@ void harvesters_edict( special_effect_t& effect )
// TODO: confirm damage doesn't increase per extra target
auto damage = create_proc_action<generic_aoe_proc_t>( "volatile_blood_blast", effect, effect.driver() );
damage->base_dd_min = damage->base_dd_max =
effect.driver()->effectN( 1 ).average( effect ) * role_mult( effect );
effect.driver()->effectN( 1 ).average( effect );
damage->base_multiplier *= role_mult( effect );
// TODO: determine travel speed to hit target, assuming 5yd/s based on 443549 range/duration
damage->travel_speed = 5.0;
damage->travel_speed = 5.0;

auto buff = create_buff<stat_buff_t>( effect.player, effect.player->find_spell( 451303 ) )
->add_stat_from_effect_type( A_MOD_RATING, effect.driver()->effectN( 2 ).average( effect ) );
Expand Down Expand Up @@ -3369,7 +3379,7 @@ void darkmoon_deck_vivacity( special_effect_t& effect )
magical_multi( nullptr )
{
auto values = e.player->find_spell( 454857 );

impact = create_buff<stat_buff_t>( e.player, e.player->find_spell( 454862 ) )
->add_stat_from_effect( 1, values->effectN( 1 ).average( e ) )
->add_stat_from_effect( 2, values->effectN( 2 ).average( e ) );
Expand Down Expand Up @@ -3437,7 +3447,7 @@ void darkmoon_deck_vivacity( special_effect_t& effect )

effect.spell_id = 454859;

effect.proc_flags2_ = PF2_ALL_HIT | PF2_PERIODIC_DAMAGE;
effect.proc_flags2_ = PF2_ALL_HIT | PF2_PERIODIC_DAMAGE;

new vivacity_cb_t( effect );
}
Expand Down Expand Up @@ -3878,6 +3888,7 @@ void shadowed_essence( special_effect_t& effect )
// TODO: determine if damage is affected by role mult
auto damage = create_proc_action<generic_proc_t>( "shadowed_essence_damage", e, 455654 );
damage->base_dd_min = damage->base_dd_max = e.driver()->effectN( 1 ).average( e );
damage->base_multiplier *= role_mult( e.player );

auto missile = create_proc_action<generic_proc_t>( "shadowed_essence", e, 455653 );
missile->add_child( damage );
Expand Down Expand Up @@ -4070,7 +4081,7 @@ void shining_arathor_insignia( special_effect_t& effect )
// TODO: determine if this is affected by role mult
auto damage_proc = create_proc_action<generic_proc_t>( "shining_arathor_insignia_damage", effect, 455433 );
damage_proc->base_dd_min = damage_proc->base_dd_max = effect.driver()->effectN( 1 ).average( effect );

effect.execute_action = damage_proc;

new dbc_proc_callback_t( effect.player, effect );
Expand All @@ -4086,7 +4097,8 @@ void void_reapers_claw( special_effect_t& effect )
effect.tick = effect.trigger()->effectN( 1 ).period();
// TODO: confirm effect value is for the entire dot and not per tick
effect.discharge_amount =
effect.driver()->effectN( 1 ).average( effect ) * effect.tick / effect.duration_ * role_mult( effect );
effect.driver()->effectN( 1 ).average( effect ) * effect.tick / effect.duration_;
effect.discharge_amount *= role_mult( effect );

new dbc_proc_callback_t( effect.player, effect );
}
Expand Down Expand Up @@ -4211,16 +4223,6 @@ void befoulers_syringe( special_effect_t& effect )
}
};

struct befouling_strike_t : public generic_proc_t
{
befouling_strike_t( const special_effect_t& e )
: generic_proc_t( e, "befouling_strike", e.player->find_spell( 442280 ) )
{
base_dd_min = base_dd_max = e.driver()->effectN( 2 ).average( e );
base_multiplier *= role_mult( e );
}
};

// create on-next melee damage
auto strike = create_proc_action<generic_proc_t>( "befouling_strike", effect, 442280 );
strike->base_dd_min = strike->base_dd_max = effect.driver()->effectN( 2 ).average( effect );
Expand Down Expand Up @@ -4264,7 +4266,8 @@ void voltaic_stormcaller( special_effect_t& effect )

voltaic_stormstrike_t( const special_effect_t& e ) : generic_aoe_proc_t( e, "voltaic_stormstrike", 455910, true )
{
base_dd_min = base_dd_max = e.driver()->effectN( 1 ).average( e ) * role_mult( e );
base_dd_min = base_dd_max = e.driver()->effectN( 1 ).average( e );
base_multiplier *= role_mult( e );

buff = create_buff<stat_buff_with_multiplier_t>( e.player, e.player->find_spell( 456652 ) );
buff->add_stat_from_effect_type( A_MOD_RATING, e.driver()->effectN( 2 ).average( e ) );
Expand Down Expand Up @@ -4298,7 +4301,7 @@ void harvesters_interdiction( special_effect_t& effect )
new dbc_proc_callback_t( effect.player, effect );
}

// Siphoning Stilleto
// Siphoning Stilleto
// 453573 Driver
// Effect 1: Self Damage
// Effect 2: Damage
Expand Down Expand Up @@ -4329,7 +4332,9 @@ void siphoning_stilleto( special_effect_t& effect )

damage = create_proc_action<generic_proc_t>( "siphoning_stilleto", e, 458624 );
damage->base_dd_min = damage->base_dd_max =
e.driver()->effectN( 2 ).average( e ) * role_mult( e ) * writhing_mul( e.player );
e.driver()->effectN( 2 ).average( e );
damage->base_multiplier *= role_mult( e );
damage->base_multiplier *= writhing_mul( e.player );
}

void execute( action_t*, action_state_t* ) override
Expand Down Expand Up @@ -4618,7 +4623,7 @@ void woven_dusk( special_effect_t& effect )
auto buff = create_buff<stat_buff_t>( effect.player, effect.player->find_spell( 457630 ) )
->add_stat_from_effect_type( A_MOD_RATING, effect.driver()->effectN( 2 ).average( effect ) );

// Something *VERY* weird is going on here. It appears to work properly for Discipline Priest, but not Shadow.
// Something *VERY* weird is going on here. It appears to work properly for Discipline Priest, but not Shadow.
if ( effect.player->specialization() == PRIEST_DISCIPLINE )
{
buff->set_chance( 1.0 )->set_rppm( RPPM_DISABLE );
Expand Down Expand Up @@ -4877,8 +4882,8 @@ void register_special_effects()
register_special_effect( 455419, items::spelunkers_waning_candle );
register_special_effect( 455436, items::unstable_power_core );
register_special_effect( 451742, items::stormrider_flight_badge );
register_special_effect( 451750, DISABLED_EFFECT ); // stormrider flight badge special effect
register_special_effect( 435502, items::shadowbinding_ritual_knife );
register_special_effect( 451750, DISABLED_EFFECT ); // stormrider flight badge special effect
register_special_effect( 435502, items::shadowbinding_ritual_knife );
register_special_effect( 455432, items::shining_arathor_insignia );

// Weapons
Expand Down Expand Up @@ -4925,8 +4930,10 @@ action_t* create_action( player_t* p, util::string_view n, util::string_view opt
double role_mult( player_t* player, const spell_data_t* s_data )
{
double mult = 1.0;
auto vars = player->dbc->spell_desc_vars( s_data->id() ).desc_vars();

if ( auto vars = player->dbc->spell_desc_vars( s_data->id() ).desc_vars() )
assert( vars && "No spell description variables found. role_mult( player_t* ) can provide a default value." );
if ( vars )
{
std::cmatch m;
std::regex get_var( R"(\$rolemult=\$(.*))" ); // find the $rolemult= variable
Expand Down Expand Up @@ -4961,6 +4968,12 @@ double role_mult( const special_effect_t& effect )
return role_mult( effect.player, effect.driver() );
}

// Default role_mult if none can be found on any related spell.
double role_mult( player_t *p )
{
return role_mult( p, p->find_spell( 445339 ) );
}

// writhing armor banding embellishment, doubles nerubian embellishment values
double writhing_mul( player_t* p )
{
Expand Down
1 change: 1 addition & 0 deletions engine/player/unique_gear_thewarwithin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ void register_hotfixes();
action_t* create_action( player_t*, std::string_view, std::string_view );
double role_mult( player_t*, const spell_data_t* );
double role_mult( const special_effect_t& );
double role_mult( player_t* );
double writhing_mul( player_t* );
} // namespace unique_gear::thewarwithin
8 changes: 6 additions & 2 deletions engine/report/report_html_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1036,13 +1036,15 @@ void print_html_action_info( report::sc_html_stream& os, unsigned stats_mask, co
"<li><span>spell_power_mod.direct:</span>{:.6f}</li>"
"<li><span>base_dd_min:</span>{:.2f}</li>"
"<li><span>base_dd_max:</span>{:.2f}</li>"
"<li><span>base_dd_mult:</span>{:.2f}</li></ul></div>\n",
"<li><span>base_dd_mult:</span>{:.2f}</li>\n"
"<li><span>base_multiplier:</span>{:.2f}</li></ul></div>\n",
a->may_crit ? "true" : "false",
a->attack_power_mod.direct,
a->spell_power_mod.direct,
a->base_dd_min,
a->base_dd_max,
a->base_dd_multiplier );
a->base_dd_multiplier,
a->base_multiplier );
}

if ( a->dot_duration > timespan_t::zero() )
Expand All @@ -1056,6 +1058,7 @@ void print_html_action_info( report::sc_html_stream& os, unsigned stats_mask, co
"<li><span>spell_power_mod.tick:</span>{:.6f}</li>"
"<li><span>base_td:</span>{:.2f}</li>"
"<li><span>base_td_mult:</span>{:.2f}</li>"
"<li><span>base_multiplier:</span>{:.2f}</li>"
"<li><span>dot_duration:</span>{:.2f}</li>"
"<li><span>base_tick_time:</span>{:.2f}</li>"
"<li><span>hasted_ticks:</span>{}</li>"
Expand All @@ -1068,6 +1071,7 @@ void print_html_action_info( report::sc_html_stream& os, unsigned stats_mask, co
a->spell_power_mod.tick,
a->base_td,
a->base_td_multiplier,
a->base_multiplier,
a->dot_duration.total_seconds(),
a->base_tick_time.total_seconds(),
a->hasted_ticks ? "true" : "false",
Expand Down

0 comments on commit c302d41

Please sign in to comment.