Index: binaries/data/mods/public/gui/session/selection_panels.js
===================================================================
--- binaries/data/mods/public/gui/session/selection_panels.js
+++ binaries/data/mods/public/gui/session/selection_panels.js
@@ -1019,6 +1019,139 @@
return true;
}
};
+/*
+g_SelectionPanels.GroupTraining = {
+ "getMaxNumberOfItems": function()
+ {
+ return 24 - getNumberOfRightPanelButtons();
+ },
+ "getItems": function()
+ {
+ return getAllTrainableGroupsFromSelection();
+ },
+ "setupButton": function(data)
+ {
+ let template = GetGroupTemplateData(data.item);
+ if (!template)
+ return false;
+
+ let technologyEnabled = true;
+ for (let entry in template.Entries)
+ {
+ technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", {
+ "tech": template.Entries[entry].templateData.requiredTechnology,
+ "player": data.player
+ });
+ if (!technologyEnabled)
+ break;
+ }
+
+ let unitIds = data.unitEntStates.map(status => status.id);
+
+ let trainNum = 0;
+ let tooltips = [];
+ let maxNeededResources;
+ let entriesToRecruit = Object.keys(template.Entries);
+ if (template.MutuallyExclusive && entriesToRecruit.length > 1)
+ {
+ let weightedListOfEntries = [];
+ let maxTrainNum = 0;
+ for (let entry in template.Entries)
+ {
+ let entTemplate = template.Entries[entry].data.Template;
+ let [buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch] =
+ getTrainingStatus(unitIds, entTemplate, data.playerState);
+ trainNum = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch;
+ maxTrainNum = Math.max(+(template.Entries[entry].data.Amount || 1) * trainNum, maxTrainNum);
+
+ let neededResources;
+ if (template.cost)
+ neededResources = Engine.GuiInterfaceCall("GetNeededResources", {
+ "cost": multiplyEntityCosts(template, trainNum),
+ "player": data.player
+ });
+ maxNeededResources = neededResources;
+warn("MNR: " + uneval(maxNeededResources)); // Needs to be split to check all resources seperately.
+warn("MTN: " + uneval(maxTrainNum));
+
+ let limits = getEntityLimitAndCount(data.playerState, entTemplate);
+ tooltips.push(formatLimitString(limits.entLimit, limits.entCount, limits.entLimitChangers));
+
+ let chance = +(template.Entries[entry].data.Chance || 1);
+ for (let i = 0; i < chance; i++)
+ weightedListOfEntries.push(entry);
+ }
+ entriesToRecruit = pickRandom(weightedListOfEntries);
+ }
+
+ data.button.onPress = function() {
+ if (!maxNeededResources)
+ addTrainingToQueue(unitIds, template.Entries[entriesToRecruit].data.Template, data.playerState);
+ };
+
+ // Not yet supported.
+// data.button.onPressRight = function() {
+// showTemplateDetails(data.item);
+// };
+
+ data.countDisplay.caption = trainNum > 1 ? trainNum : "";
+
+ // Not yet supported
+ tooltips = [
+ "[font=\"sans-bold-16\"]" +
+ colorizeHotkey("%(hotkey)s", "session.queueunit." + (data.i + 1)) +
+ "[/font]" + " " + template.Name //+ getEntityNamesFormatted(template),
+// getVisibleEntityClassesFormatted(template),
+// getAurasTooltip(template),
+// getEntityTooltip(template),
+// getEntityCostTooltip(template, unitIds[0], buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch)
+ ];
+
+// if (Engine.ConfigDB_GetValue("user", "showdetailedtooltips") === "true")
+// tooltips = tooltips.concat([
+// getHealthTooltip,
+// getAttackTooltip,
+// getSplashDamageTooltip,
+// getHealerTooltip,
+// getArmorTooltip,
+// getGarrisonTooltip,
+// getProjectilesTooltip,
+// getSpeedTooltip
+// ].map(func => func(template)));
+
+// tooltips.push(showTemplateViewerOnRightClickTooltip());
+// tooltips.push(
+// formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch),
+// getRequiredTechnologyTooltip(technologyEnabled, template.requiredTechnology, GetSimState().players[data.player].civ),
+// getNeededResourcesTooltip(neededResources));
+
+ data.button.tooltip = tooltips.filter(tip => tip).join("\n");
+
+ let modifier = "";
+// if (!technologyEnabled || limits.canBeAddedCount == 0)
+// {
+// data.button.enabled = false;
+// modifier = "color:0 0 0 127:grayscale:";
+// }
+// else
+ {
+ data.button.enabled = controlsPlayer(data.player);
+ if (maxNeededResources)
+ modifier = resourcesToAlphaMask(maxNeededResources) + ":";
+ }
+
+ if (template.icon)
+ data.icon.sprite = modifier + "stretched:session/portraits/" + template.icon;
+
+ let index = data.i + getNumberOfRightPanelButtons();
+ setPanelObjectPosition(data.button, index, data.rowLength);
+
+warn("Called: " + uneval(template.Entries[entriesToRecruit].data.Template));
+//return false;
+
+ return true;
+ }
+};*/
g_SelectionPanels.Upgrade = {
"getMaxNumberOfItems": function()
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
@@ -557,6 +557,98 @@
return GetTemplateDataHelper(template, player, aurasTemplate, Resources);
};
+/*
+ * Calculate and pass the data of a group.
+ * @param {number} player - The entityID of the player to check for.
+ * @param {object} group - The group to check.
+ * @return {object} - A object with e.g. maximum tech-requirements, resource costs etc.
+ */
+GuiInterface.prototype.GetGroupTemplateData = function(player, templateName)
+{
+ let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+ let template = cmpTemplateManager.GetTemplate(templateName);
+
+ if (!template || !template.Identity ||
+ !template.Identity.Composition || !template.Identity.Composition.Entries)
+ return null;
+
+ let ret = {
+ "Name": template.Identity.GenericName,
+ "Tooltip": template.Identity.Tooltip,
+ "MutuallyExclusive": template.Identity.Composition.MutuallyExclusive,
+ "Icon": template.Identity.Icon,
+ "Entries" : {}
+ };
+ for (let entry in template.Identity.Composition.Entries)
+ ret.Entries[entry] = {
+ "data": template.Identity.Composition.Entries[entry],
+ "templateData": this.GetTemplateData(player, template.Identity.Composition.Entries[entry].Template)
+ };
+warn(uneval(GetTemplateDataHelper(template, player, {}, Resources) ));
+ return ret;
+
+/*
+getTrainingStatus on selection_panels.js?
+
+ let maxNeededResources = "ToDo";
+ let maxAmount = 0;
+ let limits = "ToDo";
+ let requiredTechs = [];
+ let entriesToRecruit = Object.keys(group.Entries);
+ let weightedListOfTemplates = [];
+ let recruitableTemplates = [];
+
+ for (let entry in entriesToRecruit)
+ {
+ let template = GetTemplateDataHelper(group.Entries[entry])
+
+ requiredTechs.push(template.requiredTechnology);
+ recruitableTemplates.push(group.Entries[entry].data.Template);
+// Limits
+
+ }
+
+ if (group.MutuallyExclusive && entriesToRecruit.length > 1)
+ {
+ for (let entry in entriesToRecruit)
+ {
+ let template = GetTemplateDataHelper(group.Entries[entry])
+
+ let entTemplateName = group.Entries[entry].data.Template;
+ maxAmount = Math.max(+(group.Entries[entry].data.Amount || 1), maxAmount);
+// Resources
+
+ // Construct something of a weighted list.
+ let chance = +(group.Entries[entry].data.Chance || 1);
+ for (let i = 0; i < chance; i++)
+ weightedListOfTemplates.push(entTemplateName);
+ }
+ }
+ else
+ for (let entry in entriesToRecruit)
+ {
+ let template = GetTemplateDataHelper(group.Entries[entry])
+
+ let entTemplateName = group.Entries[entry].data.Template;
+ maxAmount += +(group.Entries[entry].data.Amount || 1);
+ }
+
+ data = {
+ "GenericName": group.GenericName,
+ "SpecificName": group.SpecificName,
+ "Tooltip": group.Tooltip,
+ "technologies": requiredTechs,
+ "resources": maxNeededResources,
+ "maxAmount": maxAmount,
+ "icon": group.Icon,
+ "weightedListOfTemplates": weightedListOfTemplates,
+ "recruitableTemplates": recruitableTemplates
+ };
+warn(uneval(data));
+ return data;
+*/
+};
+
GuiInterface.prototype.IsTechnologyResearched = function(player, data)
{
if (!data.tech)
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/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
+
+
+ units/athen_black_cloak
+ 5
+ 1
+
+
+ units/athen_champion_infantry
+ 5
+ 2
+
+
+
+ true
+
+
+ 2
+ 5
+ 0
+
+ 500
+ 0
+ 0
+ 100
+
+
+