diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js index a8466361d9..a325f6d1b8 100644 --- a/binaries/data/mods/public/simulation/components/UnitAI.js +++ b/binaries/data/mods/public/simulation/components/UnitAI.js @@ -140,7 +140,7 @@ var UnitFsmSpec = { "Order.LeaveFoundation": function(msg) { // Default behaviour is to ignore the order since we're busy - this.DiscardOrder(); + return { "discardOrder": true }; }, // Individual orders: @@ -1368,7 +1368,18 @@ UnitAI.prototype.FinishOrder = function() if (this.orderQueue.length) { - UnitFsm.ProcessMessage(this, {"type": "Order."+this.order.type, "data": this.order.data}); + var ret = UnitFsm.ProcessMessage(this, + {"type": "Order."+this.order.type, "data": this.order.data} + ); + + // If the order was rejected then immediately take it off + // and process the remaining queue + if (ret && ret.discardOrder) + { + return this.FinishOrder(); + } + + // Otherwise we've successfully processed a new order return true; } else @@ -1378,23 +1389,6 @@ UnitAI.prototype.FinishOrder = function() } }; -/** - * Call when you want to drop an order inside a FSM order handler. - * Don't change the FSM state. - */ -UnitAI.prototype.DiscardOrder = function() -{ - if (!this.orderQueue.length) - error("DiscardOrder called when order queue is empty"); - - this.orderQueue.shift(); - this.order = this.orderQueue[0]; - if (!this.orderQueue.length) - { - this.SetNextState("IDLE"); - } -}; - /** * Add an order onto the back of the queue, * and execute it if we didn't already have an order. @@ -1408,7 +1402,16 @@ UnitAI.prototype.PushOrder = function(type, data) if (this.orderQueue.length == 1) { this.order = order; - UnitFsm.ProcessMessage(this, {"type": "Order."+this.order.type, "data": this.order.data}); + var ret = UnitFsm.ProcessMessage(this, + {"type": "Order."+this.order.type, "data": this.order.data} + ); + + // If the order was rejected then immediately take it off + // and process the remaining queue + if (ret && ret.discardOrder) + { + this.FinishOrder(); + } } }; @@ -1429,7 +1432,19 @@ UnitAI.prototype.PushOrderFront = function(type, data) { this.orderQueue.unshift(order); this.order = order; - UnitFsm.ProcessMessage(this, {"type": "Order."+this.order.type, "data": this.order.data}); + var ret = UnitFsm.ProcessMessage(this, + {"type": "Order."+this.order.type, "data": this.order.data} + ); + + // If the order was rejected then immediately take it off again; + // assume the previous active order is still valid (the short-lived + // new order hasn't changed state or anything) so we can carry on + // as if nothing had happened + if (ret && ret.discardOrder) + { + this.orderQueue.shift(); + this.order = this.orderQueue[0]; + } } }; diff --git a/binaries/data/mods/public/simulation/helpers/FSM.js b/binaries/data/mods/public/simulation/helpers/FSM.js index 8b0d60cb30..2b1c795dd5 100644 --- a/binaries/data/mods/public/simulation/helpers/FSM.js +++ b/binaries/data/mods/public/simulation/helpers/FSM.js @@ -245,10 +245,13 @@ FSM.prototype.ProcessMessage = function(obj, msg) if (!func) { error("Tried to process unhandled event '" + msg.type + "' in state '" + obj.fsmStateName + "'"); - return; + return undefined; } - func.apply(obj, [msg]); + var ret = func.apply(obj, [msg]); + + // If func called SetNextState then switch into the new state, + // and continue switching if the new state's 'enter' called SetNextState again while (obj.fsmNextState) { var nextStateName = this.LookupState(obj.fsmStateName, obj.fsmNextState); @@ -257,6 +260,8 @@ FSM.prototype.ProcessMessage = function(obj, msg) if (nextStateName != obj.fsmStateName) this.SwitchToNextState(obj, nextStateName); } + + return ret; }; FSM.prototype.DeferMessage = function(obj, msg) @@ -339,6 +344,6 @@ FSM.prototype.SwitchToNextState = function(obj, nextStateName) } obj.fsmStateName = nextStateName; -} +}; Engine.RegisterGlobal("FSM", FSM);