mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 14:43:52 +00:00
Workaround TriggerHelper.js not being able to spawn units correctly because of promotion.
Avoid duplication by moving the function to Transform.js. Add tests to Transform.js Add tests to TurretHolder.js Optimize slightly Trainer.js by removing some useless Engine.QueryInterface calls. Refs #6784 (symptoms in TriggerHelper.js are fixed underlying cause not) `SkirmishReplacer` is called before the Modifier Manager so it does not suffer the same fate. Entities using `ChangeEntityTemplate` function are still affected. Maps calling Engine.AddEntity directly are still affected. Ideally this should be handled by hotloading components instead of creating new entities each time. See => https://code.wildfiregames.com/D4991 Tested using: https://github.com/0ADMods/trailer_tools/commit/908dd631d950b5050d1784530c65f29ccfc67913 Differential Revision: https://code.wildfiregames.com/D4984 This was SVN commit r27636.
This commit is contained in:
@@ -95,6 +95,21 @@ TriggerHelper.SetUnitFormation = function(playerID, entities, formation)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new unit taking into account possible 0 experience promotion.
|
||||
* @param {number} owner Player id of the owner of the new units.
|
||||
* @param {string} template Name of the template.
|
||||
* @returns the created entity id.
|
||||
*/
|
||||
TriggerHelper.AddUpgradeTemplate = function(owner, template)
|
||||
{
|
||||
const upgradedTemplate = GetUpgradedTemplate(owner, template);
|
||||
if (upgradedTemplate !== template)
|
||||
warn(`tried to spawn template '${template}' but upgraded template '${upgradedTemplate}' will be spawned instead. You might want to create a template that is not affected by this promotion.`);
|
||||
|
||||
return Engine.AddEntity(upgradedTemplate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Can be used to "force" a building/unit to spawn a group of entities.
|
||||
*
|
||||
@@ -121,7 +136,8 @@ TriggerHelper.SpawnUnits = function(source, template, count, owner)
|
||||
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
let ent = Engine.AddEntity(template);
|
||||
const ent = this.AddUpgradeTemplate(owner, template);
|
||||
|
||||
let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
|
||||
if (!cmpEntPosition)
|
||||
{
|
||||
@@ -178,7 +194,7 @@ TriggerHelper.SpawnGarrisonedUnits = function(entity, template, count, owner)
|
||||
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
let ent = Engine.AddEntity(template);
|
||||
const ent = this.AddUpgradeTemplate(owner, template);
|
||||
|
||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
if (cmpOwnership)
|
||||
@@ -219,7 +235,7 @@ TriggerHelper.SpawnTurretedUnits = function(entity, template, count, owner)
|
||||
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
let ent = Engine.AddEntity(template);
|
||||
const ent = this.AddUpgradeTemplate(owner, template);
|
||||
|
||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
if (cmpOwnership)
|
||||
|
||||
@@ -554,7 +554,7 @@ Trainer.prototype.CalculateEntitiesMap = function()
|
||||
return entMap;
|
||||
}
|
||||
|
||||
token = this.GetUpgradedTemplate(token);
|
||||
token = GetUpgradedTemplate(cmpPlayer.GetPlayerID(), token);
|
||||
entMap.set(rawToken, token);
|
||||
updateAllQueuedTemplate(rawToken, token);
|
||||
return entMap;
|
||||
@@ -563,32 +563,6 @@ Trainer.prototype.CalculateEntitiesMap = function()
|
||||
this.CalculateTrainCostMultiplier();
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the upgraded template name if necessary.
|
||||
*/
|
||||
Trainer.prototype.GetUpgradedTemplate = function(templateName)
|
||||
{
|
||||
const cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
if (!cmpPlayer)
|
||||
return templateName;
|
||||
|
||||
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
||||
let template = cmpTemplateManager.GetTemplate(templateName);
|
||||
while (template && template.Promotion !== undefined)
|
||||
{
|
||||
const requiredXp = ApplyValueModificationsToTemplate(
|
||||
"Promotion/RequiredXp",
|
||||
+template.Promotion.RequiredXp,
|
||||
cmpPlayer.GetPlayerID(),
|
||||
template);
|
||||
if (requiredXp > 0)
|
||||
break;
|
||||
templateName = template.Promotion.Entity;
|
||||
template = cmpTemplateManager.GetTemplate(templateName);
|
||||
}
|
||||
return templateName;
|
||||
};
|
||||
|
||||
Trainer.prototype.CalculateTrainCostMultiplier = function()
|
||||
{
|
||||
for (const res of Resources.GetCodes().concat(["time"]))
|
||||
|
||||
@@ -35,22 +35,21 @@ class TurretHolder
|
||||
*/
|
||||
CreateSubunit(turretPointName)
|
||||
{
|
||||
let turretPoint = this.TurretPointByName(turretPointName);
|
||||
const turretPoint = this.TurretPointByName(turretPointName);
|
||||
if (!turretPoint || turretPoint.entity ||
|
||||
this.initTurrets?.has(turretPointName) ||
|
||||
this.reservedTurrets?.has(turretPointName))
|
||||
return false;
|
||||
|
||||
let ent = Engine.AddEntity(turretPoint.template);
|
||||
const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
|
||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (cmpOwnership)
|
||||
{
|
||||
let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
cmpEntOwnership?.SetOwner(cmpOwnership.GetOwner());
|
||||
}
|
||||
const upgradedTemplate = GetUpgradedTemplate(cmpOwnership.GetOwner(), turretPoint.template);
|
||||
const ent = Engine.AddEntity(upgradedTemplate);
|
||||
|
||||
let cmpTurretable = Engine.QueryInterface(ent, IID_Turretable);
|
||||
const cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
cmpEntOwnership?.SetOwner(cmpOwnership.GetOwner());
|
||||
|
||||
const cmpTurretable = Engine.QueryInterface(ent, IID_Turretable);
|
||||
return cmpTurretable?.OccupyTurret(this.entity, turretPoint.name, turretPoint.ejectable) || Engine.DestroyEntity(ent);
|
||||
}
|
||||
|
||||
@@ -389,6 +388,7 @@ class TurretHolder
|
||||
this.EjectOrKill(this.GetEntities());
|
||||
return;
|
||||
}
|
||||
|
||||
for (let point of this.turretPoints)
|
||||
{
|
||||
// If we were created, create any subunits now.
|
||||
|
||||
@@ -55,6 +55,16 @@ AddMock(entityID, IID_Identity, {
|
||||
"GetCiv": () => "iber"
|
||||
});
|
||||
|
||||
let GetUpgradedTemplate = (_, template) => template === "units/iber/cavalry_javelineer_b" ? "units/iber/cavalry_javelineer_a" : template;
|
||||
Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
|
||||
cmpTrainer.CalculateEntitiesMap();
|
||||
TS_ASSERT_UNEVAL_EQUALS(
|
||||
cmpTrainer.GetEntitiesList(),
|
||||
["units/iber/cavalry_javelineer_a", "units/iber/infantry_swordsman_b", "units/iber/support_female_citizen"]
|
||||
);
|
||||
|
||||
GetUpgradedTemplate = (_, template) => template;
|
||||
Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
|
||||
cmpTrainer.CalculateEntitiesMap();
|
||||
TS_ASSERT_UNEVAL_EQUALS(
|
||||
cmpTrainer.GetEntitiesList(),
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
Engine.LoadHelperScript("Player.js");
|
||||
Engine.LoadComponentScript("interfaces/TurretHolder.js");
|
||||
Engine.LoadComponentScript("interfaces/Turretable.js");
|
||||
Engine.LoadComponentScript("interfaces/UnitAI.js");
|
||||
Engine.LoadComponentScript("TurretHolder.js");
|
||||
Engine.LoadComponentScript("Turretable.js");
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
|
||||
"GetPlayerByID": id => id
|
||||
@@ -122,3 +124,100 @@ TS_ASSERT(cmpTurretHolder.OccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[
|
||||
TS_ASSERT(cmpTurretHolder.LeaveTurretPoint(archerID));
|
||||
TS_ASSERT(!cmpTurretHolder.LeaveTurretPoint(cavID, false, cmpTurretHolder.turretPoints[1]));
|
||||
TS_ASSERT(cmpTurretHolder.LeaveTurretPoint(cavID, false, cmpTurretHolder.turretPoints[2]));
|
||||
|
||||
// Incremental Turret creation.
|
||||
cmpTurretHolder = ConstructComponent(turretHolderID, "TurretHolder", {
|
||||
"TurretPoints": {
|
||||
"Turret": {
|
||||
"X": "15.0",
|
||||
"Y": "5.0",
|
||||
"Z": "6.0",
|
||||
"Template": "units/iber/cavalry_javelineer_c"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let spawned = 100;
|
||||
Engine.AddEntity = function() {
|
||||
++spawned;
|
||||
if(spawned > 101)
|
||||
{
|
||||
ConstructComponent(spawned, "Turretable", {});
|
||||
}
|
||||
if(spawned > 102)
|
||||
{
|
||||
AddMock(spawned, IID_Ownership, {
|
||||
"GetOwner": () => player,
|
||||
"SetOwner": () => {}
|
||||
});
|
||||
}
|
||||
if(spawned > 103)
|
||||
{
|
||||
AddMock(spawned, IID_Position, {
|
||||
"GetPosition": () => new Vector3D(4, 3, 25),
|
||||
"GetRotation": () => new Vector3D(4, 0, 6),
|
||||
"SetTurretParent": () => {},
|
||||
"IsInWorld": () => true
|
||||
});
|
||||
}
|
||||
return spawned;
|
||||
}
|
||||
|
||||
const GetUpgradedTemplate = (_, template) => template === "units/iber/cavalry_javelineer_b" ? "units/iber/cavalry_javelineer_a" : template;
|
||||
Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
|
||||
cmpTurretHolder.OnOwnershipChanged({
|
||||
"to": 1,
|
||||
"from": INVALID_PLAYER
|
||||
});
|
||||
TS_ASSERT(!cmpTurretHolder.OccupiesTurretPoint(spawned));
|
||||
cmpTurretHolder.OnOwnershipChanged({
|
||||
"to": 1,
|
||||
"from": INVALID_PLAYER
|
||||
});
|
||||
TS_ASSERT(!cmpTurretHolder.OccupiesTurretPoint(spawned));
|
||||
cmpTurretHolder.OnOwnershipChanged({
|
||||
"to": 1,
|
||||
"from": INVALID_PLAYER
|
||||
});
|
||||
TS_ASSERT(!cmpTurretHolder.OccupiesTurretPoint(spawned));
|
||||
cmpTurretHolder.OnOwnershipChanged({
|
||||
"to": 1,
|
||||
"from": INVALID_PLAYER
|
||||
});
|
||||
TS_ASSERT(cmpTurretHolder.OccupiesTurretPoint(spawned));
|
||||
|
||||
// Normal turret creation.
|
||||
Engine.AddEntity = function(t) {
|
||||
++spawned;
|
||||
// Check that we're using the upgraded template.
|
||||
TS_ASSERT(t, "units/iber/cavalry_javelineer_a");
|
||||
ConstructComponent(spawned, "Turretable", {});
|
||||
AddMock(spawned, IID_Ownership, {
|
||||
"GetOwner": () => player,
|
||||
"SetOwner": () => {}
|
||||
});
|
||||
AddMock(spawned, IID_Position, {
|
||||
"GetPosition": () => new Vector3D(4, 3, 25),
|
||||
"GetRotation": () => new Vector3D(4, 0, 6),
|
||||
"SetTurretParent": () => {},
|
||||
"IsInWorld": () => true
|
||||
});
|
||||
return spawned;
|
||||
}
|
||||
|
||||
cmpTurretHolder = ConstructComponent(turretHolderID, "TurretHolder", {
|
||||
"TurretPoints": {
|
||||
"Turret": {
|
||||
"X": "15.0",
|
||||
"Y": "5.0",
|
||||
"Z": "6.0",
|
||||
"Template": "units/iber/cavalry_javelineer_b"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cmpTurretHolder.OnOwnershipChanged({
|
||||
"to": 1,
|
||||
"from": INVALID_PLAYER
|
||||
});
|
||||
TS_ASSERT(cmpTurretHolder.OccupiesTurretPoint(spawned));
|
||||
|
||||
@@ -294,5 +294,30 @@ function TransferGarrisonedUnits(oldEnt, newEnt)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} playerId - the player id to check technologies for.
|
||||
* @param {string} templateName - the original template name.
|
||||
* @returns the upgraded template name if it exists else the original template.
|
||||
*/
|
||||
function GetUpgradedTemplate(playerId, templateName)
|
||||
{
|
||||
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
||||
let template = cmpTemplateManager.GetTemplate(templateName);
|
||||
while (template && template.Promotion !== undefined)
|
||||
{
|
||||
const requiredXp = ApplyValueModificationsToTemplate(
|
||||
"Promotion/RequiredXp",
|
||||
+template.Promotion.RequiredXp,
|
||||
playerId,
|
||||
template);
|
||||
if (requiredXp > 0)
|
||||
break;
|
||||
templateName = template.Promotion.Entity;
|
||||
template = cmpTemplateManager.GetTemplate(templateName);
|
||||
}
|
||||
return templateName;
|
||||
};
|
||||
|
||||
Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
|
||||
Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate);
|
||||
Engine.RegisterGlobal("ObstructionsBlockingTemplateChange", ObstructionsBlockingTemplateChange);
|
||||
|
||||
Reference in New Issue
Block a user