Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -4,7 +4,7 @@ import type { CharacterStats, WotlkAttackKind } from "./wotlkStats";
|
||||
export type CombatAttackKind = WotlkAttackKind;
|
||||
export type CombatOutcome = "hit" | "crit" | "miss" | "dodge" | "parry" | "block" | "resist";
|
||||
export type CombatResistanceMode = "none" | "partial" | "binary";
|
||||
export type CombatRollStage = "outcome" | "resistance";
|
||||
export type CombatRollStage = "outcome" | "resistance" | "block" | "critical-block";
|
||||
|
||||
/** A roll must be in [0, 1). Values outside that range are safely clamped. */
|
||||
export type CombatRollSource = (stage: CombatRollStage) => number;
|
||||
@@ -26,6 +26,8 @@ export interface CombatDefenderStats {
|
||||
readonly parryPercent?: number;
|
||||
readonly blockPercent?: number;
|
||||
readonly blockValue?: number;
|
||||
/** Integer chance passed to AzerothCore's roll_chance_i after a successful block. */
|
||||
readonly criticalBlockChancePercent?: number;
|
||||
readonly criticalAvoidancePercent?: number;
|
||||
readonly damageReductionPercent?: number;
|
||||
readonly resistances?: Partial<Readonly<Record<DamageSchool, number>>>;
|
||||
@@ -47,6 +49,8 @@ export interface CombatResultRules {
|
||||
readonly canDodge?: boolean;
|
||||
readonly canParry?: boolean;
|
||||
readonly canBlock?: boolean;
|
||||
/** Source direct physical spells roll block separately after landing, including crits. */
|
||||
readonly blockMode?: "post-hit";
|
||||
/** Source mechanic exception (for example, bleed effects that bypass armor). */
|
||||
readonly ignoreArmor?: boolean;
|
||||
readonly resistanceMode?: CombatResistanceMode;
|
||||
@@ -98,6 +102,12 @@ export interface CombatResult {
|
||||
readonly outcomeRoll: number;
|
||||
readonly resistanceRoll: number | null;
|
||||
readonly resistanceFraction: number;
|
||||
readonly postHitBlockRoll?: number;
|
||||
readonly postHitBlockChancePercent?: number;
|
||||
/** Integer in [0, 99], matching the sample consumed by roll_chance_i. */
|
||||
readonly criticalBlockRoll?: number;
|
||||
readonly criticalBlockChancePercent?: number;
|
||||
readonly criticalBlocked?: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_CRITICAL_DAMAGE_MULTIPLIER = 2;
|
||||
@@ -180,7 +190,7 @@ export function combatAttackTable(input: ResolveCombatResultInput): CombatAttack
|
||||
(rules.canParry ?? defaultCanParry)
|
||||
? Math.max(0, finitePercent(defender.parryPercent) - expertise)
|
||||
: 0,
|
||||
(rules.canBlock ?? defaultCanBlock) ? finitePercent(defender.blockPercent) : 0,
|
||||
rules.blockMode !== "post-hit" && (rules.canBlock ?? defaultCanBlock) ? finitePercent(defender.blockPercent) : 0,
|
||||
rules.canCrit === false
|
||||
? 0
|
||||
: Math.max(
|
||||
@@ -319,9 +329,33 @@ export function resolveCombatResult(input: ResolveCombatResultInput): CombatResu
|
||||
);
|
||||
let remaining = damageBeforeMitigation - armorMitigatedAmount;
|
||||
|
||||
const blocked = rolledOutcome === "block";
|
||||
const postHitBlockChancePercent = input.rules?.blockMode === "post-hit"
|
||||
&& input.rules.canBlock !== false && input.damageSchool === "physical"
|
||||
&& (input.attackKind === "melee" || input.attackKind === "ranged")
|
||||
? finitePercent(input.defender.blockPercent) : 0;
|
||||
const postHitBlockRoll = postHitBlockChancePercent > 0
|
||||
? normalizedRoll(rollSource("block")) : undefined;
|
||||
const blocked = rolledOutcome === "block"
|
||||
|| (postHitBlockRoll !== undefined && postHitBlockRoll * 100 < postHitBlockChancePercent);
|
||||
// AzerothCore's roll_chance_i is chance > irand(0, 99), so even 0% and
|
||||
// 100% consume a roll when the source supplied this stat. Keep the optional
|
||||
// field absent as the compatibility boundary for existing callers.
|
||||
const hasCriticalBlockChance = input.defender.criticalBlockChancePercent !== undefined;
|
||||
const criticalBlockChancePercent = hasCriticalBlockChance
|
||||
? (Number.isFinite(input.defender.criticalBlockChancePercent)
|
||||
? Math.trunc(Number(input.defender.criticalBlockChancePercent))
|
||||
: 0)
|
||||
: undefined;
|
||||
const criticalBlockRoll = blocked && hasCriticalBlockChance
|
||||
? Math.floor(normalizedRoll(rollSource("critical-block")) * 100)
|
||||
: undefined;
|
||||
const criticalBlocked = criticalBlockRoll !== undefined
|
||||
&& criticalBlockChancePercent !== undefined
|
||||
&& criticalBlockChancePercent > criticalBlockRoll;
|
||||
const blockedAmount = blocked
|
||||
? Math.min(remaining, Math.round(finiteNonNegative(input.defender.blockValue)))
|
||||
? Math.min(remaining, Math.round(
|
||||
finiteNonNegative(input.defender.blockValue) * (criticalBlocked ? 2 : 1),
|
||||
))
|
||||
: 0;
|
||||
remaining -= blockedAmount;
|
||||
|
||||
@@ -359,7 +393,7 @@ export function resolveCombatResult(input: ResolveCombatResultInput): CombatResu
|
||||
remaining -= damageReductionAmount;
|
||||
|
||||
return Object.freeze({
|
||||
outcome: rolledOutcome,
|
||||
outcome: blocked && !critical ? "block" : rolledOutcome,
|
||||
landed: true,
|
||||
critical,
|
||||
missed: false,
|
||||
@@ -382,6 +416,12 @@ export function resolveCombatResult(input: ResolveCombatResultInput): CombatResu
|
||||
outcomeRoll,
|
||||
resistanceRoll,
|
||||
resistanceFraction: resistedFraction,
|
||||
...(postHitBlockRoll !== undefined ? { postHitBlockRoll, postHitBlockChancePercent } : {}),
|
||||
...(criticalBlockChancePercent !== undefined && criticalBlockRoll !== undefined ? {
|
||||
criticalBlockChancePercent,
|
||||
criticalBlocked,
|
||||
criticalBlockRoll,
|
||||
} : {}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user