Skip to content

Commit

Permalink
Initial implementation of Shadowgrasp Totem
Browse files Browse the repository at this point in the history
A new option shadowlands.shadowgrasp_totem_retarget has been
implemented. Represents the retargeting delay after the target the
Shadowgrasp Totem is damaging dies. Default is disabled (i.e., no
retargeting occurs).

To control the retargeting behavior, the totem uses the use_item line to
select the target.
  • Loading branch information
navv1234 committed Dec 10, 2020
1 parent 5e3fc8c commit 32752fe
Show file tree
Hide file tree
Showing 8 changed files with 2,988 additions and 2,871 deletions.
2 changes: 2 additions & 0 deletions dbc_extract3/dbc/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,8 @@ class SpellDataGenerator(DataGenerator):
345535,
# Hateful Chain
345364, 345361,
# Shadowgrasp Totem damage
331537,
),

# Warrior:
Expand Down
5 changes: 5 additions & 0 deletions engine/action/sc_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4344,6 +4344,11 @@ void action_t::acquire_target( retarget_source /* event */, player_t* /* context
target_cache.is_valid = false;
}

if ( !target->is_sleeping() )
{
return;
}

// Don't change targets if they are not of the same generic type (both enemies, or both friendlies)
if ( target && candidate_target && target->is_enemy() != candidate_target->is_enemy() )
{
Expand Down
4 changes: 2 additions & 2 deletions engine/dbc/generated/client_data_version.inc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

// Hotfix data versioning information

#define CLIENT_DATA_HOTFIX_DATE "2020-12-09"
#define CLIENT_DATA_HOTFIX_DATE "2020-12-10"
#define CLIENT_DATA_HOTFIX_BUILD (36839)
#define CLIENT_DATA_HOTFIX_HASH "fa27993ccdee8cdc03fd0a2a3932bd65510626bc8784ab4b3c80bc98994613fc"
#define CLIENT_DATA_HOTFIX_HASH "933dc6c600e69aba8b43deec0a0adbc5244082d7cba3880bc166b93c8289d229"

#endif /* CLIENT_DATA_VERSION_INC*/
5,746 changes: 2,878 additions & 2,868 deletions engine/dbc/generated/sc_spell_data.inc

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion engine/dbc/generated/spelltext_data.inc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Spell text, wow build 9.0.2.36839
static const std::array<spelltext_data_t, 15089> __spelltext_data { {
static const std::array<spelltext_data_t, 15091> __spelltext_data { {
{ 17, "Shields an ally for $d, absorbing $<shield> damage. You cannot shield the target again for $6788d.", "Absorbs $w1 damage.", 0 },
{ 53, "Stab the target, causing ${$s2*$<mult>} Physical damage. Damage increased by $s4% when you are behind your target$?s319949[, and critical strikes apply Find Weakness for $319949s1 sec][].\r\n\r\n|cFFFFFFFFAwards $s3 combo $lpoint:points;.|r", 0, 0 },
{ 56, "Stuns target for $d.", "Stunned.", 0 },
Expand Down Expand Up @@ -7500,6 +7500,7 @@ static const std::array<spelltext_data_t, 15089> __spelltext_data { {
{ 220499, "Summons and dismisses an Ebon Blade Deathcharger that can be ridden while in combat.\r\n\r\nOnly usable on the Broken Isles and Argus.", 0, 0 },
{ 220508, "Summons and dismisses a Silver Hand Charger that can be ridden while in combat.\r\n\r\nOnly usable on the Broken Isles and Argus.", 0, 0 },
{ 220637, "$@spelldesc20271", 0, 0 },
{ 220890, "Grants the Death Knight $s2 runic power.", 0, 0 },
{ 220971, "Dig through the salvage to look for hidden treasure. Only available at your Salvage Yard.", 0, 0 },
{ 220972, "Dig through the salvage to look for hidden treasure. Only available at your Salvage Yard.", 0, 0 },
{ 220973, "Dig through the salvage to look for hidden treasure. Only available at your Salvage Yard.", 0, 0 },
Expand Down Expand Up @@ -13728,6 +13729,7 @@ static const std::array<spelltext_data_t, 15089> __spelltext_data { {
{ 331497, "You cannot benefit from Darkest Hour again for $d.", "You have recently benefited from Darkest Hour and cannot benefit from it again.", 0 },
{ 331523, "Drop a Shadowgrasp Totem at your feet for $d that harvests your target, inflicting $329878s1 Shadow damage every $331532t1 sec. Each time a target dies while affected by Shadowgrasp Totem, you are healed for $329878s2 and this cooldown is reduced by $329878s3 sec.", 0, 0 },
{ 331532, "$@spelldesc331523", 0, 0 },
{ 331537, "$@spelldesc331523", 0, 0 },
{ 331576, "Door of Shadows disorients all nearby enemies at the target location for $331866d when you appear.", 0, 0 },
{ 331577, "Door of Shadows increases your movement speed by $331868s1%, decaying over $331868d.", 0, 0 },
{ 331579, "You loot $s1% more Infused Rubies, and dredgers throughout Revendreth offer you an expanded selection of goods.", 0, 0 },
Expand Down
94 changes: 94 additions & 0 deletions engine/player/unique_gear_shadowlands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,99 @@ void bloodspattered_scale( special_effect_t& effect )
}
}

void shadowgrasp_totem( special_effect_t& effect )
{
struct shadowgrasp_totem_damage_t : public generic_proc_t
{
action_t* parent;

shadowgrasp_totem_damage_t( const special_effect_t& effect ) :
generic_proc_t( effect, "shadowgrasp_totem", 331537 ), parent( nullptr )
{
dot_duration = 0_s;
base_dd_min = base_dd_max = player->find_spell( 329878 )->effectN( 1 ).average( effect.item );
}

void init_finished() override
{
generic_proc_t::init_finished();

parent = player->find_action( "use_item_shadowgrasp_totem" );
}
};

struct shadowgrasp_totem_buff_t : public buff_t
{
event_t* retarget_event;
shadowgrasp_totem_damage_t* action;
cooldown_t* item_cd;
timespan_t cd_adjust;

shadowgrasp_totem_buff_t( const special_effect_t& effect ) :
buff_t( effect.player, "shadowgrasp_totem", effect.player->find_spell( 331537 ) ),
retarget_event( nullptr ), action( new shadowgrasp_totem_damage_t( effect ) )
{
set_tick_callback( [this]( buff_t*, int, timespan_t ) {
action->set_target( action->parent->target );
action->execute();
} );

item_cd = effect.player->get_cooldown( effect.cooldown_name() );
cd_adjust = timespan_t::from_seconds(
-source->find_spell( 329878 )->effectN( 3 ).base_value() );

range::for_each( effect.player->sim->actor_list, [this]( player_t* t ) {
t->register_on_demise_callback( source, [this]( player_t* actor ) {
trigger_target_death( actor );
} );
} );
}

void reset() override
{
buff_t::reset();

retarget_event = nullptr;
}

void trigger_target_death( const player_t* actor )
{
if ( !check() || !actor->is_enemy() || action->parent->target != actor )
{
return;
}

item_cd->adjust( cd_adjust );

if ( !retarget_event && sim->shadowlands_opts.retarget_shadowgrasp_totem > 0_s )
{
retarget_event = make_event( sim, sim->shadowlands_opts.retarget_shadowgrasp_totem, [this]() {
retarget_event = nullptr;

// Retarget parent action to emulate player "retargeting" during Shadowgrasp
// Totem duration to grab more 15 second cooldown reductions
{
auto new_target = action->parent->select_target_if_target();
if ( new_target )
{
sim->print_debug( "{} action {} retargeting to a new target: {}",
source->name(), action->parent->name(), new_target->name() );
action->parent->set_target( new_target );
}
}
} );
}
}
};

auto buff = buff_t::find( effect.player, "shadowgrasp_totem" );
if ( !buff )
{
buff = make_buff<shadowgrasp_totem_buff_t>( effect );
effect.custom_buff = buff;
}
}

// Runecarves

void echo_of_eonar( special_effect_t& effect )
Expand Down Expand Up @@ -1619,6 +1712,7 @@ void register_special_effects()
unique_gear::register_special_effect( 345533, items::anima_field_emitter );
unique_gear::register_special_effect( 342427, items::decanter_of_animacharged_winds );
unique_gear::register_special_effect( 329840, items::bloodspattered_scale );
unique_gear::register_special_effect( 331523, items::shadowgrasp_totem );

// Runecarves
unique_gear::register_special_effect( 338477, items::echo_of_eonar );
Expand Down
1 change: 1 addition & 0 deletions engine/sim/sc_sim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3809,6 +3809,7 @@ void sim_t::create_options()
shadowlands_opts.anima_field_emitter_mean, 0.0, std::numeric_limits<double>::max() ) );
add_option( opt_float( "shadowlands.anima_field_emitter_stddev",
shadowlands_opts.anima_field_emitter_stddev, 0.0, std::numeric_limits<double>::max() ) );
add_option( opt_timespan( "shadowlands.retarget_shadowgrasp_totem", shadowlands_opts.retarget_shadowgrasp_totem ) );
}

// sim_t::parse_option ======================================================
Expand Down
3 changes: 3 additions & 0 deletions engine/sim/sc_sim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,9 @@ struct sim_t : private sc_thread_t
/// Anima Field Emitter buff duration distribution, defaults to full duration.
double anima_field_emitter_mean = std::numeric_limits<double>::max(),
anima_field_emitter_stddev = 0.0;

/// Retarget Shadowgrasp Totem if the use_item target demises after this many seconds
timespan_t retarget_shadowgrasp_totem = 0_s;
} shadowlands_opts;

// Auras and De-Buffs
Expand Down

0 comments on commit 32752fe

Please sign in to comment.