diff --git a/binaries/data/mods/public/gui/reference/common/TemplateLoader.js b/binaries/data/mods/public/gui/reference/common/TemplateLoader.js index 217d2444b2..fd5a9eb027 100644 --- a/binaries/data/mods/public/gui/reference/common/TemplateLoader.js +++ b/binaries/data/mods/public/gui/reference/common/TemplateLoader.js @@ -132,7 +132,7 @@ class TemplateLoader { const template = this.loadTechnologyTemplate(templateName); return { - "techs": [template.top, template.bottom], + "techs": template.pair, "reqs": DeriveTechnologyRequirements(template, civCode) }; } @@ -308,7 +308,7 @@ class TemplateLoader isPairTech(technologyCode) { - return !!this.loadTechnologyTemplate(technologyCode).top; + return !!this.loadTechnologyTemplate(technologyCode).pair; } isPhaseTech(technologyCode) diff --git a/binaries/data/mods/public/gui/reference/common/TemplateParser.js b/binaries/data/mods/public/gui/reference/common/TemplateParser.js index 77ceec0de1..9cfab247d0 100644 --- a/binaries/data/mods/public/gui/reference/common/TemplateParser.js +++ b/binaries/data/mods/public/gui/reference/common/TemplateParser.js @@ -196,10 +196,10 @@ class TemplateParser const tech = GetTechnologyDataHelper(template, civCode, g_ResourceData, this.modifiers[civCode] || {}); tech.name.internal = technologyName; - if (template.pair !== undefined) + if (template.partOfPair !== undefined) { - tech.pair = template.pair; - tech.reqs = this.mergeRequirements(tech.reqs, this.TemplateLoader.loadTechnologyPairTemplate(template.pair).reqs); + tech.partOfPair = template.partOfPair; + tech.reqs = this.mergeRequirements(tech.reqs, this.TemplateLoader.loadTechnologyPairTemplate(template.partOfPair).reqs); } if (this.TemplateLoader.isPhaseTech(technologyName)) diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js index d8ee139c9d..3134c54736 100644 --- a/binaries/data/mods/public/gui/session/selection_panels.js +++ b/binaries/data/mods/public/gui/session/selection_panels.js @@ -684,8 +684,8 @@ g_SelectionPanels.Research = { (item.tech == tech || item.tech.pair && tech.pair && - item.tech.bottom == tech.bottom && - item.tech.top == tech.top) && + item.tech.pair?.[0] == tech.pair?.[0] && + item.tech.pair?.[1] == tech.pair?.[1]) && Object.keys(item.techCostMultiplier).every( k => item.techCostMultiplier[k] == state.researcher.techCostMultiplier[k]) )); @@ -731,7 +731,7 @@ g_SelectionPanels.Research = { // Handle one or two techs (tech pair) const player = data.player; const playerState = GetSimState().players[player]; - for (const tech of data.item.tech.pair ? [data.item.tech.bottom, data.item.tech.top] : [data.item.tech]) + for (const tech of (data.item.tech.pair || [data.item.tech])) { // Don't change the object returned by GetTechnologyData const template = clone(GetTechnologyData(tech, playerState.civ)); diff --git a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js index 0b87e05f11..dad41f0d84 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js +++ b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js @@ -48,8 +48,8 @@ GameState.prototype.init = function(SharedScript, state, player) { // Cannot call pickrandom because this function is called on rejoin and that causes oos. // (reverting rP20750) - techName = this.playerData.disabledTechnologies[techData._template.bottom] ? - techData._template.top : techData._template.bottom; + techName = this.playerData.disabledTechnologies[techData._template.pair[0]] ? + techData._template.pair[1] : techData._template.pair[0]; const supersedes = techData._template.supersedes; techData = clone(this.getTemplate(techName)); diff --git a/binaries/data/mods/public/simulation/ai/common-api/technology.js b/binaries/data/mods/public/simulation/ai/common-api/technology.js index b6b74f7a54..cd8783cb80 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/technology.js +++ b/binaries/data/mods/public/simulation/ai/common-api/technology.js @@ -7,15 +7,14 @@ export function Technology(templateName) const template = TechnologyTemplates.Get(templateName); // check if this is one of two paired technologies. - this._isPair = template.pair !== undefined; - if (this._isPair) + if (template.partOfPair) { - const pairTech = TechnologyTemplates.Get(template.pair); - this._pairedWith = pairTech.top == templateName ? pairTech.bottom : pairTech.top; + const parentTech = TechnologyTemplates.Get(template.partOfPair); + this._pairedWith = parentTech.pair[0] == templateName ? parentTech.pair[1] : parentTech.pair[0]; } // check if it only defines a pair: - this._definesPair = template.top !== undefined; + this._definesPair = !!template.pair; this._template = template; } @@ -41,22 +40,17 @@ Technology.prototype.getPairedTechs = function() if (!this._definesPair) return undefined; - return [ - new Technology(this._template.top), - new Technology(this._template.bottom) - ]; + return this._template.pair.map(name => new Technology(name)); }; Technology.prototype.pair = function() { - if (!this._isPair) - return undefined; - return this._template.pair; + return this._template.partOfPair; }; Technology.prototype.pairedWith = function() { - if (!this._isPair) + if (!this._template.partOfPair) return undefined; return this._pairedWith; }; diff --git a/binaries/data/mods/public/simulation/components/Researcher.js b/binaries/data/mods/public/simulation/components/Researcher.js index 1ab5bef73d..6e832eb8f1 100644 --- a/binaries/data/mods/public/simulation/components/Researcher.js +++ b/binaries/data/mods/public/simulation/components/Researcher.js @@ -234,36 +234,22 @@ Researcher.prototype.GetTechnologiesList = function() superseded[template.supersedes] = tech; } - // Now make researched/in progress techs invisible. - for (const i in techList) + return techList.map(tech => { - let tech = techList[i]; - while (this.IsTechnologyResearchedOrInProgress(tech)) - tech = superseded[tech]; + // Make researched/in progress techs invisible. + while (tech && this.IsTechnologyResearchedOrInProgress(tech)) + tech = superseded[tech]; // might be undefined - techList[i] = tech; - } - - const ret = []; - - // This inserts the techs into the correct positions to line up the technology pairs. - for (let i = 0; i < techList.length; ++i) - { - const tech = techList[i]; if (!tech) - { - ret[i] = undefined; - continue; - } + return undefined; + // "Unwrap" tech pairs const template = TechnologyTemplates.Get(tech); - if (template.top) - ret[i] = { "pair": true, "top": template.top, "bottom": template.bottom }; - else - ret[i] = tech; - } + if (template?.pair) + tech = { "pair": template.pair }; - return ret; + return tech; + }); }; /** @@ -294,11 +280,9 @@ Researcher.prototype.IsTechnologyResearchedOrInProgress = function(tech) return false; const template = TechnologyTemplates.Get(tech); - if (template.top) - return cmpTechnologyManager.IsTechnologyResearched(template.top) || - cmpTechnologyManager.IsInProgress(template.top) || - cmpTechnologyManager.IsTechnologyResearched(template.bottom) || - cmpTechnologyManager.IsInProgress(template.bottom); + if (template.pair) + return template.pair.some(t => cmpTechnologyManager.IsTechnologyResearched(t) || + cmpTechnologyManager.IsInProgress(t)); return cmpTechnologyManager.IsTechnologyResearched(tech) || cmpTechnologyManager.IsInProgress(tech); }; @@ -310,9 +294,7 @@ Researcher.prototype.IsTechnologyResearchedOrInProgress = function(tech) */ Researcher.prototype.QueueTechnology = function(templateName, metadata) { - if (!this.GetTechnologiesList().some(tech => - tech && (tech == templateName || - tech.pair && (tech.top == templateName || tech.bottom == templateName)))) + if (!this.GetTechnologiesList().some(tech => tech === templateName || tech?.pair?.includes(templateName))) { error("This entity cannot research " + templateName + "."); return -1; diff --git a/binaries/data/mods/public/simulation/components/TechnologyManager.js b/binaries/data/mods/public/simulation/components/TechnologyManager.js index dadd550900..a3cbb5aef0 100644 --- a/binaries/data/mods/public/simulation/components/TechnologyManager.js +++ b/binaries/data/mods/public/simulation/components/TechnologyManager.js @@ -212,7 +212,7 @@ TechnologyManager.prototype.Init = function() this.unresearchedAutoResearchTechs = new Set(); const allTechs = TechnologyTemplates.GetAll(); for (const key in allTechs) - if (allTechs[key].autoResearch || allTechs[key].top) + if (allTechs[key].autoResearch || allTechs[key].pair) this.unresearchedAutoResearchTechs.add(key); }; @@ -263,8 +263,7 @@ TechnologyManager.prototype.UpdateAutoResearch = function() for (const key of this.unresearchedAutoResearchTechs) { const tech = TechnologyTemplates.Get(key); - if ((tech.autoResearch && this.CanResearch(key)) || - (tech.top && (this.IsTechnologyResearched(tech.top) || this.IsTechnologyResearched(tech.bottom)))) + if ((tech.autoResearch && this.CanResearch(key)) || (tech.pair?.some(t => this.IsTechnologyResearched(t)))) { this.unresearchedAutoResearchTechs.delete(key); this.ResearchTechnology(key); @@ -306,11 +305,10 @@ TechnologyManager.prototype.CanResearch = function(tech) return false; } - if (template.top && this.IsInProgress(template.top) || - template.bottom && this.IsInProgress(template.bottom)) + if (template.pair?.some(t => this.IsInProgress(t))) return false; - if (template.pair && !this.CanResearch(template.pair)) + if (template.partOfPair && !this.CanResearch(template.partOfPair)) return false; if (this.IsInProgress(tech)) diff --git a/binaries/data/mods/public/simulation/data/technologies/civil_engineering_01.json b/binaries/data/mods/public/simulation/data/technologies/civil_engineering_01.json index 9e98caa26a..0d52bde09a 100644 --- a/binaries/data/mods/public/simulation/data/technologies/civil_engineering_01.json +++ b/binaries/data/mods/public/simulation/data/technologies/civil_engineering_01.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_civil_engineering_han", + "partOfPair": "pair_unlock_civil_engineering_han", "genericName": "Improved Construction", "specificName": { "han": "Gōngchéng" }, "description": "", diff --git a/binaries/data/mods/public/simulation/data/technologies/civil_engineering_02.json b/binaries/data/mods/public/simulation/data/technologies/civil_engineering_02.json index d17d62b0f2..6f76b0cdfd 100644 --- a/binaries/data/mods/public/simulation/data/technologies/civil_engineering_02.json +++ b/binaries/data/mods/public/simulation/data/technologies/civil_engineering_02.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_civil_engineering_han", + "partOfPair": "pair_unlock_civil_engineering_han", "genericName": "Robust Architecture", "specificName": { "han": "Gōngchéng" }, "description": "", diff --git a/binaries/data/mods/public/simulation/data/technologies/civil_service_01.json b/binaries/data/mods/public/simulation/data/technologies/civil_service_01.json index 11aa3cba36..e73fc3d875 100644 --- a/binaries/data/mods/public/simulation/data/technologies/civil_service_01.json +++ b/binaries/data/mods/public/simulation/data/technologies/civil_service_01.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_civil_service_han", + "partOfPair": "pair_unlock_civil_service_han", "genericName": "Efficient Bureaucracy", "specificName": { "han": "Guānliáo" }, "description": "", diff --git a/binaries/data/mods/public/simulation/data/technologies/civil_service_02.json b/binaries/data/mods/public/simulation/data/technologies/civil_service_02.json index 833cd8d008..a07e509c55 100644 --- a/binaries/data/mods/public/simulation/data/technologies/civil_service_02.json +++ b/binaries/data/mods/public/simulation/data/technologies/civil_service_02.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_civil_service_han", + "partOfPair": "pair_unlock_civil_service_han", "genericName": "Intensive Training", "specificName": { "han": "Guānliáo" }, "description": "", diff --git a/binaries/data/mods/public/simulation/data/technologies/gather_ahimsa.json b/binaries/data/mods/public/simulation/data/technologies/gather_ahimsa.json index e50d92dd01..31f1c641f4 100644 --- a/binaries/data/mods/public/simulation/data/technologies/gather_ahimsa.json +++ b/binaries/data/mods/public/simulation/data/technologies/gather_ahimsa.json @@ -1,5 +1,5 @@ { - "pair": "pair_gather_food_maur", + "partOfPair": "pair_gather_food_maur", "genericName": "Ahimsa", "description": "Ahimsa is the ancient Indian principle of nonviolence which applies to actions towards all living beings. It is a key virtue in Indian religions like Jainism, Buddhism, Hinduism, and Sikhism.", "cost": { diff --git a/binaries/data/mods/public/simulation/data/technologies/gather_wicker_baskets_maur.json b/binaries/data/mods/public/simulation/data/technologies/gather_wicker_baskets_maur.json index a82da57e06..a2e3af7d65 100644 --- a/binaries/data/mods/public/simulation/data/technologies/gather_wicker_baskets_maur.json +++ b/binaries/data/mods/public/simulation/data/technologies/gather_wicker_baskets_maur.json @@ -1,5 +1,5 @@ { - "pair": "pair_gather_food_maur", + "partOfPair": "pair_gather_food_maur", "genericName": "Wicker Baskets", "description": "Equip your foragers with wicker baskets for foraging.", "cost": { diff --git a/binaries/data/mods/public/simulation/data/technologies/pair_gather_food_maur.json b/binaries/data/mods/public/simulation/data/technologies/pair_gather_food_maur.json index edc884f2b2..e68b4020fb 100644 --- a/binaries/data/mods/public/simulation/data/technologies/pair_gather_food_maur.json +++ b/binaries/data/mods/public/simulation/data/technologies/pair_gather_food_maur.json @@ -1,6 +1,5 @@ { "genericName": "Wicker Basket vs Ahimsa", - "top": "gather_wicker_baskets_maur", - "bottom": "gather_ahimsa", + "pair": ["gather_wicker_baskets_maur", "gather_ahimsa"], "requirements": { "civ": "maur" } } diff --git a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_champions_sele.json b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_champions_sele.json index f44e7a966c..f5d7012466 100644 --- a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_champions_sele.json +++ b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_champions_sele.json @@ -1,6 +1,5 @@ { "genericName": "Traditional Army vs Reform Army", - "top": "traditional_army_sele", - "bottom": "reformed_army_sele", + "pair": ["traditional_army_sele", "reformed_army_sele"], "requirements": { "civ": "sele" } } diff --git a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_engineering_han.json b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_engineering_han.json index eda3dff108..57c06a3a3c 100644 --- a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_engineering_han.json +++ b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_engineering_han.json @@ -1,6 +1,5 @@ { "genericName": "Civil Engineering", - "top": "civil_engineering_01", - "bottom": "civil_engineering_02", + "pair": ["civil_engineering_01", "civil_engineering_02"], "requirements": { "civ": "han" } } diff --git a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_service_han.json b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_service_han.json index 4d63b65814..e9d5a07c30 100644 --- a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_service_han.json +++ b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_civil_service_han.json @@ -1,6 +1,5 @@ { "genericName": "Civil Service", - "top": "civil_service_01", - "bottom": "civil_service_02", + "pair": ["civil_service_01", "civil_service_02"], "requirements": { "civ": "han" } } diff --git a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_cult_ptol.json b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_cult_ptol.json index e8b64011d5..71627bed91 100644 --- a/binaries/data/mods/public/simulation/data/technologies/pair_unlock_cult_ptol.json +++ b/binaries/data/mods/public/simulation/data/technologies/pair_unlock_cult_ptol.json @@ -1,6 +1,5 @@ { "genericName": "Cult", - "top": "pharaonic_cult", - "bottom": "serapis_cult", + "pair": ["pharaonic_cult", "serapis_cult"], "requirements": { "civ": "ptol" } } diff --git a/binaries/data/mods/public/simulation/data/technologies/pharaonic_cult.json b/binaries/data/mods/public/simulation/data/technologies/pharaonic_cult.json index ba75821f53..7e9839b604 100644 --- a/binaries/data/mods/public/simulation/data/technologies/pharaonic_cult.json +++ b/binaries/data/mods/public/simulation/data/technologies/pharaonic_cult.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_cult_ptol", + "partOfPair": "pair_unlock_cult_ptol", "genericName": "Pharaonic Cult", "description": "The Pharaohs were worshipped as living gods. Their word was sacrosanct and beyond reproach, at least among the common people. The Ptolemaic dynasts certainly took advantage of this ancient custom to the fullest, to varying degrees of success.", "cost": { diff --git a/binaries/data/mods/public/simulation/data/technologies/reformed_army_sele.json b/binaries/data/mods/public/simulation/data/technologies/reformed_army_sele.json index 2ab106cc34..e5d430bd0c 100644 --- a/binaries/data/mods/public/simulation/data/technologies/reformed_army_sele.json +++ b/binaries/data/mods/public/simulation/data/technologies/reformed_army_sele.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_champions_sele", + "partOfPair": "pair_unlock_champions_sele", "genericName": "Reform Army", "description": "The Roman-style core of the Seleucid army.", "requirements": { diff --git a/binaries/data/mods/public/simulation/data/technologies/serapis_cult.json b/binaries/data/mods/public/simulation/data/technologies/serapis_cult.json index d114df4733..a5e2cc196e 100644 --- a/binaries/data/mods/public/simulation/data/technologies/serapis_cult.json +++ b/binaries/data/mods/public/simulation/data/technologies/serapis_cult.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_cult_ptol", + "partOfPair": "pair_unlock_cult_ptol", "genericName": "Serapis Cult", "description": "The cult of Serapis was introduced during the 3rd century BC on the orders of Ptolemy I of Egypt as a means to unify the Greeks and Egyptians in his realm. The god was depicted as Greek in appearance, but with Egyptian trappings, and combined iconography from a great many cults, signifying both abundance and resurrection. A serapeion was any temple or religious precinct devoted to Serapis. The cult of Serapis was spread as a matter of deliberate policy by the Ptolemaic kings, who also built an immense serapeum in Alexandria.", "cost": { diff --git a/binaries/data/mods/public/simulation/data/technologies/traditional_army_sele.json b/binaries/data/mods/public/simulation/data/technologies/traditional_army_sele.json index 3888657012..7b20847e98 100644 --- a/binaries/data/mods/public/simulation/data/technologies/traditional_army_sele.json +++ b/binaries/data/mods/public/simulation/data/technologies/traditional_army_sele.json @@ -1,5 +1,5 @@ { - "pair": "pair_unlock_champions_sele", + "partOfPair": "pair_unlock_champions_sele", "genericName": "Traditional Army", "description": "The Macedonian-style core of the Seleucid army.", "requirements": { diff --git a/binaries/data/mods/public/simulation/helpers/Cheat.js b/binaries/data/mods/public/simulation/helpers/Cheat.js index 598c2f95a3..eb12000daf 100644 --- a/binaries/data/mods/public/simulation/helpers/Cheat.js +++ b/binaries/data/mods/public/simulation/helpers/Cheat.js @@ -151,7 +151,6 @@ function Cheat(input) // try to spilt the input const tmp = input.parameter.split(/\s+/); const number = +tmp[0]; - const pair = tmp.length > 1 && (tmp[1] == "top" || tmp[1] == "bottom") ? tmp[1] : "top"; // use top as default value // check, if valid number was parsed. if (!isNaN(number)) @@ -166,7 +165,7 @@ function Cheat(input) // get name of tech if (tech.pair) - techname = tech[pair]; + techname = tech.pair[tmp[1] === "1" ? 1 : 0]; else techname = tech; }