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 @@ -429,39 +429,11 @@ */ GarrisonHolder.prototype.EjectOrKill = function(entities) { - let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); - // Eject the units which can be ejected (if not in world, it generally means this holder - // is inside a holder which kills its entities, so do not eject) - if (cmpPosition && cmpPosition.IsInWorld()) - { - let ejectables = entities.filter(ent => this.IsEjectable(ent)); - if (ejectables.length) - this.UnloadEntities(ejectables); - } - - // And destroy all remaining entities - let killedEntities = []; for (let entity of entities) { - let entityIndex = this.entities.indexOf(entity); - if (entityIndex == -1) - continue; - let cmpHealth = Engine.QueryInterface(entity, IID_Health); - if (cmpHealth) - cmpHealth.Kill(); - else - Engine.DestroyEntity(entity); - this.entities.splice(entityIndex, 1); - killedEntities.push(entity); - } - - if (killedEntities.length) - { - Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { - "added": [], - "removed": killedEntities - }); - this.UpdateGarrisonFlag(); + let cmpGarrisonable = Engine.QueryInterface(entity, IID_Garrisonable); + if (cmpGarrisonable) + cmpGarrisonable.UnGarrisonOrDie(); } }; 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 @@ -144,16 +144,49 @@ return true; }; +/** + * @param {boolean} forced + */ +Garrisonable.prototype.UnGarrisonOrDie = function(forced = false) +{ + if (this.UnGarrison(forced)) + return; + + let cmpGarrisonHolder = Engine.QueryInterface(this.holder, IID_GarrisonHolder); + if (cmpGarrisonHolder) + cmpGarrisonHolder.Eject(this.entity, true); + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + if (cmpHealth) + cmpHealth.Kill(); + else + Engine.DestroyEntity(this.entity); +}; + Garrisonable.prototype.OnEntityRenamed = function(msg) { if (!this.holder) return; let holder = this.holder; - this.UnGarrison(true, true); + this.UnGarrisonOrDie(true); let cmpGarrisonable = Engine.QueryInterface(msg.newentity, IID_Garrisonable); - if (cmpGarrisonable) - cmpGarrisonable.Garrison(holder, true); + if (!cmpGarrisonable || !cmpGarrisonable.Garrison(holder, true)) + { + let cmpPositionSelf = Engine.QueryInterface(this.entity, IID_Position); + let cmpPositionNew = Engine.QueryInterface(msg.newentity, IID_Position); + if (cmpPositionSelf && cmpPositionNew) + { + if (cmpPositionSelf.IsInWorld()) + { + let pos = cmpPositionSelf.GetPosition2D(); + cmpPositionNew.JumpTo(pos.x, pos.y); + } + let rot = cmpPositionSelf.GetRotation(); + cmpPositionNew.SetYRotation(rot.y); + cmpPositionNew.SetXZRotation(rot.x, rot.z); + cmpPositionNew.SetHeightOffset(cmpPositionSelf.GetHeightOffset()); + } + } }; Engine.RegisterComponentType(IID_Garrisonable, "Garrisonable", Garrisonable); Index: binaries/data/mods/public/simulation/components/TurretHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/TurretHolder.js +++ binaries/data/mods/public/simulation/components/TurretHolder.js @@ -237,25 +237,12 @@ */ EjectOrKill(entities) { - let removedEntities = []; for (let entity of entities) { let cmpTurretable = Engine.QueryInterface(entity, IID_Turretable); - if (!cmpTurretable || !cmpTurretable.LeaveTurret(true)) - { - let cmpHealth = Engine.QueryInterface(entity, IID_Health); - if (cmpHealth) - cmpHealth.Kill(); - else - Engine.DestroyEntity(entity); - removedEntities.push(entity); - } + if (cmpTurretable) + cmpTurretable.LeaveTurretOrDie(); } - if (removedEntities.length) - Engine.PostMessage(this.entity, MT_TurretsChanged, { - "added": [], - "removed": removedEntities - }); } /** Index: binaries/data/mods/public/simulation/components/Turretable.js =================================================================== --- binaries/data/mods/public/simulation/components/Turretable.js +++ binaries/data/mods/public/simulation/components/Turretable.js @@ -134,6 +134,24 @@ return true; }; +/** + * @param {boolean} forced + */ +Turretable.prototype.LeaveTurretOrDie = function(forced = false) +{ + if (this.LeaveTurret(forced)) + return; + + let cmpTurretHolder = Engine.QueryInterface(this.holder, IID_TurretHolder); + if (cmpTurretHolder) + cmpTurretHolder.LeaveTurret(this.entity); + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + if (cmpHealth) + cmpHealth.Kill(); + else + Engine.DestroyEntity(this.entity); +}; + Turretable.prototype.OnEntityRenamed = function(msg) { if (!this.holder) @@ -145,10 +163,25 @@ let holder = this.holder; let currentPoint = cmpTurretHolder.GetOccupiedTurretName(this.entity); - this.LeaveTurret(true); + this.LeaveTurretOrDie(true); let cmpTurretableNew = Engine.QueryInterface(msg.newentity, IID_Turretable); - if (cmpTurretableNew) - cmpTurretableNew.OccupyTurret(holder, currentPoint); + if (!cmpTurretableNew || !cmpTurretableNew.OccupyTurret(holder, currentPoint)) + { + let cmpPositionSelf = Engine.QueryInterface(this.entity, IID_Position); + let cmpPositionNew = Engine.QueryInterface(msg.newentity, IID_Position); + if (cmpPositionSelf && cmpPositionNew) + { + if (cmpPositionSelf.IsInWorld()) + { + let pos = cmpPositionSelf.GetPosition2D(); + cmpPositionNew.JumpTo(pos.x, pos.y); + } + let rot = cmpPositionSelf.GetRotation(); + cmpPositionNew.SetYRotation(rot.y); + cmpPositionNew.SetXZRotation(rot.x, rot.z); + cmpPositionNew.SetHeightOffset(cmpPositionSelf.GetHeightOffset()); + } + } }; Turretable.prototype.OnOwnershipChanged = function(msg) @@ -157,7 +190,7 @@ return; if (msg.to == INVALID_PLAYER) - this.LeaveTurret(true); + this.LeaveTurretOrDie(true); else if (!IsOwnedByMutualAllyOfEntity(this.entity, this.holder)) this.LeaveTurret(); }; 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 @@ -58,30 +58,6 @@ if (cmpBuilderList && cmpNewBuilderList) cmpNewBuilderList.AddBuilders(cmpBuilderList.GetBuilders()); - var cmpUnitAI = Engine.QueryInterface(oldEnt, IID_UnitAI); - var cmpNewUnitAI = Engine.QueryInterface(newEnt, IID_UnitAI); - if (cmpUnitAI && cmpNewUnitAI) - { - let pos = cmpUnitAI.GetHeldPosition(); - if (pos) - cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); - if (cmpUnitAI.GetStanceName()) - cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName()); - if (cmpUnitAI.GetGarrisonHolder() != INVALID_ENTITY) - cmpNewUnitAI.SetGarrisoned(); - cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); - if (cmpUnitAI.IsGuardOf()) - { - let guarded = cmpUnitAI.IsGuardOf(); - let cmpGuard = Engine.QueryInterface(guarded, IID_Guard); - if (cmpGuard) - { - cmpGuard.RenameGuard(oldEnt, newEnt); - cmpNewUnitAI.SetGuardOf(guarded); - } - } - } - let cmpPromotion = Engine.QueryInterface(oldEnt, IID_Promotion); let cmpNewPromotion = Engine.QueryInterface(newEnt, IID_Promotion); if (cmpPromotion && cmpNewPromotion) @@ -133,6 +109,27 @@ Engine.PostMessage(oldEnt, MT_EntityRenamed, { "entity": oldEnt, "newentity": newEnt }); + // UnitAI generally needs other components to be properly initialised. + let cmpUnitAI = Engine.QueryInterface(oldEnt, IID_UnitAI); + let cmpNewUnitAI = Engine.QueryInterface(newEnt, IID_UnitAI); + if (cmpUnitAI && cmpNewUnitAI) + { + let pos = cmpUnitAI.GetHeldPosition(); + if (pos) + cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); + cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); + let guarded = cmpUnitAI.IsGuardOf(); + if (guarded) + { + let cmpGuarded = Engine.QueryInterface(guarded, IID_Guard); + if (cmpGuarded) + { + cmpGuarded.RenameGuard(oldEnt, newEnt); + cmpNewUnitAI.SetGuardOf(guarded); + } + } + } + if (cmpPosition && cmpPosition.IsInWorld()) cmpPosition.MoveOutOfWorld(); Engine.DestroyEntity(oldEnt); Index: binaries/data/mods/public/simulation/templates/units/athen/infantry_slinger_a.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/athen/infantry_slinger_a.xml +++ binaries/data/mods/public/simulation/templates/units/athen/infantry_slinger_a.xml @@ -3,9 +3,11 @@ Advanced + units/athen/infantry_slinger_e + units/athenians/infantry_slinger_a.xml