Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'Should Refresh Aura' APL value, and use it in mage fire preset #3414

Merged
merged 1 commit into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions proto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ message AuraStats {
ActionID id = 1;
int32 max_stacks = 2;
bool has_icd = 3;
bool has_exclusive_effect = 4;
}
message SpellStats {
ActionID id = 1;
Expand Down
8 changes: 7 additions & 1 deletion proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ message APLAction {
}
}

// NextIndex: 43
// NextIndex: 44
message APLValue {
oneof value {
// Operators
Expand Down Expand Up @@ -106,6 +106,7 @@ message APLValue {
APLValueAuraRemainingTime aura_remaining_time = 23;
APLValueAuraNumStacks aura_num_stacks = 24;
APLValueAuraInternalCooldown aura_internal_cooldown = 39;
APLValueAuraShouldRefresh aura_should_refresh = 43;

// Dot values
APLValueDotIsActive dot_is_active = 6;
Expand Down Expand Up @@ -327,6 +328,11 @@ message APLValueAuraInternalCooldown {
UnitReference source_unit = 2;
ActionID aura_id = 1;
}
message APLValueAuraShouldRefresh {
UnitReference source_unit = 2;
ActionID aura_id = 1;
APLValue max_overlap = 3;
}

message APLValueDotIsActive {
ActionID spell_id = 1;
Expand Down
4 changes: 2 additions & 2 deletions sim/core/apl_actions_misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type APLActionCancelAura struct {
}

func (rot *APLRotation) newActionCancelAura(config *proto.APLActionCancelAura) APLActionImpl {
aura := rot.aplGetAura(&proto.UnitReference{Type: proto.UnitReference_Self}, config.AuraId)
aura := rot.aplGetAura(rot.getSourceUnit(&proto.UnitReference{Type: proto.UnitReference_Self}), config.AuraId)
if aura.Get() == nil {
return nil
}
Expand All @@ -67,7 +67,7 @@ type APLActionTriggerICD struct {
}

func (rot *APLRotation) newActionTriggerICD(config *proto.APLActionTriggerICD) APLActionImpl {
aura := rot.aplGetICDAura(&proto.UnitReference{Type: proto.UnitReference_Self}, config.AuraId)
aura := rot.aplGetICDAura(rot.getSourceUnit(&proto.UnitReference{Type: proto.UnitReference_Self}), config.AuraId)
if aura.Get() == nil {
return nil
}
Expand Down
6 changes: 2 additions & 4 deletions sim/core/apl_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ func NewIcdAuraReference(sourceUnit UnitReference, auraId *proto.ActionID) AuraR
return newAuraReferenceHelper(sourceUnit, auraId, func(unit *Unit, actionID ActionID) *Aura { return unit.GetIcdAuraByID(actionID) })
}

func (rot *APLRotation) aplGetAura(sourceRef *proto.UnitReference, auraId *proto.ActionID) AuraReference {
sourceUnit := rot.getSourceUnit(sourceRef)
func (rot *APLRotation) aplGetAura(sourceUnit UnitReference, auraId *proto.ActionID) AuraReference {
if sourceUnit.Get() == nil {
return AuraReference{}
}
Expand All @@ -116,8 +115,7 @@ func (rot *APLRotation) aplGetAura(sourceRef *proto.UnitReference, auraId *proto
return aura
}

func (rot *APLRotation) aplGetICDAura(sourceRef *proto.UnitReference, auraId *proto.ActionID) AuraReference {
sourceUnit := rot.getSourceUnit(sourceRef)
func (rot *APLRotation) aplGetICDAura(sourceUnit UnitReference, auraId *proto.ActionID) AuraReference {
if sourceUnit.Get() == nil {
return AuraReference{}
}
Expand Down
2 changes: 2 additions & 0 deletions sim/core/apl_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue {
return rot.newValueAuraNumStacks(config.GetAuraNumStacks())
case *proto.APLValue_AuraInternalCooldown:
return rot.newValueAuraInternalCooldown(config.GetAuraInternalCooldown())
case *proto.APLValue_AuraShouldRefresh:
return rot.newValueAuraShouldRefresh(config.GetAuraShouldRefresh())

// Dots
case *proto.APLValue_DotIsActive:
Expand Down
40 changes: 36 additions & 4 deletions sim/core/apl_values_aura.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type APLValueAuraIsActive struct {
}

func (rot *APLRotation) newValueAuraIsActive(config *proto.APLValueAuraIsActive) APLValue {
aura := rot.aplGetAura(config.SourceUnit, config.AuraId)
aura := rot.aplGetAura(rot.getSourceUnit(config.SourceUnit), config.AuraId)
if aura.Get() == nil {
return nil
}
Expand All @@ -37,7 +37,7 @@ type APLValueAuraRemainingTime struct {
}

func (rot *APLRotation) newValueAuraRemainingTime(config *proto.APLValueAuraRemainingTime) APLValue {
aura := rot.aplGetAura(config.SourceUnit, config.AuraId)
aura := rot.aplGetAura(rot.getSourceUnit(config.SourceUnit), config.AuraId)
if aura.Get() == nil {
return nil
}
Expand All @@ -61,7 +61,7 @@ type APLValueAuraNumStacks struct {
}

func (rot *APLRotation) newValueAuraNumStacks(config *proto.APLValueAuraNumStacks) APLValue {
aura := rot.aplGetAura(config.SourceUnit, config.AuraId)
aura := rot.aplGetAura(rot.getSourceUnit(config.SourceUnit), config.AuraId)
if aura.Get() == nil {
return nil
}
Expand Down Expand Up @@ -89,7 +89,7 @@ type APLValueAuraInternalCooldown struct {
}

func (rot *APLRotation) newValueAuraInternalCooldown(config *proto.APLValueAuraInternalCooldown) APLValue {
aura := rot.aplGetICDAura(config.SourceUnit, config.AuraId)
aura := rot.aplGetICDAura(rot.getSourceUnit(config.SourceUnit), config.AuraId)
if aura.Get() == nil {
return nil
}
Expand All @@ -106,3 +106,35 @@ func (value *APLValueAuraInternalCooldown) GetDuration(sim *Simulation) time.Dur
func (value *APLValueAuraInternalCooldown) String() string {
return fmt.Sprintf("Aura ICD(%s)", value.aura.String())
}

type APLValueAuraShouldRefresh struct {
defaultAPLValueImpl
aura AuraReference
maxOverlap APLValue
}

func (rot *APLRotation) newValueAuraShouldRefresh(config *proto.APLValueAuraShouldRefresh) APLValue {
aura := rot.aplGetAura(rot.getTargetUnit(config.SourceUnit), config.AuraId)
if aura.Get() == nil {
return nil
}

maxOverlap := rot.coerceTo(rot.newAPLValue(config.MaxOverlap), proto.APLValueType_ValueTypeDuration)
if maxOverlap == nil {
maxOverlap = rot.newValueConst(&proto.APLValueConst{Val: "0ms"})
}

return &APLValueAuraShouldRefresh{
aura: aura,
maxOverlap: maxOverlap,
}
}
func (value *APLValueAuraShouldRefresh) Type() proto.APLValueType {
return proto.APLValueType_ValueTypeBool
}
func (value *APLValueAuraShouldRefresh) GetBool(sim *Simulation) bool {
return value.aura.Get().ShouldRefreshExclusiveEffects(sim, value.maxOverlap.GetDuration(sim))
}
func (value *APLValueAuraShouldRefresh) String() string {
return fmt.Sprintf("Should Refresh Aura(%s)", value.aura.String())
}
7 changes: 4 additions & 3 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,10 @@ func (unit *Unit) GetMetadata() *proto.UnitMetadata {
})
metadata.Auras = MapSlice(aplAuras, func(aura *Aura) *proto.AuraStats {
return &proto.AuraStats{
Id: aura.ActionID.ToProto(),
MaxStacks: aura.MaxStacks,
HasIcd: aura.Icd != nil,
Id: aura.ActionID.ToProto(),
MaxStacks: aura.MaxStacks,
HasIcd: aura.Icd != nil,
HasExclusiveEffect: len(aura.ExclusiveEffects) > 0,
}
})

Expand Down
21 changes: 18 additions & 3 deletions ui/core/components/individual_sim_ui/apl_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ActionID } from '../../proto/common.js';
import { BooleanPicker } from '../boolean_picker.js';
import { APLValueRuneSlot, APLValueRuneType } from '../../proto/apl.js';

export type ACTION_ID_SET = 'auras' | 'stackable_auras' | 'icd_auras' | 'castable_spells' | 'dot_spells';
export type ACTION_ID_SET = 'auras' | 'stackable_auras' | 'icd_auras' | 'exclusive_effect_auras' | 'castable_spells' | 'dot_spells';

const actionIdSets: Record<ACTION_ID_SET, {
defaultLabel: string,
Expand Down Expand Up @@ -48,6 +48,16 @@ const actionIdSets: Record<ACTION_ID_SET, {
});
},
},
'exclusive_effect_auras': {
defaultLabel: 'Aura',
getActionIDs: async (metadata) => {
return metadata.getAuras().filter(aura => aura.data.hasExclusiveEffect).map(actionId => {
return {
value: actionId.id,
};
});
},
},
'castable_spells': {
defaultLabel: 'Spell',
getActionIDs: async (metadata) => {
Expand Down Expand Up @@ -106,9 +116,12 @@ const actionIdSets: Record<ACTION_ID_SET, {
},
};

export type DEFAULT_UNIT_REF = 'self' | 'currentTarget';

export interface APLActionIDPickerConfig<ModObject> extends Omit<DropdownPickerConfig<ModObject, ActionID, ActionId>, 'defaultLabel' | 'equals' | 'setOptionContent' | 'values' | 'getValue' | 'setValue'> {
actionIdSet: ACTION_ID_SET,
getUnitRef: (player: Player<any>) => UnitReference,
defaultUnitRef: DEFAULT_UNIT_REF,
getValue: (obj: ModObject) => ActionID,
setValue: (eventID: EventID, obj: ModObject, newValue: ActionID) => void,
}
Expand Down Expand Up @@ -142,10 +155,11 @@ export class APLActionIDPicker extends DropdownPicker<Player<any>, ActionID, Act
});

const getUnitRef = config.getUnitRef;
const defaultRef = config.defaultUnitRef == 'self' ? UnitReference.create({type: UnitType.Self}) : UnitReference.create({type: UnitType.CurrentTarget});
const getActionIDs = actionIdSet.getActionIDs;
const updateValues = async () => {
const unitRef = getUnitRef(player);
const metadata = player.sim.getUnitMetadata(unitRef, player, UnitReference.create({type: UnitType.Self}))
const metadata = player.sim.getUnitMetadata(unitRef, player, defaultRef)
if (metadata) {
const values = await getActionIDs(metadata);
this.setOptions(values);
Expand Down Expand Up @@ -376,14 +390,15 @@ export class APLPickerBuilder<T> extends Input<Player<any>, T> {
}
}

export function actionIdFieldConfig(field: string, actionIdSet: ACTION_ID_SET, unitRefField?: string, options?: Partial<APLPickerBuilderFieldConfig<any, any>>): APLPickerBuilderFieldConfig<any, any> {
export function actionIdFieldConfig(field: string, actionIdSet: ACTION_ID_SET, unitRefField?: string, defaultUnitRef?: DEFAULT_UNIT_REF, options?: Partial<APLPickerBuilderFieldConfig<any, any>>): APLPickerBuilderFieldConfig<any, any> {
return {
field: field,
newValue: () => ActionID.create(),
factory: (parent, player, config, getParentValue) => new APLActionIDPicker(parent, player, {
...config,
actionIdSet: actionIdSet,
getUnitRef: () => unitRefField ? getParentValue()[unitRefField] : UnitReference.create(),
defaultUnitRef: defaultUnitRef || 'self',
}),
...(options || {}),
};
Expand Down
28 changes: 28 additions & 0 deletions ui/core/components/individual_sim_ui/apl_values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
APLValueAuraRemainingTime,
APLValueAuraNumStacks,
APLValueAuraInternalCooldown,
APLValueAuraShouldRefresh,
APLValueDotIsActive,
APLValueDotRemainingTime,
APLValueRuneCooldown,
Expand Down Expand Up @@ -705,6 +706,33 @@ const valueKindFactories: {[f in NonNullable<APLValueKind>]: ValueKindConfig<APL
AplHelpers.actionIdFieldConfig('auraId', 'icd_auras', 'sourceUnit'),
],
}),
'auraShouldRefresh': inputBuilder({
label: 'Should Refresh Aura',
submenu: ['Aura'],
shortDescription: 'Whether this aura should be refreshed, e.g. for the purpose of maintaining a debuff.',
fullDescription: `
<p>This condition checks not only the specified aura but also any other auras on the same unit, including auras applied by other raid members, which apply the same debuff category.</p>
<p>For example, 'Should Refresh Debuff(Sunder Armor)' will return <b>False</b> if the unit has an active Expose Armor aura.</p>
`,
newValue: () => APLValueAuraShouldRefresh.create({
maxOverlap: {
value: {
oneofKind: 'const',
const: {
val: '0ms',
},
},
},
}),
fields: [
AplHelpers.unitFieldConfig('sourceUnit', 'targets'),
AplHelpers.actionIdFieldConfig('auraId', 'exclusive_effect_auras', 'sourceUnit', 'currentTarget'),
valueFieldConfig('maxOverlap', {
label: 'Overlap',
labelTooltip: 'Maximum amount of time before the aura expires when it may be refreshed.',
}),
],
}),

// DoT
'dotIsActive': inputBuilder({
Expand Down
16 changes: 9 additions & 7 deletions ui/mage/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,16 @@ export const FIRE_ROTATION_PRESET_DEFAULT = {
rotation: APLRotation.fromJsonString(`{
"enabled": true,
"prepullActions": [
{"action":{"castSpell":{"spellId":{"otherId":"OtherActionPotion"}}},"doAtValue":{"const":{"val":"-1s"}}}
{"action":{"castSpell":{"spellId":{"otherId":"OtherActionPotion"}}},"doAtValue":{"const":{"val":"-1s"}}}
],
"priorityList": [
{"action":{"autocastOtherCooldowns":{}}},
{"action":{"condition":{"auraIsActive":{"auraId":{"spellId":44448}}},"castSpell":{"spellId":{"spellId":42891}}}},
{"action":{"condition":{"and":{"vals":[{"not":{"val":{"dotIsActive":{"spellId":{"spellId":55360}}}}},{"cmp":{"op":"OpGt","lhs":{"remainingTime":{}},"rhs":{"const":{"val":"12s"}}}}]}},"castSpell":{"spellId":{"spellId":55360}}}},
{"action":{"condition":{"cmp":{"op":"OpLe","lhs":{"remainingTime":{}},"rhs":{"spellCastTime":{"spellId":{"spellId":42859}}}}},"castSpell":{"spellId":{"spellId":42873}}}},
{"action":{"condition":{"cmp":{"op":"OpLe","lhs":{"remainingTime":{}},"rhs":{"const":{"val":"4s"}}}},"castSpell":{"spellId":{"spellId":42859}}}},
{"action":{"castSpell":{"spellId":{"spellId":42833}}}}
{"action":{"autocastOtherCooldowns":{}}},
{"action":{"condition":{"auraShouldRefresh":{"auraId":{"spellId":12873},"maxOverlap":{"const":{"val":"4s"}}}},"castSpell":{"spellId":{"spellId":42859}}}},
{"action":{"condition":{"auraIsActive":{"auraId":{"spellId":44448}}},"castSpell":{"spellId":{"spellId":42891}}}},
{"action":{"condition":{"and":{"vals":[{"not":{"val":{"dotIsActive":{"spellId":{"spellId":55360}}}}},{"cmp":{"op":"OpGt","lhs":{"remainingTime":{}},"rhs":{"const":{"val":"12s"}}}}]}},"castSpell":{"spellId":{"spellId":55360}}}},
{"action":{"condition":{"cmp":{"op":"OpLe","lhs":{"remainingTime":{}},"rhs":{"spellCastTime":{"spellId":{"spellId":42859}}}}},"castSpell":{"spellId":{"spellId":42873}}}},
{"action":{"condition":{"cmp":{"op":"OpLe","lhs":{"remainingTime":{}},"rhs":{"const":{"val":"4s"}}}},"castSpell":{"spellId":{"spellId":42859}}}},
{"action":{"castSpell":{"spellId":{"spellId":42833}}}}
]
}`),
}),
Expand All @@ -238,6 +239,7 @@ export const FROSTFIRE_ROTATION_PRESET_DEFAULT = {
],
"priorityList": [
{"action":{"autocastOtherCooldowns":{}}},
{"action":{"condition":{"auraShouldRefresh":{"auraId":{"spellId":12873},"maxOverlap":{"const":{"val":"4s"}}}},"castSpell":{"spellId":{"spellId":42859}}}},
{"action":{"condition":{"auraIsActive":{"auraId":{"spellId":44448}}},"castSpell":{"spellId":{"spellId":42891}}}},
{"action":{"condition":{"and":{"vals":[{"not":{"val":{"dotIsActive":{"spellId":{"spellId":55360}}}}},{"cmp":{"op":"OpGt","lhs":{"remainingTime":{}},"rhs":{"const":{"val":"12s"}}}}]}},"castSpell":{"spellId":{"spellId":55360}}}},
{"action":{"condition":{"cmp":{"op":"OpLe","lhs":{"remainingTime":{}},"rhs":{"spellCastTime":{"spellId":{"spellId":42859}}}}},"castSpell":{"spellId":{"spellId":42873}}}},
Expand Down
Loading