diff --git a/sim/core/apl.go b/sim/core/apl.go index 88741763e5..fe2dd4a6ac 100644 --- a/sim/core/apl.go +++ b/sim/core/apl.go @@ -14,7 +14,7 @@ type APLRotation struct { priorityList []*APLAction // Action currently controlling this rotation (only used for certain actions, such as StrictSequence). - controllingAction APLActionImpl + controllingActions []APLActionImpl // Value that should evaluate to 'true' if the current channel is to be interrupted. // Will be nil when there is no active channel. @@ -166,7 +166,7 @@ func (rot *APLRotation) allPrepullActions() []*APLAction { } func (rot *APLRotation) reset(sim *Simulation) { - rot.controllingAction = nil + rot.controllingActions = nil rot.inLoop = false rot.interruptChannelIf = nil rot.allowChannelRecastOnInterrupt = false @@ -219,8 +219,8 @@ func (apl *APLRotation) DoNextAction(sim *Simulation) { } func (apl *APLRotation) getNextAction(sim *Simulation) *APLAction { - if apl.controllingAction != nil { - return apl.controllingAction.GetNextAction(sim) + if len(apl.controllingActions) != 0 { + return apl.controllingActions[len(apl.controllingActions)-1].GetNextAction(sim) } for _, action := range apl.priorityList { @@ -232,6 +232,17 @@ func (apl *APLRotation) getNextAction(sim *Simulation) *APLAction { return nil } +func (apl *APLRotation) pushControllingAction(ca APLActionImpl) { + apl.controllingActions = append(apl.controllingActions, ca) +} + +func (apl *APLRotation) popControllingAction(ca APLActionImpl) { + if len(apl.controllingActions) == 0 || apl.controllingActions[len(apl.controllingActions)-1] != ca { + panic("Wrong APL controllingAction in pop()") + } + apl.controllingActions = apl.controllingActions[:len(apl.controllingActions)-1] +} + func (apl *APLRotation) shouldInterruptChannel(sim *Simulation) bool { channeledDot := apl.unit.ChanneledDot diff --git a/sim/core/apl_actions_sequences.go b/sim/core/apl_actions_sequences.go index a754413078..a2cfb4d27f 100644 --- a/sim/core/apl_actions_sequences.go +++ b/sim/core/apl_actions_sequences.go @@ -136,7 +136,7 @@ func (action *APLActionStrictSequence) IsReady(sim *Simulation) bool { return true } func (action *APLActionStrictSequence) Execute(sim *Simulation) { - action.unit.Rotation.controllingAction = action + action.unit.Rotation.pushControllingAction(action) } func (action *APLActionStrictSequence) GetNextAction(sim *Simulation) *APLAction { if action.subactions[action.curIdx].IsReady(sim) { @@ -145,7 +145,7 @@ func (action *APLActionStrictSequence) GetNextAction(sim *Simulation) *APLAction action.curIdx++ if action.curIdx == len(action.subactions) { action.curIdx = 0 - action.unit.Rotation.controllingAction = nil + action.unit.Rotation.popControllingAction(action) } return nextAction @@ -153,7 +153,7 @@ func (action *APLActionStrictSequence) GetNextAction(sim *Simulation) *APLAction // If the GCD is ready when the next subaction isn't, it means the sequence is bad // so reset and exit the sequence. action.curIdx = 0 - action.unit.Rotation.controllingAction = nil + action.unit.Rotation.popControllingAction(action) return action.unit.Rotation.getNextAction(sim) } else { // Return nil to wait for the GCD to become ready. diff --git a/sim/core/apl_actions_timing.go b/sim/core/apl_actions_timing.go index 77e520c2a3..3552133d52 100644 --- a/sim/core/apl_actions_timing.go +++ b/sim/core/apl_actions_timing.go @@ -36,7 +36,7 @@ func (action *APLActionWait) IsReady(sim *Simulation) bool { } func (action *APLActionWait) Execute(sim *Simulation) { - action.unit.Rotation.controllingAction = action + action.unit.Rotation.pushControllingAction(action) action.curWaitTime = sim.CurrentTime + action.duration.GetDuration(sim) pa := &PendingAction{ @@ -49,7 +49,7 @@ func (action *APLActionWait) Execute(sim *Simulation) { func (action *APLActionWait) GetNextAction(sim *Simulation) *APLAction { if sim.CurrentTime >= action.curWaitTime { - action.unit.Rotation.controllingAction = nil + action.unit.Rotation.popControllingAction(action) return action.unit.Rotation.getNextAction(sim) } else { return nil @@ -86,12 +86,12 @@ func (action *APLActionWaitUntil) IsReady(sim *Simulation) bool { } func (action *APLActionWaitUntil) Execute(sim *Simulation) { - action.unit.Rotation.controllingAction = action + action.unit.Rotation.pushControllingAction(action) } func (action *APLActionWaitUntil) GetNextAction(sim *Simulation) *APLAction { if action.condition.GetBool(sim) { - action.unit.Rotation.controllingAction = nil + action.unit.Rotation.popControllingAction(action) return action.unit.Rotation.getNextAction(sim) } else { return nil