Files
healer-man/src/game/romRogueMechanics.ts
2026-10-02 10:38:12 -04:00

136 lines
5.0 KiB
TypeScript

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;
}