Skip to content

Commit

Permalink
update boolean picker styles
Browse files Browse the repository at this point in the history
  • Loading branch information
kayla-glick committed Mar 19, 2024
1 parent 4f22564 commit b4b7f10
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 277 deletions.
7 changes: 4 additions & 3 deletions ui/core/components/boolean_picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ export class BooleanPicker<ModObject> extends Input<ModObject, boolean> {
constructor(parent: HTMLElement, modObject: ModObject, config: BooleanPickerConfig<ModObject>) {
super(parent, 'boolean-picker-root', modObject, config);

this.rootElem.classList.add('form-check', 'form-check-reverse');
this.rootElem.classList.add('form-check');

this.inputElem = document.createElement('input');
this.inputElem.type = 'checkbox';
this.inputElem.classList.add('boolean-picker-input', 'form-check-input');

if (config.reverse) {
this.rootElem.prepend(this.inputElem);
} else {
this.rootElem.classList.add('form-check-reverse');
this.rootElem.appendChild(this.inputElem);
} else {
this.rootElem.prepend(this.inputElem);
}

this.init();
Expand Down
183 changes: 106 additions & 77 deletions ui/core/components/encounter_picker.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
import {
InputType,
MobType,
SpellSchool,
Stat,
Target as TargetProto,
TargetInput,
Target,
} from '../proto/common.js';
import { Encounter } from '../encounter.js';
import { Raid } from '../raid.js';
import { EventID, TypedEvent } from '../typed_event.js';
import { BooleanPicker } from '../components/boolean_picker.js';
import { EnumPicker } from '../components/enum_picker.js';
import { ListItemPickerConfig, ListPicker } from '../components/list_picker.js';
import { NumberPicker } from '../components/number_picker.js';
import { Stats } from '../proto_utils/stats.js';
import { isHealingSpec, isTankSpec } from '../proto_utils/utils.js';
import { statNames } from '../proto_utils/names.js';

import { Component } from './component.js';

import * as Mechanics from '../constants/mechanics.js';
import { Encounter } from '../encounter.js';
import { IndividualSimUI } from '../individual_sim_ui.js';
import { InputType, MobType, SpellSchool, Stat, Target, Target as TargetProto, TargetInput } from '../proto/common.js';
import { statNames } from '../proto_utils/names.js';
import { Stats } from '../proto_utils/stats.js';
import { isHealingSpec, isTankSpec } from '../proto_utils/utils.js';
import { Raid } from '../raid.js';
import { SimUI } from '../sim_ui.js';
import { Input } from './input.js';
import { EventID, TypedEvent } from '../typed_event.js';
import { BaseModal } from './base_modal.js';
import { Component } from './component.js';
import { Input } from './input.js';

export interface EncounterPickerConfig {
showExecuteProportion: boolean,
showExecuteProportion: boolean;
}

export class EncounterPicker extends Component {
Expand All @@ -44,14 +34,14 @@ export class EncounterPicker extends Component {
extraCssClasses: ['damage-metrics', 'npc-picker'],
label: 'NPC',
labelTooltip: 'Selects a preset NPC configuration.',
values: [
{ name: 'Custom', value: -1 },
].concat(presetTargets.map((pe, i) => {
return {
name: pe.path,
value: i,
};
})),
values: [{ name: 'Custom', value: -1 }].concat(
presetTargets.map((pe, i) => {
return {
name: pe.path,
value: i,
};
}),
),
changedEvent: (encounter: Encounter) => encounter.changeEmitter,
getValue: (encounter: Encounter) => presetTargets.findIndex(pe => equalTargetsIgnoreInputs(encounter.primaryTarget, pe.target)),
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
Expand Down Expand Up @@ -127,11 +117,13 @@ export class EncounterPicker extends Component {
}

// Transfer Target Inputs from target Id if they dont match (possible when custom AI is selected)
let targetIndex = presetTargets.findIndex(pe => modEncounter.primaryTarget.id == pe.target?.id);
let targetInputs = presetTargets[targetIndex]?.target?.targetInputs || [];
const targetIndex = presetTargets.findIndex(pe => modEncounter.primaryTarget.id == pe.target?.id);
const targetInputs = presetTargets[targetIndex]?.target?.targetInputs || [];

if (targetInputs.length != modEncounter.primaryTarget.targetInputs.length
|| modEncounter.primaryTarget.targetInputs.some((ti, i) => ti.label != targetInputs[i].label)) {
if (
targetInputs.length != modEncounter.primaryTarget.targetInputs.length ||
modEncounter.primaryTarget.targetInputs.some((ti, i) => ti.label != targetInputs[i].label)
) {
modEncounter.primaryTarget.targetInputs = targetInputs;
modEncounter.targetsChangeEmitter.emit(TypedEvent.nextEventID());
}
Expand Down Expand Up @@ -187,7 +179,12 @@ class AdvancedEncounterModal extends BaseModal {
},
newItem: () => Encounter.defaultTargetProto(),
copyItem: (oldItem: TargetProto) => TargetProto.clone(oldItem),
newItemPicker: (parent: HTMLElement, listPicker: ListPicker<Encounter, TargetProto>, index: number, config: ListItemPickerConfig<Encounter, TargetProto>) => new TargetPicker(parent, encounter, index, config),
newItemPicker: (
parent: HTMLElement,
listPicker: ListPicker<Encounter, TargetProto>,
index: number,
config: ListItemPickerConfig<Encounter, TargetProto>,
) => new TargetPicker(parent, encounter, index, config),
});
}

Expand All @@ -197,14 +194,14 @@ class AdvancedEncounterModal extends BaseModal {
new EnumPicker<Encounter>(this.header as HTMLElement, this.encounter, {
label: 'Encounter',
extraCssClasses: ['encounter-picker', 'mb-0', 'pe-2'],
values: [
{ name: 'Custom', value: -1 },
].concat(presetEncounters.map((pe, i) => {
return {
name: pe.path,
value: i,
};
})),
values: [{ name: 'Custom', value: -1 }].concat(
presetEncounters.map((pe, i) => {
return {
name: pe.path,
value: i,
};
}),
),
changedEvent: (encounter: Encounter) => encounter.changeEmitter,
getValue: (encounter: Encounter) => presetEncounters.findIndex(pe => encounter.matchesPreset(pe)),
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
Expand Down Expand Up @@ -240,7 +237,7 @@ class TargetPicker extends Input<Encounter, TargetProto> {
}

constructor(parent: HTMLElement, encounter: Encounter, targetIndex: number, config: ListItemPickerConfig<Encounter, TargetProto>) {
super(parent, 'target-picker-root', encounter, config)
super(parent, 'target-picker-root', encounter, config);
this.encounter = encounter;
this.targetIndex = targetIndex;

Expand All @@ -259,14 +256,14 @@ class TargetPicker extends Input<Encounter, TargetProto> {
extraCssClasses: ['npc-picker'],
label: 'NPC',
labelTooltip: 'Selects a preset NPC configuration.',
values: [
{ name: 'Custom', value: -1 },
].concat(presetTargets.map((pe, i) => {
return {
name: pe.path,
value: i,
};
})),
values: [{ name: 'Custom', value: -1 }].concat(
presetTargets.map((pe, i) => {
return {
name: pe.path,
value: i,
};
}),
),
changedEvent: () => encounter.targetsChangeEmitter,
getValue: () => presetTargets.findIndex(pe => equalTargetsIgnoreInputs(this.getTarget(), pe.target)),
setValue: (eventID: EventID, _: null, newValue: number) => {
Expand All @@ -284,14 +281,14 @@ class TargetPicker extends Input<Encounter, TargetProto> {
<p>Determines the target\'s ability rotation.</p>
<p>Note that most rotations are not yet implemented.</p>
`,
values: [
{ name: 'None', value: 0 },
].concat(presetTargets.map(pe => {
return {
name: pe.path,
value: pe.target!.id,
};
})),
values: [{ name: 'None', value: 0 }].concat(
presetTargets.map(pe => {
return {
name: pe.path,
value: pe.target!.id,
};
}),
),
changedEvent: () => encounter.targetsChangeEmitter,
getValue: () => this.getTarget().id,
setValue: (eventID: EventID, _: null, newValue: number) => {
Expand Down Expand Up @@ -333,7 +330,8 @@ class TargetPicker extends Input<Encounter, TargetProto> {
this.tankIndexPicker = new EnumPicker<null>(section1, null, {
extraCssClasses: ['threat-metrics'],
label: 'Tanked By',
labelTooltip: 'Determines which player in the raid this enemy will attack. If no player is assigned to the specified tank slot, this enemy will not attack.',
labelTooltip:
'Determines which player in the raid this enemy will attack. If no player is assigned to the specified tank slot, this enemy will not attack.',
values: [
{ name: 'None', value: -1 },
{ name: 'Main Tank', value: 0 },
Expand Down Expand Up @@ -403,6 +401,7 @@ class TargetPicker extends Input<Encounter, TargetProto> {
label: 'Dual Wield',
labelTooltip: 'Uses 2 separate weapons to attack.',
inline: true,
reverse: true,
changedEvent: () => encounter.targetsChangeEmitter,
getValue: () => this.getTarget().dualWield,
setValue: (eventID: EventID, _: null, newValue: boolean) => {
Expand All @@ -412,8 +411,10 @@ class TargetPicker extends Input<Encounter, TargetProto> {
});
this.dwMissPenaltyPicker = new BooleanPicker(section3, null, {
label: 'DW Miss Penalty',
labelTooltip: 'Enables the Dual Wield Miss Penalty (+19% chance to miss) if dual wielding. Bosses in Hyjal/BT/SWP usually have this disabled to stop tanks from avoidance stacking.',
labelTooltip:
'Enables the Dual Wield Miss Penalty (+19% chance to miss) if dual wielding. Bosses in Hyjal/BT/SWP usually have this disabled to stop tanks from avoidance stacking.',
inline: true,
reverse: true,
changedEvent: () => encounter.targetsChangeEmitter,
getValue: () => this.getTarget().dualWieldPenalty,
setValue: (eventID: EventID, _: null, newValue: boolean) => {
Expand All @@ -426,6 +427,7 @@ class TargetPicker extends Input<Encounter, TargetProto> {
label: 'Parry Haste',
labelTooltip: 'Whether this enemy will gain parry haste when parrying attacks.',
inline: true,
reverse: true,
changedEvent: () => encounter.targetsChangeEmitter,
getValue: () => this.getTarget().parryHaste,
setValue: (eventID: EventID, _: null, newValue: boolean) => {
Expand Down Expand Up @@ -454,8 +456,9 @@ class TargetPicker extends Input<Encounter, TargetProto> {
});
this.suppressDodgePicker = new BooleanPicker(section3, null, {
label: 'Chill of the Throne',
labelTooltip: 'Reduces the chance for this enemy\'s attacks to be dodged by 20%. Active in Icecrown Citadel.',
labelTooltip: "Reduces the chance for this enemy's attacks to be dodged by 20%. Active in Icecrown Citadel.",
inline: true,
reverse: true,
changedEvent: () => encounter.targetsChangeEmitter,
getValue: () => this.getTarget().suppressDodge,
setValue: (eventID: EventID, _: null, newValue: boolean) => {
Expand Down Expand Up @@ -488,7 +491,8 @@ class TargetPicker extends Input<Encounter, TargetProto> {
stats: this.statPickers
.map(picker => picker.getInputValue())
.map((statValue, i) => new Stats().withStat(ALL_TARGET_STATS[i].stat, statValue))
.reduce((totalStats, curStats) => totalStats.add(curStats)).asArray(),
.reduce((totalStats, curStats) => totalStats.add(curStats))
.asArray(),
targetInputs: this.targetInputPickers.getInputValue(),
});
}
Expand Down Expand Up @@ -525,8 +529,14 @@ class TargetInputPicker extends Input<Encounter, TargetInput> {
return this.encounter.targets[this.targetIndex].targetInputs[this.targetInputIndex] || TargetInput.create();
}

constructor(parent: HTMLElement, encounter: Encounter, targetIndex: number, targetInputIndex: number, config: ListItemPickerConfig<Encounter, TargetInput>) {
super(parent, 'target-input-picker-root', encounter, config)
constructor(
parent: HTMLElement,
encounter: Encounter,
targetIndex: number,
targetInputIndex: number,
config: ListItemPickerConfig<Encounter, TargetInput>,
) {
super(parent, 'target-input-picker-root', encounter, config);
this.encounter = encounter;
this.targetIndex = targetIndex;
this.targetInputIndex = targetInputIndex;
Expand Down Expand Up @@ -584,7 +594,7 @@ class TargetInputPicker extends Input<Encounter, TargetInput> {
}

function addEncounterFieldPickers(rootElem: HTMLElement, encounter: Encounter, showExecuteProportion: boolean) {
let durationGroup = Input.newGroupContainer();
const durationGroup = Input.newGroupContainer();
rootElem.appendChild(durationGroup);

new NumberPicker(durationGroup, encounter, {
Expand All @@ -595,53 +605,67 @@ function addEncounterFieldPickers(rootElem: HTMLElement, encounter: Encounter, s
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
encounter.setDuration(eventID, newValue);
},
enableWhen: (obj) => { return !encounter.getUseHealth() },
enableWhen: obj => {
return !encounter.getUseHealth();
},
});
new NumberPicker(durationGroup, encounter, {
label: 'Duration +/-',
labelTooltip: 'Adds a random amount of time, in seconds, between [value, -1 * value] to each sim iteration. For example, setting Duration to 180 and Duration +/- to 10 will result in random durations between 170s and 190s.',
labelTooltip:
'Adds a random amount of time, in seconds, between [value, -1 * value] to each sim iteration. For example, setting Duration to 180 and Duration +/- to 10 will result in random durations between 170s and 190s.',
changedEvent: (encounter: Encounter) => encounter.changeEmitter,
getValue: (encounter: Encounter) => encounter.getDurationVariation(),
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
encounter.setDurationVariation(eventID, newValue);
},
enableWhen: (obj) => { return !encounter.getUseHealth() },
enableWhen: obj => {
return !encounter.getUseHealth();
},
});

if (showExecuteProportion) {
let executeGroup = Input.newGroupContainer();
const executeGroup = Input.newGroupContainer();
executeGroup.classList.add('execute-group');
rootElem.appendChild(executeGroup);

new NumberPicker(executeGroup, encounter, {
label: 'Execute Duration 20 (%)',
labelTooltip: 'Percentage of the total encounter duration, for which the targets will be considered to be in execute range (< 20% HP) for the purpose of effects like Warrior Execute or Mage Molten Fury.',
labelTooltip:
'Percentage of the total encounter duration, for which the targets will be considered to be in execute range (< 20% HP) for the purpose of effects like Warrior Execute or Mage Molten Fury.',
changedEvent: (encounter: Encounter) => encounter.changeEmitter,
getValue: (encounter: Encounter) => encounter.getExecuteProportion20() * 100,
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
encounter.setExecuteProportion20(eventID, newValue / 100);
},
enableWhen: (obj) => { return !encounter.getUseHealth() },
enableWhen: obj => {
return !encounter.getUseHealth();
},
});
new NumberPicker(executeGroup, encounter, {
label: 'Execute Duration 25 (%)',
labelTooltip: 'Percentage of the total encounter duration, for which the targets will be considered to be in execute range (< 25% HP) for the purpose of effects like Warlock\'s Drain Soul.',
labelTooltip:
"Percentage of the total encounter duration, for which the targets will be considered to be in execute range (< 25% HP) for the purpose of effects like Warlock's Drain Soul.",
changedEvent: (encounter: Encounter) => encounter.changeEmitter,
getValue: (encounter: Encounter) => encounter.getExecuteProportion25() * 100,
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
encounter.setExecuteProportion25(eventID, newValue / 100);
},
enableWhen: (obj) => { return !encounter.getUseHealth() },
enableWhen: obj => {
return !encounter.getUseHealth();
},
});
new NumberPicker(executeGroup, encounter, {
label: 'Execute Duration 35 (%)',
labelTooltip: 'Percentage of the total encounter duration, for which the targets will be considered to be in execute range (< 35% HP) for the purpose of effects like Warrior Execute or Mage Molten Fury.',
labelTooltip:
'Percentage of the total encounter duration, for which the targets will be considered to be in execute range (< 35% HP) for the purpose of effects like Warrior Execute or Mage Molten Fury.',
changedEvent: (encounter: Encounter) => encounter.changeEmitter,
getValue: (encounter: Encounter) => encounter.getExecuteProportion35() * 100,
setValue: (eventID: EventID, encounter: Encounter, newValue: number) => {
encounter.setExecuteProportion35(eventID, newValue / 100);
},
enableWhen: (obj) => { return !encounter.getUseHealth() },
enableWhen: obj => {
return !encounter.getUseHealth();
},
});
}
}
Expand All @@ -657,7 +681,12 @@ function makeTargetInputsPicker(parent: HTMLElement, encounter: Encounter, targe
},
newItem: () => TargetInput.create(),
copyItem: (oldItem: TargetInput) => TargetInput.clone(oldItem),
newItemPicker: (parent: HTMLElement, listPicker: ListPicker<Encounter, TargetInput>, index: number, config: ListItemPickerConfig<Encounter, TargetInput>) => new TargetInputPicker(parent, encounter, targetIndex, index, config),
newItemPicker: (
parent: HTMLElement,
listPicker: ListPicker<Encounter, TargetInput>,
index: number,
config: ListItemPickerConfig<Encounter, TargetInput>,
) => new TargetInputPicker(parent, encounter, targetIndex, index, config),
hideUi: true,
});
}
Expand All @@ -674,7 +703,7 @@ function equalTargetsIgnoreInputs(target1: TargetProto | undefined, target2: Tar
return TargetProto.equals(target1, modTarget2);
}

const ALL_TARGET_STATS: Array<{ stat: Stat, tooltip: string, extraCssClasses: Array<string> }> = [
const ALL_TARGET_STATS: Array<{ stat: Stat; tooltip: string; extraCssClasses: Array<string> }> = [
{ stat: Stat.StatHealth, tooltip: '', extraCssClasses: [] },
{ stat: Stat.StatArmor, tooltip: '', extraCssClasses: [] },
{ stat: Stat.StatArcaneResistance, tooltip: '', extraCssClasses: [] },
Expand Down
Loading

0 comments on commit b4b7f10

Please sign in to comment.