1
0
forked from mirrors/0ad

Use transform to finish construction.

Decreases duplication.

Differential revision: D3804
Comment from: @wraitii (also on IRC)

This was SVN commit r25197.
This commit is contained in:
Freagarach
2021-04-06 12:54:33 +00:00
parent 973de1ccd7
commit 5b3bdf3647
5 changed files with 56 additions and 116 deletions
@@ -342,132 +342,24 @@ Foundation.prototype.Build = function(builderEnt, work)
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);
}
};
@@ -127,7 +127,7 @@ RallyPoint.prototype.OrderToRallyPoint = function(entity, ignore = [])
RallyPoint.prototype.OnGlobalEntityRenamed = function(msg)
{
for (var data of this.data)
for (let data of this.data)
{
if (!data)
continue;
@@ -136,6 +136,21 @@ RallyPoint.prototype.OnGlobalEntityRenamed = function(msg)
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)
@@ -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("interfaces/UnitAI.js");
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 @@ function testFoundation(...mocks)
"GetRotation": () => rot,
"SetConstructionProgress": () => {},
"IsInWorld": () => true,
"GetHeightOffset": () => {},
"MoveOutOfWorld": () => {}
});
AddMock(previewEnt, IID_Ownership, {
@@ -108,6 +118,7 @@ function testFoundation(...mocks)
});
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 @@ function testFoundation(...mocks)
TS_ASSERT_EQUALS(rx, rot.x);
TS_ASSERT_EQUALS(rz, rot.z);
},
"SetHeightOffset": () => {}
});
for (let mock of mocks)
@@ -14,6 +14,7 @@ Engine.LoadComponentScript("interfaces/Promotion.js");
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");
@@ -33,12 +33,24 @@ function ChangeEntityTemplate(oldEnt, newTemplate)
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 @@ function ChangeEntityTemplate(oldEnt, newTemplate)
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);