Skip to content

Commit

Permalink
Merge pull request #1045 from ncberman/movement_update
Browse files Browse the repository at this point in the history
Movement update
  • Loading branch information
kayla-glick authored Oct 3, 2024
2 parents ee0ecdd + f68dfd0 commit 9dcdd69
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 171 deletions.
12 changes: 12 additions & 0 deletions sim/common/vanilla/enchant_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,17 @@ func init() {
character.PseudoStats.RangedSpeedMultiplier *= 1.01
})

// Boots - Minor Speed
core.NewEnchantEffect(911, func(agent core.Agent) {
character := agent.GetCharacter()

character.RegisterAura(core.Aura{
Label: "Minor Speed",
OnInit: func(aura *core.Aura, sim *core.Simulation) {
character.AddMoveSpeedModifier(&core.ActionID{SpellID: 13889}, 1.08)
},
})
})

core.AddEffectsToTest = true
}
8 changes: 4 additions & 4 deletions sim/common/vanilla/item_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -859,10 +859,10 @@ func init() {
Label: "Chilled (Frostguard)",
Duration: time.Second * 5,
OnGain: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.MoveSpeed *= .70
aura.Unit.AddMoveSpeedModifier(&aura.ActionID, 0.30)
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.MoveSpeed /= .70
aura.Unit.RemoveMoveSpeedModifier(&aura.ActionID)
},
})
core.AtkSpeedReductionEffect(aura, 1.25)
Expand Down Expand Up @@ -1031,10 +1031,10 @@ func init() {
Label: "Chilled (Hardened Frostguard)",
Duration: time.Second * 5,
OnGain: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.MoveSpeed *= .70
aura.Unit.AddMoveSpeedModifier(&aura.ActionID, 0.30)
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
aura.Unit.MoveSpeed /= .70
aura.Unit.RemoveMoveSpeedModifier(&aura.ActionID)
},
})
core.AtkSpeedReductionEffect(aura, 1.25)
Expand Down
2 changes: 1 addition & 1 deletion sim/core/apl_actions_misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func (rot *APLRotation) newActionMove(config *proto.APLActionMove) APLActionImpl
}
func (action *APLActionMove) IsReady(sim *Simulation) bool {
isPrepull := sim.CurrentTime < 0
return !action.unit.Moving && (action.moveRange.GetFloat(sim) != action.unit.DistanceFromTarget || isPrepull) && !action.unit.IsCasting(sim)
return !action.unit.IsMoving() && (action.moveRange.GetFloat(sim) != action.unit.DistanceFromTarget || isPrepull) && !action.unit.IsCasting(sim)
}
func (action *APLActionMove) Execute(sim *Simulation) {
moveRange := action.moveRange.GetFloat(sim)
Expand Down
3 changes: 3 additions & 0 deletions sim/core/buffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,9 @@ func ApplySpiritOfZandalar(unit *Unit) {
aura := MakePermanent(unit.RegisterAura(Aura{
Label: "Spirit of Zandalar",
ActionID: ActionID{SpellID: 24425},
OnInit: func(aura *Aura, sim *Simulation) {
unit.AddMoveSpeedModifier(&aura.ActionID, 1.10)
},
}))

makeExclusiveBuff(aura, BuffConfig{
Expand Down
2 changes: 1 addition & 1 deletion sim/core/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
spell.Unit.SetGCDTimer(sim, sim.CurrentTime+effectiveTime)
}

if (spell.CurCast.CastTime > 0) && spell.Unit.Moving {
if (spell.CurCast.CastTime > 0) && spell.Unit.IsMoving() {
return spell.castFailureHelper(sim, "casting/channeling while moving not allowed!")
}

Expand Down
182 changes: 182 additions & 0 deletions sim/core/movement.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package core

import (
"container/heap"
"math"
"time"

"github.com/wowsims/sod/sim/core/proto"
)

type MoveModifier struct {
ActionId *ActionID
Modifier float64
}

type MoveHeap []MoveModifier

func (h MoveHeap) Len() int { return len(h) }
func (h MoveHeap) Less(i, j int) bool { return h[i].Modifier > h[j].Modifier }
func (h MoveHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

func (h *MoveHeap) Push(x any) {
*h = append(*h, x.(MoveModifier))
}

func (h *MoveHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}

func (h *MoveHeap) activeModifier() float64 {
heap := *h
if len(heap) < 1 {
panic("Movement Heaps should never be missing their base case!!!")
}
n := heap[0]
return n.Modifier
}

func (h *MoveHeap) Find(actionId *ActionID) int {
for i, mod := range *h {
if mod.ActionId == actionId {
return i
}
}
return -1
}

func (move *MovementHandler) addMoveSpeedModifier(moveHeap *MoveHeap, moveMod MoveModifier) {
heap.Push(moveHeap, moveMod)
move.updateMoveSpeed()
}

func (move *MovementHandler) removeMoveSpeedModifier(moveHeap *MoveHeap, actionID *ActionID) {
index := moveHeap.Find(actionID)
if index == -1 {
return
}
heap.Remove(moveHeap, index)
move.updateMoveSpeed()
}

func (move *MovementHandler) updateMoveSpeed() {
move.MoveSpeed = move.baseSpeed * move.getActveModifier(move.moveSpeedBonuses) * (1-move.getActveModifier(move.moveSpeedPenalties))
}

func (move *MovementHandler) getActveModifier(moveHeap *MoveHeap) float64 {
return moveHeap.activeModifier()
}

type MovementHandler struct {
Moving bool
MoveSpeed float64

baseSpeed float64
moveAura *Aura
moveSpell *Spell
moveSpeedBonuses *MoveHeap
moveSpeedPenalties *MoveHeap
}

func (unit *Unit) initMovement() {
unit.MovementHandler = &MovementHandler{
moveSpeedBonuses: &MoveHeap{
MoveModifier{
Modifier: 1,
},
},
moveSpeedPenalties: &MoveHeap{
MoveModifier{
Modifier: 0,
},
},
baseSpeed: 7.0,
}
unit.MovementHandler.updateMoveSpeed()

unit.MovementHandler.moveAura = unit.GetOrRegisterAura(Aura{
Label: "Movement",
ActionID: ActionID{OtherID: proto.OtherAction_OtherActionMove},
Duration: NeverExpires,
MaxStacks: 30,

OnGain: func(aura *Aura, sim *Simulation) {
if unit.IsChanneling(sim) {
unit.ChanneledDot.Cancel(sim)
}
unit.AutoAttacks.CancelAutoSwing(sim)
unit.MovementHandler.Moving = true
},
OnExpire: func(aura *Aura, sim *Simulation) {
unit.MovementHandler.Moving = false
unit.AutoAttacks.EnableAutoSwing(sim)

// Simulate the delay from starting attack
unit.AutoAttacks.DelayMeleeBy(sim, time.Millisecond*50)
},
})

unit.MovementHandler.moveSpell = unit.GetOrRegisterSpell(SpellConfig{
ActionID: ActionID{OtherID: proto.OtherAction_OtherActionMove},
Flags: SpellFlagMeleeMetrics,

ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) {
unit.MovementHandler.moveAura.Activate(sim)
unit.MovementHandler.moveAura.SetStacks(sim, int32(unit.DistanceFromTarget))
},
})
}

func (unit *Unit) IsMoving() bool {
return unit.MovementHandler.Moving
}

func (unit *Unit) MoveTo(moveRange float64, sim *Simulation) {
if moveRange == unit.DistanceFromTarget {
return
}

moveDistance := moveRange - unit.DistanceFromTarget
moveTicks := math.Abs(moveDistance)
moveInterval := moveDistance / float64(moveTicks)

unit.MovementHandler.moveSpell.Cast(sim, unit.CurrentTarget)

sim.AddPendingAction(NewPeriodicAction(sim, PeriodicActionOptions{
Period: time.Millisecond * time.Duration(1000/(unit.MovementHandler.MoveSpeed)),
NumTicks: int(moveTicks),
TickImmediately: false,

OnAction: func(sim *Simulation) {
unit.DistanceFromTarget += moveInterval
unit.MovementHandler.moveAura.SetStacks(sim, int32(unit.DistanceFromTarget))

if unit.DistanceFromTarget == moveRange {
unit.MovementHandler.moveAura.Deactivate(sim)
}
},
}))
}

// A move speed increase of 30% should be represented as 1.30 and a move speed slow of 70% should be respresented as 0.70
func (unit *Unit) AddMoveSpeedModifier(actionId *ActionID, modifier float64) {
moveSpeedMod := MoveModifier{
ActionId: actionId,
Modifier: modifier,
}
if(moveSpeedMod.Modifier < 1) {
unit.MovementHandler.addMoveSpeedModifier(unit.MovementHandler.moveSpeedPenalties, moveSpeedMod)
} else {
unit.MovementHandler.addMoveSpeedModifier(unit.MovementHandler.moveSpeedBonuses, moveSpeedMod)
}

}

func (unit *Unit) RemoveMoveSpeedModifier(actionID *ActionID) {
unit.MovementHandler.removeMoveSpeedModifier(unit.MovementHandler.moveSpeedPenalties, actionID)
unit.MovementHandler.removeMoveSpeedModifier(unit.MovementHandler.moveSpeedBonuses, actionID)
}
2 changes: 1 addition & 1 deletion sim/core/spell.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ func (spell *Spell) CanCast(sim *Simulation, target *Unit) bool {
}

// While moving only instant casts are possible
if spell.DefaultCast.CastTime > 0 && spell.Unit.Moving {
if spell.DefaultCast.CastTime > 0 && spell.Unit.IsMoving() {
//if sim.Log != nil {
// sim.Log("Cant cast because moving")
//}
Expand Down
70 changes: 3 additions & 67 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package core

import (
"math"
"time"

"github.com/wowsims/sod/sim/core/proto"
Expand All @@ -27,6 +26,7 @@ const (

type DynamicDamageTakenModifier func(sim *Simulation, spell *Spell, result *SpellResult)


// Unit is an abstraction of a Character/Boss/Pet/etc, containing functionality
// shared by all of them.
type Unit struct {
Expand Down Expand Up @@ -60,10 +60,8 @@ type Unit struct {
// for calculating spell travel time for certain spells.
StartDistanceFromTarget float64
DistanceFromTarget float64
Moving bool
moveAura *Aura
moveSpell *Spell
MoveSpeed float64

MovementHandler *MovementHandler

// Environment in which this Unit exists. This will be nil until after the
// construction phase.
Expand Down Expand Up @@ -412,68 +410,6 @@ func (unit *Unit) AddBonusRangedHitRating(amount float64) {
})
}

func (unit *Unit) initMovement() {
unit.MoveSpeed = 7.0
unit.moveAura = unit.GetOrRegisterAura(Aura{
Label: "Movement",
ActionID: ActionID{OtherID: proto.OtherAction_OtherActionMove},
Duration: NeverExpires,
MaxStacks: 30,

OnGain: func(aura *Aura, sim *Simulation) {
if unit.IsChanneling(sim) {
unit.ChanneledDot.Cancel(sim)
}
unit.AutoAttacks.CancelAutoSwing(sim)
unit.Moving = true
},
OnExpire: func(aura *Aura, sim *Simulation) {
unit.Moving = false
unit.AutoAttacks.EnableAutoSwing(sim)

// Simulate the delay from starting attack
unit.AutoAttacks.DelayMeleeBy(sim, time.Millisecond*50)
},
})

unit.moveSpell = unit.GetOrRegisterSpell(SpellConfig{
ActionID: ActionID{OtherID: proto.OtherAction_OtherActionMove},
Flags: SpellFlagMeleeMetrics,

ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) {
unit.moveAura.Activate(sim)
unit.moveAura.SetStacks(sim, int32(unit.DistanceFromTarget))
},
})
}

func (unit *Unit) MoveTo(moveRange float64, sim *Simulation) {
if moveRange == unit.DistanceFromTarget {
return
}

moveDistance := moveRange - unit.DistanceFromTarget
moveTicks := math.Abs(moveDistance)
moveInterval := moveDistance / float64(moveTicks)

unit.moveSpell.Cast(sim, unit.CurrentTarget)

sim.AddPendingAction(NewPeriodicAction(sim, PeriodicActionOptions{
Period: time.Millisecond * 1000 / time.Duration(unit.MoveSpeed),
NumTicks: int(moveTicks),
TickImmediately: false,

OnAction: func(sim *Simulation) {
unit.DistanceFromTarget += moveInterval
unit.moveAura.SetStacks(sim, int32(unit.DistanceFromTarget))

if unit.DistanceFromTarget == moveRange {
unit.moveAura.Deactivate(sim)
}
},
}))
}

func (unit *Unit) SetCurrentPowerBar(bar PowerBarType) {
unit.currentPowerBar = bar
}
Expand Down
Loading

0 comments on commit 9dcdd69

Please sign in to comment.