Index: binaries/data/mods/public/globalscripts/Templates.js
===================================================================
--- binaries/data/mods/public/globalscripts/Templates.js
+++ binaries/data/mods/public/globalscripts/Templates.js
@@ -401,6 +401,7 @@
ret.requiredTechnology = template.Identity.RequiredTechnology;
ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity);
ret.nativeCiv = template.Identity.Civ;
+ ret.composition = template.Identity.Composition;
}
if (template.UnitMotion)
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
@@ -742,6 +742,40 @@
return tooltips.join("\n");
}
+function getCompositionTooltip(template)
+{
+ if (!template.composition)
+ return "";
+
+ let composition = [];
+ if (template.composition.MutuallyExclusive == "true")
+ {
+ let total = 0;
+ for (let entry in template.composition.Entries)
+ total += +template.composition.Entries[entry].Chance;
+
+ for (let entry in template.composition.Entries)
+ composition.push(sprintf(translate("• %(amount)s %(entity)s (%(chance)s %%)"), {
+ "amount": template.composition.Entries[entry].Amount,
+ "entity": getEntityNames(GetTemplateData(template.composition.Entries[entry].Template)),
+ "chance": (template.composition.Entries[entry].Chance / total * 100).toFixed(0),
+ }));
+ }
+ else
+ for (let entry in template.composition.Entries)
+ composition.push(sprintf(translate("• %(amount)s %(entity)s"), {
+ "amount": template.composition.Entries[entry].Amount,
+ "entity": getEntityNames(GetTemplateData(template.composition.Entries[entry].Template))
+ }));
+
+ let tooltip = sprintf(translate("%(label)s\n%(composition)s"), {
+ "label": headerFont(translate("Composition:")),
+ "composition": composition.join("\n")
+ });
+
+ return tooltip;
+}
+
function getEntityNames(template)
{
if (!template.name.specific)
Index: binaries/data/mods/public/gui/reference/common/draw.js
===================================================================
--- binaries/data/mods/public/gui/reference/common/draw.js
+++ binaries/data/mods/public/gui/reference/common/draw.js
@@ -11,6 +11,7 @@
*/
var g_StatsFunctions = [
getHealthTooltip,
+ getCompositionTooltip,
getHealerTooltip,
getAttackTooltip,
getSplashDamageTooltip,
Index: binaries/data/mods/public/simulation/components/Identity.js
===================================================================
--- binaries/data/mods/public/simulation/components/Identity.js
+++ binaries/data/mods/public/simulation/components/Identity.js
@@ -92,7 +92,32 @@
"" +
"" +
"" +
- "";
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
Identity.prototype.Init = function()
{
Index: binaries/data/mods/public/simulation/components/ProductionQueue.js
===================================================================
--- binaries/data/mods/public/simulation/components/ProductionQueue.js
+++ binaries/data/mods/public/simulation/components/ProductionQueue.js
@@ -68,6 +68,10 @@
this.entityCache = [];
this.spawnNotified = false;
+
+ this.compositionCount = {};
+ this.compositionSpawned = {};
+ this.compositionEntries = {};
};
/*
@@ -401,6 +405,9 @@
Engine.DestroyEntity(ent);
this.entityCache = [];
+ this.compositionCount = {};
+ this.compositionSpawned = {};
+ this.compositionEntries = {};
for (var i = 0; i < this.queue.length; ++i)
{
@@ -726,7 +733,54 @@
if (item.unitTemplate)
{
- var numSpawned = this.SpawnUnits(item.unitTemplate, item.count, item.metadata);
+ let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
+ template = cmpGuiInterface.GetTemplateData(item.player, item.unitTemplate);
+ let numSpawned = 0;
+ if (template.composition)
+ {
+ if (Object.keys(this.compositionEntries).length == 0)
+ {
+ this.compositionEntries = template.composition.Entries;
+ if (template.composition.MutuallyExclusive != "false")
+ {
+ let weightedListOfTemplates = [];
+ for (let entry in this.compositionEntries)
+ {
+ // Construct something of a weighted list.
+ let chance = +(this.compositionEntries[entry].Chance || 1);
+ for (let i = 0; i < chance; i++)
+ weightedListOfTemplates.push(this.compositionEntries[entry]);
+ }
+ this.compositionEntries = {};
+ for (let i = 0; i < item.count; i++)
+ this.compositionEntries[i] = pickRandom(weightedListOfTemplates);
+ item.count = 1;
+ }
+ }
+ let finished = true;
+ for (let entry in this.compositionEntries)
+ {
+ let amount = +this.compositionEntries[entry].Amount * item.count - (this.compositionSpawned[entry] || 0);
+ if (this.compositionCount[entry] == undefined)
+ {
+ this.compositionCount[entry] = amount;
+ this.compositionSpawned[entry] = 0;
+ }
+ this.compositionSpawned[entry] += this.SpawnUnits(this.compositionEntries[entry].Template, amount, {});
+ if (finished)
+ finished = this.compositionSpawned[entry] == this.compositionCount[entry];
+ }
+
+ if (finished)
+ {
+ numSpawned = item.count;
+ this.compositionCount = {};
+ this.compositionSpawned = {};
+ this.compositionEntries = {};
+ }
+ }
+ else
+ numSpawned = this.SpawnUnits(item.unitTemplate, item.count, item.metadata);
if (numSpawned == item.count)
{
// All entities spawned, this batch finished
Index: binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js
+++ binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js
@@ -202,7 +202,8 @@
});
AddMock(SYSTEM_ENTITY, IID_GuiInterface, {
- "PushNotification": () => {}
+ "PushNotification": () => {},
+ "GetTemplateData": playerID => ({})
});
AddMock(SYSTEM_ENTITY, IID_Trigger, {
Index: binaries/data/mods/public/simulation/templates/structures/athen_civil_centre.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/athen_civil_centre.xml
+++ binaries/data/mods/public/simulation/templates/structures/athen_civil_centre.xml
@@ -12,6 +12,7 @@
units/{civ}_infantry_spearman_b
units/{civ}_infantry_slinger_b
units/{civ}_cavalry_javelinist_b
+ units/compositions/athen_example
Index: binaries/data/mods/public/simulation/templates/units/compositions/athen_example.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/templates/units/compositions/athen_example.xml
@@ -0,0 +1,38 @@
+
+
+
+ athen
+ Some generic name.
+ Some specific name.
+ Some elaborate tooltip.
+ units/viking_longship.png
+ phase_town
+
+ true
+
+
+ units/athen_black_cloak
+ 5
+ 1
+
+
+ units/athen_champion_infantry
+ 5
+ 2
+
+
+
+ true
+
+
+ 2
+ 5
+ 0
+
+ 500
+ 0
+ 0
+ 100
+
+
+
Index: binaries/data/mods/public/simulation/templates/units/compositions/group.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/templates/units/compositions/group.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+ gaia
+ Group.
+ Group S.
+ Group T.
+ phase_village
+ true
+
+
+ 0
+ 0
+ 0
+
+ 0
+ 0
+ 0
+ 0
+
+
+