Skip to content

Commit

Permalink
Merge pull request #3564 from wowsims/apl
Browse files Browse the repository at this point in the history
Add apl value for aura active with reaction time
  • Loading branch information
jimmyt857 authored Aug 27, 2023
2 parents 0b46cd8 + ea9ad07 commit ab20649
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 1 deletion.
1 change: 1 addition & 0 deletions proto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ message Player {

APLRotation rotation = 40;

int32 reaction_time_ms = 41;
bool in_front_of_target = 23;
double distance_from_target = 33;

Expand Down
7 changes: 6 additions & 1 deletion proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ message APLAction {
}
}

// NextIndex: 50
// NextIndex: 51
message APLValue {
oneof value {
// Operators
Expand Down Expand Up @@ -109,6 +109,7 @@ message APLValue {

// Aura values
APLValueAuraIsActive aura_is_active = 22;
APLValueAuraIsActiveWithReactionTime aura_is_active_with_reaction_time = 50;
APLValueAuraRemainingTime aura_remaining_time = 23;
APLValueAuraNumStacks aura_num_stacks = 24;
APLValueAuraInternalCooldown aura_internal_cooldown = 39;
Expand Down Expand Up @@ -346,6 +347,10 @@ message APLValueAuraIsActive {
UnitReference source_unit = 2;
ActionID aura_id = 1;
}
message APLValueAuraIsActiveWithReactionTime {
UnitReference source_unit = 2;
ActionID aura_id = 1;
}
message APLValueAuraRemainingTime {
UnitReference source_unit = 2;
ActionID aura_id = 1;
Expand Down
5 changes: 5 additions & 0 deletions proto/ui.proto
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ message SavedSettings {
Cooldowns cooldowns = 6;
string rotation_json = 8;
repeated Profession professions = 9;

int32 reaction_time_ms = 10;
bool in_front_of_target = 11;
double distance_from_target = 12;
HealingModel healing_model = 13;
}

message SavedTalents {
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 @@ -155,6 +155,8 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue {
// Auras
case *proto.APLValue_AuraIsActive:
return rot.newValueAuraIsActive(config.GetAuraIsActive())
case *proto.APLValue_AuraIsActiveWithReactionTime:
return rot.newValueAuraIsActiveWithReactionTime(config.GetAuraIsActiveWithReactionTime())
case *proto.APLValue_AuraRemainingTime:
return rot.newValueAuraRemainingTime(config.GetAuraRemainingTime())
case *proto.APLValue_AuraNumStacks:
Expand Down
27 changes: 27 additions & 0 deletions sim/core/apl_values_aura.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,33 @@ func (value *APLValueAuraIsActive) String() string {
return fmt.Sprintf("Aura Active(%s)", value.aura.String())
}

type APLValueAuraIsActiveWithReactionTime struct {
DefaultAPLValueImpl
aura AuraReference
reactionTime time.Duration
}

func (rot *APLRotation) newValueAuraIsActiveWithReactionTime(config *proto.APLValueAuraIsActiveWithReactionTime) APLValue {
aura := rot.GetAPLAura(rot.GetSourceUnit(config.SourceUnit), config.AuraId)
if aura.Get() == nil {
return nil
}
return &APLValueAuraIsActiveWithReactionTime{
aura: aura,
reactionTime: rot.unit.ReactionTime,
}
}
func (value *APLValueAuraIsActiveWithReactionTime) Type() proto.APLValueType {
return proto.APLValueType_ValueTypeBool
}
func (value *APLValueAuraIsActiveWithReactionTime) GetBool(sim *Simulation) bool {
aura := value.aura.Get()
return aura.IsActive() && aura.TimeActive(sim) >= value.reactionTime
}
func (value *APLValueAuraIsActiveWithReactionTime) String() string {
return fmt.Sprintf("Aura Active With Reaction Time(%s)", value.aura.String())
}

type APLValueAuraRemainingTime struct {
DefaultAPLValueImpl
aura AuraReference
Expand Down
1 change: 1 addition & 0 deletions sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character

StatDependencyManager: stats.NewStatDependencyManager(),

ReactionTime: time.Duration(player.ReactionTimeMs) * time.Millisecond,
DistanceFromTarget: player.DistanceFromTarget,
IsUsingAPL: player.Rotation != nil && player.Rotation.Enabled,
},
Expand Down
4 changes: 4 additions & 0 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ type Unit struct {

MobType proto.MobType

// Amount of time it takes for the human agent to react to in-game events.
// Used by certain APL values and actions.
ReactionTime time.Duration

// How far this unit is from its target(s). Measured in yards, this is used
// for calculating spell travel time for certain spells.
DistanceFromTarget float64
Expand Down
1 change: 1 addition & 0 deletions ui/balance_druid/sim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class BalanceDruidSimUI extends IndividualSimUI<Spec.SpecBalanceDruid> {
otherInputs: {
inputs: [
OtherInputs.TankAssignment,
OtherInputs.ReactionTime,
OtherInputs.DistanceFromTarget,
],
},
Expand Down
11 changes: 11 additions & 0 deletions ui/core/components/individual_sim_ui/apl_values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
APLValueSpellChannelTime,
APLValueSpellCPM,
APLValueAuraIsActive,
APLValueAuraIsActiveWithReactionTime,
APLValueAuraRemainingTime,
APLValueAuraNumStacks,
APLValueAuraInternalCooldown,
Expand Down Expand Up @@ -754,6 +755,16 @@ const valueKindFactories: {[f in NonNullable<APLValueKind>]: ValueKindConfig<APL
AplHelpers.actionIdFieldConfig('auraId', 'auras', 'sourceUnit'),
],
}),
'auraIsActiveWithReactionTime': inputBuilder({
label: 'Aura Active (with Reaction Time)',
submenu: ['Aura'],
shortDescription: '<b>True</b> if the aura is currently active on self AND it has been active for at least as long as the player reaction time (configured in Settings), otherwise <b>False</b>.',
newValue: APLValueAuraIsActiveWithReactionTime.create,
fields: [
AplHelpers.unitFieldConfig('sourceUnit', 'aura_sources'),
AplHelpers.actionIdFieldConfig('auraId', 'auras', 'sourceUnit'),
],
}),
'auraRemainingTime': inputBuilder({
label: 'Aura Remaining Time',
submenu: ['Aura'],
Expand Down
13 changes: 13 additions & 0 deletions ui/core/components/individual_sim_ui/settings_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Consumes,
Cooldowns,
Debuffs,
HealingModel,
IndividualBuffs,
PartyBuffs,
Profession,
Expand Down Expand Up @@ -394,6 +395,10 @@ export class SettingsTab extends SimTab {
consumes: player.getConsumes(),
race: player.getRace(),
professions: player.getProfessions(),
reactionTimeMs: player.getReactionTime(),
inFrontOfTarget: player.getInFrontOfTarget(),
distanceFromTarget: player.getDistanceFromTarget(),
healingModel: player.getHealingModel(),
cooldowns: aplLaunchStatuses[simUI.player.spec] == LaunchStatus.Unlaunched ? player.getCooldowns() : undefined,
rotationJson: aplLaunchStatuses[simUI.player.spec] == LaunchStatus.Unlaunched ? JSON.stringify(player.specTypeFunctions.rotationToJson(player.getRotation())) : undefined,
});
Expand All @@ -410,6 +415,10 @@ export class SettingsTab extends SimTab {
simUI.player.setConsumes(eventID, newSettings.consumes || Consumes.create());
simUI.player.setRace(eventID, newSettings.race);
simUI.player.setProfessions(eventID, newSettings.professions);
simUI.player.setReactionTime(eventID, newSettings.reactionTimeMs);
simUI.player.setInFrontOfTarget(eventID, newSettings.inFrontOfTarget);
simUI.player.setDistanceFromTarget(eventID, newSettings.distanceFromTarget);
simUI.player.setHealingModel(eventID, newSettings.healingModel || HealingModel.create());
if (aplLaunchStatuses[simUI.player.spec] == LaunchStatus.Unlaunched) {
simUI.player.setCooldowns(eventID, newSettings.cooldowns || Cooldowns.create());
if (newSettings.rotationJson) {
Expand All @@ -426,6 +435,10 @@ export class SettingsTab extends SimTab {
this.simUI.player.consumesChangeEmitter,
this.simUI.player.raceChangeEmitter,
this.simUI.player.professionChangeEmitter,
this.simUI.player.reactionTimeChangeEmitter,
this.simUI.player.inFrontOfTargetChangeEmitter,
this.simUI.player.distanceFromTargetChangeEmitter,
this.simUI.player.healingModelChangeEmitter,
].concat(aplLaunchStatuses[this.simUI.player.spec] == LaunchStatus.Unlaunched ? [
this.simUI.player.cooldownsChangeEmitter,
this.simUI.player.rotationChangeEmitter,
Expand Down
12 changes: 12 additions & 0 deletions ui/core/components/other_inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ export function makePhaseSelector(parent: HTMLElement, sim: Sim): EnumPicker<Sim
});
}

export const ReactionTime = {
type: 'number' as const,
label: 'Reaction Time',
labelTooltip: 'Reaction time of the player, in milliseconds. Used with certain APL values (such as \'Aura Is Active With Reaction Time\').',
changedEvent: (player: Player<any>) => TypedEvent.onAny([player.reactionTimeChangeEmitter, player.rotationChangeEmitter]),
getValue: (player: Player<any>) => player.getReactionTime(),
setValue: (eventID: EventID, player: Player<any>, newValue: number) => {
player.setReactionTime(eventID, newValue);
},
enableWhen: (player: Player<any>) => player.aplRotation.enabled,
};

export const InFrontOfTarget = {
type: 'boolean' as const,
label: 'In Front of Target',
Expand Down
18 changes: 18 additions & 0 deletions ui/core/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ export class Player<SpecType extends Spec> {
private glyphs: Glyphs = Glyphs.create();
private specOptions: SpecOptions<SpecType>;
private cooldowns: Cooldowns = Cooldowns.create();
private reactionTime: number = 0;
private inFrontOfTarget: boolean = false;
private distanceFromTarget: number = 0;
private healingModel: HealingModel = HealingModel.create();
Expand Down Expand Up @@ -236,6 +237,7 @@ export class Player<SpecType extends Spec> {
readonly glyphsChangeEmitter = new TypedEvent<void>('PlayerGlyphs');
readonly specOptionsChangeEmitter = new TypedEvent<void>('PlayerSpecOptions');
readonly cooldownsChangeEmitter = new TypedEvent<void>('PlayerCooldowns');
readonly reactionTimeChangeEmitter = new TypedEvent<void>('PlayerReactionTime');
readonly inFrontOfTargetChangeEmitter = new TypedEvent<void>('PlayerInFrontOfTarget');
readonly distanceFromTargetChangeEmitter = new TypedEvent<void>('PlayerDistanceFromTarget');
readonly healingModelChangeEmitter = new TypedEvent<void>('PlayerHealingModel');
Expand Down Expand Up @@ -272,6 +274,7 @@ export class Player<SpecType extends Spec> {
this.glyphsChangeEmitter,
this.specOptionsChangeEmitter,
this.cooldownsChangeEmitter,
this.reactionTimeChangeEmitter,
this.inFrontOfTargetChangeEmitter,
this.distanceFromTargetChangeEmitter,
this.healingModelChangeEmitter,
Expand Down Expand Up @@ -715,6 +718,18 @@ export class Player<SpecType extends Spec> {
this.specOptionsChangeEmitter.emit(eventID);
}

getReactionTime(): number {
return this.reactionTime;
}

setReactionTime(eventID: EventID, newReactionTime: number) {
if (newReactionTime == this.reactionTime)
return;

this.reactionTime = newReactionTime;
this.reactionTimeChangeEmitter.emit(eventID);
}

getInFrontOfTarget(): boolean {
return this.inFrontOfTarget;
}
Expand Down Expand Up @@ -1104,6 +1119,7 @@ export class Player<SpecType extends Spec> {
rotation: this.aplRotation,
profession1: this.getProfession1(),
profession2: this.getProfession2(),
reactionTimeMs: this.getReactionTime(),
inFrontOfTarget: this.getInFrontOfTarget(),
distanceFromTarget: this.getDistanceFromTarget(),
healingModel: this.getHealingModel(),
Expand Down Expand Up @@ -1138,6 +1154,7 @@ export class Player<SpecType extends Spec> {
this.setGlyphs(eventID, proto.glyphs || Glyphs.create());
this.setProfession1(eventID, proto.profession1);
this.setProfession2(eventID, proto.profession2);
this.setReactionTime(eventID, proto.reactionTimeMs);
this.setInFrontOfTarget(eventID, proto.inFrontOfTarget);
this.setDistanceFromTarget(eventID, proto.distanceFromTarget);
this.setHealingModel(eventID, proto.healingModel || HealingModel.create());
Expand Down Expand Up @@ -1183,6 +1200,7 @@ export class Player<SpecType extends Spec> {

applySharedDefaults(eventID: EventID) {
TypedEvent.freezeAllAndDo(() => {
this.setReactionTime(eventID, 200);
this.setInFrontOfTarget(eventID, isTankSpec(this.spec));
this.setHealingModel(eventID, HealingModel.create({
burstWindow: isTankSpec(this.spec) ? 6 : 0,
Expand Down

0 comments on commit ab20649

Please sign in to comment.