Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
bbf50c3
[Feature] Generic secondary resouces
May 3, 2025
2e79f66
Merge branch 'master' into feature/generic-resources
1337LutZ May 4, 2025
837193f
Remove unintended file
May 4, 2025
eda54c5
[Feature]Generic Resoruces: Update implementation and replace Holy P…
May 5, 2025
5d1fe07
[Feature] Generic Resources: Remove line comments from test
May 5, 2025
98dd829
[Feature] Generic Resource: Remove old proto mappings
May 5, 2025
ddea63f
[Feature] Generic resources - Part 1 APL implementation
May 5, 2025
758fb68
[Feature] Generic Resource: Add support for callbacks
May 5, 2025
c49ff3c
[Feature] Generic Resource: Add missing callback invoke
May 5, 2025
5d8d680
Add SecondaryResource class & extend APL dynamic string
1337LutZ May 5, 2025
1bd49b8
Merge branch 'feature/generic-resources' of https://github.com/wowsim…
1337LutZ May 5, 2025
d53ff8a
[Feature] Generic Resource: Fix APL
May 5, 2025
b1592a1
[Feature] Generic Resources: Make bar track Int32
May 5, 2025
0022a93
[Feature] Generic Resource: Update resource implementation
May 6, 2025
c4c9ecf
[Feature] Generic Resources: Make resource bar private to core
May 6, 2025
014be3c
[Feature] Generic Resource: Map secondary resource names correctly in…
May 6, 2025
e1ed415
Merge remote-tracking branch 'origin/master' into feature/generic-res…
May 6, 2025
5ac1cb8
[Feature] Generic resource: Remove chi from secondary resources
May 6, 2025
44bce62
Merge branch 'master' into feature/generic-resources
May 9, 2025
54c93d8
[Feature] Generic Resouce: Fixup unintended removed code
May 9, 2025
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
4 changes: 2 additions & 2 deletions proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ message APLValue {
APLValueCurrentRunicPower current_runic_power = 25;
APLValueCurrentSolarEnergy current_solar_energy = 68;
APLValueCurrentLunarEnergy current_lunar_energy = 69;
APLValueCurrentHolyPower current_holy_power = 75;
APLValueCurrentGenericResource current_generic_resource = 75;
APLValueMaxComboPoints max_combo_points = 94;
APLValueMaxEnergy max_energy = 88;
APLValueMaxFocus max_focus = 89;
Expand Down Expand Up @@ -470,7 +470,7 @@ message APLValueCurrentComboPoints {}
message APLValueCurrentRunicPower {}
message APLValueCurrentSolarEnergy {}
message APLValueCurrentLunarEnergy {}
message APLValueCurrentHolyPower {}
message APLValueCurrentGenericResource {}
message APLValueMaxComboPoints {}
message APLValueMaxEnergy {}
message APLValueMaxFocus {}
Expand Down
3 changes: 1 addition & 2 deletions proto/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -872,5 +872,4 @@ enum LogLevel {
Error = 2;

Undefined = -1;
}

}
14 changes: 12 additions & 2 deletions proto/spell.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ enum ResourceType {
ResourceTypeDeathRune = 11;
ResourceTypeSolarEnergy = 12;
ResourceTypeLunarEnergy = 13;
ResourceTypeHolyPower = 14;
ResourceTypeChi = 15;
ResourceTypeChi = 14;
ResourceTypeGenericResource = 15;
}

