From 6ce43166530a188abc1bfc051208fccb87c1d8b6 Mon Sep 17 00:00:00 2001 From: Saeldur <5496498+Saeldur@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:13:03 +0000 Subject: [PATCH] [Priest] Adjust how Power Word Shield works --- engine/class_modules/priest/sc_priest.cpp | 130 +++++++++++++++------- engine/class_modules/priest/sc_priest.hpp | 6 + 2 files changed, 94 insertions(+), 42 deletions(-) diff --git a/engine/class_modules/priest/sc_priest.cpp b/engine/class_modules/priest/sc_priest.cpp index 59aa4122d45..76b64a5e470 100644 --- a/engine/class_modules/priest/sc_priest.cpp +++ b/engine/class_modules/priest/sc_priest.cpp @@ -15,6 +15,67 @@ namespace priestspace { +namespace buffs +{ +// ========================================================================== +// Power Word: Shield +// ========================================================================== +struct power_word_shield_buff_t : public priest_buff_t +{ + double initial_size; + double energize_amount; + using ab = priest_buff_t; + + power_word_shield_buff_t( priest_t* player, player_t* target ) + : ab( actor_pair_t( target, player ), "power_word_shield", player->find_class_spell( "Power Word: Shield" ) ), + energize_amount( player->find_spell( 47755 )->effectN( 1 ).percent() / 100 * + priest().resources.max[ RESOURCE_MANA ] ) + { + set_absorb_source( player->get_stats( "power_word_shield" ) ); + set_cooldown( 0_s ); + initial_size = 0; + buff_period = 0_s; // TODO: Work out why Power Word: Shield has buff period. Work out why shields ticking refreshes + // them to full value. + } + + bool trigger( int stacks, double value, double chance, timespan_t duration ) override + { + sim->print_debug( "{} changes stored Power Word: Shield maximum from {} to {}", *player, initial_size, value ); + initial_size = value; + + return ab::trigger( stacks, value, chance, duration ); + } + + void trigger_void_shield( double result_amount ) + { + // The initial amount of the shield and our "cap" is stored in the Void Shield buff + double left_to_refill = initial_size - current_value; + double refill_amount = std::min( left_to_refill, result_amount ); + + if ( refill_amount > 0 ) + { + sim->print_debug( "{} adds value to Power Word: Shield. original={}, left_to_refill={}, refill_amount={}", + *player, current_value, left_to_refill, refill_amount ); + current_value += refill_amount; + } + } + + void expire_override( int expiration_stacks, timespan_t remaining_duration ) override + { + if ( remaining_duration > timespan_t::zero() ) + { + if ( priest().talents.discipline.shield_discipline.enabled() ) + { + priest().resource_gain( RESOURCE_MANA, energize_amount, priest().gains.shield_discipline ); + } + } + + ab::expire_override( expiration_stacks, remaining_duration ); + } +}; + +} // namespace buffs + namespace actions { namespace spells @@ -2272,9 +2333,32 @@ struct power_word_shield_t final : public priest_absorb_t } // Manually create the buff so we can reference it with Void Shield - absorb_buff_t* create_buff( const action_state_t* ) override + absorb_buff_t* create_buff( const action_state_t* s ) override { - return priest().buffs.power_word_shield; + if ( s->target == player ) + { + if ( priest().buffs.power_word_shield->absorb_source != stats ) + priest().buffs.power_word_shield->set_absorb_source( stats ); + return priest().buffs.power_word_shield; + } + + buff_t* b = buff_t::find( s->target, name_str ); + if ( b ) + return debug_cast( b ); + + std::string stats_obj_name = name_str; + if ( s->target != player ) + stats_obj_name += "_" + player->name_str; + stats_t* stats_obj = player->get_stats( stats_obj_name, this ); + if ( stats != stats_obj ) + { + // Add absorb target stats as a child to the main stats object for reporting + stats->add_child( stats_obj ); + } + auto buff = make_buff( &priest(), s->target ); + buff->set_absorb_source( stats_obj ); + + return buff; } double composite_da_multiplier( const action_state_t* s ) const override @@ -2553,45 +2637,6 @@ struct cauterizing_shadows_t final : public priest_heal_t namespace buffs { -// ========================================================================== -// Power Word: Shield -// ========================================================================== -struct power_word_shield_buff_t : public absorb_buff_t -{ - double initial_size; - - power_word_shield_buff_t( priest_t* player ) - : absorb_buff_t( player, "power_word_shield", player->find_class_spell( "Power Word: Shield" ) ) - { - set_absorb_source( player->get_stats( "power_word_shield" ) ); - set_cooldown( 0_s ); - initial_size = 0; - buff_period = 0_s; // TODO: Work out why Power Word: Shield has buff period. Work out why shields ticking refreshes - // them to full value. - } - - bool trigger( int stacks, double value, double chance, timespan_t duration ) override - { - sim->print_debug( "{} changes stored Power Word: Shield maximum from {} to {}", *player, initial_size, value ); - initial_size = value; - - return absorb_buff_t::trigger( stacks, value, chance, duration ); - } - - void trigger_void_shield( double result_amount ) - { - // The initial amount of the shield and our "cap" is stored in the Void Shield buff - double left_to_refill = initial_size - current_value; - double refill_amount = std::min( left_to_refill, result_amount ); - - if ( refill_amount > 0 ) - { - sim->print_debug( "{} adds value to Power Word: Shield. original={}, left_to_refill={}, refill_amount={}", - *player, current_value, left_to_refill, refill_amount ); - current_value += refill_amount; - } - } -}; // ========================================================================== // Desperate Prayer - Health Increase buff @@ -2859,6 +2904,7 @@ void priest_t::create_gains() gains.insanity_maddening_touch = get_gain( "Maddening Touch" ); gains.insanity_t30_2pc = get_gain( "Insanity Gained from T30 2PC" ); gains.cauterizing_shadows_health = get_gain( "Health from Cauterizing Shadows" ); + gains.shield_discipline = get_gain( "Shield Discipline" ); } /** Construct priest procs */ @@ -3785,7 +3831,7 @@ void priest_t::create_buffs() // Generic buffs buffs.desperate_prayer = make_buff( *this ); - buffs.power_word_shield = new buffs::power_word_shield_buff_t( this ); + buffs.power_word_shield = new buffs::power_word_shield_buff_t( this, this ); buffs.fade = make_buff( this, "fade", find_class_spell( "Fade" ) )->set_default_value_from_effect( 1 ); buffs.levitate = make_buff( this, "levitate", specs.levitate_buff )->set_duration( timespan_t::zero() ); diff --git a/engine/class_modules/priest/sc_priest.hpp b/engine/class_modules/priest/sc_priest.hpp index fbd59792a88..744d278f78e 100644 --- a/engine/class_modules/priest/sc_priest.hpp +++ b/engine/class_modules/priest/sc_priest.hpp @@ -714,6 +714,7 @@ struct priest_t final : public player_t propagate_const insanity_maddening_touch; propagate_const insanity_t30_2pc; propagate_const cauterizing_shadows_health; + propagate_const shield_discipline; } gains; // Benefits @@ -1672,6 +1673,11 @@ struct priest_buff_t : public Base : Base( td, name, s, item ) { } + priest_buff_t( actor_pair_t q, util::string_view name, const spell_data_t* s = spell_data_t::nil(), + const item_t* item = nullptr ) + : Base( q, name, s, item ) + { + } priest_buff_t( priest_t& p, util::string_view name, const spell_data_t* s = spell_data_t::nil(), const item_t* item = nullptr )