Index: binaries/data/mods/public/simulation/components/Promotion.js =================================================================== --- binaries/data/mods/public/simulation/components/Promotion.js +++ binaries/data/mods/public/simulation/components/Promotion.js @@ -40,12 +40,6 @@ // Save the entity id. this.promotedUnitEntity = ChangeEntityTemplate(this.entity, promotedTemplateName); - - let cmpPosition = Engine.QueryInterface(this.promotedUnitEntity, IID_Position); - let cmpUnitAI = Engine.QueryInterface(this.promotedUnitEntity, IID_UnitAI); - - if (cmpPosition && cmpPosition.IsInWorld() && cmpUnitAI) - cmpUnitAI.Cheer(); }; Promotion.prototype.IncreaseXp = function(amount) Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -1119,6 +1119,9 @@ }, "COMBAT": { + "Order.Cheering": function() { + return { "discardOrder": true }; + }, "APPROACHING": { "enter": function() { if (!this.MoveTo(this.order.data)) @@ -2020,6 +2023,9 @@ if (this.GetStance().respondHoldGround) this.WalkToHeldPosition(); + this.Cheer(); + this.TellFriendlyUnitsToCheer(); + return true; }, }, @@ -2989,20 +2995,18 @@ }, "CHEERING": { + "Order.Cheering": function () { + return { "discardOrder": true }; + }, "enter": function() { - // Unit is invulnerable while cheering - var cmpResistance = Engine.QueryInterface(this.entity, IID_Resistance); - cmpResistance.SetInvulnerability(true); this.SelectAnimation("promotion"); - this.StartTimer(2800, 2800); + this.StartTimer(2800); return false; }, "leave": function() { this.StopTimer(); this.ResetAnimation(); - var cmpResistance = Engine.QueryInterface(this.entity, IID_Resistance); - cmpResistance.SetInvulnerability(false); }, "Timer": function(msg) { @@ -3383,8 +3387,8 @@ if (msg.to != INVALID_PLAYER && msg.from != INVALID_PLAYER) { // Switch to a virgin state to let states execute their leave handlers. - // except if garrisoned or cheering or (un)packing, in which case we only clear the order queue - if (this.isGarrisoned || this.IsPacking() || this.orderQueue[0] && this.orderQueue[0].type == "Cheering") + // except if garrisoned or or (un)packing, in which case we only clear the order queue + if (this.isGarrisoned || this.IsPacking()) { this.orderQueue.length = Math.min(this.orderQueue.length, 1); Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); @@ -3652,14 +3656,8 @@ UnitAI.prototype.PushOrderFront = function(type, data) { var order = { "type": type, "data": data }; - // If current order is cheering then add new order after it - // same thing if current order if packing/unpacking - if (this.order && this.order.type == "Cheering") - { - var cheeringOrder = this.orderQueue.shift(); - this.orderQueue.unshift(cheeringOrder, order); - } - else if (this.order && this.IsPacking()) + // If current order is packing/unpacking then add new order after it + if (this.order && this.IsPacking()) { var packingOrder = this.orderQueue.shift(); this.orderQueue.unshift(packingOrder, order); @@ -3726,17 +3724,9 @@ let garrisonHolder = this.IsGarrisoned() && type != "Ungarrison" ? this.GetGarrisonHolder() : null; - // Special cases of orders that shouldn't be replaced: - // 1. Cheering - we're invulnerable, add order after we finish - // 2. Packing/unpacking - we're immobile, add order after we finish (unless it's cancel) + // Do not replace Packing/unpacking unless it is cancel order // TODO: maybe a better way of doing this would be to use priority levels - if (this.order && this.order.type == "Cheering") - { - var order = { "type": type, "data": data }; - var cheeringOrder = this.orderQueue.shift(); - this.orderQueue = [cheeringOrder, order]; - } - else if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") + if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") { var order = { "type": type, "data": data }; var packingOrder = this.orderQueue.shift(); @@ -3830,13 +3820,7 @@ } // Clear the order queue considering special orders not to avoid - if (this.order && this.order.type == "Cheering") - { - var cheeringOrder = this.orderQueue.shift(); - this.orderQueue = [cheeringOrder]; - } - else - this.orderQueue = []; + this.orderQueue = []; this.AddOrders(this.workOrders); Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); @@ -5405,12 +5389,28 @@ this.AddOrder("Flee", { "target": target, "force": false }, queued); }; +UnitAI.prototype.TellFriendlyUnitsToCheer = function() +{ + let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + if (!cmpOwnership) + return; + let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); + // Keep that range small so units cheer in reasonable distance + let nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, 10, [cmpOwnership.GetOwner()], IID_UnitAI); + let length = nearby.length; + for (let i = 0; i < length; ++i) + { + let cmpUnitAI = Engine.QueryInterface(nearby[i], IID_UnitAI); + cmpUnitAI.Cheer(); + } +} + /** - * Adds cheer order to the queue. Forced so it won't be interrupted by attacks. + * Adds cheer order to the queue. Do not force so it can be interrupted by attacks. */ UnitAI.prototype.Cheer = function() { - this.AddOrder("Cheering", { "force": true }, false); + this.AddOrder("Cheering", { "force": false }, false); }; UnitAI.prototype.Pack = function(queued)