Skip to content

Commit

Permalink
Merge pull request #846 from wowsims/feature/mage-pi-lust-zerking-dyn…
Browse files Browse the repository at this point in the history
…amic-breakpoints

[MAGE] Add dynamic breakpoints
  • Loading branch information
1337LutZ authored Jul 16, 2024
2 parents 370344d + f7ecaca commit 1277638
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 27 deletions.
33 changes: 25 additions & 8 deletions ui/core/components/suggest_reforges_action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ const INCLUDED_STATS = [
Stat.StatParry,
];

type StatTooltips = { [key in Stat]?: () => Element | string };
type StatTooltipContent = { [key in Stat]?: () => Element | string };

const STAT_TOOLTIPS: StatTooltips = {
const STAT_TOOLTIPS: StatTooltipContent = {
[Stat.StatMastery]: () => (
<>
Rating: <strong>excluding</strong> your base mastery
Expand All @@ -61,14 +61,19 @@ const STAT_TOOLTIPS: StatTooltips = {

export type ReforgeOptimizerOptions = {
experimental?: true;
statTooltips?: StatTooltips;
statTooltips?: StatTooltipContent;
statSelectionPresets?: Map<Stat, Map<string, number>>;
// Allows you to modify the stats before they are returned for the calculations
// For example: Adding class specific Glyphs/Talents that are not added by the backend
updateGearStatsModifier?: (baseStats: Stats) => Stats;
// Allows you to get alternate default EPs
// For example for Fury where you have SMF and TG EPs
getEPDefaults?: (player: Player<any>) => Stats;
// Allows you to modify default softCaps
// For example you wish to add breakpoints for Berserking / Bloodlust if enabled
updateSoftCaps?: (softCaps: StatCapConfig[]) => StatCapConfig[];
// Allows you to specifiy additional information for the soft cap tooltips
additionalSoftCapTooltipInformation?: StatTooltipContent;
};

export class ReforgeOptimizer {
Expand All @@ -82,8 +87,10 @@ export class ReforgeOptimizer {
protected getEPDefaults: ReforgeOptimizerOptions['getEPDefaults'];
protected _statCaps: Stats;
protected updateGearStatsModifier: ReforgeOptimizerOptions['updateGearStatsModifier'];
protected softCapsConfig: StatCapConfig[];
protected statTooltips: StatTooltips = {};
protected _softCapsConfig: StatCapConfig[];
protected updateSoftCaps: ReforgeOptimizerOptions['updateSoftCaps'];
protected statTooltips: StatTooltipContent = {};
protected additionalSoftCapTooltipInformation: StatTooltipContent = {};
protected statSelectionPresets: ReforgeOptimizerOptions['statSelectionPresets'];
readonly freezeItemSlotsChangeEmitter = new TypedEvent<void>();
protected freezeItemSlots = false;
Expand All @@ -98,9 +105,11 @@ export class ReforgeOptimizer {
this.sim = simUI.sim;
this.defaults = simUI.individualConfig.defaults;
this.getEPDefaults = options?.getEPDefaults;
this.updateSoftCaps = options?.updateSoftCaps;
this.updateGearStatsModifier = options?.updateGearStatsModifier;
this.softCapsConfig = this.defaults.softCapBreakpoints || [];
this._softCapsConfig = this.defaults.softCapBreakpoints || [];
this.statTooltips = { ...STAT_TOOLTIPS, ...options?.statTooltips };
this.additionalSoftCapTooltipInformation = { ...options?.additionalSoftCapTooltipInformation };
this.statSelectionPresets = options?.statSelectionPresets;
this._statCaps = this.statCaps;

Expand Down Expand Up @@ -163,10 +172,10 @@ export class ReforgeOptimizer {
if (!!this.softCapsConfig?.length)
tippy(startReforgeOptimizationButton, {
theme: 'suggest-reforges-softcaps',
content: this.buildReforgeButtonTooltip(),
placement: 'bottom',
maxWidth: 310,
interactive: true,
onShow: instance => instance.setContent(this.buildReforgeButtonTooltip()),
});

tippy(contextMenuButton, {
Expand All @@ -185,6 +194,10 @@ export class ReforgeOptimizer {
});
}

get softCapsConfig() {
return this.updateSoftCaps?.(structuredClone(this._softCapsConfig)) || this._softCapsConfig;
}

get statCaps() {
return this.sim.getUseCustomEPValues() ? this.player.getStatCaps() : this.defaults.statCaps || new Stats();
}
Expand Down Expand Up @@ -224,6 +237,11 @@ export class ReforgeOptimizer {
<th colSpan={2}>{getClassStatName(stat, this.player.getClass())}</th>
<td className="text-end">{statCapTypeNames.get(capType)}</td>
</tr>
{this.additionalSoftCapTooltipInformation[stat] && (
<tr>
<td colSpan={3}>{this.additionalSoftCapTooltipInformation[stat]?.()}</td>
</tr>
)}
<tr>
<th>
<em>Rating</em>
Expand Down Expand Up @@ -290,7 +308,6 @@ export class ReforgeOptimizer {
useSoftCapBreakpointsInput = new BooleanPicker(null, this.player, {
id: 'reforge-optimizer-enable-soft-cap-breakpoints',
label: 'Use soft cap breakpoints',
labelTooltip: this.buildReforgeButtonTooltip(),
inline: true,
changedEvent: () => this.sim.useSoftCapBreakpointsChangeEmitter,
getValue: () => this.sim.getUseSoftCapBreakpoints(),
Expand Down
2 changes: 1 addition & 1 deletion ui/core/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ import {
import {
DungeonDifficulty,
RaidFilterOption,
StatCapConfig,
SourceFilterOption,
StatCapConfig,
UIEnchant as Enchant,
UIGem as Gem,
UIItem as Item,
Expand Down
16 changes: 8 additions & 8 deletions ui/mage/fire/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,14 @@ export const FIRE_BREAKPOINTS = new Map([
['14-tick Combust', 4488],
['6-tick LvB/Pyro', 4805],
['15-tick Combust', 5767],
// ['16-tick Combust', 7033],
// ['7-tick LvB/Pyro', 8000],
// ['17-tick Combust', 8309],
// ['18-tick Combust', 9602],
// ['19-tick Combust', 10887],
// ['8-tick LvB/Pyro', 11198],
// ['20-tick Combust', 12182],
// ['21-tick Combust', 13463],
['16-tick Combust', 7033],
['7-tick LvB/Pyro', 8000],
['17-tick Combust', 8309],
['18-tick Combust', 9602],
['19-tick Combust', 10887],
['8-tick LvB/Pyro', 11198],
['20-tick Combust', 12182],
['21-tick Combust', 13463],
// ['9-tick LvB/Pyro', 14412],
// ['22-tick Combust', 14704],
// ['23-tick Combust', 16004],
Expand Down
101 changes: 91 additions & 10 deletions ui/mage/fire/sim.ts → ui/mage/fire/sim.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { CharacterStats } from '../../core/components/character_stats';
import * as OtherInputs from '../../core/components/inputs/other_inputs';
import { ReforgeOptimizer } from '../../core/components/suggest_reforges_action';
import * as Mechanics from '../../core/constants/mechanics';
Expand All @@ -13,6 +12,8 @@ import { sharedMageDisplayStatsModifiers } from '../shared';
import * as FireInputs from './inputs';
import * as Presets from './presets';

const hasteBreakpoints = Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!;

const SPEC_CONFIG = registerSpecConfig(Spec.SpecFireMage, {
cssClass: 'fire-mage-sim-ui',
cssScheme: PlayerClasses.getCssClass(PlayerClasses.Mage),
Expand Down Expand Up @@ -53,15 +54,20 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecFireMage, {
const hasteSoftCapConfig = {
stat: Stat.StatSpellHaste,
breakpoints: [
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('5-tick LvB/Pyro')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('12-tick Combust')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('BL - 16-tick Combust')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('BL - 7-tick LvB/Pyro')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('13-tick Combust')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('BL - 17-tick Combust')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('14-tick Combust')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('6-tick LvB/Pyro')!,
Presets.FIRE_BREAKPOINTS.get(Stat.StatSpellHaste)!.get('15-tick Combust')!,
hasteBreakpoints.get('5-tick LvB/Pyro')!,
hasteBreakpoints.get('12-tick Combust')!,
hasteBreakpoints.get('13-tick Combust')!,
hasteBreakpoints.get('14-tick Combust')!,
hasteBreakpoints.get('6-tick LvB/Pyro')!,
hasteBreakpoints.get('15-tick Combust')!,
hasteBreakpoints.get('16-tick Combust')!,
hasteBreakpoints.get('7-tick LvB/Pyro')!,
hasteBreakpoints.get('17-tick Combust')!,
hasteBreakpoints.get('18-tick Combust')!,
hasteBreakpoints.get('19-tick Combust')!,
hasteBreakpoints.get('8-tick LvB/Pyro')!,
hasteBreakpoints.get('20-tick Combust')!,
hasteBreakpoints.get('21-tick Combust')!,
],
capType: StatCapType.TypeThreshold,
postCapEPs: [0.61],
Expand Down Expand Up @@ -162,6 +168,81 @@ export class FireMageSimUI extends IndividualSimUI<Spec.SpecFireMage> {
new ReforgeOptimizer(this, {
experimental: true,
statSelectionPresets: Presets.FIRE_BREAKPOINTS,
updateSoftCaps: softCaps => {
const hasBL = !!player.getRaid()?.getBuffs()?.bloodlust;
const hasPI = !!player.getBuffs().powerInfusionCount;
const hasBerserking = player.getRace() === Race.RaceTroll;

const modifyHaste = (rating: number, modifier: number) =>
Math.round(
((rating / Mechanics.HASTE_RATING_PER_HASTE_PERCENT / 100 + 1) / modifier - 1) * 100 * Mechanics.HASTE_RATING_PER_HASTE_PERCENT,
);

this.individualConfig.defaults.softCapBreakpoints!.forEach(softCap => {
const softCapToModify = softCaps.find(sc => sc.stat === softCap.stat);
if (softCap.stat === Stat.StatSpellHaste && softCapToModify) {
const adjustedHastedBreakpoints = new Set([...softCap.breakpoints]);
// LvB/Pyro are not worth adjusting for
const excludedHasteBreakpoints = [
hasteBreakpoints.get('5-tick LvB/Pyro')!,
hasteBreakpoints.get('6-tick LvB/Pyro')!,
hasteBreakpoints.get('7-tick LvB/Pyro')!,
hasteBreakpoints.get('8-tick LvB/Pyro')!,
];
softCap.breakpoints.forEach(breakpoint => {
const isExcludedFromPiZerk = excludedHasteBreakpoints.includes(breakpoint);
if (hasBL) {
const blBreakpoint = modifyHaste(breakpoint, 1.3);
if (blBreakpoint > 0) {
adjustedHastedBreakpoints.add(blBreakpoint);
if (hasBerserking) {
const berserkingBreakpoint = modifyHaste(blBreakpoint, 1.2);
if (berserkingBreakpoint > 0) {
adjustedHastedBreakpoints.add(berserkingBreakpoint);
}
}
}
}
if (hasPI && !isExcludedFromPiZerk) {
const piBreakpoint = modifyHaste(breakpoint, 1.2);
if (piBreakpoint > 0) {
adjustedHastedBreakpoints.add(piBreakpoint);
if (hasBerserking) {
const berserkingBreakpoint = modifyHaste(piBreakpoint, 1.2);
if (berserkingBreakpoint > 0) {
adjustedHastedBreakpoints.add(berserkingBreakpoint);
}
}
}
}
});
softCapToModify.breakpoints = [...adjustedHastedBreakpoints].sort((a, b) => a - b);
}
});
return softCaps;
},
additionalSoftCapTooltipInformation: {
[Stat.StatSpellHaste]: () => {
const hasBL = !!player.getRaid()?.getBuffs()?.bloodlust;
const hasPI = !!player.getBuffs().powerInfusionCount;
const hasBerserking = player.getRace() === Race.RaceTroll;

return (
<>
{(hasBL || hasPI || hasBerserking) && (
<>
<p className="mb-0">Additional breakpoints have been created using the following cooldowns:</p>
<ul className="mb-0">
{hasBL && <li>Bloodlust</li>}
{hasPI && <li>Power Infusion</li>}
{hasBerserking && <li>Berserking</li>}
</ul>
</>
)}
</>
);
},
},
});
});
}
Expand Down

0 comments on commit 1277638

Please sign in to comment.