enum SecondaryResourceType {
SecondaryResourceTypeNone = 0;
SecondaryResourceTypeArcaneCharges = 36032;
SecondaryResourceTypeShadowOrbs = 95740;
SecondaryResourceTypeDemonicFury = 104315;
SecondaryResourceTypeBurningEmbers = 108647;
SecondaryResourceTypeSoulShards = 117198;
SecondaryResourceTypeHolyPower = 138248;
}
File renamed without changes.
2 changes: 2 additions & 0 deletions sim/core/apl_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue {
value = rot.newValueEnergyTimeToTarget(config.GetEnergyTimeToTarget(), config.Uuid)
case *proto.APLValue_FocusTimeToTarget:
value = rot.newValueFocusTimeToTarget(config.GetFocusTimeToTarget(), config.Uuid)
case *proto.APLValue_CurrentGenericResource:
value = rot.newValueCurrentGenericResource(config.GetCurrentGenericResource(), config.Uuid)

// Resources Runes
case *proto.APLValue_CurrentRuneCount:
Expand Down
25 changes: 25 additions & 0 deletions sim/core/apl_values_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,28 @@ func (value *APLValueMaxRunicPower) GetInt(sim *Simulation) int32 {
func (value *APLValueMaxRunicPower) String() string {
return fmt.Sprintf("Max Runic Power(%d)", value.maxRunicPower)
}

type APLValueCurrentGenericResource struct {
DefaultAPLValueImpl
unit *Unit
}

func (rot *APLRotation) newValueCurrentGenericResource(_ *proto.APLValueCurrentGenericResource, uuid *proto.UUID) APLValue {
unit := rot.unit
if unit.secondaryResourceBar == nil {
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not have secondary resource", unit.Label)
return nil
}
return &APLValueCurrentGenericResource{
unit: unit,
}
}
func (value *APLValueCurrentGenericResource) Type() proto.APLValueType {
return proto.APLValueType_ValueTypeInt
}
func (value *APLValueCurrentGenericResource) GetInt(sim *Simulation) int32 {
return value.unit.secondaryResourceBar.Value()
}
func (value *APLValueCurrentGenericResource) String() string {
return "Current {GENERIC_RESOURCE}"
}
4 changes: 4 additions & 0 deletions sim/core/metrics_aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ func (unit *Unit) NewFocusMetrics(actionID ActionID) *ResourceMetrics {
return unit.Metrics.NewResourceMetrics(actionID, proto.ResourceType_ResourceTypeFocus)
}

func (unit *Unit) NewGenericMetric(actionID ActionID) *ResourceMetrics {
return unit.Metrics.NewResourceMetrics(actionID, proto.ResourceType_ResourceTypeGenericResource)
}

// Adds the results of a spell to the character metrics.
func (unitMetrics *UnitMetrics) addSpellMetrics(spell *Spell, actionID ActionID, spellMetrics []SpellMetrics) {
actionMetrics, ok := unitMetrics.actions[actionID]
Expand Down
201 changes: 201 additions & 0 deletions sim/core/secondary_resource_bar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// Implements a generic resource bar that can be used to implement secondary resources
// TODO: Check whether pre-pull OOC resource loss needs to be supported for DemonicFury
package core

import (
"github.com/wowsims/mop/sim/core/proto"
)

type OnGainCallback func(gain int32, realGain int32)
type OnSpendCallback func(amount int32)

type SecondaryResourceBar interface {
CanSpend(limit int32) bool // Check whether the current resource is available or not
Spend(amount int32, action ActionID, sim *Simulation) // Spend the specified amount of resource
SpendUpTo(limit int32, action ActionID, sim *Simulation) int32 // Spends as much resource as possible up to the speciefied limit; Returns the amount of resource spent
Gain(amount int32, action ActionID, sim *Simulation) // Gain the amount specified from the action
Reset(sim *Simulation) // Resets the current resource bar
Value() int32 // Returns the current amount of resource
RegisterOnGain(callback OnGainCallback) // Registers a callback that will be called. Gain = amount gained, realGain = actual amount gained due to caps
RegisterOnSpend(callback OnSpendCallback) // Registers a callback that will be called when the resource was spend
}

type SecondaryResourceConfig struct {
Type proto.SecondaryResourceType // The type of resource the bar tracks
Max int32 // The maximum amount the bar tracks
Default int32 // The default value this bar should be initialized with
}

// Default implementation of SecondaryResourceBar
// Use RegisterSecondaryResourceBar to intantiate the resource bar
type DefaultSecondaryResourceBarImpl struct {
config SecondaryResourceConfig
value int32
unit *Unit
metrics map[ActionID]*ResourceMetrics
onGain []OnGainCallback
onSpend []OnSpendCallback
}

// CanSpend implements SecondaryResourceBar.
func (bar *DefaultSecondaryResourceBarImpl) CanSpend(limit int32) bool {
return bar.value >= limit
}

// Gain implements SecondaryResourceBar.
func (bar *DefaultSecondaryResourceBarImpl) Gain(amount int32, action ActionID, sim *Simulation) {
if amount < 0 {
panic("Can not gain negative amount")
}

oldValue := bar.value
bar.value = min(bar.value+amount, bar.config.Max)
amountGained := bar.value - oldValue
metrics := bar.GetMetric(action)
metrics.AddEvent(float64(amount), float64(amountGained))
if sim.Log != nil {
bar.unit.Log(
sim,
"Gained %d %s from %s (%d --> %d) of %d total.",
amountGained,
proto.SecondaryResourceType_name[int32(bar.config.Type)],
action,
oldValue,
bar.value,
bar.config.Max,
)
}

bar.invokeOnGain(amount, amountGained)
}

// Reset implements SecondaryResourceBar.
func (bar *DefaultSecondaryResourceBarImpl) Reset(sim *Simulation) {
bar.value = 0
if bar.config.Default > 0 {
bar.Gain(bar.config.Default, ActionID{SpellID: int32(bar.config.Type)}, sim)
}
}

// Spend implements SecondaryResourceBar.
func (bar *DefaultSecondaryResourceBarImpl) Spend(amount int32, action ActionID, sim *Simulation) {
if amount > bar.value {
panic("Trying to spend more resource than is available.")
}

if amount < 0 {
panic("Trying to spend negative amount.")
}

metrics := bar.GetMetric(action)
if sim.Log != nil {
bar.unit.Log(
sim,
"Spent %d %s from %s (%d --> %d) of %d total.",
amount,
proto.SecondaryResourceType_name[int32(bar.config.Type)],
metrics.ActionID,
bar.value,
bar.value-amount,
bar.config.Max,
)
}

metrics.AddEvent(float64(-amount), float64(-amount))
bar.invokeOnSpend(amount)
bar.value -= amount
}

// SpendUpTo implements SecondaryResourceBar.
func (bar *DefaultSecondaryResourceBarImpl) SpendUpTo(limit int32, action ActionID, sim *Simulation) int32 {
if bar.value > limit {
bar.Spend(limit, action, sim)
return limit
}

bar.Spend(bar.value, action, sim)
return bar.value
}

// Value implements SecondaryResourceBar.
func (bar *DefaultSecondaryResourceBarImpl) Value() int32 {
return bar.value
}

func (bar *DefaultSecondaryResourceBarImpl) GetMetric(action ActionID) *ResourceMetrics {
metric, ok := bar.metrics[action]
if !ok {
metric = bar.unit.NewGenericMetric(action)
bar.metrics[action] = metric
}

return metric
}

func (bar *DefaultSecondaryResourceBarImpl) RegisterOnGain(callback OnGainCallback) {
if callback == nil {
panic("Can not register nil callback")
}

bar.onGain = append(bar.onGain, callback)
}

func (bar *DefaultSecondaryResourceBarImpl) RegisterOnSpend(callback OnSpendCallback) {
if callback == nil {
panic("Can not register nil callback")
}

bar.onSpend = append(bar.onSpend, callback)
}

func (bar *DefaultSecondaryResourceBarImpl) invokeOnGain(gain int32, realGain int32) {
for _, callback := range bar.onGain {
callback(gain, realGain)
}
}

func (bar *DefaultSecondaryResourceBarImpl) invokeOnSpend(amount int32) {
for _, callback := range bar.onSpend {
callback(amount)
}
}

func (unit *Unit) NewDefaultSecondaryResourceBar(config SecondaryResourceConfig) *DefaultSecondaryResourceBarImpl {
if config.Type <= 0 {
panic("Invalid SecondaryResourceType given.")
}

if config.Max <= 0 {
panic("Invalid maximum resource value given.")
}

if config.Default < 0 || config.Default > config.Max {
panic("Invalid default value given for resource bar")
}

return &DefaultSecondaryResourceBarImpl{
config: config,
unit: unit,
metrics: make(map[ActionID]*ResourceMetrics),
onGain: []OnGainCallback{},
onSpend: []OnSpendCallback{},
}
}

func (unit *Unit) RegisterSecondaryResourceBar(config SecondaryResourceBar) {
if unit.secondaryResourceBar != nil {
panic("A secondary resource bar has already been registered.")
}

unit.secondaryResourceBar = config
}

func (unit *Unit) RegisterNewDefaultSecondaryResourceBar(config SecondaryResourceConfig) SecondaryResourceBar {
bar := unit.NewDefaultSecondaryResourceBar(config)
unit.RegisterSecondaryResourceBar(bar)
return bar
}

func (unit *Unit) GetSecondaryResourceBar() SecondaryResourceBar {
return unit.secondaryResourceBar
}
6 changes: 6 additions & 0 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ type Unit struct {
focusBar
runicPowerBar

secondaryResourceBar SecondaryResourceBar

// All spells that can be cast by this unit.
Spellbook []*Spell
spellRegistrationHandlers []SpellRegisteredHandler
Expand Down Expand Up @@ -585,6 +587,10 @@ func (unit *Unit) reset(sim *Simulation, _ Agent) {
unit.rageBar.reset(sim)
unit.runicPowerBar.reset(sim)

if unit.secondaryResourceBar != nil {
unit.secondaryResourceBar.Reset(sim)
}

unit.AutoAttacks.reset(sim)

if unit.Rotation != nil {
Expand Down
39 changes: 0 additions & 39 deletions sim/paladin/apl_values.go

This file was deleted.

4 changes: 1 addition & 3 deletions sim/paladin/crusader_strike.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (

func (paladin *Paladin) registerCrusaderStrike() {
actionId := core.ActionID{SpellID: 35395}
hpMetrics := paladin.NewHolyPowerMetrics(actionId)

paladin.CrusaderStrike = paladin.RegisterSpell(core.SpellConfig{
ActionID: actionId,
SpellSchool: core.SpellSchoolPhysical,
Expand Down Expand Up @@ -41,7 +39,7 @@ func (paladin *Paladin) registerCrusaderStrike() {

if result.Landed() {
holyPowerGain := core.TernaryInt32(paladin.ZealotryAura.IsActive(), 3, 1)
paladin.GainHolyPower(sim, holyPowerGain, hpMetrics)
paladin.HolyPower.Gain(holyPowerGain, actionId, sim)
}

spell.DealOutcome(sim, result)
Expand Down
Loading
Loading