You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2374 lines
112 KiB

4 years ago
-- RogueAssassination.lua
-- June 2018
local addon, ns = ...
local Hekili = _G[ addon ]
local class = Hekili.Class
4 years ago
local state = Hekili.State
4 years ago
local PTR = ns.PTR
local FindUnitBuffByID, FindUnitDebuffByID = ns.FindUnitBuffByID, ns.FindUnitDebuffByID
local IterateTargets, ActorHasDebuff = ns.iterateTargets, ns.actorHasDebuff
4 years ago
local orderedPairs = ns.orderedPairs
local format = string.format
4 years ago
-- Conduits
-- [-] lethal_poisons
-- [-] maim_mangle
-- [-] poisoned_katar
-- [x] wellplaced_steel
-- Covenant
-- [-] reverberation
-- [-] slaughter_scars
-- [-] sudden_fractures
-- [-] septic_shock
-- Endurance
-- [x] cloaked_in_shadows
-- [x] nimble_fingers -- may need to double check which reductions come first.
-- [-] recuperator
-- Finesse
-- [x] fade_to_nothing
-- [x] prepared_for_all
-- [x] quick_decisions
-- [x] rushed_setup
if UnitClassBase( 'player' ) == 'ROGUE' then
local spec = Hekili:NewSpecialization( 259 )
spec:RegisterResource( Enum.PowerType.ComboPoints )
spec:RegisterResource( Enum.PowerType.Energy, {
vendetta_regen = {
aura = "vendetta_regen",
last = function ()
local app = state.buff.vendetta_regen.applied
local t = state.query_time
return app + floor( t - app )
end,
interval = 1,
value = 20,
},
garrote_vim = {
aura = "garrote",
debuff = true,
last = function ()
local app = state.debuff.garrote.last_tick
local exp = state.debuff.garrote.expires
local tick = state.debuff.garrote.tick_time
local t = state.query_time
return min( exp, app + ( floor( ( t - app ) / tick ) * tick ) )
end,
stop = function ()
return state.debuff.wound_poison_dot.down and state.debuff.deadly_poison_dot.down
end,
interval = function ()
return state.debuff.garrote.tick_time
end,
value = 8
},
internal_bleeding_vim = {
aura = "internal_bleeding",
debuff = true,
last = function ()
local app = state.debuff.internal_bleeding.last_tick
local exp = state.debuff.internal_bleeding.expires
local tick = state.debuff.internal_bleeding.tick_time
local t = state.query_time
return min( exp, app + ( floor( ( t - app ) / tick ) * tick ) )
end,
stop = function ()
return state.debuff.wound_poison_dot.down and state.debuff.deadly_poison_dot.down
end,
interval = function ()
return state.debuff.internal_bleeding.tick_time
end,
value = 8
},
rupture_vim = {
aura = "rupture",
debuff = true,
last = function ()
local app = state.debuff.rupture.last_tick
local exp = state.debuff.rupture.expires
local tick = state.debuff.rupture.tick_time
local t = state.query_time
return min( exp, app + ( floor( ( t - app ) / tick ) * tick ) )
end,
stop = function ()
return state.debuff.wound_poison_dot.down and state.debuff.deadly_poison_dot.down
end,
interval = function ()
return state.debuff.rupture.tick_time
end,
value = 8
},
crimson_tempest_vim = {
aura = "crimson_tempest",
debuff = true,
last = function ()
local app = state.debuff.crimson_tempest.last_tick
local exp = state.debuff.crimson_tempest.expires
local tick = state.debuff.crimson_tempest.tick_time
local t = state.query_time
return min( exp, app + ( floor( ( t - app ) / tick ) * tick ) )
end,
stop = function ()
return state.debuff.wound_poison_dot.down and state.debuff.deadly_poison_dot.down
end,
interval = function ()
return state.debuff.crimson_tempest.tick_time
end,
value = 8
},
nothing_personal = {
aura = "nothing_personal_regen",
last = function ()
local app = state.buff.nothing_personal_regen.applied
local exp = state.buff.nothing_personal_regen.expires
local tick = state.buff.nothing_personal_regen.tick_time
local t = state.query_time
return min( exp, app + ( floor( ( t - app ) / tick ) * tick ) )
end,
stop = function ()
return state.buff.nothing_personal_regen.down
end,
interval = function ()
return state.buff.nothing_personal_regen.tick_time
end,
value = 4
}
} )
-- Talents
spec:RegisterTalents( {
master_poisoner = 22337, -- 196864
elaborate_planning = 22338, -- 193640
blindside = 22339, -- 111240
nightstalker = 22331, -- 14062
subterfuge = 22332, -- 108208
master_assassin = 23022, -- 255989
vigor = 19239, -- 14983
deeper_stratagem = 19240, -- 193531
marked_for_death = 19241, -- 137619
leeching_poison = 22340, -- 280716
cheat_death = 22122, -- 31230
elusiveness = 22123, -- 79008
internal_bleeding = 19245, -- 154904
iron_wire = 23037, -- 196861
prey_on_the_weak = 22115, -- 131511
venom_rush = 22343, -- 152152
alacrity = 23015, -- 193539
exsanguinate = 22344, -- 200806
poison_bomb = 21186, -- 255544
hidden_blades = 22133, -- 270061
crimson_tempest = 23174, -- 121411
} )
-- PvP Talents
spec:RegisterPvpTalents( {
creeping_venom = 141, -- 354895
death_from_above = 3479, -- 269513
dismantle = 5405, -- 207777
flying_daggers = 144, -- 198128
hemotoxin = 830, -- 354124
intent_to_kill = 130, -- 197007
maneuverability = 3448, -- 197000
smoke_bomb = 3480, -- 212182
system_shock = 147, -- 198145
thick_as_thieves = 5408, -- 221622
} )
spec:RegisterStateExpr( "cp_max_spend", function ()
return combo_points.max
end )
-- Commented out in SimC, but my implementation should hold up vs. theirs.
-- APLs will use effective_combo_points.
spec:RegisterStateExpr( "animacharged_cp", function ()
local n = buff.echoing_reprimand.stack
if n > 0 then return n end
return combo_points.max
end )
spec:RegisterStateExpr( "effective_combo_points", function ()
if buff.echoing_reprimand.up and combo_points.current == buff.echoing_reprimand.stack then
return 7
end
return combo_points.current
end )
local stealth = {
rogue = { "stealth", "vanish", "shadow_dance", "subterfuge" },
mantle = { "stealth", "vanish" },
sepsis = { "sepsis_buff" },
all = { "stealth", "vanish", "shadow_dance", "subterfuge", "shadowmeld", "sepsis_buff" }
}
spec:RegisterStateTable( "stealthed", setmetatable( {}, {
__index = function( t, k )
if k == "rogue" then
return buff.stealth.up or buff.vanish.up or buff.shadow_dance.up or buff.subterfuge.up
elseif k == "rogue_remains" then
return max( buff.stealth.remains, buff.vanish.remains, buff.shadow_dance.remains, buff.subterfuge.remains )
elseif k == "mantle" then
return buff.stealth.up or buff.vanish.up
elseif k == "mantle_remains" then
return max( buff.stealth.remains, buff.vanish.remains )
elseif k == "sepsis" then
return buff.sepsis_buff.up
elseif k == "sepsis_remains" then
return buff.sepsis_buff.remains
elseif k == "all" then
return buff.stealth.up or buff.vanish.up or buff.shadow_dance.up or buff.subterfuge.up or buff.shadowmeld.up or buff.sepsis_buff.up
elseif k == "remains" or k == "all_remains" then
return max( buff.stealth.remains, buff.vanish.remains, buff.shadow_dance.remains, buff.subterfuge.remains, buff.shadowmeld.remains, buff.sepsis_buff.remains )
end
return false
end
} ) )
spec:RegisterStateExpr( "master_assassin_remains", function ()
if not ( talent.master_assassin.enabled or legendary.mark_of_the_master_assassin.enabled ) then return 0 end
if stealthed.mantle then return cooldown.global_cooldown.remains + ( legendary.mark_of_the_master_assassin.enabled and 4 or 3 )
elseif buff.master_assassin_any.up then return buff.master_assassin_any.remains end
return 0
end )
local stealth_dropped = 0
local function isStealthed()
return ( FindUnitBuffByID( "player", 1784 ) or FindUnitBuffByID( "player", 115191 ) or FindUnitBuffByID( "player", 115192 ) or FindUnitBuffByID( "player", 11327 ) or GetTime() - stealth_dropped < 0.2 )
end
local calculate_multiplier = setfenv( function( spellID )
local mult = 1
local stealth = isStealthed()
if stealth then
if talent.nightstalker.enabled then
mult = mult * 1.5
end
-- Garrote.
if talent.subterfuge.enabled and spellID == 703 then
mult = mult * 1.8
end
end
return mult
end, state )
4 years ago
-- Bleed Modifiers
-- 9.2 adds a set bonus that is essentially a second Exsanguinate.
-- We need to be able to tell that an aura has been Exsanguinated via talent *and* Exsanguinated by Vendetta and 4pc.
local tier28_vendetta_spells = {
garrote = 1,
rupture = 1,
crimson_tempest = 1,
internal_bleeding = 1,
deadly_poison_dot = 1,
sepsis = 1,
serrated_bone_spike = 1,
}
local tracked_bleeds = {}
local function NewBleed( key, spellID )
tracked_bleeds[ key ] = {
id = spellID,
exsanguinate = {},
vendetta = {},
rate = {},
last_tick = {}
}
tracked_bleeds[ spellID ] = tracked_bleeds[ key ]
end
local function ApplyBleed( key, target, exsanguinate, vendetta )
local bleed = tracked_bleeds[ key ]
bleed.rate[ target ] = 1 + ( exsanguinate and 1 or 0 ) + ( vendetta and 1 or 0 )
bleed.last_tick[ target ] = GetTime()
bleed.exsanguinate[ target ] = exsanguinate
bleed.vendetta[ target ] = vendetta
end
local function UpdateBleed( key, target, exsanguinate, vendetta )
local bleed = tracked_bleeds[ key ]
if not bleed.rate[ target ] then
return
end
if exsanguinate and not bleed.exsanguinate[ target ] then
bleed.rate[ target ] = bleed.rate[ target ] + 1
bleed.exsanguinate[ target ] = true
end
if vendetta and not bleed.vendetta[ target ] then
bleed.rate[ target ] = bleed.rate[ target ] + 1
bleed.vendetta[ target ] = true
end
end
local function UpdateBleedTick( key, target, time )
local bleed = tracked_bleeds[ key ]
if not bleed.rate[ target ] then return end
bleed.last_tick[ target ] = time or GetTime()
end
local function RemoveBleed( key, target )
local bleed = tracked_bleeds[ key ]
bleed.rate[ target ] = nil
bleed.last_tick[ target ] = nil
bleed.exsanguinate[ target ] = nil
bleed.vendetta[ target ] = nil
end
local function GetExsanguinateRate( aura, target )
return tracked_bleeds[ aura ] and tracked_bleeds[ aura ].rate[ target ] or 1
end
NewBleed( "garrote", 703 )
NewBleed( "rupture", 1943 )
NewBleed( "crimson_tempest", 121411 )
NewBleed( "internal_bleeding", 154904 )
4 years ago
4 years ago
NewBleed( "deadly_poison_dot", 2823 )
NewBleed( "sepsis", 328305 )
NewBleed( "serrated_bone_spike", 324073 )
4 years ago
4 years ago
local application_events = {
SPELL_AURA_APPLIED = true,
SPELL_AURA_APPLIED_DOSE = true,
SPELL_AURA_REFRESH = true,
}
local removal_events = {
SPELL_AURA_REMOVED = true,
SPELL_AURA_BROKEN = true,
SPELL_AURA_BROKEN_SPELL = true,
}
4 years ago
4 years ago
local stealth_spells = {
[1784 ] = true,
[115191] = true,
}
4 years ago
4 years ago
local tick_events = {
SPELL_PERIODIC_DAMAGE = true,
4 years ago
}
local death_events = {
UNIT_DIED = true,
UNIT_DESTROYED = true,
4 years ago
UNIT_DISSIPATES = true,
4 years ago
PARTY_KILL = true,
SPELL_INSTAKILL = true,
}
4 years ago
-- We need to know if a target has Vendetta on it when we apply a bleed, for Tier 28 purposes.
local vendetta_info = {}
4 years ago
spec:RegisterEvent( "COMBAT_LOG_EVENT_UNFILTERED", function()
local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName = CombatLogGetCurrentEventInfo()
if sourceGUID == state.GUID then
4 years ago
if removal_events[ subtype ] then
if stealth_spells[ spellID ] then
4 years ago
stealth_dropped = GetTime()
4 years ago
return
end
end
if application_events[ subtype ] then
if spellID == 79140 then
-- TODO: Review for Vendetta duration extensions.
vendetta_info[ destGUID ] = GetTime() + 20
-- We applied Vendetta; if we have Tier28 2pc, we have to modify the applied aura.
if state.set_bonus.tier28_4pc > 0 then
UpdateBleed( "garrote", destGUID, nil, true )
UpdateBleed( "rupture", destGUID, nil, true )
UpdateBleed( "crimson_tempest", destGUID, nil, true )
UpdateBleed( "internal_bleeding", destGUID, nil, true )
UpdateBleed( "deadly_poison_dot", destGUID, nil, true )
UpdateBleed( "sepsis", destGUID, nil, true )
UpdateBleed( "serrated_bone_spike", destGUID, nil, true )
end
4 years ago
4 years ago
return
4 years ago
end
4 years ago
if tracked_bleeds[ spellID ] then
-- TODO: Modernize basic debuff tracking and snapshotting.
4 years ago
ns.saveDebuffModifier( spellID, calculate_multiplier( spellID ) )
ns.trackDebuff( spellID, destGUID, GetTime(), true )
4 years ago
ApplyBleed( spellID, destGUID, nil, state.set_bonus.tier28_4pc > 0 and vendetta_info[ destGUID ] and vendetta_info[ destGUID ] > GetTime() )
return
end
4 years ago
4 years ago
return
end
4 years ago
4 years ago
if tick_events[ subtype ] and tracked_bleeds[ spellID ] then
UpdateBleedTick( spellID, destGUID, GetTime() )
return
end
4 years ago
4 years ago
-- Exsanguinate was used.
if subtype == "SPELL_CAST_SUCCESS" and spellID == 200806 then
UpdateBleed( "garrote", destGUID, true, nil )
UpdateBleed( "rupture", destGUID, true, nil )
UpdateBleed( "crimson_tempest", destGUID, true, nil )
UpdateBleed( "internal_bleeding", destGUID, true, nil )
return
4 years ago
end
end
if death_events[ subtype ] then
4 years ago
--[[ TODO: Deal with annoying Training Dummy resets.
RemoveBleed( "garrote", destGUID )
RemoveBleed( "rupture", destGUID )
RemoveBleed( "crimson_tempest", destGUID )
RemoveBleed( "internal_bleeding", destGUID )
RemoveBleed( "deadly_poison_dot", destGUID )
RemoveBleed( "sepsis", destGUID )
RemoveBleed( "serrated_bone_spike", destGUID ) ]]
vendetta_info[ destGUID ] = nil
4 years ago
end
end )
spec:RegisterHook( "UNIT_ELIMINATED", function( guid )
4 years ago
vendetta_info[ guid ] = nil
4 years ago
end )
local energySpent = 0
local ENERGY = Enum.PowerType.Energy
local lastEnergy = -1
spec:RegisterUnitEvent( "UNIT_POWER_FREQUENT", "player", nil, function( event, unit, powerType )
if powerType == "ENERGY" then
local current = UnitPower( "player", ENERGY )
if current < lastEnergy then
energySpent = ( energySpent + lastEnergy - current ) % 30
end
lastEnergy = current
end
end )
spec:RegisterCycle( function ()
if active_enemies == 1 then return end
if this_action == "marked_for_death" then
if active_dot.marked_for_death >= cycle_enemies then return end -- As far as we can tell, MfD is on everything we care about, so we don't cycle.
if debuff.marked_for_death.up then return "cycle" end -- If current target already has MfD, cycle.
if target.time_to_die > 3 + Hekili:GetLowestTTD() and active_dot.marked_for_death == 0 then return "cycle" end -- If our target isn't lowest TTD, and we don't have to worry that the lowest TTD target is already MfD'd, cycle.
end
end )
spec:RegisterStateExpr( "energy_spent", function ()
return energySpent
end )
spec:RegisterHook( "spend", function( amt, resource )
if legendary.duskwalkers_patch.enabled and cooldown.vendetta.remains > 0 and resource == "energy" and amt > 0 then
energy_spent = energy_spent + amt
local reduction = floor( energy_spent / 30 )
energy_spent = energy_spent % 30
if reduction > 0 then
reduceCooldown( "vendetta", reduction )
end
end
if resource == "combo_points" and legendary.obedience.enabled and buff.flagellation_buff.up then
reduceCooldown( "flagellation", amt )
end
end )
spec:RegisterStateExpr( 'persistent_multiplier', function ()
local mult = 1
if not this_action then return mult end
local stealth = buff.stealth.up or buff.subterfuge.up
if stealth then
if talent.nightstalker.enabled then
mult = mult * 2
end
if talent.subterfuge.enabled and this_action == "garrote" then
mult = mult * 1.8
end
end
return mult
end )
4 years ago
local exsanguinated_spells = {
garrote = "garrote",
kidney_shot = "internal_bleeding",
rupture = "rupture",
crimson_tempest = "crimson_tempest",
deadly_poison = "deadly_poison_dot",
sepsis = "sepsis",
serrated_bone_spike = "serrated_bone_spike",
}
-- Auras that aren't impacted by Tier 28.
local true_exsanguinated = {
"garrote",
"internal_bleeding",
"rupture",
"crimson_tempest",
}
spec:RegisterStateExpr( "exsanguinated", function ()
local aura = this_action and exsanguinated_spells[ this_action ]
aura = aura and debuff[ aura ]
if not aura or not aura.up then return false end
return aura.exsanguinated_rate > 1
end )
spec:RegisterStateExpr( "will_lose_exsanguinate", function ()
local aura = this_action and exsanguinated_spells[ this_action ]
aura = aura and debuff[ aura ]
if not aura or not aura.up then return false end
return aura.exsanguinated_rate > ( debuff.vendetta.up and 2 or 1 )
4 years ago
end )
4 years ago
spec:RegisterStateExpr( "exsanguinated_rate", function ()
local aura = this_action and exsanguinated_spells[ this_action ]
aura = aura and debuff[ aura ]
if not aura or not aura.up then return 1 end
return aura.exsanguinated_rate
end )
4 years ago
-- Enemies with either Deadly Poison or Wound Poison applied.
4 years ago
spec:RegisterStateExpr( "poisoned_enemies", function ()
4 years ago
return ns.countUnitsWithDebuffs( "deadly_poison_dot", "wound_poison_dot", "crippling_poison_dot" )
end )
4 years ago
spec:RegisterStateExpr( "poison_remains", function ()
4 years ago
return debuff.lethal_poison.remains
end )
4 years ago
local valid_bleeds = { "garrote", "internal_bleeding", "rupture", "crimson_tempest", "mutilated_flesh", "serrated_bone_spike" }
4 years ago
-- Count of bleeds on targets.
4 years ago
spec:RegisterStateExpr( "bleeds", function ()
4 years ago
local n = 0
4 years ago
for _, aura in pairs( valid_bleeds ) do
if debuff[ aura ].up then
n = n + 1
end
end
4 years ago
return n
end )
-- Count of bleeds on all poisoned (Deadly/Wound) targets.
4 years ago
spec:RegisterStateExpr( "poisoned_bleeds", function ()
4 years ago
return ns.conditionalDebuffCount( "deadly_poison_dot", "wound_poison_dot", "garrote", "internal_bleeding", "rupture" )
end )
spec:RegisterStateExpr( "ss_buffed", function ()
4 years ago
return false
4 years ago
end )
spec:RegisterStateExpr( "non_ss_buffed_targets", function ()
4 years ago
return active_enemies
--[[ local count = ( debuff.garrote.down or not debuff.garrote.exsanguinated ) and 1 or 0
4 years ago
for guid, counted in ns.iterateTargets() do
if guid ~= target.unit and counted and ( not ns.actorHasDebuff( guid, 703 ) or not ssG[ guid ] ) then
count = count + 1
end
end
4 years ago
return count ]]
4 years ago
end )
spec:RegisterStateExpr( "ss_buffed_targets_above_pandemic", function ()
4 years ago
--[[ if not debuff.garrote.refreshable and debuff.garrote.ss_buffed then
4 years ago
return 1
4 years ago
end ]]
return 0
4 years ago
end )
spec:RegisterStateExpr( "pmultiplier", function ()
if not this_action then return 0 end
local a = class.abilities[ this_action ]
if not a then return 0 end
local aura = a.aura or this_action
if not aura then return 0 end
if debuff[ aura ] and debuff[ aura ].up then
return debuff[ aura ].pmultiplier or 1
end
return 0
end )
spec:RegisterStateExpr( "priority_rotation", function ()
return settings.priority_rotation
end )
local ExpireSepsis = setfenv( function ()
applyBuff( "sepsis_buff" )
4 years ago
if legendary.toxic_onslaught.enabled then
applyBuff( "adrenaline_rush", 10 )
applyBuff( "shadow_blades", 10 )
end
end, state )
-- Tier 28
spec:RegisterSetBonuses( "tier28_2pc", 364667, "tier28_4pc", 363591 )
-- 2-Set - Grudge Match - Shiv causes enemies within 15 yards to take 40% increased damage from your Poisons and Bleeds for 9 seconds.
-- 4-Set - Grudge Match - Vendetta causes Poisons and Bleeds on your target to expire 100% faster.
spec:RegisterAuras( {
grudge_match = {
id = 264668,
duration = 9,
max_stack = 1,
},
} )
local ExpireVendetta = setfenv( function ()
if debuff.serrated_bone_spike.up and debuff.serrated_bone_spike.vendetta_exsg then
debuff.serrated_bone_spike.vendetta_exsg = false
debuff.serrated_bone_spike.exsanguinated_rate = max( 1, debuff.serrated_bone_spike.exsanguinated_rate - 1 )
end
4 years ago
end, state )
4 years ago
4 years ago
spec:RegisterHook( "reset_precast", function ()
4 years ago
Hekili.Exsg = "Bleed Snapshots Remains Multip. RateMod Exsang. Tier-28\n"
for _, aura in orderedPairs( exsanguinated_spells ) do
local d = debuff[ aura ]
d.pmultiplier = nil
d.exsanguinated_rate = nil
d.vendetta_exsg = nil
d.exsanguinated = nil
Hekili.Exsg = format( "%s%-20s %7.2f %7.2f %7.2f %7s %7s\n", Hekili.Exsg, aura, d.remains, d.pmultiplier, d.exsanguinated_rate, d.exsanguinated and "true" or "false", d.vendetta_exsg and "true" or "false" )
end
4 years ago
4 years ago
if Hekili.ActiveDebug then Hekili:Debug( Hekili.Exsg ) end
4 years ago
if debuff.sepsis.up then
state:QueueAuraExpiration( "sepsis", ExpireSepsis, debuff.sepsis.expires )
end
4 years ago
for guid, expiration in pairs( vendetta_info ) do
if expiration < now then
vendetta_info[ guid ] = nil
if tracked_bleeds.serrated_bone_spike.vendetta[ guid ] and tracked_bleeds.serrated_bone_spike.vendetta[ guid ] > 1 then
tracked_bleeds.serrated_bone_spike.vendetta[ guid ] = tracked_bleeds.serrated_bone_spike.vendetta[ guid ] - 1
end
end
end
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
state:QueueAuraExpiration( "vendetta", ExpireVendetta, debuff.vendetta.expires )
end
class.abilities.apply_poison = class.abilities.apply_poison_actual
if buff.lethal_poison.down or level < 33 then
class.abilities.apply_poison = state.spec.assassination and level > 12 and class.abilities.deadly_poison or class.abilities.instant_poison
else
if level > 32 and buff.nonlethal_poison.down then class.abilities.apply_poison = class.abilities.crippling_poison end
end
end )
4 years ago
-- We need to break stealth when we start combat from an ability.
spec:RegisterHook( "runHandler", function( ability )
local a = class.abilities[ ability ]
if stealthed.mantle and ( not a or a.startsCombat ) then
if talent.master_assassin.enabled then
applyBuff( "master_assassin" )
end
if talent.subterfuge.enabled then
applyBuff( "subterfuge" )
end
if legendary.mark_of_the_master_assassin.enabled and stealthed.mantle then
applyBuff( "master_assassins_mark", 4 )
end
if buff.stealth.up then
setCooldown( "stealth", 2 )
end
removeBuff( "stealth" )
removeBuff( "shadowmeld" )
removeBuff( "vanish" )
end
4 years ago
class.abilities.apply_poison = class.abilities.apply_poison_actual
if buff.lethal_poison.down or level < 33 then
class.abilities.apply_poison = state.spec.assassination and level > 12 and class.abilities.deadly_poison or class.abilities.instant_poison
else
if level > 32 and buff.nonlethal_poison.down then class.abilities.apply_poison = class.abilities.crippling_poison end
end
4 years ago
end )
-- Auras
spec:RegisterAuras( {
blind = {
id = 2094,
duration = 60,
max_stack = 1,
},
blindside = {
id = 121153,
duration = 10,
max_stack = 1,
},
cheap_shot = {
id = 1833,
duration = 4,
max_stack = 1,
},
cloak_of_shadows = {
id = 31224,
duration = 5,
max_stack = 1,
},
crimson_tempest = {
id = 121411,
4 years ago
duration = function () return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * ( talent.deeper_stratagem.enabled and 14 or 12 ) end,
4 years ago
max_stack = 1,
meta = {
4 years ago
exsanguinated = function( t ) return t.up and tracked_bleeds.crimson_tempest.exsanguinate[ target.unit ] or false end,
vendetta_exsg = function( t ) return t.up and tracked_bleeds.crimson_tempest.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.crimson_tempest.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.crimson_tempest.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * ( 2 / t.exsanguinated_rate ) ) or ( haste * 2 ) end,
4 years ago
},
},
crimson_vial = {
id = 185311,
duration = 4,
max_stack = 1,
},
crippling_poison = {
id = 3408,
duration = 3600,
max_stack = 1,
},
crippling_poison_dot = {
id = 3409,
duration = 12,
max_stack = 1,
},
deadly_poison = {
id = 2823,
duration = 3600,
max_stack = 1,
},
deadly_poison_dot = {
id = 2818,
4 years ago
duration = function () return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * ( 12 * haste ) end,
4 years ago
max_stack = 1,
4 years ago
exsanguinated = false,
meta = {
vendetta_exsg = function( t ) return t.up and tracked_bleeds.deadly_poison_dot.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.deadly_poison_dot.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.deadly_poison_dot.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * ( 2 / t.exsanguinated_rate ) ) or ( haste * 2 ) end,
},
4 years ago
},
elaborate_planning = {
id = 193641,
duration = 4,
max_stack = 1,
},
envenom = {
id = 32645,
duration = function () return talent.deeper_stratagem.enabled and 7 or 6 end,
type = "Poison",
max_stack = 1,
},
evasion = {
id = 5277,
duration = 10,
max_stack = 1,
},
feint = {
id = 1966,
duration = 6,
max_stack = 1,
},
fleet_footed = {
id = 31209,
},
garrote = {
id = 703,
4 years ago
duration = function() return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * 18 end,
4 years ago
max_stack = 1,
4 years ago
ss_buffed = false,
4 years ago
meta = {
4 years ago
duration = function( t ) return t.up and ( 18 * haste / t.exsanguinated_rate ) or class.auras.garrote.duration end,
exsanguinated = function( t ) return t.up and tracked_bleeds.garrote.exsanguinate[ target.unit ] or false end,
vendetta_exsg = function( t ) return t.up and tracked_bleeds.garrote.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.garrote.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.garrote.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * 2 / t.exsanguinated_rate ) or ( haste * 2 ) end,
},
4 years ago
},
garrote_silence = {
id = 1330,
duration = function () return talent.iron_wire.enabled and 6 or 3 end,
max_stack = 1,
},
hidden_blades = {
id = 270070,
duration = 3600,
max_stack = 20,
},
internal_bleeding = {
id = 154953,
4 years ago
duration = function () return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * 6 end,
4 years ago
max_stack = 1,
meta = {
4 years ago
exsanguinated = function( t ) return t.up and tracked_bleeds.internal_bleeding.exsanguinate[ target.unit ] or false end,
vendetta_exsg = function( t ) return t.up and tracked_bleeds.internal_bleeding.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.internal_bleeding.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.internal_bleeding.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * 2 / t.exsanguinated_rate ) or ( haste * 2 ) end,
4 years ago
},
},
iron_wire = {
id = 256148,
duration = 8,
max_stack = 1,
},
kidney_shot = {
id = 408,
duration = function () return talent.deeper_stratagem.enabled and 7 or 6 end,
max_stack = 1,
},
marked_for_death = {
id = 137619,
duration = 60,
max_stack = 1,
},
master_assassin = {
id = 256735,
duration = 3,
max_stack = 1,
},
prey_on_the_weak = {
id = 255909,
duration = 6,
max_stack = 1,
},
rupture = {
id = 1943,
4 years ago
duration = function () return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * ( talent.deeper_stratagem.enabled and 28 or 24 ) end,
tick_time = function () return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * ( debuff.rupture.exsanguinated and haste or ( 2 * haste ) ) end,
4 years ago
max_stack = 1,
meta = {
4 years ago
exsanguinated = function( t ) return t.up and tracked_bleeds.rupture.exsanguinate[ target.unit ] or false end,
vendetta_exsg = function( t ) return t.up and tracked_bleeds.rupture.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.rupture.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.rupture.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * 2 / t.exsanguinated_rate ) or ( haste * 2 ) end,
},
4 years ago
},
shadowstep = {
id = 36554,
duration = 2,
max_stack = 1,
},
shroud_of_concealment = {
id = 114018,
duration = 15,
max_stack = 1,
},
slice_and_dice = {
id = 315496,
duration = function () return talent.deeper_stratagem.enabled and 42 or 36 end,
max_stack = 1
},
sprint = {
id = 2983,
duration = 8,
max_stack = 1,
},
stealth = {
id = function () return talent.subterfuge.enabled and 115191 or 1784 end,
duration = 3600,
max_stack = 1,
copy = { 115191, 1784 }
},
subterfuge = {
id = 115192,
duration = 3,
max_stack = 1,
},
tricks_of_the_trade = {
id = 57934,
duration = 30,
max_stack = 1,
},
vanish = {
id = 11327,
duration = 3,
max_stack = 1,
},
vendetta = {
id = 79140,
duration = 20,
max_stack = 1,
},
vendetta_regen = {
name = "Vendetta Regen",
duration = 3,
max_stack = 1,
generate = function ()
local cast = action.vendetta.lastCast or 0
local up = cast + 3 < query_time
local vr = buff.vendetta_regen
if up then
vr.count = 1
vr.expires = cast + 3
vr.applied = cast
vr.caster = "player"
return
end
vr.count = 0
vr.expires = 0
vr.applied = 0
vr.caster = "nobody"
end,
},
venomous_wounds = {
id = 79134,
},
wound_poison = {
id = 8679,
duration = 3600,
max_stack = 1,
},
wound_poison_dot = {
id = 8680,
duration = 12,
max_stack = 1,
no_ticks = true,
},
lethal_poison = {
alias = { "deadly_poison", "wound_poison", "instant_poison" },
aliasMode = "first",
aliasType = "buff",
duration = 3600
},
nonlethal_poison = {
alias = { "crippling_poison", "numbing_poison" },
aliasMode = "first",
aliasType = "buff",
duration = 3600
},
-- Azerite Powers
nothing_personal = {
id = 286581,
duration = 20,
tick_time = 2,
max_stack = 1,
},
nothing_personal_regen = {
id = 289467,
duration = 20,
tick_time = 2,
max_stack = 1,
},
scent_of_blood = {
id = 277731,
duration = 24,
},
sharpened_blades = {
id = 272916,
duration = 20,
max_stack = 30
},
-- PvP Talents
creeping_venom = {
id = 198097,
duration = 4,
max_stack = 18,
},
system_shock = {
id = 198222,
duration = 2,
},
-- Legendaries
bloodfang = {
id = 23581,
duration = 6,
max_stack = 1
},
master_assassins_mark = {
id = 340094,
duration = 4,
max_stack = 1
},
master_assassin_any = {
alias = { "master_assassin", "master_assassins_mark" },
aliasMode = "longest",
aliasType = "buff",
duration = function () return legendary.mark_of_the_master_assassin.enabled and 4 or 3 end,
}
} )
4 years ago
4 years ago
-- Abilities
spec:RegisterAbilities( {
ambush = {
id = 8676,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = function () return buff.blindside.up and 0 or 50 end,
spendType = "energy",
startsCombat = true,
texture = 132282,
usable = function () return stealthed.all or buff.blindside.up or buff.sepsis_buff.up, "requires stealth or blindside or sepsis proc" end,
handler = function ()
gain( 2, "combo_points" )
if buff.sepsis_buff.up then removeBuff( "sepsis_buff" )
else
removeBuff( "blindside" )
end
end,
},
blind = {
id = 2094,
cast = 0,
cooldown = 120,
gcd = "spell",
startsCombat = true,
texture = 136175,
handler = function ()
applyDebuff( "target", "blind" )
end,
},
cheap_shot = {
id = 1833,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = function () return 40 * ( 1 + conduit.rushed_setup.mod * 0.01 ) end,
spendType = "energy",
startsCombat = true,
texture = 132092,
cycle = function ()
if talent.prey_on_the_weak.enabled then return "prey_on_the_weak" end
end,
usable = function ()
if boss then return false, "cheap_shot assumed unusable in boss fights" end
return stealthed.all, "not stealthed"
end,
nodebuff = "cheap_shot",
handler = function ()
applyDebuff( "target", "cheap_shot" )
gain( 1, "combo_points" )
if buff.sepsis_buff.up then removeBuff( "sepsis_buff" ) end
if talent.prey_on_the_weak.enabled then applyDebuff( "target", "prey_on_the_weak" ) end
end,
},
cloak_of_shadows = {
id = 31224,
cast = 0,
cooldown = 120,
gcd = "spell",
toggle = "defensives",
startsCombat = false,
texture = 136177,
handler = function ()
applyBuff( "cloak_of_shadows" )
end,
},
crimson_tempest = {
id = 121411,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 35,
spendType = "energy",
startsCombat = true,
texture = 464079,
talent = "crimson_tempest",
aura = "crimson_tempest",
cycle = "crimson_tempest",
usable = function () return combo_points.current > 0 end,
handler = function ()
applyDebuff( "target", "crimson_tempest", 2 + ( combo_points.current * 2 ) )
debuff.crimson_tempest.pmultiplier = persistent_multiplier
4 years ago
debuff.crimson_tempest.exsanguinated_rate = 1
4 years ago
debuff.crimson_tempest.exsanguinated = false
4 years ago
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
debuff.crimson_tempest.exsanguinated_rate = 2
debuff.crimson_tempest.vendetta_exsg = true
end
4 years ago
if combo_points.current == animacharged_cp then
removeBuff( "echoing_reprimand_" .. combo_points.current )
end
spend( combo_points.current, "combo_points" )
if talent.elaborate_planning.enabled then applyBuff( "elaborate_planning" ) end
end,
},
crimson_vial = {
id = 185311,
cast = 0,
cooldown = 30,
gcd = "spell",
spend = function () return 20 - conduit.nimble_fingers.mod end,
spendType = "energy",
startsCombat = false,
texture = 1373904,
toggle = "defensives",
handler = function ()
applyBuff( "crimson_vial" )
end,
},
crippling_poison = {
id = 3408,
cast = 1.5,
cooldown = 0,
gcd = "spell",
startsCombat = false,
essential = true,
texture = 132274,
readyTime = function () return buff.nonlethal_poison.remains - 120 end,
handler = function ()
applyBuff( "crippling_poison" )
end,
},
deadly_poison = {
id = 2823,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = false,
essential = true,
texture = 132290,
readyTime = function () return buff.lethal_poison.remains - 120 end,
handler = function ()
applyBuff( "deadly_poison" )
end,
},
distract = {
id = 1725,
cast = 0,
cooldown = 30,
gcd = "spell",
spend = function () return 30 * ( 1 + conduit.rushed_setup.mod * 0.01 ) end,
spendType = "energy",
startsCombat = false,
texture = 132289,
handler = function ()
end,
},
envenom = {
id = 32645,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 35,
spendType = "energy",
startsCombat = true,
texture = 132287,
usable = function () return combo_points.current > 0, "requires combo_points" end,
handler = function ()
if pvptalent.system_shock.enabled then
if combo_points.current >= 5 and debuff.garrote.up and debuff.rupture.up and ( debuff.deadly_poison_dot.up or debuff.wound_poison_dot.up ) then
applyDebuff( "target", "system_shock", 2 )
end
end
if pvptalent.creeping_venom.enabled then
applyDebuff( "target", "creeping_venom" )
end
if level > 55 and buff.slice_and_dice.up then
buff.slice_and_dice.expires = buff.slice_and_dice.expires + combo_points.current * 3
end
applyBuff( "envenom", 1 + combo_points.current )
if combo_points.current == animacharged_cp then
removeBuff( "echoing_reprimand_" .. combo_points.current )
end
spend( combo_points.current, "combo_points" )
if talent.elaborate_planning.enabled then applyBuff( "elaborate_planning" ) end
end,
},
evasion = {
id = 5277,
cast = 0,
cooldown = 120,
gcd = "spell",
startsCombat = false,
texture = 136205,
handler = function ()
applyBuff( "evasion" )
end,
},
exsanguinate = {
id = 200806,
cast = 0,
cooldown = 45,
gcd = "spell",
spend = 25,
spendType = "energy",
startsCombat = true,
texture = 538040,
talent = "exsanguinate",
handler = function ()
4 years ago
local deb, rate, rem, dur
4 years ago
4 years ago
for i, aura in ipairs( true_exsanguinated ) do
local deb = debuff[ aura ]
4 years ago
4 years ago
if deb.up and not deb.exsanguinated then
deb.exsanguinated = true
rate = deb.exsanguinated_rate
deb.exsanguinated_rate = deb.exsanguinated_rate + 1
4 years ago
4 years ago
rem = deb.remains
deb.expires = query_time + ( deb.remains * rate / deb.exsanguinated_rate )
deb.duration = deb.expires - deb.applied
end
4 years ago
end
end,
},
fan_of_knives = {
id = 51723,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 35,
spendType = "energy",
startsCombat = true,
texture = 236273,
cycle = function () return buff.deadly_poison.up and "deadly_poison" or nil end,
handler = function ()
gain( 1, "combo_points" )
removeBuff( "hidden_blades" )
if buff.deadly_poison.up then
applyDebuff( "target", "deadly_poison" )
active_dot.deadly_poison = min( active_enemies, active_dot.deadly_poison + 8 )
end
end,
},
feint = {
id = 1966,
cast = 0,
cooldown = 15,
gcd = "spell",
spend = function () return 35 - conduit.nimble_fingers.mod end,
spendType = "energy",
startsCombat = false,
texture = 132294,
handler = function ()
applyBuff( "feint" )
end,
},
garrote = {
id = 703,
cast = 0,
cooldown = function () return ( talent.subterfuge.enabled and ( buff.stealth.up or buff.subterfuge.up ) ) and 0 or 6 end,
gcd = "spell",
spend = 45,
spendType = "energy",
startsCombat = true,
texture = 132297,
aura = "garrote",
cycle = "garrote",
handler = function ()
4 years ago
applyDebuff( "target", "garrote" )
4 years ago
debuff.garrote.pmultiplier = persistent_multiplier
4 years ago
debuff.garrote.exsanguinated_rate = 1
4 years ago
debuff.garrote.exsanguinated = false
4 years ago
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
debuff.garrote.exsanguinated_rate = 2
debuff.garrote.vendetta_exsg = true
end
4 years ago
gain( 1, "combo_points" )
if stealthed.rogue then
if level > 45 then applyDebuff( "target", "garrote_silence" ) end
if talent.iron_wire.enabled then applyDebuff( "target", "iron_wire" ) end
if azerite.shrouded_suffocation.enabled then
gain( 2, "combo_points" )
debuff.garrote.ss_buffed = true
end
end
end,
},
kick = {
id = 1766,
cast = 0,
cooldown = 15,
gcd = "off",
startsCombat = true,
texture = 132219,
toggle = "interrupts",
interrupt = true,
debuff = "casting",
readyTime = state.timeToInterrupt,
handler = function ()
interrupt()
if conduit.prepared_for_all.enabled and cooldown.cloak_of_shadows.remains > 0 then
reduceCooldown( "cloak_of_shadows", 2 * conduit.prepared_for_all.mod )
end
end,
},
kidney_shot = {
id = 408,
cast = 0,
cooldown = 20,
gcd = "spell",
spend = function () return 25 * ( 1 + conduit.rushed_setup.mod * 0.01 ) end,
spendType = "energy",
startsCombat = true,
texture = 132298,
aura = "internal_bleeding",
cycle = "internal_bleeding",
usable = function () return combo_points.current > 0 end,
handler = function ()
if talent.internal_bleeding.enabled then
applyDebuff( "target", "internal_bleeding" )
debuff.internal_bleeding.pmultiplier = persistent_multiplier
debuff.internal_bleeding.exsanguinated = false
4 years ago
debuff.internal_bleeding.exsanguinated_rate = 1
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
debuff.internal_bleeding.exsanguinated_rate = 2
debuff.internal_bleeding.vendetta_exsg = true
end
4 years ago
end
applyDebuff( "target", "kidney_shot", 1 + combo_points.current )
if combo_points.current == animacharged_cp then
removeBuff( "echoing_reprimand_" .. combo_points.current )
end
spend( combo_points.current, "combo_points" )
if talent.elaborate_planning.enabled then applyBuff( "elaborate_planning" ) end
end,
},
marked_for_death = {
id = 137619,
cast = 0,
cooldown = 30,
gcd = "off",
-- toggle = "cooldowns",
startsCombat = false,
texture = 236364,
usable = function ()
return combo_points.current <= settings.mfd_points, "combo_point (" .. combo_points.current .. ") > user preference (" .. settings.mfd_points .. ")"
end,
handler = function ()
gain( 5, "combo_points" )
applyDebuff( "target", "marked_for_death" )
end,
},
mutilate = {
id = 1329,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 50,
spendType = "energy",
startsCombat = true,
texture = 132304,
handler = function ()
gain( 2, "combo_points" )
if talent.venom_rush.enabled and ( debuff.deadly_poison_dot.up or debuff.wound_poison_dot.up or debuff.crippling_poison_dot.up ) then
gain( 8, "energy" )
end
4 years ago
if legendary.doomblade.enabled then
applyDebuff( "target", "mutilated_flesh" )
end
4 years ago
end,
4 years ago
auras = {
mutilated_flesh = {
id = 340431,
duration = 6,
max_stack = 1
}
}
4 years ago
},
numbing_poison = {
id = 5761,
cast = 1,
cooldown = 0,
gcd = "spell",
startsCombat = false,
texture = 136066,
readyTime = function () return buff.nonlethal_poison.remains - 120 end,
handler = function ()
applyBuff( "numbing_poison" )
end,
},
--[[ pick_lock = {
id = 1804,
cast = 1.5,
cooldown = 0,
gcd = "spell",
startsCombat = true,
texture = 136058,
handler = function ()
end,
},
pick_pocket = {
id = 921,
cast = 0,
cooldown = 0.5,
gcd = "spell",
startsCombat = true,
texture = 133644,
handler = function ()
end,
}, ]]
poisoned_knife = {
id = 185565,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 40,
spendType = "energy",
startsCombat = true,
texture = 1373909,
handler = function ()
removeBuff( "sharpened_blades" )
gain( 1, "combo_points" )
end,
},
rupture = {
id = 1943,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 25,
spendType = "energy",
startsCombat = true,
texture = 132302,
aura = "rupture",
cycle = "rupture",
usable = function () return combo_points.current > 0, "requires combo_points" end,
handler = function ()
4 years ago
applyDebuff( "target", "rupture", ( 4 + ( 4 * effective_combo_points ) ) * ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) )
4 years ago
debuff.rupture.pmultiplier = persistent_multiplier
debuff.rupture.exsanguinated = false
4 years ago
debuff.rupture.exsanguinated_rate = 1
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
debuff.rupture.exsanguinated_rate = 2
debuff.rupture.vendetta_exsg = true
end
4 years ago
if azerite.scent_of_blood.enabled then
applyBuff( "scent_of_blood", dot.rupture.remains )
end
if combo_points.current == animacharged_cp then
removeBuff( "echoing_reprimand_" .. combo_points.current )
end
spend( combo_points.current, "combo_points" )
end,
},
sap = {
id = 6770,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = function () return 35 * ( 1 + conduit.rushed_setup.mod * 0.01 ) end,
spendType = "energy",
startsCombat = true,
texture = 132310,
usable = function () return stealthed.all or buff.sepsis_buff.up, "requires stealth" end,
handler = function ()
applyDebuff( "target", "sap" )
removeBuff( "sepsis_buff" )
end,
},
shadowstep = {
id = 36554,
cast = 0,
charges = 1,
cooldown = function ()
return 30 * ( 1 - conduit.quick_decisions.mod * 0.01 ) * ( pvptalent.intent_to_kill.enabled and debuff.vendetta.up and 0.1 or 1 )
end,
recharge = function ()
if pvptalent.intent_to_kill.enabled and debuff.vendetta.up then return 10 end
return 30 * ( 1 - conduit.quick_decisions.mod * 0.01 )
end,
gcd = "spell",
startsCombat = false,
texture = 132303,
handler = function ()
applyBuff( "shadowstep" )
setDistance( 5 )
end,
},
shiv = {
id = 5938,
cast = 0,
cooldown = 25,
gcd = "spell",
spend = function () return legendary.tiny_toxic_blade.enabled and 0 or 20 end,
spendType = "energy",
startsCombat = true,
texture = 135428,
handler = function ()
gain( 1, "combo_points" )
applyDebuff( "target", "crippling_poison_shiv" )
if level > 57 then applyDebuff( "target", "shiv" ) end
if conduit.wellplaced_steel.enabled and debuff.envenom.up then
debuff.envenom.expires = debuff.envenom.expires + conduit.wellplaced_steel.mod
end
end,
auras = {
crippling_poison_shiv = {
id = 115196,
duration = 9,
max_stack = 1,
},
shiv = {
id = 319504,
duration = 9,
max_stack = 1,
},
}
},
shroud_of_concealment = {
id = 114018,
cast = 0,
cooldown = 360,
gcd = "spell",
startsCombat = false,
texture = 635350,
usable = function () return stealthed.all, "requires stealth" end,
handler = function ()
applyBuff( "shroud_of_concealment" )
if conduit.fade_to_nothing.enabled then applyBuff( "fade_to_nothing" ) end
end,
},
sprint = {
id = 2983,
cast = 0,
cooldown = 120,
gcd = "spell",
startsCombat = false,
texture = 132307,
handler = function ()
applyBuff( "sprint" )
end,
},
stealth = {
id = 1784,
cast = 0,
cooldown = 2,
gcd = "spell",
startsCombat = false,
texture = 132320,
usable = function () return time == 0 and not buff.stealth.up and not buff.vanish.up, "requires out of combat and not stealthed" end,
handler = function ()
applyBuff( "stealth" )
if conduit.cloaked_in_shadows.enabled then applyBuff( "cloaked_in_shadows" ) end
if conduit.fade_to_nothing.enabled then applyBuff( "fade_to_nothing" ) end
end,
auras = {
-- Conduit
cloaked_in_shadows = {
id = 341530,
duration = 3600,
max_stack = 1
},
-- Conduit
fade_to_nothing = {
id = 341533,
duration = 3,
max_stack = 1
}
}
},
tricks_of_the_trade = {
id = 57934,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = false,
texture = 236283,
handler = function ()
applyBuff( "tricks_of_the_trade" )
end,
},
vanish = {
id = 1856,
cast = 0,
cooldown = 120,
gcd = "spell",
startsCombat = false,
texture = 132331,
disabled = function ()
return not settings.solo_vanish and not ( boss and group ), "can only vanish in a boss encounter or with a group"
end,
handler = function ()
applyBuff( "vanish" )
applyBuff( "stealth" )
if conduit.cloaked_in_shadows.enabled then applyBuff( "cloaked_in_shadows" ) end -- ???
if conduit.fade_to_nothing.enabled then applyBuff( "fade_to_nothing" ) end
if legendary.invigorating_shadowdust.enabled then
for name, cd in pairs( cooldown ) do
if cd.remains > 0 then reduceCooldown( name, 20 ) end
end
end
end,
},
vendetta = {
id = 79140,
cast = 0,
cooldown = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * 120 end,
gcd = "off",
toggle = "cooldowns",
startsCombat = false,
texture = 458726,
aura = "vendetta",
handler = function ()
applyDebuff( "target", "vendetta" )
applyBuff( "vendetta_regen" )
4 years ago
4 years ago
if azerite.nothing_personal.enabled then
applyDebuff( "target", "nothing_personal" )
applyBuff( "nothing_personal_regen" )
end
4 years ago
if set_bonus.tier28_4pc > 0 then
for k, v in pairs( tier28_vendetta_spells ) do
local bleed = debuff[ k ]
if bleed.up and not bleed.vendetta_exsg then
local rate = bleed.exsanguinated_rate
bleed.exsanguinated_rate = rate + 1
bleed.vendetta_exsg = true
local rem = bleed.remains
bleed.expires = query_time + bleed.remains * rate / bleed.exsanguinated_rate
end
end
end
4 years ago
end,
},
wound_poison = {
id = 8679,
cast = 1.5,
cooldown = 0,
gcd = "spell",
startsCombat = false,
essential = true,
texture = 134197,
readyTime = function () return buff.lethal_poison.remains - 120 end,
handler = function ()
applyBuff( "wound_poison" )
end,
},
apply_poison = {
name = _G.MINIMAP_TRACKING_VENDOR_POISON,
cast = 1.5,
cooldown = 0,
gcd = "spell",
startsCombat = false,
essential = true,
texture = function ()
if buff.lethal_poison.down or level < 33 then
return state.spec.assassination and level > 12 and class.abilities.deadly_poison.texture or class.abilities.instant_poison.texture
end
if level > 32 and buff.nonlethal_poison.down then return class.abilities.crippling_poison.texture end
end,
4 years ago
bind = function ()
if buff.lethal_poison.down or level < 33 then
return state.spec.assassination and level > 12 and "deadly_poison" or "instant_poison"
end
if level > 32 and "nonlethal_poison" then return "crippling_poison" end
end,
4 years ago
usable = function ()
return buff.lethal_poison.down or level > 32 and buff.nonlethal_poison.down, "requires missing poison"
end,
handler = function ()
if buff.lethal_poison.down then
applyBuff( state.spec.assassination and level > 12 and "deadly_poison" or "instant_poison" )
elseif level > 32 then applyBuff( "crippling_poison" ) end
end,
4 years ago
copy = "apply_poison_actual"
4 years ago
},
-- Covenant Abilities
-- Rogue - Kyrian - 323547 - echoing_reprimand (Echoing Reprimand)
echoing_reprimand = {
id = 323547,
cast = 0,
cooldown = 45,
gcd = "spell",
spend = function () return 10 * ( ( talent.shadow_focus.enabled and ( buff.shadow_dance.up or buff.stealth.up ) ) and 0.8 or 1 ) end,
spendType = "energy",
startsCombat = true,
texture = 3565450,
toggle = "essences",
cp_gain = function () return ( buff.shadow_blades.up and 1 or 0 ) + ( buff.broadside.up and 1 or 0 ) + 2 end,
handler = function ()
-- Can't predict the Animacharge, unless you have the legendary.
if legendary.resounding_clarity.enabled then
applyBuff( "echoing_reprimand_2", nil, 2 )
applyBuff( "echoing_reprimand_3", nil, 3 )
applyBuff( "echoing_reprimand_4", nil, 4 )
applyBuff( "echoing_reprimand_5", nil, 5 )
end
gain( action.echoing_reprimand.cp_gain, "combo_points" )
end,
disabled = function ()
return covenant.kyrian and not IsSpellKnownOrOverridesKnown( 323547 ), "you have not finished your kyrian covenant intro"
end,
auras = {
echoing_reprimand_2 = {
id = 323558,
duration = 45,
max_stack = 6,
},
echoing_reprimand_3 = {
id = 323559,
duration = 45,
max_stack = 6,
},
echoing_reprimand_4 = {
id = 323560,
duration = 45,
max_stack = 6,
4 years ago
copy = 354835,
4 years ago
},
echoing_reprimand_5 = {
id = 354838,
duration = 45,
max_stack = 6,
},
echoing_reprimand = {
alias = { "echoing_reprimand_2", "echoing_reprimand_3", "echoing_reprimand_4", "echoing_reprimand_5" },
aliasMode = "first",
aliasType = "buff",
meta = {
stack = function ()
4 years ago
if combo_points.current > 1 and combo_points.current < 6 and buff[ "echoing_reprimand_" .. combo_points.current ].up then return combo_points.current end
4 years ago
if buff.echoing_reprimand_2.up then return 2 end
if buff.echoing_reprimand_3.up then return 3 end
if buff.echoing_reprimand_4.up then return 4 end
if buff.echoing_reprimand_5.up then return 5 end
return 0
end
}
}
}
},
-- Rogue - Necrolord - 328547 - serrated_bone_spike (Serrated Bone Spike)
serrated_bone_spike = {
id = 328547,
cast = 0,
charges = function () return legendary.deathspike.equipped and 5 or 3 end,
cooldown = 30,
recharge = 30,
gcd = "spell",
startsCombat = true,
texture = 3578230,
toggle = "essences",
cycle = "serrated_bone_spike",
cp_gain = function () return ( buff.broadside.up and 1 or 0 ) + active_dot.serrated_bone_spike end,
handler = function ()
applyDebuff( "target", "serrated_bone_spike" )
4 years ago
debuff.serrated_bone_spike.exsanguinated_rate = 1
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
debuff.serrated_bone_spike.exsanguinated_rate = 2
debuff.serrated_bone_spike.vendetta_exsg = true
end
4 years ago
gain( ( buff.broadside.up and 1 or 0 ) + active_dot.serrated_bone_spike, "combo_points" )
if soulbind.kevins_oozeling.enabled then applyBuff( "kevins_oozeling" ) end
end,
auras = {
serrated_bone_spike = {
id = 324073,
duration = 3600,
max_stack = 1,
4 years ago
exsanguinated = false,
meta = {
vendetta_exsg = function( t ) return t.up and tracked_bleeds.serrated_bone_spike.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.serrated_bone_spike.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.serrated_bone_spike.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * 2 / t.exsanguinated_rate ) or ( haste * 2 ) end,
},
4 years ago
copy = "serrated_bone_spike_dot",
},
}
},
-- Rogue - Night Fae - 328305 - sepsis (Sepsis)
sepsis = {
id = 328305,
cast = 0,
cooldown = 90,
gcd = "spell",
startsCombat = true,
texture = 3636848,
toggle = "essences",
handler = function ()
applyDebuff( "target", "sepsis" )
4 years ago
debuff.sepsis.exsanguinated_rate = 1
if set_bonus.tier28_4pc > 0 and debuff.vendetta.up then
debuff.sepsis.exsanguinated_rate = 2
debuff.sepsis.vendetta_exsg = true
end
4 years ago
end,
auras = {
sepsis = {
id = 328305,
4 years ago
duration = function () return ( set_bonus.tier28_4pc > 0 and debuff.vendetta.up and 0.5 or 1 ) * 10 end,
4 years ago
max_stack = 1,
4 years ago
exsanguinated = false,
meta = {
vendetta_exsg = function( t ) return t.up and tracked_bleeds.sepsis.vendetta[ target.unit ] or false end,
exsanguinated_rate = function( t ) return t.up and tracked_bleeds.sepsis.rate[ target.unit ] or 1 end,
last_tick = function( t ) return t.up and ( tracked_bleeds.sepsis.last_tick[ target.unit ] or t.applied ) or 0 end,
tick_time = function( t ) return t.up and ( haste * 2 / t.exsanguinated_rate ) or ( haste * 2 ) end,
},
4 years ago
},
sepsis_buff = {
id = 347037,
duration = 5,
max_stack = 1
}
}
},
-- Rogue - Venthyr - 323654 - flagellation (Flagellation)
flagellation = {
id = 323654,
cast = 0,
cooldown = 90,
gcd = "spell",
spend = 0,
spendType = "energy",
startsCombat = true,
texture = 3565724,
toggle = "essences",
handler = function ()
applyBuff( "flagellation" )
applyDebuff( "target", "flagellation", 30 )
end,
auras = {
flagellation = {
id = 323654,
duration = 12,
max_stack = 30,
generate = function( t, aType )
local unit, func
if aType == "debuff" then
unit = "target"
func = FindUnitDebuffByID
else
unit = "player"
func = FindUnitBuffByID
end
local name, _, count, _, duration, expires, caster = func( unit, 323654 )
if name then
t.count = 1
t.expires = expires
t.applied = expires - duration
t.caster = "player"
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
copy = "flagellation_buff"
},
},
},
-- PvP Talents
shadowy_duel = {
id = 207736,
cast = 0,
cooldown = 120,
gcd = "off",
pvptalent = "shadowy_duel",
startsCombat = false,
texture = 1020341,
usable = function () return target.is_player, "requires a player target" end,
handler = function ()
applyBuff( "shadowy_duel" )
end,
auras = {
shadowy_duel = {
id = 210558,
duration = 6,
max_stack = 1,
},
}
},
smoke_bomb = {
id = 212182,
cast = 0,
cooldown = 180,
gcd = "spell",
pvptalent = "smoke_bomb",
startsCombat = false,
texture = 458733,
handler = function ()
applyDebuff( "player", "smoke_bomb" )
if target.within8 then applyDebuff( "target", "smoke_bomb" ) end
end,
auras = {
smoke_bomb = {
id = 212183,
duration = 5,
max_stack = 1,
},
}
},
} )
spec:RegisterOptions( {
enabled = true,
aoe = 3,
nameplates = true,
nameplateRange = 8,
damage = true,
damageExpiration = 6,
potion = "phantom_fire",
package = "Assassination",
} )
spec:RegisterSetting( "priority_rotation", false, {
name = "Funnel AOE -> Target",
desc = "If checked, the addon's default priority list will focus on funneling damage into your primary target when multiple enemies are present.",
type = "toggle",
width = 1.5
} )
spec:RegisterSetting( "envenom_pool_pct", 50, {
name = "Energy % for |T132287:0|t Envenom",
desc = "If set above 0, the addon will pool to this Energy threshold before recommending |T132287:0|t Envenom.",
type = "range",
min = 0,
max = 100,
step = 1,
width = 1.5
} )
spec:RegisterStateExpr( "envenom_pool_deficit", function ()
return energy.max * ( ( 100 - ( settings.envenom_pool_pct or 100 ) ) / 100 )
end )
spec:RegisterSetting( "mfd_points", 3, {
name = "|T236340:0|t Marked for Death Combo Points",
desc = "The addon will only recommend |T236364:0|t Marked for Death when you have the specified number of combo points or fewer.",
type = "range",
min = 0,
max = 5,
step = 1,
width = "full"
} )
spec:RegisterSetting( "solo_vanish", true, {
name = "Allow |T132331:0|t Vanish when Solo",
desc = "If unchecked, the addon will not recommend |T132331:0|t Vanish when you are alone (to avoid resetting combat).",
type = "toggle",
width = "full"
} )
spec:RegisterSetting( "allow_shadowmeld", nil, {
name = "Allow |T132089:0|t Shadowmeld",
desc = "If checked, |T132089:0|t Shadowmeld can be recommended for Night Elves when its conditions are met. Your stealth-based abilities can be used in Shadowmeld, even if your action bar does not change. " ..
"Shadowmeld can only be recommended in boss fights or when you are in a group (to avoid resetting combat).",
type = "toggle",
width = "full",
get = function () return not Hekili.DB.profile.specs[ 259 ].abilities.shadowmeld.disabled end,
set = function ( _, val )
Hekili.DB.profile.specs[ 259 ].abilities.shadowmeld.disabled = not val
end,
} )
4 years ago
spec:RegisterPack( "Assassination", 20220302, [[diLTLcqiGOhjO0LqsqBIO6taHrbuofqAvQe1ReQAwcQULqL2LK(fsKHHe1XqclJq8mvcMgrHRPsOTriv9nKeLXrifNJOuX6ikY7qsK08qs6EeQ9ji9pIsvQdsuklKqYdfumrvI0ffQOnsiL(iscnsIsvYjrsGvIK6LijQMjrjUjHuzNkj9tIsvmuvIyPeL0tjYuvsCvKeP2krr9vKeXyfQWEvQ)cyWKoSOftLESkMSexgAZi1NPIrRsDAPwnsIeVwL0SPQBlKDR43QA4cCCIsLwoONJy6uUobBxj(UsQXliopq16jkv18fk7h1Bk2RSLkPH7vfHYIicLVaLfPkIiYGczqXwYapa3sb55A6GBPjJWTKSrijH0tA9pBPGeC)NL9kBjYlap4w62SaImrjk502TGB98ruI0rc(06FoWK2OePJouAl5k0EJky2UBPsA4EvrOSiIq5lqzrQIiImOqerZwkfS7hULK6OWSLU7sbNT7wQGKZws2iKKq6jT(hwL13razQfDj8CZQiHZQiuweryQzQdZDooirMyQJlRYwqGhCwbbXG9XabR0(0Hv7zL8riRY2LilSs)WRewTNvsUGSga)dsi94WQ1ryLPoUSEP)acJvzoNMCZQW4rcHvjFFqwZPW6L2hK11T3ZQpjgR(FCqiR2DoSk6sIHqwLncjjKEQm1XLvzf9ziSkA9Pd69P1)WkLyvMXPGMLSsaFoScwtZQmJtbnlzTjSAVJJhlS(00S(qw)H1Kv)poSgMlf0ktDCzv0LxrwfTEKCFGjTXApgcHcbgR9W65JCtJ1MM11iRuPiqmwlDH12yL(HSU8(0ApcqE)cowLPoUSsLMGSkjkjwJEiYQ9SseII(HvQCCPhqqyv2Zl7J(ECyTPzf8xG17Cbz1UrwjVG3TNsLPoUSgMFwqOXkuyqG1pSuPHpXy1EwDfOPRqHbbw)Wcan8jwviOYuhxwLTsblSsL0tHCsiRuj3OrSFWktDCzDL1yEflSgNHqYXrON0qwTNvh0yvGGfwBAwb)faXcYQmJtbnlJljhhHEsdl1TKVjgzVYwIyy6TBSSxzVkf7v2s4KUESSf1wkpw)Zw6a7iYpaggfGeBlvqYb2bw)ZwA125MyP)kcz9hwVWkYeRHb2rKFyDfmkaj2w6aBdHDULS0JJvN252iw6VIWkoPRhlSkNvsa69awcDqJWAOIz9cSkN1Zh5(abFpgH1qfZQmyvoRwcDqRADecypqPrwJlRqmk7HWAOSk632Evr2RSLWjD9yzlQTuES(NTeuiWeG4wQGKdSdS(NT0QTZnXs)veY6pSsXkYeRstgqUFJvzviWeG4w6aBdHDULS0JJvN252iw6VIWkoPRhlSkN1Zh5(abFpgH1qfZQmyvoRwcDqRADecypqPrwJlRqmk7HWAOSk632E1lSxzlHt66XYwuBP8y9pBPG)9aqK8cWdULki5a7aR)zljj4AiKwWbLjwLTGap4S(qwLvKgIKBwx32nRUc00yHvQycHVHKTe9dbgmeBVkfBBVQm2RSLWjD9yzlQTuES(NTKtcHVHBPdSne25wYspowLi4AiKwWbR4KUESWQCwbjRRBVhW)eeadHKJJqpPHSkNvWyfIrzpewPkRuicRuIvmesooc9KgwaGPHSglgRbrcERd8nczLQIzLcwbLv5SAj0bTQ1riG9aLgznUScXOShcRHYQiBPd4hpcyj0bnYEvk22E1lUxzlHt66XYwuBP8y9pBPG)9aqK8cWdULki5a7aR)zljj4AiKwWbznEwJZqioS(dRuSImXQSI0qKCZkvmHW3qwtJv7gzfNcRpnRedtVDZQ9S6GgRrziSweGP1)WQls)qK14mesooc9KgULOFiWGHy7vPyB7vf97v2s4KUESSf1w6aBdHDULS0JJvjcUgcPfCWkoPRhlSkNvl94yvmesooc9KgwXjD9yHv5SMhRxqaCWOgjSkMvkyvoRUc00vIGRHqAbhScXOShcRuLvkQxylLhR)zl5Kq4B4222wAjNMCVxzVkf7v2s4KUESSf1w6d2se02s5X6F2sljStxpULwsVaULaJvqYkuyq6h6G1cM2ThCaYDw(1KkoPRhlSkNvKMgpwVGaNpY9bc(EmcRHkM1taqugcajaNcRGYASyScgRqHbPFOdwlyA3EWbi3z5xtQ4KUESWQCwpFK7de89yewPkRIWkOBPcsoWoW6F2sI2EAYnRRB7M1OmewdZLWk9dzD1252iw6VIWWzvy8iHWQaPhhwVumTBp4SkDNLFnzlTKqGjJWT00o3gXs)vecCcao)uAR)zB7vfzVYwcN01JLTO2s5X6F2sl50K7Tubjhyhy9pBjzoNMCZ662UznodH4WA8SUA7CBel9xrOmXQOldPJeIynmxcR5uynodH4WkeZc4Ss)qwhmeJvQyyU0T0b2gc7ClzPhhRIHqYXrON0WkoPRhlSkNvl94y1PDUnIL(RiSIt66XcRYzDjHD66X60o3gXs)vecCcao)uAR)Hv5SE(3x(1tfdHKJJqpPHvigL9qyLQSsX22REH9kBjCsxpw2IAlLhR)zlTKttU3sfKCGDG1)SLK5CAYnRRB7M1vBNBJyP)kcznEwx9znodH4itSk6Yq6iHiwdZLWAofwLzCkOzjRcbBPdSne25wYspowDANBJyP)kcR4KUESWQCwbjRw6XXQyiKCCe6jnSIt66XcRYzDjHD66X60o3gXs)vecCcao)uAR)Hv5SwqxbA66cof0SSkeST9QYyVYwcN01JLTO2s5X6F2sb)7bGi5fGhClHHyWeiJEHX2sY4IBj6hcmyi2Evk22E1lUxzlHt66XYwuBPdSne25wYspowLi4AiKwWbR4KUESWQCwp)7l)6P6Kq4ByviGv5SwqxbA66cof0SSkeWQCwbJ1YBvNecFdRqKgIK701JSglgRL3Qoje(gwdIe8wh4BeYkvfZkfSckRYz98rUpqW3JrQfKUpTXAOIzfmwjbO3dyj0bnsLohGNg460liH1qL9MvzWkOSkNvy2faCbhRMLcP2dRHYkfISLYJ1)SLwYPj3BBVQOFVYwcN01JLTO2s5X6F2sl50K7Tubjhyhy9pBjzoNMCZ662Uzv0LedHSkBess6rMyvwfcmbigpvmHW3qwN3yThwHinej3ScZXbdN1IaShhwLzCkOzz8s39sLvjWNdRRB7MvjmG0ewP7j9SE3gRnnRbpH0UESULoW2qyNBjWy1spownkjgcbscjjKEQ4KUESWASyScfgK(HoynkHxbEAa7gbIsIHqGKqscPNkoPRhlSckRYzfKSwERcfcmbiwHinej3PRhzvoRL3Qoje(gwHyu2dH1qz9cSkN1c6kqtxxWPGMLvHawLZkySwqxbA6k5UxQcbSglgRf0vGMUUGtbnlRqmk7HWkvzvgSglgRL3QemG0KQ1NR94WkOSkN1YBvcgqAsfIrzpewPkRxyBBBlvq6uWB7v2RsXELTuES(NT01(CDlHt66XYwuBBVQi7v2s4KUESSf1wQGKdSdS(NTKSIedtVDZAtZAWtiTRhzfS5zDrWpimD9iR4GrnsyThwpFKBAGULYJ1)SLigME7EB7vVWELTeoPRhlBrTL(GTebTTuES(NT0sc701JBPL0lGBjsa69awcDqJuPZb4PbUo9csyLQSkYwAjHatgHBjspoEeWsOdABBVQm2RSLWjD9yzlQT0hSLiOTLYJ1)SLwsyNUEClTKEbClHdcDaVcrhCaoFKBpyH1qz9cxClvqYb2bw)ZwkmFKBpyH14CqOd4SkROdoSoiwWcR2ZkjnbyA4wAjHatgHBji6GdajnbyAyzB7vV4ELTeoPRhlBrTLoW2qyNBjIHP3UXsf(oc4wIyW(y7vPylLhR)zlDsVhipw)dGVj2wY3edyYiClrmm92nw22Evr)ELTeoPRhlBrTLYJ1)SLoP3dKhR)bW3eBl5BIbmzeULofY22RsLTxzlHt66XYwuBP8y9pBjIVpiqofGsFWTubjhyhy9pBPlrWyvAUuwfcyTN2607bNv6hYAyemwTNv7gznm3jbdNvis
4 years ago
end