1
1
forked from 0ad/0ad

Allow civ specific techs with {civ}

Discussed with leper

Reviewed By: bb
Trac Tickets: #4589

Differential Revision: https://code.wildfiregames.com/D1024
This was SVN commit r20551.
This commit is contained in:
mimo 2017-11-28 20:43:00 +00:00
parent 752005c4a4
commit 8de5c26540
18 changed files with 137 additions and 60 deletions

View File

@ -121,8 +121,16 @@ function getTemplateListsFromUnit(templateName)
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 @@ function getTemplateListsFromStructure(templateName)
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)

View File

@ -69,6 +69,11 @@ function loadTechData(templateName)
return g_TechnologyData[templateName];
}
function techDataExists(templateName)
{
return Engine.FileExists("simulation/data/technologies/" + templateName + ".json");
}
/**
* Loads raw aura template.
*
@ -121,11 +126,19 @@ function loadUnit(templateName)
{
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 @@ function loadStructure(templateName)
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)

View File

@ -338,13 +338,21 @@ m.Template = m.Class({
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() {

View File

@ -109,9 +109,9 @@ m.Filters = {
"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": []};
},

View File

@ -31,7 +31,7 @@ m.GameState.prototype.init = function(SharedScript, state, player) {
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.getOwnTrainingFacilities = function()
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 @@ m.GameState.prototype.findAvailableTech = function()
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 @@ m.GameState.prototype.hasResearchers = function(templateName, noRequirementCheck
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 @@ m.GameState.prototype.findResearchers = function(templateName, noRequirementChec
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);

View File

@ -60,4 +60,9 @@ DataTemplateManager.prototype.GetAllTechs = function()
return this.allTechs;
};
DataTemplateManager.prototype.TechFileExists = function(template)
{
return Engine.DataFileExists("technologies/" + template + ".json");
};
Engine.RegisterSystemComponentType(IID_DataTemplateManager, "DataTemplateManager", DataTemplateManager);

View File

@ -23,7 +23,7 @@ ProductionQueue.prototype.Schema =
"</element>" +
"</optional>" +
"<optional>" +
"<element name='Technologies' a:help='Space-separated list of technology names that this building can research.'>" +
"<element name='Technologies' a:help='Space-separated list of technology names that this building can research. When present, the special string \"{civ}\" will be automatically replaced either by the civ code of the building&apos;s owner if such a tech exists, or by \"generic\".'>" +
"<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
@ -160,6 +160,18 @@ ProductionQueue.prototype.GetTechnologiesList = function()
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());

View File

@ -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"
}

View File

@ -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"],

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"],

View File

@ -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"
}

View File

@ -35,8 +35,7 @@
units/{civ}_ship_trireme
</Entities>
<Technologies datatype="tokens">
-phase_town
-phase_town_athen
-phase_town_{civ}
</Technologies>
</ProductionQueue>
<RallyPointRenderer>

View File

@ -94,10 +94,8 @@
units/{civ}_support_female_citizen
</Entities>
<Technologies datatype="tokens">
phase_town
phase_town_athen
phase_city
phase_city_athen
phase_town_{civ}
phase_city_{civ}
unlock_spies
spy_counter
</Technologies>

View File

@ -41,10 +41,8 @@
</Obstruction>
<ProductionQueue>
<Technologies datatype="tokens">
-phase_town
-phase_town_athen
-phase_city
-phase_city_athen
-phase_town_{civ}
-phase_city_{civ}
upgrade_rank_advanced_mercenary
</Technologies>
</ProductionQueue>

View File

@ -83,6 +83,7 @@ CComponentManager::CComponentManager(CSimContext& context, shared_ptr<ScriptRunt
m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddLocalEntity> ("AddLocalEntity");
m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity");
m_ScriptInterface.RegisterFunction<void, CComponentManager::Script_FlushDestroyedEntities> ("FlushDestroyedEntities");
m_ScriptInterface.RegisterFunction<bool, std::wstring, CComponentManager::Script_DataFileExists> ("DataFileExists");
m_ScriptInterface.RegisterFunction<JS::Value, std::wstring, CComponentManager::Script_ReadJSONFile> ("ReadJSONFile");
m_ScriptInterface.RegisterFunction<JS::Value, std::wstring, CComponentManager::Script_ReadCivJSONFile> ("ReadCivJSONFile");
m_ScriptInterface.RegisterFunction<std::vector<std::string>, std::wstring, bool, CComponentManager::Script_FindJSONFiles> ("FindJSONFiles");
@ -1185,6 +1186,12 @@ std::string CComponentManager::GenerateSchema() const
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);

View File

@ -332,6 +332,7 @@ private:
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<std::string> Script_FindJSONFiles(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& subPath, bool recursive);