Index: binaries/data/mods/public/globalscripts/Templates.js
===================================================================
--- binaries/data/mods/public/globalscripts/Templates.js
+++ binaries/data/mods/public/globalscripts/Templates.js
@@ -204,11 +204,18 @@
}
}
- if (template.BuildingAI)
- ret.buildingAI = {
- "defaultArrowCount": Math.round(getEntityValue("BuildingAI/DefaultArrowCount")),
- "garrisonArrowMultiplier": getEntityValue("BuildingAI/GarrisonArrowMultiplier"),
- "maxArrowCount": Math.round(getEntityValue("BuildingAI/MaxArrowCount"))
+ if (template.ManpowerHolderBuilding)
+ ret.manpowerHolder = {
+ "defaultArrowCount": Math.round(getEntityValue("ManpowerHolderBuilding/DefaultArrowCount", "ManpowerHolder/DefaultArrowCount")),
+ "garrisonArrowMultiplier": getEntityValue("ManpowerHolderBuilding/GarrisonArrowMultiplier", "ManpowerHolder/GarrisonArrowMultiplier"),
+ "maxArrowCount": Math.round(getEntityValue("ManpowerHolderBuilding/MaxArrowCount", "ManpowerHolder/MaxArrowCount"))
+ };
+
+ else if (template.ManpowerHolderUnit)
+ ret.manpowerHolder = {
+ "defaultArrowCount": Math.round(getEntityValue("ManpowerHolderUnit/DefaultArrowCount", "ManpowerHolder/DefaultArrowCount")),
+ "garrisonArrowMultiplier": getEntityValue("ManpowerHolderUnit/GarrisonArrowMultiplier", "ManpowerHolder/GarrisonArrowMultiplier"),
+ "maxArrowCount": Math.round(getEntityValue("ManpowerHolderUnit/MaxArrowCount", "ManpowerHolder/MaxArrowCount"))
};
if (template.BuildRestrictions)
Index: binaries/data/mods/public/gui/common/tooltips.js
===================================================================
--- binaries/data/mods/public/gui/common/tooltips.js
+++ binaries/data/mods/public/gui/common/tooltips.js
@@ -146,12 +146,12 @@
// Either one arrow shot by UnitAI,
let timeString = getSecondsString(template.attack[type].repeatTime / 1000);
- // or multiple arrows shot by BuildingAI
- if (!template.buildingAI || type != "Ranged")
+ // or multiple arrows shot by ManpowerHolder
+ if (!template.manpowerHolder || type != "Ranged")
return timeString;
// Show either current rate from simulation or default count if the sim is not running
- let arrows = template.buildingAI.arrowCount || template.buildingAI.defaultArrowCount;
+ let arrows = template.manpowerHolder.arrowCount || template.manpowerHolder.defaultArrowCount;
let arrowString = sprintf(translatePlural("%(arrowcount)s %(arrows)s", "%(arrowcount)s %(arrows)s", arrows), {
"arrowcount": arrows,
"arrows": unitFont(translatePlural("arrow", "arrows", arrows))
@@ -222,7 +222,7 @@
let rate = sprintf(translate("%(label)s %(details)s"), {
"label":
headerFont(
- template.buildingAI && type == "Ranged" ?
+ template.manpowerHolder && type == "Ranged" ?
translate("Interval:") :
translate("Rate:")),
"details": attackRateDetails(template, type)
@@ -321,13 +321,13 @@
function getProjectilesTooltip(template)
{
- if (!template.garrisonHolder || !template.buildingAI)
+ if (!template.garrisonHolder || !template.manpowerHolder)
return "";
let limit = Math.min(
- template.buildingAI.maxArrowCount || Infinity,
- template.buildingAI.defaultArrowCount +
- Math.round(template.buildingAI.garrisonArrowMultiplier *
+ template.manpowerHolder.maxArrowCount || Infinity,
+ template.manpowerHolder.defaultArrowCount +
+ Math.round(template.manpowerHolder.garrisonArrowMultiplier *
template.garrisonHolder.capacity)
);
@@ -342,12 +342,12 @@
sprintf(translate("%(label)s: %(value)s"), {
"label": headerFont(translateWithContext("projectiles", "Default")),
- "value": template.buildingAI.defaultArrowCount
+ "value": template.manpowerHolder.defaultArrowCount
}),
sprintf(translate("%(label)s: %(value)s"), {
"label": headerFont(translateWithContext("projectiles", "Per Unit")),
- "value": +template.buildingAI.garrisonArrowMultiplier.toFixed(2)
+ "value": +template.manpowerHolder.garrisonArrowMultiplier.toFixed(2)
})
].join(commaFont(translate(", ")));
}
Index: binaries/data/mods/public/simulation/ai/common-api/entity.js
===================================================================
--- binaries/data/mods/public/simulation/ai/common-api/entity.js
+++ binaries/data/mods/public/simulation/ai/common-api/entity.js
@@ -428,17 +428,17 @@
},
getDefaultArrow: function() {
- return +this.get("BuildingAI/DefaultArrowCount");
+ return +this.get("ManpowerHolder/DefaultArrowCount");
},
getArrowMultiplier: function() {
- return +this.get("BuildingAI/GarrisonArrowMultiplier");
+ return +this.get("ManpowerHolder/GarrisonArrowMultiplier");
},
getGarrisonArrowClasses: function() {
- if (!this.get("BuildingAI"))
+ if (!this.get("ManpowerHolder"))
return undefined;
- return this.get("BuildingAI/GarrisonArrowClasses").split(/\s+/);
+ return this.get("ManpowerHolder/GarrisonArrowClasses").split(/\s+/);
},
buffHeal: function() {
Index: binaries/data/mods/public/simulation/ai/petra/researchManager.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/researchManager.js
+++ binaries/data/mods/public/simulation/ai/petra/researchManager.js
@@ -143,7 +143,7 @@
return { "name": tech[0], "increasePriority": this.CostSum(template.cost) < 400 };
else if (template.modifications[i].value === "ResourceGatherer/Rates/metal.ore")
return { "name": tech[0], "increasePriority": this.CostSum(template.cost) < 400 };
- else if (template.modifications[i].value === "BuildingAI/DefaultArrowCount")
+ else if (template.modifications[i].value === "ManpowerHolder/DefaultArrowCount")
return { "name": tech[0], "increasePriority": this.CostSum(template.cost) < 400 };
else if (template.modifications[i].value === "Health/RegenRate")
return { "name": tech[0], "increasePriority": false };
Index: binaries/data/mods/public/simulation/components/BuildingAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/BuildingAI.js
+++ /dev/null
@@ -1,379 +0,0 @@
-//Number of rounds of firing per 2 seconds
-const roundCount = 10;
-const attackType = "Ranged";
-
-function BuildingAI() {}
-
-BuildingAI.prototype.Schema =
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "";
-
-BuildingAI.prototype.MAX_PREFERENCE_BONUS = 2;
-
-BuildingAI.prototype.Init = function()
-{
- this.currentRound = 0;
- this.archersGarrisoned = 0;
- this.arrowsLeft = 0;
- this.targetUnits = [];
-};
-
-BuildingAI.prototype.OnGarrisonedUnitsChanged = function(msg)
-{
- let classes = this.template.GarrisonArrowClasses;
-
- for (let ent of msg.added)
- {
- let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
- if (!cmpIdentity)
- continue;
- if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
- ++this.archersGarrisoned;
- }
-
- for (let ent of msg.removed)
- {
- let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
- if (!cmpIdentity)
- continue;
- if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
- --this.archersGarrisoned;
- }
-};
-
-BuildingAI.prototype.OnOwnershipChanged = function(msg)
-{
- this.targetUnits = [];
- this.SetupRangeQuery();
- this.SetupGaiaRangeQuery();
-};
-
-BuildingAI.prototype.OnDiplomacyChanged = function(msg)
-{
- if (!IsOwnedByPlayer(msg.player, this.entity))
- return;
-
- // Remove maybe now allied/neutral units
- this.targetUnits = [];
- this.SetupRangeQuery();
- this.SetupGaiaRangeQuery();
-};
-
-BuildingAI.prototype.OnDestroy = function()
-{
- if (this.timer)
- {
- let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- cmpTimer.CancelTimer(this.timer);
- this.timer = undefined;
- }
-
- // Clean up range queries
- let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
- if (this.enemyUnitsQuery)
- cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
- if (this.gaiaUnitsQuery)
- cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
-};
-
-/**
- * React on Attack value modifications, as it might influence the range
- */
-BuildingAI.prototype.OnValueModification = function(msg)
-{
- if (msg.component != "Attack")
- return;
-
- this.targetUnits = [];
- this.SetupRangeQuery();
- this.SetupGaiaRangeQuery();
-};
-
-/**
- * Setup the Range Query to detect units coming in & out of range
- */
-BuildingAI.prototype.SetupRangeQuery = function()
-{
- var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
- if (!cmpAttack)
- return;
-
- var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
- if (this.enemyUnitsQuery)
- {
- cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
- this.enemyUnitsQuery = undefined;
- }
-
- var cmpPlayer = QueryOwnerInterface(this.entity);
- if (!cmpPlayer)
- return;
-
- var enemies = cmpPlayer.GetEnemies();
- if (enemies.length && enemies[0] == 0)
- enemies.shift(); // remove gaia
-
- if (!enemies.length)
- return;
-
- var range = cmpAttack.GetRange(attackType);
- this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
- this.entity, range.min, range.max, range.elevationBonus,
- enemies, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
-
- cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
-};
-
-// Set up a range query for Gaia units within LOS range which can be attacked.
-// This should be called whenever our ownership changes.
-BuildingAI.prototype.SetupGaiaRangeQuery = function()
-{
- var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
- if (!cmpAttack)
- return;
-
- var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
- if (this.gaiaUnitsQuery)
- {
- cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
- this.gaiaUnitsQuery = undefined;
- }
-
- var cmpPlayer = QueryOwnerInterface(this.entity);
- if (!cmpPlayer || !cmpPlayer.IsEnemy(0))
- return;
-
- var range = cmpAttack.GetRange(attackType);
-
- // This query is only interested in Gaia entities that can attack.
- this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
- this.entity, range.min, range.max, range.elevationBonus,
- [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
-
- cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
-};
-
-/**
- * Called when units enter or leave range
- */
-BuildingAI.prototype.OnRangeUpdate = function(msg)
-{
-
- var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
- if (!cmpAttack)
- return;
-
- // Target enemy units except non-dangerous animals
- if (msg.tag == this.gaiaUnitsQuery)
- {
- msg.added = msg.added.filter(e => {
- let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
- return cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal());
- });
- }
- else if (msg.tag != this.enemyUnitsQuery)
- return;
-
- // Add new targets
- for (let entity of msg.added)
- if (cmpAttack.CanAttack(entity))
- this.targetUnits.push(entity);
-
- // Remove targets outside of vision-range
- for (let entity of msg.removed)
- {
- let index = this.targetUnits.indexOf(entity);
- if (index > -1)
- this.targetUnits.splice(index, 1);
- }
-
- if (this.targetUnits.length)
- this.StartTimer();
-};
-
-BuildingAI.prototype.StartTimer = function()
-{
- if (this.timer)
- return;
-
- var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
- if (!cmpAttack)
- return;
-
- var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- var attackTimers = cmpAttack.GetTimers(attackType);
-
- this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows",
- attackTimers.prepare, attackTimers.repeat / roundCount, null);
-};
-
-BuildingAI.prototype.GetDefaultArrowCount = function()
-{
- var arrowCount = +this.template.DefaultArrowCount;
- return Math.round(ApplyValueModificationsToEntity("BuildingAI/DefaultArrowCount", arrowCount, this.entity));
-};
-
-BuildingAI.prototype.GetMaxArrowCount = function()
-{
- if (!this.template.MaxArrowCount)
- return Infinity;
-
- let maxArrowCount = +this.template.MaxArrowCount;
- return Math.round(ApplyValueModificationsToEntity("BuildingAI/MaxArrowCount", maxArrowCount, this.entity));
-};
-
-BuildingAI.prototype.GetGarrisonArrowMultiplier = function()
-{
- var arrowMult = +this.template.GarrisonArrowMultiplier;
- return ApplyValueModificationsToEntity("BuildingAI/GarrisonArrowMultiplier", arrowMult, this.entity);
-};
-
-BuildingAI.prototype.GetGarrisonArrowClasses = function()
-{
- var string = this.template.GarrisonArrowClasses;
- if (string)
- return string.split(/\s+/);
- return [];
-};
-
-/**
- * Returns the number of arrows which needs to be fired.
- * DefaultArrowCount + Garrisoned Archers(ie., any unit capable
- * of shooting arrows from inside buildings)
- */
-BuildingAI.prototype.GetArrowCount = function()
-{
- let count = this.GetDefaultArrowCount() +
- Math.round(this.archersGarrisoned * this.GetGarrisonArrowMultiplier());
-
- return Math.min(count, this.GetMaxArrowCount());
-};
-
-BuildingAI.prototype.SetUnitAITarget = function(ent)
-{
- this.unitAITarget = ent;
- if (ent)
- this.StartTimer();
-};
-
-/**
- * Fire arrows with random temporal distribution on prefered targets.
- * Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range.
- */
-BuildingAI.prototype.FireArrows = function()
-{
- if (!this.targetUnits.length && !this.unitAITarget)
- {
- if (!this.timer)
- return;
-
- let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- cmpTimer.CancelTimer(this.timer);
- this.timer = undefined;
- return;
- }
-
- let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
- if (!cmpAttack)
- return;
-
- if (this.currentRound > roundCount - 1)
- this.currentRound = 0;
-
- if (this.currentRound == 0)
- this.arrowsLeft = this.GetArrowCount();
-
- let arrowsToFire = 0;
- if (this.currentRound == roundCount - 1)
- arrowsToFire = this.arrowsLeft;
- else
- arrowsToFire = Math.min(
- randIntInclusive(0, 2 * this.GetArrowCount() / roundCount),
- this.arrowsLeft
- );
-
- if (arrowsToFire <= 0)
- {
- ++this.currentRound;
- return;
- }
-
- // Add targets to a weighted list, to allow preferences
- let targets = new WeightedList();
- let maxPreference = this.MAX_PREFERENCE_BONUS;
- let addTarget = function(target)
- {
- let preference = cmpAttack.GetPreference(target);
- let weight = 1;
-
- if (preference !== null && preference !== undefined)
- weight += maxPreference / (1 + preference);
-
- targets.push(target, weight);
- };
-
- // Add the UnitAI target separately, as the UnitMotion and RangeManager implementations differ
- if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) == -1)
- addTarget(this.unitAITarget);
- for (let target of this.targetUnits)
- addTarget(target);
-
- for (let i = 0; i < arrowsToFire; ++i)
- {
- let selectedIndex = targets.randomIndex();
- let selectedTarget = targets.itemAt(selectedIndex);
-
- if (selectedTarget && this.CheckTargetVisible(selectedTarget))
- {
- cmpAttack.PerformAttack(attackType, selectedTarget);
- PlaySound("attack", this.entity);
- continue;
- }
-
- // Could not attack target, retry
- targets.removeAt(selectedIndex);
- --i;
-
- if (!targets.length())
- {
- this.arrowsLeft += arrowsToFire;
- break;
- }
- }
-
- this.arrowsLeft -= arrowsToFire;
- this.currentRound++;
-};
-
-/**
- * Returns true if the target entity is visible through the FoW/SoD.
- */
-BuildingAI.prototype.CheckTargetVisible = function(target)
-{
- var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
- if (!cmpOwnership)
- return false;
-
- // Entities that are hidden and miraged are considered visible
- var cmpFogging = Engine.QueryInterface(target, IID_Fogging);
- if (cmpFogging && cmpFogging.IsMiraged(cmpOwnership.GetOwner()))
- return true;
-
- // Either visible directly, or visible in fog
- let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
- return cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner()) != "hidden";
-};
-
-Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI);
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js
+++ binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -433,7 +433,7 @@
let ret = {
"armour": null,
"attack": null,
- "buildingAI": null,
+ "manpowerHolder": null,
"deathDamage": null,
"heal": null,
"isBarterMarket": null,
@@ -513,14 +513,14 @@
if (cmpAuras)
ret.auras = cmpAuras.GetDescriptions();
- let cmpBuildingAI = Engine.QueryInterface(ent, IID_BuildingAI);
- if (cmpBuildingAI)
- ret.buildingAI = {
- "defaultArrowCount": cmpBuildingAI.GetDefaultArrowCount(),
- "maxArrowCount": cmpBuildingAI.GetMaxArrowCount(),
- "garrisonArrowMultiplier": cmpBuildingAI.GetGarrisonArrowMultiplier(),
- "garrisonArrowClasses": cmpBuildingAI.GetGarrisonArrowClasses(),
- "arrowCount": cmpBuildingAI.GetArrowCount()
+ let cmpManpowerHolder = Engine.QueryInterface(ent, IID_ManpowerHolder);
+ if (cmpManpowerHolder)
+ ret.manpowerHolder = {
+ "defaultArrowCount": cmpManpowerHolder.GetDefaultArrowCount(),
+ "maxArrowCount": cmpManpowerHolder.GetMaxArrowCount(),
+ "garrisonArrowMultiplier": cmpManpowerHolder.GetGarrisonArrowMultiplier(),
+ "garrisonArrowClasses": cmpManpowerHolder.GetGarrisonArrowClasses(),
+ "arrowCount": cmpManpowerHolder.GetArrowCount()
};
let cmpDeathDamage = Engine.QueryInterface(ent, IID_DeathDamage);
Index: binaries/data/mods/public/simulation/components/ManpowerHolderBuilding.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/ManpowerHolderBuilding.js
@@ -0,0 +1,369 @@
+//Number of rounds of firing per 2 seconds
+const roundCount = 10;
+const attackType = "Ranged";
+
+function ManpowerHolderBuilding() {}
+
+ManpowerHolderBuilding.prototype.Schema =
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
+ManpowerHolderBuilding.prototype.MAX_PREFERENCE_BONUS = 2;
+
+ManpowerHolderBuilding.prototype.Init = function()
+{
+ this.currentRound = 0;
+ this.archersGarrisoned = 0;
+ this.arrowsLeft = 0;
+ this.targetUnits = [];
+};
+
+ManpowerHolderBuilding.prototype.OnGarrisonedUnitsChanged = function(msg)
+{
+ let classes = this.template.GarrisonArrowClasses;
+
+ for (let ent of msg.added)
+ {
+ let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+ if (!cmpIdentity)
+ continue;
+ if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
+ ++this.archersGarrisoned;
+ }
+
+ for (let ent of msg.removed)
+ {
+ let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+ if (!cmpIdentity)
+ continue;
+ if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
+ --this.archersGarrisoned;
+ }
+};
+
+ManpowerHolderBuilding.prototype.OnOwnershipChanged = function(msg)
+{
+ this.targetUnits = [];
+ this.SetupRangeQuery();
+ this.SetupGaiaRangeQuery();
+};
+
+ManpowerHolderBuilding.prototype.OnDiplomacyChanged = function(msg)
+{
+ if (!IsOwnedByPlayer(msg.player, this.entity))
+ return;
+
+ // Remove maybe now allied/neutral units
+ this.targetUnits = [];
+ this.SetupRangeQuery();
+ this.SetupGaiaRangeQuery();
+};
+
+ManpowerHolderBuilding.prototype.OnDestroy = function()
+{
+ if (this.timer)
+ {
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ cmpTimer.CancelTimer(this.timer);
+ this.timer = undefined;
+ }
+
+ // Clean up range queries
+ let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ if (this.enemyUnitsQuery)
+ cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
+ if (this.gaiaUnitsQuery)
+ cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
+};
+
+/**
+ * React on Attack value modifications, as it might influence the range
+ */
+ManpowerHolderBuilding.prototype.OnValueModification = function(msg)
+{
+ if (msg.component != "Attack")
+ return;
+
+ this.targetUnits = [];
+ this.SetupRangeQuery();
+ this.SetupGaiaRangeQuery();
+};
+
+/**
+ * Setup the Range Query to detect units coming in & out of range
+ */
+ManpowerHolderBuilding.prototype.SetupRangeQuery = function()
+{
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ if (this.enemyUnitsQuery)
+ {
+ cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
+ this.enemyUnitsQuery = undefined;
+ }
+
+ var cmpPlayer = QueryOwnerInterface(this.entity);
+ if (!cmpPlayer)
+ return;
+
+ var enemies = cmpPlayer.GetEnemies();
+ if (enemies.length && enemies[0] == 0)
+ enemies.shift(); // remove gaia
+
+ if (!enemies.length)
+ return;
+
+ var range = cmpAttack.GetRange(attackType);
+ this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
+ this.entity, range.min, range.max, range.elevationBonus,
+ enemies, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
+
+ cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
+};
+
+// Set up a range query for Gaia units within LOS range which can be attacked.
+// This should be called whenever our ownership changes.
+ManpowerHolderBuilding.prototype.SetupGaiaRangeQuery = function()
+{
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ if (this.gaiaUnitsQuery)
+ {
+ cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
+ this.gaiaUnitsQuery = undefined;
+ }
+
+ var cmpPlayer = QueryOwnerInterface(this.entity);
+ if (!cmpPlayer || !cmpPlayer.IsEnemy(0))
+ return;
+
+ var range = cmpAttack.GetRange(attackType);
+
+ // This query is only interested in Gaia entities that can attack.
+ this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
+ this.entity, range.min, range.max, range.elevationBonus,
+ [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
+
+ cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
+};
+
+/**
+ * Called when units enter or leave range
+ */
+ManpowerHolderBuilding.prototype.OnRangeUpdate = function(msg)
+{
+
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ // Target enemy units except non-dangerous animals
+ if (msg.tag == this.gaiaUnitsQuery)
+ {
+ msg.added = msg.added.filter(e => {
+ let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
+ return cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal());
+ });
+ }
+ else if (msg.tag != this.enemyUnitsQuery)
+ return;
+
+ // Add new targets
+ for (let entity of msg.added)
+ if (cmpAttack.CanAttack(entity))
+ this.targetUnits.push(entity);
+
+ // Remove targets outside of vision-range
+ for (let entity of msg.removed)
+ {
+ let index = this.targetUnits.indexOf(entity);
+ if (index > -1)
+ this.targetUnits.splice(index, 1);
+ }
+
+ if (this.targetUnits.length)
+ this.StartTimer();
+};
+
+ManpowerHolderBuilding.prototype.StartTimer = function()
+{
+ if (this.timer)
+ return;
+
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ var attackTimers = cmpAttack.GetTimers(attackType);
+
+ this.timer = cmpTimer.SetInterval(this.entity, IID_ManpowerHolder, "FireArrows",
+ attackTimers.prepare, attackTimers.repeat / roundCount, null);
+};
+
+ManpowerHolderBuilding.prototype.GetDefaultArrowCount = function()
+{
+ var arrowCount = +this.template.DefaultArrowCount;
+ return Math.round(ApplyValueModificationsToEntity("ManpowerHolderBuilding/DefaultArrowCount", arrowCount, this.entity));
+};
+
+ManpowerHolderBuilding.prototype.GetMaxArrowCount = function()
+{
+ if (!this.template.MaxArrowCount)
+ return Infinity;
+
+ let maxArrowCount = +this.template.MaxArrowCount;
+ return Math.round(ApplyValueModificationsToEntity("ManpowerHolderBuilding/MaxArrowCount", maxArrowCount, this.entity));
+};
+
+ManpowerHolderBuilding.prototype.GetGarrisonArrowMultiplier = function()
+{
+ var arrowMult = +this.template.GarrisonArrowMultiplier;
+ return ApplyValueModificationsToEntity("ManpowerHolderBuilding/GarrisonArrowMultiplier", arrowMult, this.entity);
+};
+
+ManpowerHolderBuilding.prototype.GetGarrisonArrowClasses = function()
+{
+ var string = this.template.GarrisonArrowClasses;
+ if (string)
+ return string.split(/\s+/);
+ return [];
+};
+
+/**
+ * Returns the number of arrows which needs to be fired.
+ * DefaultArrowCount + Garrisoned Archers(ie., any unit capable
+ * of shooting arrows from inside buildings)
+ */
+ManpowerHolderBuilding.prototype.GetArrowCount = function()
+{
+ let count = this.GetDefaultArrowCount() +
+ Math.round(this.archersGarrisoned * this.GetGarrisonArrowMultiplier());
+
+ return Math.min(count, this.GetMaxArrowCount());
+};
+
+/**
+ * Fire arrows with random temporal distribution on prefered targets.
+ * Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range.
+ */
+ManpowerHolderBuilding.prototype.FireArrows = function()
+{
+ if (!this.targetUnits.length)
+ {
+ if (!this.timer)
+ return;
+
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ cmpTimer.CancelTimer(this.timer);
+ this.timer = undefined;
+ return;
+ }
+
+ let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ if (this.currentRound > roundCount - 1)
+ this.currentRound = 0;
+
+ if (this.currentRound == 0)
+ this.arrowsLeft = this.GetArrowCount();
+
+ let arrowsToFire = 0;
+ if (this.currentRound == roundCount - 1)
+ arrowsToFire = this.arrowsLeft;
+ else
+ arrowsToFire = Math.min(
+ randIntInclusive(0, 2 * this.GetArrowCount() / roundCount),
+ this.arrowsLeft
+ );
+
+ if (arrowsToFire <= 0)
+ {
+ ++this.currentRound;
+ return;
+ }
+
+ // Add targets to a weighted list, to allow preferences
+ let targets = new WeightedList();
+ let maxPreference = this.MAX_PREFERENCE_BONUS;
+ let addTarget = function(target)
+ {
+ let preference = cmpAttack.GetPreference(target);
+ let weight = 1;
+
+ if (preference !== null && preference !== undefined)
+ weight += maxPreference / (1 + preference);
+
+ targets.push(target, weight);
+ };
+
+ for (let target of this.targetUnits)
+ addTarget(target);
+
+ for (let i = 0; i < arrowsToFire; ++i)
+ {
+ let selectedIndex = targets.randomIndex();
+ let selectedTarget = targets.itemAt(selectedIndex);
+
+ if (selectedTarget && this.CheckTargetVisible(selectedTarget))
+ {
+ cmpAttack.PerformAttack(attackType, selectedTarget);
+ PlaySound("attack", this.entity);
+ continue;
+ }
+
+ // Could not attack target, retry
+ targets.removeAt(selectedIndex);
+ --i;
+
+ if (!targets.length())
+ {
+ this.arrowsLeft += arrowsToFire;
+ break;
+ }
+ }
+
+ this.arrowsLeft -= arrowsToFire;
+ this.currentRound++;
+};
+
+/**
+ * Returns true if the target entity is visible through the FoW/SoD.
+ */
+ManpowerHolderBuilding.prototype.CheckTargetVisible = function(target)
+{
+ var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+ if (!cmpOwnership)
+ return false;
+
+ // Entities that are hidden and miraged are considered visible
+ var cmpFogging = Engine.QueryInterface(target, IID_Fogging);
+ if (cmpFogging && cmpFogging.IsMiraged(cmpOwnership.GetOwner()))
+ return true;
+
+ // Either visible directly, or visible in fog
+ let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ return cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner()) != "hidden";
+};
+
+Engine.RegisterComponentType(IID_ManpowerHolder, "ManpowerHolderBuilding", ManpowerHolderBuilding);
Index: binaries/data/mods/public/simulation/components/ManpowerHolderUnit.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/ManpowerHolderUnit.js
@@ -0,0 +1,379 @@
+//Number of rounds of firing per 2 seconds
+const roundCount = 10;
+const attackType = "Ranged";
+
+function ManpowerHolderUnit() {}
+
+ManpowerHolderUnit.prototype.Schema =
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
+ManpowerHolderUnit.prototype.MAX_PREFERENCE_BONUS = 2;
+
+ManpowerHolderUnit.prototype.Init = function()
+{
+ this.currentRound = 0;
+ this.archersGarrisoned = 0;
+ this.arrowsLeft = 0;
+ this.targetUnits = [];
+};
+
+ManpowerHolderUnit.prototype.OnGarrisonedUnitsChanged = function(msg)
+{
+ let classes = this.template.GarrisonArrowClasses;
+
+ for (let ent of msg.added)
+ {
+ let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+ if (!cmpIdentity)
+ continue;
+ if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
+ ++this.archersGarrisoned;
+ }
+
+ for (let ent of msg.removed)
+ {
+ let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+ if (!cmpIdentity)
+ continue;
+ if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
+ --this.archersGarrisoned;
+ }
+};
+
+ManpowerHolderUnit.prototype.OnOwnershipChanged = function(msg)
+{
+ this.targetUnits = [];
+ this.SetupRangeQuery();
+ this.SetupGaiaRangeQuery();
+};
+
+ManpowerHolderUnit.prototype.OnDiplomacyChanged = function(msg)
+{
+ if (!IsOwnedByPlayer(msg.player, this.entity))
+ return;
+
+ // Remove maybe now allied/neutral units
+ this.targetUnits = [];
+ this.SetupRangeQuery();
+ this.SetupGaiaRangeQuery();
+};
+
+ManpowerHolderUnit.prototype.OnDestroy = function()
+{
+ if (this.timer)
+ {
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ cmpTimer.CancelTimer(this.timer);
+ this.timer = undefined;
+ }
+
+ // Clean up range queries
+ let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ if (this.enemyUnitsQuery)
+ cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
+ if (this.gaiaUnitsQuery)
+ cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
+};
+
+/**
+ * React on Attack value modifications, as it might influence the range
+ */
+ManpowerHolderUnit.prototype.OnValueModification = function(msg)
+{
+ if (msg.component != "Attack")
+ return;
+
+ this.targetUnits = [];
+ this.SetupRangeQuery();
+ this.SetupGaiaRangeQuery();
+};
+
+/**
+ * Setup the Range Query to detect units coming in & out of range
+ */
+ManpowerHolderUnit.prototype.SetupRangeQuery = function()
+{
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ if (this.enemyUnitsQuery)
+ {
+ cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
+ this.enemyUnitsQuery = undefined;
+ }
+
+ var cmpPlayer = QueryOwnerInterface(this.entity);
+ if (!cmpPlayer)
+ return;
+
+ var enemies = cmpPlayer.GetEnemies();
+ if (enemies.length && enemies[0] == 0)
+ enemies.shift(); // remove gaia
+
+ if (!enemies.length)
+ return;
+
+ var range = cmpAttack.GetRange(attackType);
+ this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
+ this.entity, range.min, range.max, range.elevationBonus,
+ enemies, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
+
+ cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
+};
+
+// Set up a range query for Gaia units within LOS range which can be attacked.
+// This should be called whenever our ownership changes.
+ManpowerHolderUnit.prototype.SetupGaiaRangeQuery = function()
+{
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ if (this.gaiaUnitsQuery)
+ {
+ cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
+ this.gaiaUnitsQuery = undefined;
+ }
+
+ var cmpPlayer = QueryOwnerInterface(this.entity);
+ if (!cmpPlayer || !cmpPlayer.IsEnemy(0))
+ return;
+
+ var range = cmpAttack.GetRange(attackType);
+
+ // This query is only interested in Gaia entities that can attack.
+ this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
+ this.entity, range.min, range.max, range.elevationBonus,
+ [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
+
+ cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
+};
+
+/**
+ * Called when units enter or leave range
+ */
+ManpowerHolderUnit.prototype.OnRangeUpdate = function(msg)
+{
+
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ // Target enemy units except non-dangerous animals
+ if (msg.tag == this.gaiaUnitsQuery)
+ {
+ msg.added = msg.added.filter(e => {
+ let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
+ return cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal());
+ });
+ }
+ else if (msg.tag != this.enemyUnitsQuery)
+ return;
+
+ // Add new targets
+ for (let entity of msg.added)
+ if (cmpAttack.CanAttack(entity))
+ this.targetUnits.push(entity);
+
+ // Remove targets outside of vision-range
+ for (let entity of msg.removed)
+ {
+ let index = this.targetUnits.indexOf(entity);
+ if (index > -1)
+ this.targetUnits.splice(index, 1);
+ }
+
+ if (this.targetUnits.length)
+ this.StartTimer();
+};
+
+ManpowerHolderUnit.prototype.StartTimer = function()
+{
+ if (this.timer)
+ return;
+
+ var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ var attackTimers = cmpAttack.GetTimers(attackType);
+
+ this.timer = cmpTimer.SetInterval(this.entity, IID_ManpowerHolder, "FireArrows",
+ attackTimers.prepare, attackTimers.repeat / roundCount, null);
+};
+
+ManpowerHolderUnit.prototype.GetDefaultArrowCount = function()
+{
+ var arrowCount = +this.template.DefaultArrowCount;
+ return Math.round(ApplyValueModificationsToEntity("ManpowerHolderUnit/DefaultArrowCount", arrowCount, this.entity));
+};
+
+ManpowerHolderUnit.prototype.GetMaxArrowCount = function()
+{
+ if (!this.template.MaxArrowCount)
+ return Infinity;
+
+ let maxArrowCount = +this.template.MaxArrowCount;
+ return Math.round(ApplyValueModificationsToEntity("ManpowerHolderUnit/MaxArrowCount", maxArrowCount, this.entity));
+};
+
+ManpowerHolderUnit.prototype.GetGarrisonArrowMultiplier = function()
+{
+ var arrowMult = +this.template.GarrisonArrowMultiplier;
+ return ApplyValueModificationsToEntity("ManpowerHolderUnit/GarrisonArrowMultiplier", arrowMult, this.entity);
+};
+
+ManpowerHolderUnit.prototype.GetGarrisonArrowClasses = function()
+{
+ var string = this.template.GarrisonArrowClasses;
+ if (string)
+ return string.split(/\s+/);
+ return [];
+};
+
+/**
+ * Returns the number of arrows which needs to be fired.
+ * DefaultArrowCount + Garrisoned Archers(ie., any unit capable
+ * of shooting arrows from inside buildings)
+ */
+ManpowerHolderUnit.prototype.GetArrowCount = function()
+{
+ let count = this.GetDefaultArrowCount() +
+ Math.round(this.archersGarrisoned * this.GetGarrisonArrowMultiplier());
+
+ return Math.min(count, this.GetMaxArrowCount());
+};
+
+ManpowerHolderUnit.prototype.SetUnitAITarget = function(ent)
+{
+ this.unitAITarget = ent;
+ if (ent)
+ this.StartTimer();
+};
+
+/**
+ * Fire arrows with random temporal distribution on prefered targets.
+ * Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range.
+ */
+ManpowerHolderUnit.prototype.FireArrows = function()
+{
+ if (!this.targetUnits.length && !this.unitAITarget)
+ {
+ if (!this.timer)
+ return;
+
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ cmpTimer.CancelTimer(this.timer);
+ this.timer = undefined;
+ return;
+ }
+
+ let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
+ if (!cmpAttack)
+ return;
+
+ if (this.currentRound > roundCount - 1)
+ this.currentRound = 0;
+
+ if (this.currentRound == 0)
+ this.arrowsLeft = this.GetArrowCount();
+
+ let arrowsToFire = 0;
+ if (this.currentRound == roundCount - 1)
+ arrowsToFire = this.arrowsLeft;
+ else
+ arrowsToFire = Math.min(
+ randIntInclusive(0, 2 * this.GetArrowCount() / roundCount),
+ this.arrowsLeft
+ );
+
+ if (arrowsToFire <= 0)
+ {
+ ++this.currentRound;
+ return;
+ }
+
+ // Add targets to a weighted list, to allow preferences
+ let targets = new WeightedList();
+ let maxPreference = this.MAX_PREFERENCE_BONUS;
+ let addTarget = function(target)
+ {
+ let preference = cmpAttack.GetPreference(target);
+ let weight = 1;
+
+ if (preference !== null && preference !== undefined)
+ weight += maxPreference / (1 + preference);
+
+ targets.push(target, weight);
+ };
+
+ // Add the UnitAI target separately, as the UnitMotion and RangeManager implementations differ
+ if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) == -1)
+ addTarget(this.unitAITarget);
+ for (let target of this.targetUnits)
+ addTarget(target);
+
+ for (let i = 0; i < arrowsToFire; ++i)
+ {
+ let selectedIndex = targets.randomIndex();
+ let selectedTarget = targets.itemAt(selectedIndex);
+
+ if (selectedTarget && this.CheckTargetVisible(selectedTarget))
+ {
+ cmpAttack.PerformAttack(attackType, selectedTarget);
+ PlaySound("attack", this.entity);
+ continue;
+ }
+
+ // Could not attack target, retry
+ targets.removeAt(selectedIndex);
+ --i;
+
+ if (!targets.length())
+ {
+ this.arrowsLeft += arrowsToFire;
+ break;
+ }
+ }
+
+ this.arrowsLeft -= arrowsToFire;
+ this.currentRound++;
+};
+
+/**
+ * Returns true if the target entity is visible through the FoW/SoD.
+ */
+ManpowerHolderUnit.prototype.CheckTargetVisible = function(target)
+{
+ var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+ if (!cmpOwnership)
+ return false;
+
+ // Entities that are hidden and miraged are considered visible
+ var cmpFogging = Engine.QueryInterface(target, IID_Fogging);
+ if (cmpFogging && cmpFogging.IsMiraged(cmpOwnership.GetOwner()))
+ return true;
+
+ // Either visible directly, or visible in fog
+ let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ return cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner()) != "hidden";
+};
+
+Engine.RegisterComponentType(IID_ManpowerHolder, "ManpowerHolderUnit", ManpowerHolderUnit);
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js
+++ binaries/data/mods/public/simulation/components/UnitAI.js
@@ -1481,8 +1481,10 @@
}
// if the attacker is a building and we can repair the guarded, repair it rather than attacking
- var cmpBuildingAI = Engine.QueryInterface(msg.data.attacker, IID_BuildingAI);
- if (cmpBuildingAI && this.CanRepair(this.isGuardOf))
+ // TODO: what's exactly the goal of that (should that apply when the attacker of the guarded unit is
+ // a structure or also a ship or a siege tower?).
+ var cmpManpowerHolder = Engine.QueryInterface(msg.data.attacker, IID_ManpowerHolder);
+ if (cmpManpowerHolder && this.CanRepair(this.isGuardOf))
{
this.PushOrderFront("Repair", { "target": this.isGuardOf, "autocontinue": false, "force": false });
return;
@@ -1962,15 +1964,15 @@
this.FaceTowardsTarget(this.order.data.target);
- var cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI);
- if (cmpBuildingAI)
- cmpBuildingAI.SetUnitAITarget(this.order.data.target);
+ var cmpManpowerHolder = Engine.QueryInterface(this.entity, IID_ManpowerHolder);
+ if (cmpManpowerHolder)
+ cmpManpowerHolder.SetUnitAITarget(this.order.data.target);
},
"leave": function() {
- var cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI);
- if (cmpBuildingAI)
- cmpBuildingAI.SetUnitAITarget(0);
+ var cmpManpowerHolder = Engine.QueryInterface(this.entity, IID_ManpowerHolder);
+ if (cmpManpowerHolder)
+ cmpManpowerHolder.SetUnitAITarget(0);
this.StopTimer();
},
@@ -2011,9 +2013,10 @@
this.FaceTowardsTarget(target);
- // BuildingAI has it's own attack-routine
- var cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI);
- if (!cmpBuildingAI)
+ // Let ManpowerHolderUnit handle ranged attack
+ // TODO: Check what should be done here
+ var cmpManpowerHolder = Engine.QueryInterface(this.entity, IID_ManpowerHolder);
+ if (!cmpManpowerHolder || this.order.data.attackType != "Ranged")
{
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
cmpAttack.PerformAttack(this.order.data.attackType, target);
Index: binaries/data/mods/public/simulation/components/interfaces/BuildingAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/interfaces/BuildingAI.js
+++ /dev/null
@@ -1 +0,0 @@
-Engine.RegisterInterface("BuildingAI");
Index: binaries/data/mods/public/simulation/components/interfaces/ManpowerHolder.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/interfaces/ManpowerHolder.js
@@ -0,0 +1 @@
+Engine.RegisterInterface("ManpowerHolder");
Index: binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
+++ binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
@@ -18,6 +18,7 @@
Engine.LoadComponentScript("interfaces/Heal.js");
Engine.LoadComponentScript("interfaces/Health.js");
Engine.LoadComponentScript("interfaces/Loot.js");
+Engine.LoadComponentScript("interfaces/ManpowerHolder.js");
Engine.LoadComponentScript("interfaces/Market.js");
Engine.LoadComponentScript("interfaces/Pack.js");
Engine.LoadComponentScript("interfaces/ProductionQueue.js");
@@ -34,7 +35,6 @@
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
Engine.LoadComponentScript("interfaces/UnitAI.js");
Engine.LoadComponentScript("interfaces/Upgrade.js");
-Engine.LoadComponentScript("interfaces/BuildingAI.js");
Engine.LoadComponentScript("GuiInterface.js");
Resources = {
@@ -644,7 +644,7 @@
TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedEntityState(-1, 10), {
armour: null,
attack: null,
- buildingAI: null,
+ manpowerHolder: null,
deathDamage:null,
heal: null,
isBarterMarket: true,
Index: binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
+++ binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
@@ -3,7 +3,7 @@
Engine.LoadHelperScript("Player.js");
Engine.LoadComponentScript("interfaces/Attack.js");
Engine.LoadComponentScript("interfaces/Auras.js");
-Engine.LoadComponentScript("interfaces/BuildingAI.js");
+Engine.LoadComponentScript("interfaces/ManpowerHolder.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
Engine.LoadComponentScript("interfaces/DamageReceiver.js");
Engine.LoadComponentScript("interfaces/Formation.js");
Index: binaries/data/mods/public/simulation/data/auras/units/heroes/iber_hero_caros_1.json
===================================================================
--- binaries/data/mods/public/simulation/data/auras/units/heroes/iber_hero_caros_1.json
+++ binaries/data/mods/public/simulation/data/auras/units/heroes/iber_hero_caros_1.json
@@ -1,10 +1,10 @@
{
"type": "garrison",
- "affects": ["Structure", "SiegeTower"],
+ "affects": ["Structure"],
"modifications": [
- { "value": "BuildingAI/GarrisonArrowMultiplier", "multiply": 1.75 },
- { "value": "BuildingAI/MaxArrowCount", "multiply": 1.75 }
+ { "value": "ManpowerHolder/GarrisonArrowMultiplier", "multiply": 1.75 },
+ { "value": "ManpowerHolder/MaxArrowCount", "multiply": 1.75 }
],
- "auraDescription": "75% more arrows per soldier for the building or siege tower he is garrisoned in.",
+ "auraDescription": "75% more arrows per soldier for the building he is garrisoned in.",
"auraName": "Valiant Defender"
}
Index: binaries/data/mods/public/simulation/data/technologies/attack_tower_crenellations.json
===================================================================
--- binaries/data/mods/public/simulation/data/technologies/attack_tower_crenellations.json
+++ binaries/data/mods/public/simulation/data/technologies/attack_tower_crenellations.json
@@ -7,7 +7,7 @@
"icon": "crenelations.png",
"researchTime": 40,
"tooltip": "Install crenellations and murder holes to have 40% more arrows fired per garrisoned soldier.",
- "modifications": [{"value": "BuildingAI/GarrisonArrowMultiplier", "multiply": 1.4}],
+ "modifications": [{"value": "ManpowerHolder/GarrisonArrowMultiplier", "multiply": 1.4}],
"affects": ["DefenseTower"],
"soundComplete": "interface/alarm/alarm_upgradearmory.xml"
}
Index: binaries/data/mods/public/simulation/data/technologies/attack_tower_watch.json
===================================================================
--- binaries/data/mods/public/simulation/data/technologies/attack_tower_watch.json
+++ binaries/data/mods/public/simulation/data/technologies/attack_tower_watch.json
@@ -15,7 +15,7 @@
"icon": "helmet_corinthian_bronze.png",
"researchTime": 40,
"tooltip": "Post sentries to add one arrow to towers.",
- "modifications": [{"value": "BuildingAI/DefaultArrowCount", "add": 1.0}],
+ "modifications": [{"value": "ManpowerHolder/DefaultArrowCount", "add": 1.0}],
"affects": ["DefenseTower"],
"soundComplete": "interface/alarm/alarm_upgradearmory.xml"
}
Index: binaries/data/mods/public/simulation/data/technologies/successors/special_hellenistic_metropolis.json
===================================================================
--- binaries/data/mods/public/simulation/data/technologies/successors/special_hellenistic_metropolis.json
+++ binaries/data/mods/public/simulation/data/technologies/successors/special_hellenistic_metropolis.json
@@ -8,7 +8,7 @@
"researchTime": 60,
"tooltip": "Civic centers +100% health and capture points, double default arrows.",
"modifications": [
- {"value": "BuildingAI/DefaultArrowCount", "multiply": 2.0},
+ {"value": "ManpowerHolder/DefaultArrowCount", "multiply": 2.0},
{"value": "Capturable/CapturePoints", "multiply": 2.0},
{"value": "Health/Max", "multiply": 2.0}
],
Index: binaries/data/mods/public/simulation/templates/campaigns/campaign_city_minor_test.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/campaigns/campaign_city_minor_test.xml
+++ binaries/data/mods/public/simulation/templates/campaigns/campaign_city_minor_test.xml
@@ -12,10 +12,10 @@
2000
-
+
3
0.5
-
+
8.0
Index: binaries/data/mods/public/simulation/templates/campaigns/campaign_city_test.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/campaigns/campaign_city_test.xml
+++ binaries/data/mods/public/simulation/templates/campaigns/campaign_city_test.xml
@@ -12,10 +12,10 @@
2000
-
+
5
0.5
-
+
8.0
Index: binaries/data/mods/public/simulation/templates/other/plane.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/other/plane.xml
+++ binaries/data/mods/public/simulation/templates/other/plane.xml
@@ -15,11 +15,11 @@
0
-
+
3
1
Infantry
-
+
true
0.0
Index: binaries/data/mods/public/simulation/templates/structures/iber_defense_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/iber_defense_tower.xml
+++ binaries/data/mods/public/simulation/templates/structures/iber_defense_tower.xml
@@ -5,9 +5,9 @@
12.0
-
+
2
-
+
5
200
Index: binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml
+++ binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml
@@ -25,11 +25,11 @@
0
-
+
1
15
1
-
+
neutral enemy
ArmyCamp
Index: binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure.xml
+++ binaries/data/mods/public/simulation/templates/template_structure.xml
@@ -10,11 +10,11 @@
1
-
+
0
0
Infantry Cavalry
-
+
land
own
Index: binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
@@ -29,10 +29,10 @@
Human
-
+
3
1
-
+
own neutral
CivilCentre
Index: binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml
@@ -1,10 +1,10 @@
-
+
1
15
1
-
+
own neutral
Colony
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
@@ -17,11 +17,11 @@
Human
-
+
1
1
Infantry
-
+
DefenseTower
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml
@@ -26,9 +26,9 @@
Human
-
+
1
-
+
Outpost
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml
@@ -16,11 +16,11 @@
Human
-
+
0
1
Infantry
-
+
land-shore
Wall
Index: binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
@@ -21,10 +21,10 @@
Human
-
+
3
1
-
+
Fortress
Index: binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml
@@ -16,12 +16,12 @@
Ship Human
-
+
2
10
1
Infantry Cavalry
-
+
2
20
Index: binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml
@@ -24,12 +24,12 @@
Ship Structure
-
+
1
10
1
Catapult
-
+
3
30
Index: binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml
@@ -16,12 +16,12 @@
Ship Human
-
+
3
13
1
Infantry Cavalry
-
+
3
25
Index: binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml
@@ -1,6 +1,11 @@
+
+ 10
+ 8
+ 1000
+
0.0
12.0
@@ -17,12 +22,12 @@
Human
-
+
0
1
10
Infantry
-
+
60