0ad/binaries/data/mods/public/gui/structree/load.js

334 lines
7.4 KiB
JavaScript
Raw Normal View History

/**
* Calculates gather rates.
*
* All available rates that have a value greater than 0 are summed and averaged
*/
function getGatherRates(templateName)
{
// TODO: It would be nice to use the gather rates present in the templates
// instead of hard-coding the possible rates here.
// We ignore ruins here, as those are not that common and would skew the results
var types = {
"food": ["food", "food.fish", "food.fruit", "food.grain", "food.meat", "food.milk"],
"wood": ["wood", "wood.tree"],
"stone": ["stone", "stone.rock"],
"metal": ["metal", "metal.ore"]
};
var rates = {};
for (let type in types)
{
let count, rate;
[rate, count] = types[type].reduce(function(sum, t) {
let r = +fetchValue(templateName, "ResourceGatherer/Rates/"+t);
return [sum[0] + (r > 0 ? r : 0), sum[1] + (r > 0 ? 1 : 0)];
}, [0, 0]);
if (rate > 0)
rates[type] = Math.round(rate / count * 100) / 100;
}
if (!Object.keys(rates).length)
return null;
return rates;
}
function loadUnit(templateName)
{
var template = loadTemplate(templateName);
var unit = GetTemplateDataHelper(template);
unit.phase = false;
if (unit.requiredTechnology)
{
if (unit.requiredTechnology.slice(0, 5) == "phase")
unit.phase = unit.requiredTechnology;
else if (unit.requiredTechnology.length)
unit.required = unit.requiredTechnology;
}
unit.gather = getGatherRates(templateName);
if (template.Heal)
unit.healer = {
"Range": +template.Heal.Range || 0,
"HP": +template.Heal.HP || 0,
"Rate": +template.Heal.Rate || 0
};
if (template.Builder && template.Builder.Entities._string)
for (let build of template.Builder.Entities._string.split(" "))
{
build = build.replace("{civ}", g_SelectedCiv);
if (g_Lists.structures.indexOf(build) < 0)
g_Lists.structures.push(build);
}
return unit;
}
function loadStructure(templateName)
{
var template = loadTemplate(templateName);
var structure = GetTemplateDataHelper(template);
structure.phase = false;
if (structure.requiredTechnology)
{
if (structure.requiredTechnology.slice(0, 5) == "phase")
structure.phase = structure.requiredTechnology;
else if (structure.requiredTechnology.length)
structure.required = structure.requiredTechnology;
}
structure.production = {
"technology": [],
"units": []
};
if (template.ProductionQueue)
{
if (template.ProductionQueue.Entities && template.ProductionQueue.Entities._string)
for (let build of template.ProductionQueue.Entities._string.split(" "))
{
build = build.replace("{civ}", g_SelectedCiv);
structure.production.units.push(build);
if (g_Lists.units.indexOf(build) < 0)
g_Lists.units.push(build);
}
if (template.ProductionQueue.Technologies && template.ProductionQueue.Technologies._string)
for (let research of template.ProductionQueue.Technologies._string.split(" "))
{
structure.production.technology.push(research);
if (g_Lists.techs.indexOf(research) < 0)
g_Lists.techs.push(research);
}
}
if (structure.wallSet)
{
structure.wallset = {};
// Note: Assume wall segments of all lengths have the same armor
structure.armour = loadStructure(structure.wallSet.templates["long"]).armour;
let health;
for (let wSegm in structure.wallSet.templates)
{
let wPart = loadStructure(structure.wallSet.templates[wSegm]);
structure.wallset[wSegm] = wPart;
for (let research of wPart.production.technology)
structure.production.technology.push(research);
if (["gate", "tower"].indexOf(wSegm) != -1)
continue;
if (!health)
{
health = { "min": wPart.health, "max": wPart.health };
continue;
}
if (health.min > wPart.health)
health.min = wPart.health;
else if (health.max < wPart.health)
health.max = wPart.health;
}
if (health.min == health.max)
structure.health = health.min;
else
structure.health = sprintf(translate("%(val1)s to %(val2)s"), {
val1: health.min,
val2: health.max
});
}
return structure;
}
function loadTechnology(techName)
{
var template = loadTechData(techName);
var tech = GetTechnologyDataHelper(template, g_SelectedCiv);
tech.reqs = {};
if (template.pair !== undefined)
tech.pair = template.pair;
if (template.requirements !== undefined)
{
for (let op in template.requirements)
{
let val = template.requirements[op];
let req = calcReqs(op, val);
switch (op)
{
case "tech":
tech.reqs.generic = [ req ];
break;
case "civ":
tech.reqs[req] = [];
break;
case "any":
if (req[0].length > 0)
for (let r of req[0])
{
let v = req[0][r];
if (typeof r == "number")
tech.reqs[v] = [];
else
tech.reqs[r] = v;
}
if (req[1].length > 0)
tech.reqs.generic = req[1];
break;
case "all":
for (let r of req[0])
tech.reqs[r] = req[1];
break;
}
}
}
if (template.supersedes !== undefined)
{
if (tech.reqs.generic !== undefined)
tech.reqs.generic.push(template.supersedes);
else
for (let ck of Object.keys(tech.reqs))
tech.reqs[ck].push(template.supersedes);
}
return tech;
}
function loadPhase(phaseCode)
{
var template = loadTechData(phaseCode);
var phase = GetTechnologyDataHelper(template, g_SelectedCiv);
phase.actualPhase = "";
return phase;
}
function loadTechnologyPair(pairCode)
{
var pairInfo = loadTechData(pairCode);
return {
"techs": [ pairInfo.top, pairInfo.bottom ],
"req": (pairInfo.supersedes !== undefined) ? pairInfo.supersedes : ""
};
}
/**
* Calculate the prerequisite requirements of a technology.
* Works recursively if needed.
*
* @param op The base operation. Can be "civ", "tech", "all" or "any".
* @param val The value associated with the above operation.
*
* @return Sorted requirments.
*/
function calcReqs(op, val)
{
switch (op)
{
case "civ":
case "tech":
// nothing needs doing
break;
case "all":
case "any":
let t = [];
let c = [];
for (let nv of val)
{
for (let o in nv)
{
let v = nv[o];
let r = calcReqs(o, v);
switch (o)
{
case "civ":
c.push(r);
break;
case "tech":
t.push(r);
break;
case "any":
c = c.concat(r[0]);
t = t.concat(r[1]);
break;
case "all":
for (let ci in r[0])
c[ci] = r[1];
t = t;
}
}
}
return [ c, t ];
default:
warn("Unknown reqs operator: "+op);
}
return val;
}
/**
* Unravel phases
*
* @param techs The current available store of techs
*
* @return List of phases
*/
function unravelPhases(techs)
{
var phaseList = [];
for (let techcode in techs)
{
let techdata = techs[techcode];
if (!("generic" in techdata.reqs) || techdata.reqs.generic.length < 2)
continue;
let reqTech = techs[techcode].reqs.generic[1];
// Tech that can't be researched anywhere
if (!(reqTech in techs))
continue;
if (!("generic" in techs[reqTech].reqs))
continue;
let reqPhase = techs[reqTech].reqs.generic[0];
let myPhase = techs[techcode].reqs.generic[0];
if (reqPhase == myPhase || depath(reqPhase).slice(0,5) !== "phase" || depath(myPhase).slice(0,5) !== "phase")
continue;
let reqPhasePos = phaseList.indexOf(reqPhase);
let myPhasePos = phaseList.indexOf(myPhase);
if (phaseList.length === 0)
phaseList = [reqPhase, myPhase];
else if (reqPhasePos < 0 && myPhasePos > -1)
phaseList.splice(myPhasePos, 0, reqPhase);
else if (myPhasePos < 0 && reqPhasePos > -1)
phaseList.splice(reqPhasePos+1, 0, myPhase);
}
return phaseList;
}