Index: binaries/data/mods/public/globalscripts/Templates.js =================================================================== --- binaries/data/mods/public/globalscripts/Templates.js +++ binaries/data/mods/public/globalscripts/Templates.js @@ -395,6 +395,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/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/group 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,38 @@ + + + + athen + Some generic name. + Some specific name. + Some elaborate tooltip. + units/viking_longship.png + phase_town + + true + + + + 5 + 1 + + + + 5 + 2 + + + + true + + + 2 + 5 + 0 + + 500 + 0 + 0 + 100 + + +