Update Healer Man server

This commit is contained in:
phenom committed 2026-10-02 10:38:12 -04:00
1 parent 4c768fbec6
commit b16821e92e
330 files changed
+35406 -1760

No files matched your search

+65 -24
View File
@@ -2,23 +2,50 @@ import type { AbilityDefinition, AbilityEffect } from "./abilityCatalog";
import type { AuraDefinition, AuraModifier, AuraProcDefinition } from "./combatAuras";
import type { RomGeneratedAbilityLike } from "./romAbilitySemantics";
import {
ROM_ROGUE_COERCE_TAG,
ROM_ROGUE_DAGGER_MASTERY_TAG,
ROM_ROGUE_OFF_HAND_MASTERY_TAG,
ROM_ROGUE_TREASURE_HUNTER_TAG,
romRogueCoerceLowBlowDamageMultiplier,
} from "./romRogueMechanics";
import { ROM_ROGUE_MAGE_CHAOS_DAGGER_TAG as ROM_CHAOS_DAGGER_TAG } from "./romRogueChaosDagger";
import {
ROM_ROGUE_CHAMPION_NERVE_GEAR_MARKER_TAG,
ROM_ROGUE_CHAMPION_NERVE_GEAR_PASSIVE_SPELL_ID,
} from "./romRogueChampionNerveGearRuntime";
export const ROM_ROGUE_MAGE_ENCHANTED_THROW_TAG = "rom-491178-enchanted-throw";
export const ROM_ROGUE_MAGE_CHAOS_DAGGER_TAG = ROM_CHAOS_DAGGER_TAG;
/** @deprecated Use ROM_ROGUE_MAGE_CHAOS_DAGGER_TAG for current CoA behavior. */
export const ROM_ROGUE_MAGE_ENCHANTED_THROW_TAG = ROM_ROGUE_MAGE_CHAOS_DAGGER_TAG;
export const ROM_ROGUE_PRIEST_SINISTER_METHODS_TAG = "rom-rogue-priest-sinister-methods";
export const ROM_ROGUE_PRIEST_SINISTER_METHODS_COOLDOWN_KEY = "rom-rogue-priest-sinister-methods";
export const ROM_SCOUT_PRIEST_SNIPER_TAG = "rom-scout-priest-sniper";
const ROM_SCOUT_KNIGHT_ENHANCED_ARMOR_PERFECTION_TAG = "rom-scout-knight-enhanced-armor-perfection";
// Local RuneWaker component 501823 sets Enhanced Armor's duration to 600s.
const ROM_SCOUT_KNIGHT_ENHANCED_ARMOR_DURATION_MS = 600_000;
/** RuneWaker itemobject/shop rows supply Poison Powder to the Scout/Rogue loadout. */
export const ROM_SCOUT_ROGUE_POISON_POWDER_SUPPLY = Object.freeze({
itemId: 200563,
name: "Poison Powder",
quantity: "unlimited",
} as const);
function firstDamage(effects: readonly AbilityEffect[]): AbilityEffect[] {
return effects.filter((effect) => effect.kind === "damage").slice(0, 1);
}
function scaleDamageEffects(effects: readonly AbilityEffect[], factor: number): readonly AbilityEffect[] {
return effects.map((effect) => effect.kind === "damage" || effect.kind === "dot" ? {
...effect,
coefficient: effect.coefficient * factor,
...(effect.coefficientPerLevel === undefined ? {} : { coefficientPerLevel: effect.coefficientPerLevel * factor }),
...(effect.basePoints === undefined ? {} : { basePoints: effect.basePoints * factor }),
...(effect.pointsPerLevel === undefined ? {} : { pointsPerLevel: effect.pointsPerLevel * factor }),
...(effect.bonusPowerCoefficient === undefined ? {} : { bonusPowerCoefficient: effect.bonusPowerCoefficient * factor }),
...(effect.kind !== "damage" || effect.bonusFlat === undefined ? {} : { bonusFlat: effect.bonusFlat * factor }),
} : effect);
}
function taggedPassive(
sourceId: number,
name: string,
@@ -137,13 +164,17 @@ export function overrideRomScoutRogueEffects(
}
case 490504:
return taggedRoguePassive(490504, "Dagger Mastery", ROM_ROGUE_DAGGER_MASTERY_TAG);
case 493019:
if (row.classId !== "rom-rogue" || row.secondaryClassId !== "rom-scout") return null;
// Current CoA Coerce directly increases Low Blow damage and reduces its
// Energy cost. Its older RuneWaker below-30% temporary buff is obsolete.
return taggedRoguePassive(493019, "Coerce", ROM_ROGUE_COERCE_TAG);
case 490316:
return taggedRoguePassive(490316, "Treasure Hunter", ROM_ROGUE_TREASURE_HUNTER_TAG);
case 490143:
// The source applies damage and accuracy only to off-hand attacks; there
// is no distinct RoM off-hand hit yet, so do not turn either value into a
// generic player melee modifier.
return [];
// Keep the source modifiers scoped to actual off-hand attacks. A generic
// melee aura would incorrectly buff the main hand as well.
return taggedRoguePassive(490143, "Off Hand Mastery", ROM_ROGUE_OFF_HAND_MASTERY_TAG);
case 493020: { // Successful Low Blow/Blind Spot hits trigger the local 10s crit buff.
if (row.classId !== "rom-rogue" || row.secondaryClassId !== "rom-priest") return null;
const buff = row.source?.components?.find((component) => component.id === 503265);
@@ -170,20 +201,10 @@ export function overrideRomScoutRogueEffects(
);
case 491178:
if (row.classId !== "rom-rogue" || row.secondaryClassId !== "rom-mage") return null;
// Hidden child 491185 has no generated payload. The auto-attack runtime
// applies its referenced Throw (490309) damage explicitly, so keep the
// tag and avoid also registering the untranslated generic child proc.
if (translated.some((effect) => effect.kind === "apply-aura")) {
return translated.map((effect) => effect.kind === "apply-aura" ? {
...effect,
aura: {
...effect.aura,
procs: [],
utilityTags: [...(effect.aura.utilityTags ?? []), ROM_ROGUE_MAGE_ENCHANTED_THROW_TAG],
},
} : effect);
}
return [...translated, ...taggedRoguePassive(491178, "Enchanted Throw", ROM_ROGUE_MAGE_ENCHANTED_THROW_TAG)];
// Current CoA reuses this exact Rogue/Mage ID as passive Chaos Dagger.
// Keep a marker for learned-passive consumers such as Day of Rain; do
// not register the incompatible RuneWaker Throw child or local aura.
return taggedRoguePassive(491178, "Chaos Dagger", ROM_ROGUE_MAGE_CHAOS_DAGGER_TAG);
case 491552:
if (row.classId !== "rom-rogue") return null;
return translated.map((effect) => effect.kind === "apply-aura" ? {
@@ -250,6 +271,9 @@ export function overrideRomScoutRogueEffects(
case 492344:
if (row.classId !== "rom-scout" || row.secondaryClassId !== "rom-priest") return null;
return taggedPassive(492344, "Sniper", ROM_SCOUT_PRIEST_SNIPER_TAG);
case 492346:
if (row.classId !== "rom-scout" || row.secondaryClassId !== "rom-knight") return null;
return taggedPassive(492346, "Enhanced Armor Perfection", ROM_SCOUT_KNIGHT_ENHANCED_ARMOR_PERFECTION_TAG);
case 493007:
return taggedPassive(493007, "Deadly Counterattack", "rom-deadly-counterattack",
customProc(493007, "hit", "rom-deadly-counterattack", { internalCooldownMs: 20_000 }));
@@ -321,6 +345,19 @@ export function romScoutRogueCastEffects(
): readonly AbilityEffect[] {
const passives = new Set(passiveTags);
const target = new Set(targetTags);
const coerceDamageMultiplier = romRogueCoerceLowBlowDamageMultiplier({
classId: ability.classId,
abilitySource: ability.source,
abilitySpellId: ability.dbcSpellId,
passiveTags,
});
if (coerceDamageMultiplier !== 1) return scaleDamageEffects(effects, coerceDamageMultiplier);
if (ability.dbcSpellId === 490152 && passives.has(ROM_SCOUT_KNIGHT_ENHANCED_ARMOR_PERFECTION_TAG)) {
// Component 501823 is the source's rank payload: Enhanced Armor lasts 600s.
return effects.map((effect) => effect.kind === "apply-aura"
? { ...effect, aura: { ...effect.aura, durationMs: ROM_SCOUT_KNIGHT_ENHANCED_ARMOR_DURATION_MS } }
: effect);
}
if (ability.dbcSpellId === 490457) {
// Replacement 499535 / component 623051 raises ranged DPS from 0.75 to 0.85.
const masteryFactor = passives.has("rom-master-reflected-shot") ? 0.85 / 0.75 : 1;
@@ -408,7 +445,7 @@ export function romScoutRogueCastEffects(
return effects;
}
/** Day of Rain has an exact 50% miss chance while Enchanted Throw is active. */
/** Day of Rain has an exact 50% miss chance while the Rogue/Mage Chaos Dagger passive is learned. */
export function romRogueMageDayOfRainBaseMissPercent(
classId: string,
secondaryClassId: string | null | undefined,
@@ -419,7 +456,7 @@ export function romRogueMageDayOfRainBaseMissPercent(
if (classId !== "rom-rogue"
|| secondaryClassId !== "rom-mage"
|| abilitySpellId !== 491183
|| !activeAuraTags.includes(ROM_ROGUE_MAGE_ENCHANTED_THROW_TAG)) return null;
|| !activeAuraTags.includes(ROM_ROGUE_MAGE_CHAOS_DAGGER_TAG)) return null;
const hitPercent = Number.isFinite(attackerHitPercent)
? Math.max(0, Math.min(100, attackerHitPercent))
: 0;
@@ -483,7 +520,7 @@ export type RomScoutRogueProcActionSpec =
export function romScoutRogueProcActionSpec(
actionId: string,
triggeringSourceSkillId: number,
casterPoisonous: boolean,
_casterPoisonous: boolean,
data: Readonly<Record<string, string | number | boolean>> = {},
): RomScoutRogueProcActionSpec | null {
switch (actionId) {
@@ -561,7 +598,11 @@ export function romScoutRogueProcActionSpec(
provenance: "hybrid-estimate",
};
case "rom-poisonous-spit":
if (!casterPoisonous || ![490457, 490424].includes(triggeringSourceSkillId)) return null;
// Poison Powder (item 200563) is supplied as an unlimited bag reagent by
// the Scout/Rogue loadout model. Do not use Rogue's separate Poison
// Bottle aura (490329) as a proxy for carrying this item.
if (ROM_SCOUT_ROGUE_POISON_POWDER_SUPPLY.quantity !== "unlimited"
|| ![490457, 490424].includes(triggeringSourceSkillId)) return null;
return {
kind: "dot",
recipient: "target",
@@ -575,7 +616,7 @@ export function romScoutRogueProcActionSpec(
intervalMs: 2_000,
tag: "rom-poisonous-spit",
},
provenance: "source", // 503522; the live Poison Powder aura gates the rider.
provenance: "source", // 503522; Poison Powder is a carried item, not Rogue's Poison Bottle buff.
};
case "rom-reclaim-energy":
if (triggeringSourceSkillId === 490306) return {