Skip to content

Commit e46c4e7

Browse files
authored
Merge pull request #1354 from wowsims/feature/rrpm-reset-on-encounter-start
Make RPPM effects reset their lastProc and lastAttempt on encounter start
2 parents 33b761b + 106a831 commit e46c4e7

42 files changed

Lines changed: 8724 additions & 8614 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

sim/core/character.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ func (cbp CharacterBuildPhase) Matches(other CharacterBuildPhase) bool {
1818
return (cbp & other) != 0
1919
}
2020

21+
type OnEncounterStartEffect func()
22+
2123
const (
2224
CharacterBuildPhaseNone CharacterBuildPhase = 0
2325
CharacterBuildPhaseBase CharacterBuildPhase = 1 << iota
@@ -82,6 +84,8 @@ type Character struct {
8284
spellCategoryTimers map[int32]*Timer
8385

8486
Pets []*Pet // cached in AddPet, for advance()
87+
88+
OnEncounterStartEffects []OnEncounterStartEffect
8589
}
8690

8791
func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character {
@@ -805,3 +809,11 @@ func (character *Character) ApplyArmorSpecializationEffect(primaryStat stats.Sta
805809
trackerAura.AttachStatDependency(armorSpecializationDependency)
806810
return trackerAura
807811
}
812+
813+
func (character *Character) RegisterOnEncounterStartEffect(onEncounterStartEffect OnEncounterStartEffect) {
814+
if onEncounterStartEffect == nil {
815+
return
816+
}
817+
818+
character.OnEncounterStartEffects = append(character.OnEncounterStartEffects, onEncounterStartEffect)
819+
}

sim/core/environment.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package core
22

33
import (
4+
"slices"
45
"time"
56

67
"github.com/wowsims/mop/sim/core/proto"
@@ -215,7 +216,7 @@ func (env *Environment) finalize(raidProto *proto.Raid, _ *proto.Encounter, raid
215216
sim := newSimWithEnv(env, &proto.SimOptions{
216217
Iterations: 1,
217218
}, simsignals.CreateSignals())
218-
sim.reset()
219+
sim.reset(true)
219220
sim.PrePull()
220221
sim.Cleanup()
221222
}
@@ -269,10 +270,7 @@ func (env *Environment) IsFinalized() bool {
269270
return env.State >= Finalized
270271
}
271272

272-
func (env *Environment) reset(sim *Simulation) {
273-
// Randomize heartbeat timer for pet stat inheritance.
274-
env.heartbeatOffset = env.PrepullStartTime(sim) - PetUpdateInterval + DurationFromSeconds(PetUpdateInterval.Seconds()*sim.RandomFloat("Pet Stat Inheritance"))
275-
273+
func (env *Environment) reset(sim *Simulation, firstIteration bool) {
276274
// Reset primary targets damage taken for tracking health fights.
277275
env.Encounter.DamageTaken = 0
278276

@@ -283,6 +281,26 @@ func (env *Environment) reset(sim *Simulation) {
283281
}
284282

285283
env.Raid.reset(sim)
284+
285+
// Re-evaluate dynamic prepull action times on the first iteration.
286+
// Must happen after Raid.reset (which re-applies auras like 5% spell haste)
287+
// but before heartbeatOffset and initManaTickAction (which read PrepullStartTime).
288+
if firstIteration {
289+
for _, action := range env.prepullActions {
290+
action.doAtTime = action.DoAt.GetDuration(sim)
291+
}
292+
293+
env.prepullActions = FilterSlice(env.prepullActions, func(action *PrepullAction) bool {
294+
return action.doAtTime <= sim.CurrentTime
295+
})
296+
297+
slices.SortStableFunc(env.prepullActions, func(a1, a2 *PrepullAction) int {
298+
return int(a1.doAtTime - a2.doAtTime)
299+
})
300+
}
301+
302+
// Randomize heartbeat timer for pet stat inheritance.
303+
env.heartbeatOffset = env.PrepullStartTime(sim) - PetUpdateInterval + DurationFromSeconds(PetUpdateInterval.Seconds()*sim.RandomFloat("Pet Stat Inheritance"))
286304
}
287305

288306
// The maximum possible duration for any iteration.

sim/core/procs.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package core
22

33
import (
4+
"time"
5+
46
"github.com/wowsims/mop/sim/core/proto"
57
)
68

@@ -263,9 +265,16 @@ func (character *Character) NewRPPMProcManager(effectID int32, isEnchant bool, i
263265
dpm := builder()
264266

265267
// Keep track of the lastProc and lastCheck values when weapon swapping.
266-
lastProc := -RppmLastProcResetValue
267-
lastCheck := -RppmLastCheckCap
268-
isFirstProc := true
268+
var lastProc time.Duration
269+
var lastCheck time.Duration
270+
var isFirstProc bool
271+
272+
resetProc := func() {
273+
lastProc = -RppmLastProcResetValue
274+
lastCheck = -RppmLastCheckCap
275+
isFirstProc = true
276+
}
277+
resetProc()
269278

270279
character.RegisterItemSwapCallback(slotList, func(_ *Simulation, _ proto.ItemSlot) {
271280
for _, proc := range dpm.procChances {
@@ -286,9 +295,18 @@ func (character *Character) NewRPPMProcManager(effectID int32, isEnchant bool, i
286295
})
287296

288297
character.RegisterResetEffect(func(_ *Simulation) {
289-
lastProc = -RppmLastProcResetValue
290-
lastCheck = -RppmLastCheckCap
291-
isFirstProc = true
298+
resetProc()
299+
})
300+
301+
character.RegisterOnEncounterStartEffect(func() {
302+
resetProc()
303+
304+
for _, proc := range dpm.procChances {
305+
resolvedProc := proc.(*RPPMProc)
306+
resolvedProc.lastProc = lastProc
307+
resolvedProc.lastCheck = lastCheck
308+
resolvedProc.isFirstProc = isFirstProc
309+
}
292310
})
293311

294312
return &dpm

sim/core/sim.go

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ func (sim *Simulation) Proc(p float64, label string) bool {
286286
}
287287

288288
func (sim *Simulation) Reset() {
289-
sim.reset()
289+
sim.reset(false)
290290
}
291291

292292
func (sim *Simulation) Reseed(seed int64) {
@@ -379,21 +379,7 @@ func (sim *Simulation) run() *proto.RaidSimResult {
379379
// RunOnce is the main event loop. It will run the simulation for number of seconds.
380380
func (sim *Simulation) runOnce(firstIteration bool) {
381381
sim.isInPrepull = true
382-
sim.reset()
383-
384-
if firstIteration {
385-
for _, action := range sim.Environment.prepullActions {
386-
action.doAtTime = action.DoAt.GetDuration(sim)
387-
}
388-
389-
sim.Environment.prepullActions = FilterSlice(sim.Environment.prepullActions, func(action *PrepullAction) bool {
390-
return action.doAtTime <= sim.CurrentTime
391-
})
392-
393-
slices.SortStableFunc(sim.Environment.prepullActions, func(a1, a2 *PrepullAction) int {
394-
return int(a1.doAtTime - a2.doAtTime)
395-
})
396-
}
382+
sim.reset(firstIteration)
397383

398384
sim.PrePull()
399385
sim.isInPrepull = false
@@ -412,7 +398,7 @@ var (
412398

413399
// Reset will set sim back and erase all current state.
414400
// This is automatically called before every 'Run'.
415-
func (sim *Simulation) reset() {
401+
func (sim *Simulation) reset(firstIteration bool) {
416402
if sim.Encounter.DurationIsEstimate && sim.CurrentTime != 0 {
417403
sim.BaseDuration = sim.CurrentTime
418404
sim.Encounter.DurationIsEstimate = false
@@ -449,7 +435,7 @@ func (sim *Simulation) reset() {
449435
sim.tasks = sim.tasks[:0]
450436
sim.minTaskTime = NeverExpires
451437

452-
sim.Environment.reset(sim)
438+
sim.Environment.reset(sim, firstIteration)
453439

454440
sim.initManaTickAction()
455441
}

sim/core/unit.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,12 @@ func (unit *Unit) reset(sim *Simulation, _ Agent) {
812812
func (unit *Unit) onEncounterStart(sim *Simulation) {
813813
if agent := unit.Env.GetAgentFromUnit(unit); agent != nil {
814814
agent.OnEncounterStart(sim)
815+
816+
if character := agent.GetCharacter(); character != nil {
817+
for i := range character.OnEncounterStartEffects {
818+
character.OnEncounterStartEffects[i]()
819+
}
820+
}
815821
}
816822

817823
// Reduce Haste fakepoints arising from overly precise swing timings relative to the GCD timer.

0 commit comments

Comments
 (0)