Index: ps/trunk/binaries/data/mods/public/gui/reference/common/core.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/core.js +++ ps/trunk/binaries/data/mods/public/gui/reference/common/core.js @@ -121,8 +121,16 @@ if (template.ProductionQueue.Technologies) for (let research of template.ProductionQueue.Technologies._string.split(" ")) + { + if (research.indexOf("{civ}") != -1) + { + let civResearch = research.replace("{civ}", g_SelectedCiv); + research = techDataExists(civResearch) ? + civResearch : research.replace("{civ}", "generic"); + } if (templateLists.techs.indexOf(research) === -1) templateLists.techs.push(research); + } } return templateLists; @@ -157,8 +165,16 @@ if (template.ProductionQueue.Technologies && template.ProductionQueue.Technologies._string) for (let research of template.ProductionQueue.Technologies._string.split(" ")) + { + if (research.indexOf("{civ}") != -1) + { + let civResearch = research.replace("{civ}", g_SelectedCiv); + research = techDataExists(civResearch) ? + civResearch : research.replace("{civ}", "generic"); + } if (templateLists.techs.indexOf(research) === -1) templateLists.techs.push(research); + } } if (template.WallSet) Index: ps/trunk/binaries/data/mods/public/gui/reference/common/load.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/load.js +++ ps/trunk/binaries/data/mods/public/gui/reference/common/load.js @@ -69,6 +69,11 @@ return g_TechnologyData[templateName]; } +function techDataExists(templateName) +{ + return Engine.FileExists("simulation/data/technologies/" + templateName + ".json"); +} + /** * Loads raw aura template. * @@ -121,11 +126,19 @@ { unit.production.techs = []; for (let research of template.ProductionQueue.Technologies._string.split(" ")) + { + if (research.indexOf("{civ}") != -1) + { + let civResearch = research.replace("{civ}", g_SelectedCiv); + research = techDataExists(civResearch) ? + civResearch : research.replace("{civ}", "generic"); + } if (isPairTech(research)) for (let tech of loadTechnologyPair(research).techs) unit.production.techs.push(tech); else unit.production.techs.push(research); + } } } @@ -177,11 +190,19 @@ if (template.ProductionQueue.Technologies && template.ProductionQueue.Technologies._string) for (let research of template.ProductionQueue.Technologies._string.split(" ")) + { + if (research.indexOf("{civ}") != -1) + { + let civResearch = research.replace("{civ}", g_SelectedCiv); + research = techDataExists(civResearch) ? + civResearch : research.replace("{civ}", "generic"); + } if (isPairTech(research)) for (let tech of loadTechnologyPair(research).techs) structure.production.technology.push(tech); else structure.production.technology.push(research); + } } if (structure.upgrades) Index: ps/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js @@ -338,13 +338,21 @@ return templates.split(/\s+/); }, - "researchableTechs": function(civ) { + "researchableTechs": function(gameState, civ) { let templates = this.get("ProductionQueue/Technologies/_string"); if (!templates) return undefined; - if (civ) - templates = templates.replace(/\{civ\}/g, civ); - return templates.split(/\s+/); + let techs = templates.split(/\s+/); + for (let i = 0; i < techs.length; ++i) + { + let tech = techs[i]; + if (tech.indexOf("{civ}") == -1) + continue; + let civTech = tech.replace("{civ}", civ); + techs[i] = gameState.techTemplates[civTech] ? + civTech : tech.replace("{civ}", "generic"); + } + return techs; }, "resourceSupplyType": function() { Index: ps/trunk/binaries/data/mods/public/simulation/ai/common-api/filters.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/common-api/filters.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/common-api/filters.js @@ -109,9 +109,9 @@ "dynamicProperties": ['trainingQueue']}; }, - "byResearchAvailable": function(civ){ + "byResearchAvailable": function(gameState, civ){ return {"func" : function(ent){ - return ent.researchableTechs(civ) !== undefined; + return ent.researchableTechs(gameState, civ) !== undefined; }, "dynamicProperties": []}; }, Index: ps/trunk/binaries/data/mods/public/simulation/ai/common-api/gamestate.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/common-api/gamestate.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/common-api/gamestate.js @@ -31,7 +31,7 @@ if (!cctemplate) return; let civ = this.getPlayerCiv(); - let techs = cctemplate.researchableTechs(civ); + let techs = cctemplate.researchableTechs(this, civ); for (let phase of this.phases) { phase.requirements = []; @@ -586,7 +586,7 @@ m.GameState.prototype.getOwnResearchFacilities = function() { - return this.updatingGlobalCollection("player-" + this.player + "-research-facilities", m.Filters.byResearchAvailable(this.playerData.civ), this.getOwnEntities()); + return this.updatingGlobalCollection("player-" + this.player + "-research-facilities", m.Filters.byResearchAvailable(this, this.playerData.civ), this.getOwnEntities()); }; @@ -748,7 +748,7 @@ let civ = this.playerData.civ; for (let ent of this.getOwnEntities().values()) { - let searchable = ent.researchableTechs(civ); + let searchable = ent.researchableTechs(this, civ); if (!searchable) continue; for (let tech of searchable) @@ -831,7 +831,7 @@ for (let ent of this.getOwnResearchFacilities().values()) { - let techs = ent.researchableTechs(civ); + let techs = ent.researchableTechs(this, civ); for (let tech of techs) { let temp = this.getTemplate(tech); @@ -860,7 +860,7 @@ let civ = this.playerData.civ; return this.getOwnResearchFacilities().filter(function(ent) { - let techs = ent.researchableTechs(civ); + let techs = ent.researchableTechs(self, civ); for (let tech of techs) { let thisTemp = self.getTemplate(tech); Index: ps/trunk/binaries/data/mods/public/simulation/components/DataTemplateManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/DataTemplateManager.js +++ ps/trunk/binaries/data/mods/public/simulation/components/DataTemplateManager.js @@ -60,4 +60,9 @@ return this.allTechs; }; +DataTemplateManager.prototype.TechFileExists = function(template) +{ + return Engine.DataFileExists("technologies/" + template + ".json"); +}; + Engine.RegisterSystemComponentType(IID_DataTemplateManager, "DataTemplateManager", DataTemplateManager); Index: ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js +++ ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js @@ -23,7 +23,7 @@ "" + "" + "" + - "" + + "" + "" + "tokens" + "" + @@ -160,6 +160,18 @@ var techs = string.split(/\s+/); + // Replace the civ specific technologies + let cmpDataTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_DataTemplateManager); + for (let i = 0; i < techs.length; ++i) + { + let tech = techs[i]; + if (tech.indexOf("{civ}") == -1) + continue; + let civTech = tech.replace("{civ}", cmpPlayer.GetCiv()); + techs[i] = cmpDataTemplateManager.TechFileExists(civTech) ? + civTech : tech.replace("{civ}", "generic"); + } + // Remove any technologies that can't be researched by this civ techs = techs.filter(tech => { let reqs = DeriveTechnologyRequirements(cmpTechnologyManager.GetTechnologyTemplate(tech), cmpPlayer.GetCiv()); Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city.json @@ -1,21 +1,5 @@ { "genericName": "City Phase", - "specificName": { - "mace": "Megalópolis", - "spart": "Megalópolis" - }, - "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology.", - "cost": { "food": 0, "wood": 0, "stone": 750, "metal": 750 }, - "requirements": { "all": [{ "entity": { "class": "Town", "number": 4 } }, { "notciv": "athen" }] }, - "requirementsTooltip": "Requires 4 new Town Phase structures (except Walls and Civic Centers).", - "supersedes": "phase_town", - "icon": "city_phase.png", - "researchTime": 60, - "tooltip": "Advance to City Phase, which unlocks more structures and units. Territory radius for Civic Centers increased by another +50%. Citizen soldiers max health increased by +10%. All structures +9 garrisoned regeneration rate.", - "modifications": [ - { "value": "TerritoryInfluence/Radius", "multiply": 1.50, "affects": "CivCentre" }, - { "value": "Health/Max", "multiply": 1.1, "affects": "CitizenSoldier" }, - { "value": "Capturable/GarrisonRegenRate", "add": 9.0, "affects": "Structure" } - ], - "soundComplete": "interface/alarm/alarm_phase.xml" + "description": "Dummy technology for use in templates requirements, replaced by phase_city_generic or phase_city_{civ}.", + "icon": "city_phase.png" } Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city_athen.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city_athen.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city_athen.json @@ -5,7 +5,7 @@ }, "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology. This is the Athenian city phase, where metal gathering rates are boosted because of the 'Silver Owls' bonus.", "cost": { "food": 0, "wood": 0, "stone": 750, "metal": 750 }, - "requirements": { "all": [{ "entity": { "class": "Town", "number": 4 } }, { "civ": "athen" }] }, + "requirements": { "entity": { "class": "Town", "number": 4 } }, "requirementsTooltip": "Requires 4 new Town Phase structures (except Walls and Civic Centers).", "supersedes": "phase_town_athen", "replaces": ["phase_city"], Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city_generic.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city_generic.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_city_generic.json @@ -0,0 +1,22 @@ +{ + "genericName": "City Phase", + "specificName": { + "mace": "Megalópolis", + "spart": "Megalópolis" + }, + "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology.", + "cost": { "food": 0, "wood": 0, "stone": 750, "metal": 750 }, + "requirements": { "entity": { "class": "Town", "number": 4 } }, + "requirementsTooltip": "Requires 4 new Town Phase structures (except Walls and Civic Centers).", + "supersedes": "phase_town_generic", + "replaces": ["phase_city"], + "icon": "city_phase.png", + "researchTime": 60, + "tooltip": "Advance to City Phase, which unlocks more structures and units. Territory radius for Civic Centers increased by another +50%. Citizen soldiers max health increased by +10%. All structures +9 garrisoned regeneration rate.", + "modifications": [ + { "value": "TerritoryInfluence/Radius", "multiply": 1.50, "affects": "CivCentre" }, + { "value": "Health/Max", "multiply": 1.1, "affects": "CitizenSoldier" }, + { "value": "Capturable/GarrisonRegenRate", "add": 9.0, "affects": "Structure" } + ], + "soundComplete": "interface/alarm/alarm_phase.xml" +} Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town.json @@ -1,21 +1,5 @@ { "genericName": "Town Phase", - "specificName": { - "mace": "Kōmópolis", - "spart": "Kōmópolis" - }, - "description": "Advances from a small village to a bustling town, ready to expand rapidly.", - "cost": { "food": 500, "wood": 500, "stone": 0, "metal": 0 }, - "requirements": { "all": [{ "entity": { "class": "Village", "number": 5 } }, { "notciv": "athen" }] }, - "requirementsTooltip": "Requires 5 Village Phase structures (except Palisades and Farm Fields).", - "supersedes": "phase_village", - "icon": "town_phase.png", - "researchTime": 30, - "tooltip": "Advance to Town Phase, which unlocks more structures and units. Territory radius for Civic Centers increased by +30%. Citizen soldiers max health increased by +20%. All structures +7 garrisoned regeneration rate.", - "modifications": [ - { "value": "TerritoryInfluence/Radius", "multiply": 1.30, "affects": "CivCentre" }, - { "value": "Health/Max", "multiply": 1.2, "affects": "CitizenSoldier" }, - { "value": "Capturable/GarrisonRegenRate", "add": 7.0, "affects": "Structure" } - ], - "soundComplete": "interface/alarm/alarm_phase.xml" + "description": "Dummy technology for use in templates requirements, replaced by phase_town_generic or phase_town_{civ}.", + "icon": "town_phase.png" } Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town_athen.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town_athen.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town_athen.json @@ -5,7 +5,7 @@ }, "description": "Advances from a small village to a bustling town, ready to expand rapidly. This is the Athenian town phase, where metal gathering rates are boosted because of the 'Silver Owls' bonus.", "cost": { "food": 500, "wood": 500, "stone": 0, "metal": 0 }, - "requirements": { "all": [{ "entity": { "class": "Village", "number": 5 } }, { "civ": "athen" }] }, + "requirements": { "entity": { "class": "Village", "number": 5 } }, "requirementsTooltip": "Requires 5 Village Phase structures (except Palisades and Farm Fields).", "supersedes": "phase_village", "replaces": ["phase_town"], Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town_generic.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town_generic.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/phase_town_generic.json @@ -0,0 +1,22 @@ +{ + "genericName": "Town Phase", + "specificName": { + "mace": "Kōmópolis", + "spart": "Kōmópolis" + }, + "description": "Advances from a small village to a bustling town, ready to expand rapidly.", + "cost": { "food": 500, "wood": 500, "stone": 0, "metal": 0 }, + "requirements": { "entity": { "class": "Village", "number": 5 } }, + "requirementsTooltip": "Requires 5 Village Phase structures (except Palisades and Farm Fields).", + "supersedes": "phase_village", + "replaces": ["phase_town"], + "icon": "town_phase.png", + "researchTime": 30, + "tooltip": "Advance to Town Phase, which unlocks more structures and units. Territory radius for Civic Centers increased by +30%. Citizen soldiers max health increased by +20%. All structures +7 garrisoned regeneration rate.", + "modifications": [ + { "value": "TerritoryInfluence/Radius", "multiply": 1.30, "affects": "CivCentre" }, + { "value": "Health/Max", "multiply": 1.2, "affects": "CitizenSoldier" }, + { "value": "Capturable/GarrisonRegenRate", "add": 7.0, "affects": "Structure" } + ], + "soundComplete": "interface/alarm/alarm_phase.xml" +} Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml @@ -35,8 +35,7 @@ units/{civ}_ship_trireme - -phase_town - -phase_town_athen + -phase_town_{civ} Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml @@ -94,10 +94,8 @@ units/{civ}_support_female_citizen - phase_town - phase_town_athen - phase_city - phase_city_athen + phase_town_{civ} + phase_city_{civ} unlock_spies spy_counter Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml @@ -41,10 +41,8 @@ - -phase_town - -phase_town_athen - -phase_city - -phase_city_athen + -phase_town_{civ} + -phase_city_{civ} upgrade_rank_advanced_mercenary Index: ps/trunk/source/simulation2/system/ComponentManager.h =================================================================== --- ps/trunk/source/simulation2/system/ComponentManager.h +++ ps/trunk/source/simulation2/system/ComponentManager.h @@ -332,6 +332,7 @@ static int Script_AddLocalEntity(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName); static void Script_DestroyEntity(ScriptInterface::CxPrivate* pCxPrivate, int ent); static void Script_FlushDestroyedEntities(ScriptInterface::CxPrivate* pCxPrivate); + static bool Script_DataFileExists(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName); static JS::Value Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName); static JS::Value Script_ReadCivJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName); static std::vector Script_FindJSONFiles(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& subPath, bool recursive); Index: ps/trunk/source/simulation2/system/ComponentManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/ComponentManager.cpp +++ ps/trunk/source/simulation2/system/ComponentManager.cpp @@ -83,6 +83,7 @@ m_ScriptInterface.RegisterFunction ("AddLocalEntity"); m_ScriptInterface.RegisterFunction ("DestroyEntity"); m_ScriptInterface.RegisterFunction ("FlushDestroyedEntities"); + m_ScriptInterface.RegisterFunction ("DataFileExists"); m_ScriptInterface.RegisterFunction ("ReadJSONFile"); m_ScriptInterface.RegisterFunction ("ReadCivJSONFile"); m_ScriptInterface.RegisterFunction, std::wstring, bool, CComponentManager::Script_FindJSONFiles> ("FindJSONFiles"); @@ -1185,6 +1186,12 @@ return schema; } +bool CComponentManager::Script_DataFileExists(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& fileName) +{ + VfsPath path = VfsPath(L"simulation/data") / fileName; + return VfsFileExists(path); +} + JS::Value CComponentManager::Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName) { return ReadJSONFile(pCxPrivate, L"simulation/data", fileName);