Index: binaries/data/mods/public/simulation/components/Garrisonable.js =================================================================== --- binaries/data/mods/public/simulation/components/Garrisonable.js +++ binaries/data/mods/public/simulation/components/Garrisonable.js @@ -15,6 +15,14 @@ }; /** + * @return {boolean} - Whether this entity is garrisoned. + */ +Garrisonable.prototype.IsGarrisoned = function() +{ + return !!this.holder; +}; + +/** * @param {number} entity - The entity ID of the entity this entity is being garrisoned in. * @return {boolean} - Whether garrisoning succeeded. */ @@ -23,6 +31,10 @@ if (this.holder) return false; + let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); + if (cmpUnitAI) + cmpUnitAI.SetGarrisoned(); + this.holder = entity; return true; }; @@ -32,6 +44,10 @@ */ Garrisonable.prototype.UnGarrison = function() { + let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); + if (cmpUnitAI) + cmpUnitAI.SetUngarrisoned(); + delete this.holder; }; Index: binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- binaries/data/mods/public/simulation/components/GuiInterface.js +++ binaries/data/mods/public/simulation/components/GuiInterface.js @@ -1828,7 +1828,7 @@ GuiInterface.prototype.IdleUnitFilter = function(unit, idleClasses, excludeUnits) { let cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI); - if (!cmpUnitAI || !cmpUnitAI.IsIdle() || cmpUnitAI.IsGarrisoned()) + if (!cmpUnitAI || !cmpUnitAI.IsIdle() || cmpUnitAI.IsTurret()) return { "idle": false }; let cmpIdentity = Engine.QueryInterface(unit, IID_Identity); Index: binaries/data/mods/public/simulation/components/Health.js =================================================================== --- binaries/data/mods/public/simulation/components/Health.js +++ binaries/data/mods/public/simulation/components/Health.js @@ -131,11 +131,13 @@ Health.prototype.ExecuteRegeneration = function() { let regen = this.GetRegenRate(); - if (this.GetIdleRegenRate() != 0) + if (this.idleRegenRate != 0) { let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); - if (cmpUnitAI && (cmpUnitAI.IsIdle() || cmpUnitAI.IsGarrisoned() && !cmpUnitAI.IsTurret())) - regen += this.GetIdleRegenRate(); + let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); + if (cmpUnitAI && (cmpUnitAI.IsIdle() || + cmpGarrisonable && cmpGarrisonable.IsGarrisoned() && !cmpUnitAI.IsTurret())) + regen += this.idleRegenRate; } if (regen > 0) 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 @@ -626,7 +626,7 @@ this.SetNextState("IDLE"); return; } - else if (this.IsGarrisoned()) + else if (this.isGarrisoned) { if (this.IsAnimal()) this.SetNextState("ANIMAL.GARRISON.GARRISONED"); @@ -649,7 +649,6 @@ "Order.Ungarrison": function() { this.FinishOrder(); - this.isGarrisoned = false; }, "Order.Cheer": function(msg) { @@ -3102,8 +3101,16 @@ return true; } - if (this.IsGarrisoned()) + // Called when autogarrisoning. + if (this.isGarrisoned) + { + if (this.IsTurret()) + { + this.SetNextState("IDLE"); + return true; + } return false; + } if (this.CanGarrison(target)) if (this.CheckGarrisonRange(target)) @@ -3111,9 +3118,6 @@ var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); if (cmpGarrisonHolder.Garrison(this.entity)) { - this.isGarrisoned = true; - this.SetImmobile(true); - if (this.formationController) { var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation); @@ -3448,9 +3452,7 @@ this.orderQueue = []; // current order is at the front of the list this.order = undefined; // always == this.orderQueue[0] this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to - this.isGarrisoned = false; this.isIdle = false; - this.isImmobile = false; // True if the unit is currently unable to move (garrisoned,...) this.heldPosition = undefined; @@ -3505,14 +3507,17 @@ return this.isIdle; }; -UnitAI.prototype.IsGarrisoned = function() +UnitAI.prototype.SetGarrisoned = function() { - return this.isGarrisoned; + // UnitAI caches its own garrisoned state for performance. + this.isGarrisoned = true; + this.SetImmobile(); }; -UnitAI.prototype.SetGarrisoned = function() +UnitAI.prototype.SetUngarrisoned = function() { - this.isGarrisoned = true; + delete this.isGarrisoned; + this.SetMobile(); }; UnitAI.prototype.GetGarrisonHolder = function() @@ -3529,9 +3534,24 @@ return !this.orderQueue.length || this.orderQueue[0].type == "Garrison"; }; -UnitAI.prototype.SetImmobile = function(immobile) +UnitAI.prototype.SetImmobile = function() +{ + if (this.isImmobile) + return; + + this.isImmobile = true; + Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, { + "entity": this.entity, + "ableToMove": this.AbleToMove() + }); +}; + +UnitAI.prototype.SetMobile = function() { - this.isImmobile = immobile; + if (!this.isImmobile) + return; + + delete this.isImmobile; Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, { "entity": this.entity, "ableToMove": this.AbleToMove() @@ -3845,7 +3865,7 @@ this.order = this.orderQueue[0]; let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); - if (this.orderQueue.length && (this.IsGarrisoned() || this.IsFormationController() || + if (this.orderQueue.length && (this.isGarrisoned || this.IsFormationController() || cmpPosition && cmpPosition.IsInWorld())) { let ret = this.UnitFsm.ProcessMessage(this, @@ -4040,7 +4060,7 @@ this.UpdateWorkOrders(type); } - let garrisonHolder = this.IsGarrisoned() && type != "Ungarrison" ? this.GetGarrisonHolder() : null; + let garrisonHolder = this.isGarrisoned && type != "Ungarrison" ? this.GetGarrisonHolder() : null; // Do not replace packing/unpacking unless it is cancel order. // TODO: maybe a better way of doing this would be to use priority levels @@ -4141,7 +4161,7 @@ if (this.workOrders.length == 0) return false; - if (this.IsGarrisoned()) + if (this.isGarrisoned) { let cmpGarrisonHolder = Engine.QueryInterface(this.GetGarrisonHolder(), IID_GarrisonHolder); if (!cmpGarrisonHolder || !cmpGarrisonHolder.PerformEject([this.entity], false)) @@ -5287,7 +5307,7 @@ { // May happen if an order arrives on the same turn the unit is garrisoned // in that case, just forget the order as this will lead to an infinite loop - if (this.IsGarrisoned() && !this.IsTurret() && type != "Ungarrison") + if (this.isGarrisoned && !this.IsTurret() && type != "Ungarrison") return; this.ReplaceOrder(type, data); } @@ -5522,11 +5542,8 @@ */ UnitAI.prototype.Ungarrison = function() { - if (this.IsGarrisoned()) - { - this.SetImmobile(false); + if (this.isGarrisoned) this.AddOrder("Ungarrison", null, false); - } }; /** @@ -5534,7 +5551,6 @@ */ UnitAI.prototype.Autogarrison = function(target) { - this.isGarrisoned = true; this.PushOrderFront("Garrison", { "target": target }); }; Index: binaries/data/mods/public/simulation/components/tests/test_Garrisonable.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Garrisonable.js +++ binaries/data/mods/public/simulation/components/tests/test_Garrisonable.js @@ -1,4 +1,5 @@ Engine.LoadComponentScript("interfaces/Garrisonable.js"); +Engine.LoadComponentScript("interfaces/UnitAI.js"); Engine.LoadComponentScript("Garrisonable.js"); const garrisonHolderID = 1; Index: binaries/data/mods/public/simulation/helpers/Transform.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Transform.js +++ binaries/data/mods/public/simulation/helpers/Transform.js @@ -78,8 +78,6 @@ cmpNewUnitAI.SetGuardOf(guarded); } } - if (cmpUnitAI.IsGarrisoned()) - cmpNewUnitAI.SetGarrisoned(); } let cmpPromotion = Engine.QueryInterface(oldEnt, IID_Promotion);