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 @@ -529,17 +529,6 @@ { this.Eject(msg.entity, true, true); this.Garrison(msg.newentity, true); - - // TurretHolder is not subscribed to GarrisonChanged, so we must inform it explicitly. - // Otherwise a renaming entity may re-occupy another turret instead of its previous one, - // since the message does not know what turret point whas used, which is not wanted. - // Also ensure the TurretHolder receives the message after we process it. - // If it processes it before us we garrison a turret and subsequently - // are hidden by GarrisonHolder again. - // This could be fixed by not requiring a turret to be 'garrisoned'. - let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder); - if (cmpTurretHolder) - cmpTurretHolder.SwapEntities(msg.entity, msg.newentity); } if (!this.initGarrison) 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 @@ -1,8 +1,6 @@ /** * This class holds the functions regarding entities being visible on * another entity, but tied to their parents location. - * Currently renaming and changing ownership are still managed by GarrisonHolder.js, - * but in the future these components should be independent. */ class TurretHolder { @@ -138,7 +136,7 @@ * * @return {boolean} - Whether the entity was occupying a/the turret before. */ - LeaveTurret(entity, requestedTurretPoint) + LeaveTurret(entity, forced, requestedTurretPoint) { let turretPoint; if (requestedTurretPoint) @@ -152,6 +150,31 @@ if (!turretPoint) return false; + // Find spawning location (copied from GarrisonHolder). + let cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint); + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); + + // If the TurretHolder is a sinking ship, restrict the location to the intersection of both passabilities + // TODO: should use passability classes to be more generic. + let pos; + if ((!cmpHealth || cmpHealth.GetHitpoints() == 0) && cmpIdentity && cmpIdentity.HasClass("Ship")) + pos = cmpFootprint.PickSpawnPointBothPass(entity); + else + pos = cmpFootprint.PickSpawnPoint(entity); + + if (pos.y < 0) + { + if (!forced) + return false; + + // If ejection is forced, we need to continue, so use center of the TurretHolder. + let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); + pos = cmpPosition.GetPosition(); + } + + turretPoint.entity = null; + let cmpPositionEntity = Engine.QueryInterface(entity, IID_Position); cmpPositionEntity.SetTurretParent(INVALID_ENTITY, new Vector3D()); @@ -163,7 +186,16 @@ if (cmpUnitAIEntity) cmpUnitAIEntity.ResetTurretStance(); - turretPoint.entity = null; + let cmpEntPosition = Engine.QueryInterface(entity, IID_Position); + if (cmpEntPosition) + { + cmpEntPosition.JumpTo(pos.x, pos.z); + cmpEntPosition.SetHeightOffset(0); + + let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); + if (cmpPosition) + cmpEntPosition.SetYRotation(cmpPosition.GetPosition().horizAngleTo(pos)); + } // Reset the obstruction flags to template defaults. let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction); @@ -238,12 +270,6 @@ } /** - * We process EntityRenamed here because we need to be sure that we receive - * it after it is processed by GarrisonHolder.js. - * ToDo: Make this not needed by fully separating TurretHolder from GarrisonHolder. - * That means an entity with TurretHolder should not need a GarrisonHolder - * for e.g. the garrisoning logic. - * * @param {number} from - The entity to substitute. * @param {number} to - The entity to subtitute with. */ @@ -251,31 +277,41 @@ { let turretPoint = this.GetOccupiedTurret(from); if (turretPoint) - this.LeaveTurret(from, turretPoint); + this.LeaveTurret(from, true, turretPoint); - let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); - if (cmpGarrisonHolder && cmpGarrisonHolder.IsGarrisoned(to)) - this.OccupyTurret(to, turretPoint); + this.OccupyTurret(to, turretPoint); } - OnGarrisonedUnitsChanged(msg) + /** + * Update list of turreted entities if one gets renamed (e.g. by promotion). + */ + OnGlobalEntityRenamed(msg) { - // Ignore renaming for that is handled seperately - // (i.e. called directly from GarrisonHolder.js). - if (msg.renamed) + let turretPoint = this.OccupiesTurret(msg.entity); + if (turretPoint) + this.SwapEntities(msg.entity, msg.newentity); + + if (!this.initTurrets) return; - for (let entity of msg.removed) - this.LeaveTurret(entity); - for (let entity of msg.added) - this.OccupyTurret(entity); + // Update the pre-game turrets because of SkirmishReplacement. + if (msg.entity == this.entity) + { + let cmpTurretHolder = Engine.QueryInterface(msg.newentity, IID_TurretHolder); + if (cmpTurretHolder) + cmpTurretHolder.initTurrets = this.initTurrets; + } + else + { +return;//ToDo + entityIndex = this.initTurrets.indexOf(msg.entity); + if (entityIndex != -1) + this.initTurrets[entityIndex] = msg.newentity; + } } /** * Initialise the turreted units. - * Really ugly, but because GarrisonHolder is processed earlier, and also turrets - * entities on init, we can find an entity that already is present. - * In that case we reject and occupy. */ OnGlobalInitGame(msg) { @@ -283,13 +319,9 @@ return; for (let [turretPointName, entity] of this.initTurrets) - { - if (this.OccupiesTurret(entity)) - this.LeaveTurret(entity); if (!this.OccupyNamedTurret(entity, turretPointName)) warn("Entity " + entity + " could not occupy the turret point " + turretPointName + " of turret holder " + this.entity + "."); - } delete this.initTurrets; }