Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/GarrisonHolder.js +++ binaries/data/mods/public/simulation/components/GarrisonHolder.js @@ -186,10 +186,6 @@ */ GarrisonHolder.prototype.Garrison = function(entity, vgpEntity) { - let cmpPosition = Engine.QueryInterface(entity, IID_Position); - if (!cmpPosition) - return false; - if (!this.PerformGarrison(entity)) return false; @@ -204,29 +200,7 @@ } if (visibleGarrisonPoint) - { - visibleGarrisonPoint.entity = entity; - // Angle of turrets: - // Renamed entities (vgpEntity != undefined) should keep their angle. - // Otherwise if an angle is given in the visibleGarrisonPoint, use it. - // If no such angle given (usually walls for which outside/inside not well defined), we keep - // the current angle as it was used for garrisoning and thus quite often was from inside to - // outside, except when garrisoning from outWorld where we take as default PI. - let cmpTurretPosition = Engine.QueryInterface(this.entity, IID_Position); - if (!vgpEntity && visibleGarrisonPoint.angle != null) - cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + visibleGarrisonPoint.angle); - else if (!vgpEntity && !cmpPosition.IsInWorld()) - cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + Math.PI); - let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); - if (cmpUnitMotion) - cmpUnitMotion.SetFacePointAfterMove(false); - cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset); - let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI); - if (cmpUnitAI) - cmpUnitAI.SetTurretStance(); - } - else - cmpPosition.MoveOutOfWorld(); + this.GarrisonVisibly(entity, visibleGarrisonPoint, !!vgpEntity); return true; }; @@ -236,6 +210,10 @@ */ GarrisonHolder.prototype.PerformGarrison = function(entity) { + let cmpPosition = Engine.QueryInterface(entity, IID_Position); + if (!cmpPosition) + return false; + if (!this.HasEnoughHealth()) return false; @@ -268,11 +246,84 @@ if (cmpAura && cmpAura.HasGarrisonAura()) cmpAura.ApplyGarrisonAura(this.entity); + cmpPosition.MoveOutOfWorld(); + Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added": [entity], "removed": [] }); return true; }; /** + * Switch the entity from the inside of a garrison holder to the outside (visibly garrisoned). + * + * @param {number} entity - The entity ID of the entity to garrison visibly. + * @param {object} visibleGarrisonPoint - The visible garrison point to use. + * @param {boolean} renamed - Whether this function was called by a renaming entity (we need to preserve the angle then). + */ +GarrisonHolder.prototype.GarrisonVisibly = function(entity, visibleGarrisonPoint, renamed) +{ + if (!visibleGarrisonPoint || this.entities.indexOf(entity) == -1) + return; + + let cmpPosition = Engine.QueryInterface(entity, IID_Position); + if (!cmpPosition) + return; + + visibleGarrisonPoint.entity = entity; + // Angle of turrets: + // Renamed entities (vgpEntity != undefined) should keep their angle. + // Otherwise if an angle is given in the visibleGarrisonPoint, use it. + // If no such angle given (usually walls for which outside/inside not well defined), we keep + // the current angle as it was used for garrisoning and thus quite often was from inside to + // outside. + if (!renamed && visibleGarrisonPoint.angle != null) + { + let cmpTurretPosition = Engine.QueryInterface(this.entity, IID_Position); + if (cmpTurretPosition) + cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + visibleGarrisonPoint.angle); + } + + let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); + if (cmpUnitMotion) + cmpUnitMotion.SetFacePointAfterMove(false); + + cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset); + let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI); + if (cmpUnitAI) + cmpUnitAI.SetTurretStance(); +}; + +/** + * Switch the entity from the outside of a garrison holder (visibly garrisoned) to the inside. + * + * @param {number} entity - The entity ID of the entity to turn in. + */ +GarrisonHolder.prototype.TurnIn = function(entity) +{ + let cmpPosition = Engine.QueryInterface(entity, IID_Position); + if (!cmpPosition) + return; + + for (let vgp of this.visibleGarrisonPoints) + { + if (vgp.entity != entity) + continue; + cmpPosition.SetTurretParent(INVALID_ENTITY, new Vector3D()); + + let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); + if (cmpUnitMotion) + cmpUnitMotion.SetFacePointAfterMove(true); + + let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI); + if (cmpUnitAI) + cmpUnitAI.ResetTurretStance(); + + vgp.entity = null; + cmpPosition.MoveOutOfWorld(); + break; + } +}; + +/** * Simply eject the unit from the garrisoning entity without moving it * @param {number} entity - Id of the entity to be ejected. * @param {boolean} forced - Whether eject is forced (i.e. if building is destroyed). @@ -313,19 +364,7 @@ let cmpEntPosition = Engine.QueryInterface(entity, IID_Position); let cmpEntUnitAI = Engine.QueryInterface(entity, IID_UnitAI); - for (let vgp of this.visibleGarrisonPoints) - { - if (vgp.entity != entity) - continue; - cmpEntPosition.SetTurretParent(INVALID_ENTITY, new Vector3D()); - let cmpEntUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); - if (cmpEntUnitMotion) - cmpEntUnitMotion.SetFacePointAfterMove(true); - if (cmpEntUnitAI) - cmpEntUnitAI.ResetTurretStance(); - vgp.entity = null; - break; - } + this.TurnIn(entity); if (cmpEntUnitAI) cmpEntUnitAI.Ungarrison();