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 + + + + 5 + 1 + + + + 5 + 2 + + + + true + + + 2 + 5 + 0 + + 500 + 0 + 0 + 100 + + +