Index: ps/trunk/binaries/data/mods/public/simulation/components/Foundation.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Foundation.js +++ ps/trunk/binaries/data/mods/public/simulation/components/Foundation.js @@ -342,132 +342,24 @@ if (progress >= 1.0) { - // Finished construction + let cmpPlayerStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); - // Create the real entity - var building = Engine.AddEntity(this.finalTemplateName); + let building = ChangeEntityTemplate(this.entity, this.finalTemplateName); - // Copy various parameters from the foundation - - var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual); - var cmpBuildingVisual = Engine.QueryInterface(building, IID_Visual); - if (cmpVisual && cmpBuildingVisual) - cmpBuildingVisual.SetActorSeed(cmpVisual.GetActorSeed()); - - var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); - if (!cmpPosition || !cmpPosition.IsInWorld()) - { - error("Foundation " + this.entity + " does not have a position in-world."); - Engine.DestroyEntity(building); - return; - } - var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position); - if (!cmpBuildingPosition) - { - error("New building " + building + " has no position component."); - Engine.DestroyEntity(building); - return; - } - var pos = cmpPosition.GetPosition2D(); - cmpBuildingPosition.JumpTo(pos.x, pos.y); - var rot = cmpPosition.GetRotation(); - cmpBuildingPosition.SetYRotation(rot.y); - cmpBuildingPosition.SetXZRotation(rot.x, rot.z); - // TODO: should add a ICmpPosition::CopyFrom() instead of all this - - var cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint); - var cmpBuildingRallyPoint = Engine.QueryInterface(building, IID_RallyPoint); - if(cmpRallyPoint && cmpBuildingRallyPoint) - { - var rallyCoords = cmpRallyPoint.GetPositions(); - var rallyData = cmpRallyPoint.GetData(); - for (var i = 0; i < rallyCoords.length; ++i) - { - cmpBuildingRallyPoint.AddPosition(rallyCoords[i].x, rallyCoords[i].z); - cmpBuildingRallyPoint.AddData(rallyData[i]); - } - } - - // ---------------------------------------------------------------------- - - var owner; - var cmpTerritoryDecay = Engine.QueryInterface(building, IID_TerritoryDecay); - if (cmpTerritoryDecay && cmpTerritoryDecay.HasTerritoryOwnership()) - { - let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); - owner = cmpTerritoryManager.GetOwner(pos.x, pos.y); - } - else - { - let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); - if (!cmpOwnership) - { - error("Foundation " + this.entity + " has no ownership."); - Engine.DestroyEntity(building); - return; - } - owner = cmpOwnership.GetOwner(); - } - var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership); - if (!cmpBuildingOwnership) - { - error("New Building " + building + " has no ownership."); - Engine.DestroyEntity(building); - return; - } - cmpBuildingOwnership.SetOwner(owner); - - /* - Copy over the obstruction control group IDs from the foundation - entities. This is needed to ensure that when a foundation is completed - and replaced by a new entity, it remains in the same control group(s) - as any other foundation entities that may surround it. This is the - mechanism that is used to e.g. enable wall pieces to be built closely - together, ignoring their mutual obstruction shapes (since they would - otherwise be prevented from being built so closely together). If the - control groups are not copied over, the new entity will default to a - new control group containing only itself, and will hence block - construction of any surrounding foundations that it was previously in - the same control group with. - - Note that this will result in the completed building entities having - control group IDs that equal entity IDs of old (and soon to be deleted) - foundation entities. This should not have any consequences, however, - since the control group IDs are only meant to be unique identifiers, - which is still true when reusing the old ones. - */ - - var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction); - if (cmpObstruction && cmpBuildingObstruction) - { - cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup()); - cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2()); - } - - var cmpPlayerStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); if (cmpPlayerStatisticsTracker) cmpPlayerStatisticsTracker.IncreaseConstructedBuildingsCounter(building); - var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health); - if (cmpBuildingHealth) - cmpBuildingHealth.SetHitpoints(progress * cmpBuildingHealth.GetMaxHitpoints()); - PlaySound("constructed", building); Engine.PostMessage(this.entity, MT_ConstructionFinished, { "entity": this.entity, "newentity": building }); - Engine.PostMessage(this.entity, MT_EntityRenamed, { "entity": this.entity, "newentity": building }); - // Inform the builders that repairing has finished. - // This not done by listening to a global message due to performance. for (let builder of this.GetBuilders()) { let cmpUnitAIBuilder = Engine.QueryInterface(builder, IID_UnitAI); if (cmpUnitAIBuilder) cmpUnitAIBuilder.ConstructionFinished({ "entity": this.entity, "newentity": building }); } - - Engine.DestroyEntity(this.entity); } }; Index: ps/trunk/binaries/data/mods/public/simulation/components/RallyPoint.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/RallyPoint.js +++ ps/trunk/binaries/data/mods/public/simulation/components/RallyPoint.js @@ -127,7 +127,7 @@ RallyPoint.prototype.OnGlobalEntityRenamed = function(msg) { - for (var data of this.data) + for (let data of this.data) { if (!data) continue; @@ -136,6 +136,21 @@ if (data.source && data.source == msg.entity) data.source = msg.newentity; } + + if (msg.entity != this.entity) + return; + + let cmpRallyPointNew = Engine.QueryInterface(msg.newentity, IID_RallyPoint); + if (cmpRallyPointNew) + { + let rallyCoords = this.GetPositions(); + let rallyData = this.GetData(); + for (let i = 0; i < rallyCoords.length; ++i) + { + cmpRallyPointNew.AddPosition(rallyCoords[i].x, rallyCoords[i].z); + cmpRallyPointNew.AddData(rallyData[i]); + } + } }; RallyPoint.prototype.OnOwnershipChanged = function(msg) Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js @@ -1,13 +1,20 @@ Engine.LoadHelperScript("Player.js"); +Engine.LoadHelperScript("Transform.js"); Engine.LoadHelperScript("ValueModification.js"); Engine.LoadComponentScript("interfaces/AutoBuildable.js"); Engine.LoadComponentScript("interfaces/Builder.js"); +Engine.LoadComponentScript("interfaces/Capturable.js"); Engine.LoadComponentScript("interfaces/Cost.js"); Engine.LoadComponentScript("interfaces/Foundation.js"); +Engine.LoadComponentScript("interfaces/Guard.js"); Engine.LoadComponentScript("interfaces/Health.js"); Engine.LoadComponentScript("interfaces/ModifiersManager.js"); Engine.LoadComponentScript("interfaces/Population.js"); +Engine.LoadComponentScript("interfaces/Promotion.js"); +Engine.LoadComponentScript("interfaces/Repairable.js"); +Engine.LoadComponentScript("interfaces/ResourceGatherer.js"); Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); +Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js"); Engine.LoadComponentScript("interfaces/TerritoryDecay.js"); Engine.LoadComponentScript("interfaces/Trigger.js"); Engine.LoadComponentScript("interfaces/Timer.js"); @@ -15,6 +22,7 @@ Engine.LoadComponentScript("AutoBuildable.js"); Engine.LoadComponentScript("Foundation.js"); Engine.LoadComponentScript("Timer.js"); + let player = 1; let playerEnt = 3; let foundationEnt = 20; @@ -84,6 +92,8 @@ "GetRotation": () => rot, "SetConstructionProgress": () => {}, "IsInWorld": () => true, + "GetHeightOffset": () => {}, + "MoveOutOfWorld": () => {} }); AddMock(previewEnt, IID_Ownership, { @@ -108,6 +118,7 @@ }); AddMock(newEnt, IID_Position, { + "GetPosition2D": () => pos, "JumpTo": (x, y) => { TS_ASSERT_EQUALS(x, pos.x); TS_ASSERT_EQUALS(y, pos.y); @@ -117,6 +128,7 @@ TS_ASSERT_EQUALS(rx, rot.x); TS_ASSERT_EQUALS(rz, rot.z); }, + "SetHeightOffset": () => {} }); for (let mock of mocks) Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Pack.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Pack.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Pack.js @@ -14,6 +14,7 @@ Engine.LoadComponentScript("interfaces/Repairable.js"); Engine.LoadComponentScript("interfaces/ResourceGatherer.js"); Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js"); +Engine.LoadComponentScript("interfaces/TerritoryDecay.js"); Engine.LoadComponentScript("interfaces/Timer.js"); Engine.LoadComponentScript("interfaces/UnitAI.js"); Engine.LoadComponentScript("Pack.js"); Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Transform.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Transform.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Transform.js @@ -33,12 +33,24 @@ for (let entity of cmpTurretHolder.GetEntities()) cmpNewTurretHolder.SetReservedTurretPoint(cmpTurretHolder.GetOccupiedTurretPointName(entity)); - var cmpOwnership = Engine.QueryInterface(oldEnt, IID_Ownership); - var cmpNewOwnership = Engine.QueryInterface(newEnt, IID_Ownership); - if (cmpOwnership && cmpNewOwnership) - cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); + let owner; + let cmpTerritoryDecay = Engine.QueryInterface(newEnt, IID_TerritoryDecay); + if (cmpTerritoryDecay && cmpTerritoryDecay.HasTerritoryOwnership() && cmpNewPosition) + { + let pos = cmpNewPosition.GetPosition2D(); + let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); + owner = cmpTerritoryManager.GetOwner(pos.x, pos.y); + } + else + { + let cmpOwnership = Engine.QueryInterface(oldEnt, IID_Ownership); + if (cmpOwnership) + owner = cmpOwnership.GetOwner(); + } + let cmpNewOwnership = Engine.QueryInterface(newEnt, IID_Ownership); + if (cmpNewOwnership) + cmpNewOwnership.SetOwner(owner); - // Copy control groups CopyControlGroups(oldEnt, newEnt); // Rescale capture points @@ -143,6 +155,14 @@ return newEnt; } +/** + * Copy over the obstruction control group IDs. + * This is needed to ensure that when a group of structures with the same + * control groups is replaced by a new entity, they remains in the same control group(s). + * This is the mechanism that is used to e.g. enable wall pieces to be built closely + * together, ignoring their mutual obstruction shapes (since they would + * otherwise be prevented from being built so closely together). + */ function CopyControlGroups(oldEnt, newEnt) { let cmpObstruction = Engine.QueryInterface(oldEnt, IID_Obstruction);