export const ROM_ROGUE_DAGGER_MASTERY_TAG = "rom-dagger-mastery"; export const ROM_ROGUE_TREASURE_HUNTER_TAG = "rom-treasure-hunter"; export const ROM_ROGUE_OFF_HAND_MASTERY_TAG = "rom-off-hand-mastery"; export const ROM_ROGUE_OFF_HAND_MASTERY_DAMAGE_PERCENT = 4; export const ROM_ROGUE_OFF_HAND_MASTERY_ACCURACY_PERCENT = 4; export const ROM_ROGUE_COERCE_TAG = "rom-rogue-coerce"; export const ROM_ROGUE_COERCE_PASSIVE_SPELL_ID = 493019; export const ROM_ROGUE_COERCE_LOW_BLOW_SPELL_ID = 490323; export const ROM_ROGUE_COERCE_DAMAGE_MULTIPLIER = 1.202; export const ROM_ROGUE_COERCE_ENERGY_COST_REDUCTION = 5; export const ROM_ROGUE_SHADOW_WALKER_PASSIVE_SPELL_ID = 491537; export const ROM_ROGUE_INSTANT_SHADOW_READY_TAG = "rom-rogue-instant-shadow-ready"; export interface RomRogueEnchantedThrowContext { readonly classId: string; readonly secondaryClassId: string | null | undefined; readonly sourceActorId: string; readonly playerActorId: string; readonly attackKind: string; readonly isAutoAttack: boolean; readonly attackLanded: boolean; readonly enchantedThrowActive: boolean; } /** Enchanted Throw only follows a landed Rogue/Mage normal attack while its buff is active. */ export function romRogueEnchantedThrowShouldProc(context: RomRogueEnchantedThrowContext): boolean { return context.classId === "rom-rogue" && context.secondaryClassId === "rom-mage" && context.sourceActorId === context.playerActorId && context.attackKind === "melee" && context.isAutoAttack && context.attackLanded && context.enchantedThrowActive; } export interface RomRogueAbilityAdjustment { readonly allowsCombatUse: boolean; readonly energyCostReduction: number; readonly cooldownIncreaseMs: number; } const NO_SHADOW_WALKER_ADJUSTMENT: RomRogueAbilityAdjustment = Object.freeze({ allowsCombatUse: false, energyCostReduction: 0, cooldownIncreaseMs: 0, }); /** Coerce reduces only Low Blow's Energy cost for a Rogue/Scout who learned the passive. */ export function romRogueCoerceAbilityAdjustment( classId: string, secondaryClassId: string | null | undefined, abilitySource: string | undefined, abilitySpellId: number, passiveSpellIds: readonly number[], ): RomRogueAbilityAdjustment { if (classId !== "rom-rogue" || secondaryClassId !== "rom-scout" || abilitySource !== "runewaker" || abilitySpellId !== ROM_ROGUE_COERCE_LOW_BLOW_SPELL_ID || !passiveSpellIds.includes(ROM_ROGUE_COERCE_PASSIVE_SPELL_ID)) { return NO_SHADOW_WALKER_ADJUSTMENT; } return { allowsCombatUse: false, energyCostReduction: ROM_ROGUE_COERCE_ENERGY_COST_REDUCTION, cooldownIncreaseMs: 0, }; } export interface RomRogueCoerceDamageContext { readonly classId: string; readonly abilitySource: string | undefined; readonly abilitySpellId: number | undefined; readonly passiveTags: readonly string[]; } /** Current CoA Coerce adds 20.2% damage to Low Blow for a Rogue/Scout. */ export function romRogueCoerceLowBlowDamageMultiplier(context: RomRogueCoerceDamageContext): number { return context.classId === "rom-rogue" && context.abilitySource === "runewaker" && context.abilitySpellId === ROM_ROGUE_COERCE_LOW_BLOW_SPELL_ID && context.passiveTags.includes(ROM_ROGUE_COERCE_TAG) ? ROM_ROGUE_COERCE_DAMAGE_MULTIPLIER : 1; } /** Shadow Walker's exact Rogue/Priest payload applies only to Sneak Attack. */ export function romRogueShadowWalkerAdjustment( classId: string, secondaryClassId: string | null | undefined, abilitySource: string | undefined, abilitySpellId: number, passiveSpellIds: readonly number[], ): RomRogueAbilityAdjustment { if (classId !== "rom-rogue" || secondaryClassId !== "rom-priest" || abilitySource !== "runewaker" || abilitySpellId !== 490337 || !passiveSpellIds.includes(ROM_ROGUE_SHADOW_WALKER_PASSIVE_SPELL_ID)) { return NO_SHADOW_WALKER_ADJUSTMENT; } return { allowsCombatUse: true, energyCostReduction: 10, cooldownIncreaseMs: 10_000, }; } export interface RomRogueDaggerDamageContext { readonly classId: string; readonly sourceActorId: string; readonly playerActorId: string; readonly attackKind: string; readonly school: string; readonly mainHandDagger: boolean; readonly passiveTags: readonly string[]; } /** The RoM passive modifies only the player's physical melee hits while a dagger is equipped in the main hand. */ export function romRogueDaggerDamageMultiplier(context: RomRogueDaggerDamageContext): number { return context.classId === "rom-rogue" && context.sourceActorId === context.playerActorId && context.attackKind === "melee" && context.school === "physical" && context.mainHandDagger && context.passiveTags.includes(ROM_ROGUE_DAGGER_MASTERY_TAG) ? 1.1 : 1; } /** Treasure Hunter adds one five percentage point bonus roll to the supported boss-loot path. */ export function romRogueTreasureHunterLootChance(baseChance: number | undefined, passiveActive: boolean): number { const base = Number.isFinite(baseChance) ? Math.max(0, Math.min(1, baseChance!)) : 0; return passiveActive ? Math.min(1, base + 0.05) : base; }