forked from 0ad/0ad
Import s0600204's structree.
Taken from https://github.com/s0600204/0ad-structree-mod with some improvements from my fork. On small resolutions some buildings might not be fully visible (see #3038). This was SVN commit r16276.
This commit is contained in:
parent
f6903393bd
commit
932dbc7221
17
binaries/data/mods/public/gui/page_structree.xml
Normal file
17
binaries/data/mods/public/gui/page_structree.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<page>
|
||||
<include>common/modern/setup.xml</include>
|
||||
<include>common/modern/styles.xml</include>
|
||||
<include>common/modern/sprites.xml</include>
|
||||
|
||||
<include>common/setup_resources.xml</include>
|
||||
<include>common/sprite1.xml</include>
|
||||
<include>common/styles.xml</include>
|
||||
<include>common/common_sprites.xml</include>
|
||||
<include>common/common_styles.xml</include>
|
||||
|
||||
<include>structree/styles.xml</include>
|
||||
<include>structree/sprites.xml</include>
|
||||
<include>structree/structree.xml</include>
|
||||
<include>structree/setup.xml</include>
|
||||
</page>
|
@ -139,6 +139,66 @@
|
||||
size="60 50%-100 300 50%+100"
|
||||
hidden="true"
|
||||
>
|
||||
<!-- submenuSinglePlayer -->
|
||||
<object name="submenuLearn"
|
||||
type="image"
|
||||
size="0 4 100%-4 100%-4"
|
||||
tooltip_style="pgToolTip"
|
||||
hidden="true"
|
||||
>
|
||||
<!-- LEARN TO PLAY BUTTON -->
|
||||
<object name="menuManualButton"
|
||||
type="button"
|
||||
style="StoneButtonFancy"
|
||||
size="0 0 100% 28"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Manual</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Open the 0 A.D. Game Manual.</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
<![CDATA[
|
||||
Engine.PushGuiPage("page_manual.xml", {"page":"manual/intro", "title":getManual(), "url":"http://trac.wildfiregames.com/wiki/0adManual"});
|
||||
]]>
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- STRUCTREE BUTTON -->
|
||||
<object name="menuStrucTreeButton"
|
||||
style="StoneButtonFancy"
|
||||
type="button"
|
||||
size="0 32 100% 60"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Structure Tree</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">View the structure tree of civilizations featured in 0 A.D.</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
<![CDATA[
|
||||
Engine.PushGuiPage("page_structree.xml");
|
||||
]]>
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- HISTORY BUTTON -->
|
||||
<object name="menuHistoryButton"
|
||||
style="StoneButtonFancy"
|
||||
type="button"
|
||||
size="0 64 100% 92"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">History</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Learn about the many civilizations featured in 0 A.D.</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
<![CDATA[
|
||||
Engine.PushGuiPage("page_civinfo.xml");
|
||||
]]>
|
||||
</action>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
||||
<!-- submenuSinglePlayer -->
|
||||
<object name="submenuSinglePlayer"
|
||||
type="image"
|
||||
@ -374,20 +434,19 @@
|
||||
size="8 156 100%-8 356"
|
||||
ghost="false"
|
||||
>
|
||||
<!-- LEARN TO PLAY BUTTON -->
|
||||
|
||||
<!-- LEARN BUTTON -->
|
||||
<object name="menuLearnToPlayButton"
|
||||
type="button"
|
||||
style="StoneButtonFancy"
|
||||
type="button"
|
||||
size="4 4 100%-4 32"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Learn To Play</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Open the 0 A.D. Game Manual.</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Learn how to play, discover the technology trees, and the history behind the civilizations</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
<![CDATA[
|
||||
Engine.PushGuiPage("page_manual.xml", {"page":"manual/intro", "title":getManual(), "url":"http://trac.wildfiregames.com/wiki/0adManual"});
|
||||
]]>
|
||||
openMenu("submenuLearn", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 3);
|
||||
</action>
|
||||
</object>
|
||||
|
||||
@ -436,28 +495,11 @@
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- HISTORY BUTTON -->
|
||||
<object name="menuHistoryButton"
|
||||
style="StoneButtonFancy"
|
||||
type="button"
|
||||
size="4 132 100%-4 160"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">History</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Learn about the many civilizations featured in 0 A.D.</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
<![CDATA[
|
||||
Engine.PushGuiPage("page_civinfo.xml");
|
||||
]]>
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- EXIT BUTTON -->
|
||||
<object name="menuExitButton"
|
||||
type="button"
|
||||
style="StoneButtonFancy"
|
||||
size="4 164 100%-4 192"
|
||||
size="4 132 100%-4 160"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Exit</translatableAttribute>
|
||||
|
298
binaries/data/mods/public/gui/structree/draw.js
Normal file
298
binaries/data/mods/public/gui/structree/draw.js
Normal file
@ -0,0 +1,298 @@
|
||||
var g_DrawLimits = {}; // GUI limits. Populated by predraw()
|
||||
|
||||
/**
|
||||
* Draw the structree
|
||||
*
|
||||
* (Actually resizes and changes visibility of elements, and populates text)
|
||||
*/
|
||||
function draw()
|
||||
{
|
||||
// Set basic state (positioning of elements mainly), but only once
|
||||
if (!Object.keys(g_DrawLimits).length)
|
||||
predraw();
|
||||
|
||||
var defWidth = 96;
|
||||
var defMargin = 4;
|
||||
var phaseList = g_ParsedData.phaseList;
|
||||
|
||||
Engine.GetGUIObjectByName("civEmblem").sprite = "stretched:"+g_CivData[g_SelectedCiv].Emblem;
|
||||
Engine.GetGUIObjectByName("civName").caption = g_CivData[g_SelectedCiv].Name;
|
||||
Engine.GetGUIObjectByName("civHistory").caption = g_CivData[g_SelectedCiv].History;
|
||||
|
||||
let i = 0;
|
||||
for (let pha of phaseList)
|
||||
{
|
||||
let s = 0;
|
||||
let y = 0;
|
||||
|
||||
for (let stru of g_CivData[g_SelectedCiv].buildList[pha])
|
||||
{
|
||||
let thisEle = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]");
|
||||
if (thisEle === undefined)
|
||||
{
|
||||
error("\""+g_SelectedCiv+"\" has more structures in phase "+pha+" than can be supported by the current GUI layout");
|
||||
break;
|
||||
}
|
||||
|
||||
let c = 0;
|
||||
let rowCounts = [];
|
||||
stru = g_ParsedData.structures[stru];
|
||||
Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_icon").sprite = "stretched:session/portraits/"+stru.icon;
|
||||
Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_icon").tooltip = assembleTooltip(stru);
|
||||
Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_name").caption = translate(stru.name.specific);
|
||||
thisEle.hidden = false;
|
||||
|
||||
for (let r in g_DrawLimits[pha].prodQuant)
|
||||
{
|
||||
let p = 0;
|
||||
r = +r; // force int
|
||||
let prod_pha = phaseList[phaseList.indexOf(pha) + r];
|
||||
if (stru.production.units[prod_pha])
|
||||
{
|
||||
for (let prod of stru.production.units[prod_pha])
|
||||
{
|
||||
prod = g_ParsedData.units[prod];
|
||||
if (!drawProdIcon(i, s, r, p, prod))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (stru.wallset && prod_pha == pha)
|
||||
{
|
||||
for (let prod of [stru.wallset.gate, stru.wallset.tower])
|
||||
{
|
||||
if (!drawProdIcon(i, s, r, p, prod))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (stru.production.technology[prod_pha])
|
||||
{
|
||||
for (let prod of stru.production.technology[prod_pha])
|
||||
{
|
||||
prod = (prod.slice(0,5) == "phase") ? g_ParsedData.phases[prod] : g_ParsedData.techs[prod];
|
||||
if (!drawProdIcon(i, s, r, p, prod))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
rowCounts[r] = p;
|
||||
if (p>c)
|
||||
c = p;
|
||||
hideRemaining("phase["+i+"]_struct["+s+"]_row["+r+"]_prod[", p, "]");
|
||||
}
|
||||
|
||||
let size = thisEle.size;
|
||||
size.left = y;
|
||||
size.right = size.left + ((c*24 < defWidth)?defWidth:c*24)+4;
|
||||
y = size.right + defMargin;
|
||||
thisEle.size = size;
|
||||
|
||||
let eleWidth = size.right - size.left;
|
||||
let r;
|
||||
for (r in rowCounts)
|
||||
{
|
||||
let wid = rowCounts[r] * 24 - 4;
|
||||
let phaEle = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_row["+r+"]");
|
||||
size = phaEle.size;
|
||||
size.left = (eleWidth - wid)/2;
|
||||
phaEle.size = size;
|
||||
}
|
||||
++r;
|
||||
hideRemaining("phase["+i+"]_struct["+s+"]_row[", r, "]");
|
||||
++s;
|
||||
}
|
||||
hideRemaining("phase["+i+"]_struct[", s, "]");
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
function drawProdIcon(pha, s, r, p, prod)
|
||||
{
|
||||
var prodEle = Engine.GetGUIObjectByName("phase["+pha+"]_struct["+s+"]_row["+r+"]_prod["+p+"]");
|
||||
if (prodEle === undefined)
|
||||
{
|
||||
error("The structures of \""+g_SelectedCiv+"\" have more production icons in phase "+pha+" than can be supported by the current GUI layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
prodEle.sprite = "stretched:session/portraits/"+prod.icon;
|
||||
prodEle.tooltip = assembleTooltip(prod);
|
||||
prodEle.hidden = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate row position offset (accounting for different number of prod rows per phase).
|
||||
*/
|
||||
function getPositionOffset(idx)
|
||||
{
|
||||
var phases = g_ParsedData.phaseList.length;
|
||||
|
||||
var size = 92*idx; // text, image and offset
|
||||
size += 24 * (phases*idx - (idx-1)*idx/2); // phase rows (phase-currphase+1 per row)
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
function hideRemaining(prefix, idx, suffix)
|
||||
{
|
||||
let obj = Engine.GetGUIObjectByName(prefix+idx+suffix);
|
||||
while (obj)
|
||||
{
|
||||
obj.hidden = true;
|
||||
++idx;
|
||||
obj = Engine.GetGUIObjectByName(prefix+idx+suffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Positions certain elements that only need to be positioned once
|
||||
* (as <repeat> does not reposition automatically).
|
||||
*
|
||||
* Also detects limits on what the GUI can display by iterating through the set
|
||||
* elements of the GUI. These limits are then used by draw().
|
||||
*/
|
||||
function predraw()
|
||||
{
|
||||
var phaseList = g_ParsedData.phaseList;
|
||||
var initIconSize = Engine.GetGUIObjectByName("phase[0]_struct[0]_row[0]_prod[0]").size;
|
||||
|
||||
let phaseCount = phaseList.length;
|
||||
let i = 0;
|
||||
for (let pha of phaseList)
|
||||
{
|
||||
let offset = getPositionOffset(i);
|
||||
// Align the phase row
|
||||
Engine.GetGUIObjectByName("phase["+i+"]").size = "8 16+"+offset+" 100% 100%";
|
||||
|
||||
// Set phase icon
|
||||
let phaseIcon = Engine.GetGUIObjectByName("phase["+i+"]_phase");
|
||||
phaseIcon.sprite = "stretched:session/portraits/"+g_ParsedData.phases[pha].icon;
|
||||
phaseIcon.size = "16 32+"+offset+" 48+16 48+32+"+offset;
|
||||
|
||||
// Position prod bars
|
||||
let j = 1;
|
||||
for (; j < phaseCount - i; ++j)
|
||||
{
|
||||
let prodBar = Engine.GetGUIObjectByName("phase["+i+"]_bar["+(j-1)+"]");
|
||||
prodBar.size = "40 1+"+(24*j)+"+98+"+offset+" 100%-8 1+"+(24*j)+"+98+"+offset+"+22";
|
||||
// Set phase icon
|
||||
let prodBarIcon = Engine.GetGUIObjectByName("phase["+i+"]_bar["+(j-1)+"]_icon");
|
||||
prodBarIcon.sprite = "stretched:session/portraits/"+g_ParsedData.phases[phaseList[i+j]].icon;
|
||||
}
|
||||
// Hide remaining prod bars
|
||||
hideRemaining("phase["+i+"]_bar[", j-1, "]");
|
||||
|
||||
let s = 0;
|
||||
let ele = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]");
|
||||
g_DrawLimits[pha] = {
|
||||
structQuant: 0,
|
||||
prodQuant: []
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
// Position production icons
|
||||
for (let r in phaseList.slice(phaseList.indexOf(pha)))
|
||||
{
|
||||
let p=1;
|
||||
let prodEle = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_row["+r+"]_prod["+p+"]");
|
||||
|
||||
do
|
||||
{
|
||||
let prodsize = prodEle.size;
|
||||
prodsize.left = (initIconSize.right+4) * p;
|
||||
prodsize.right = (initIconSize.right+4) * (p+1) - 4;
|
||||
prodEle.size = prodsize;
|
||||
|
||||
p++;
|
||||
prodEle = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_row["+r+"]_prod["+p+"]");
|
||||
} while (prodEle !== undefined);
|
||||
|
||||
// Set quantity of productions in this row
|
||||
g_DrawLimits[pha].prodQuant[r] = p;
|
||||
|
||||
// Position the prod row
|
||||
Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_row["+r+"]").size = "4 100%-"+24*(phaseCount - i - r)+" 100%-4 100%";
|
||||
}
|
||||
|
||||
// Hide unused struct rows
|
||||
for (let j = phaseCount - i; j < phaseCount; ++j)
|
||||
Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_row["+j+"]").hidden = true;
|
||||
|
||||
let size = ele.size;
|
||||
size.bottom += Object.keys(g_DrawLimits[pha].prodQuant).length*24;
|
||||
ele.size = size;
|
||||
|
||||
s++;
|
||||
ele = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]");
|
||||
} while (ele !== undefined);
|
||||
|
||||
// Set quantity of structures in each phase
|
||||
g_DrawLimits[pha].structQuant = s;
|
||||
++i;
|
||||
}
|
||||
hideRemaining("phase[", i, "]");
|
||||
hideRemaining("phase[", i, "]_bar");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble a tooltip text
|
||||
*
|
||||
* @param template Information about a Unit, a Structure or a Technology
|
||||
*
|
||||
* @return The tooltip text, formatted.
|
||||
*/
|
||||
function assembleTooltip(template)
|
||||
{
|
||||
var txt = getEntityNamesFormatted(template);
|
||||
txt += '\n' + getEntityCostTooltip(template, 1);
|
||||
|
||||
if (template.tooltip)
|
||||
txt += '\n' + txtFormats.body[0] + translate(template.tooltip) + txtFormats.body[1];
|
||||
|
||||
if (template.auras)
|
||||
for (let aura in template.auras)
|
||||
txt += '\n' + sprintf(translate("%(auralabel)s %(aurainfo)s"), {
|
||||
auralabel: txtFormats.header[0] + sprintf(translate("%(auraname)s:"), {
|
||||
auraname: translate(aura)
|
||||
}) + txtFormats.header[1],
|
||||
aurainfo: txtFormats.body[0] + translate(template.auras[aura]) + txtFormats.body[1]
|
||||
});
|
||||
|
||||
if (template.health)
|
||||
txt += '\n' + sprintf(translate("%(label)s %(details)s"), {
|
||||
label: txtFormats.header[0] + translate("Health:") + txtFormats.header[1],
|
||||
details: template.health
|
||||
});
|
||||
|
||||
if (template.healer)
|
||||
txt += '\n' + getHealerTooltip(template);
|
||||
|
||||
if (template.attack)
|
||||
txt += '\n' + getAttackTooltip(template);
|
||||
|
||||
if (template.armour)
|
||||
txt += '\n' + getArmorTooltip(template.armour);
|
||||
|
||||
txt += '\n' + getSpeedTooltip(template);
|
||||
|
||||
if (template.gather)
|
||||
{
|
||||
var rates = [];
|
||||
for (let type in template.gather)
|
||||
rates.push(sprintf(translate("%(resourceIcon)s %(rate)s"), {
|
||||
resourceIcon: getCostComponentDisplayName(type),
|
||||
rate: template.gather[type]
|
||||
}));
|
||||
|
||||
txt += '\n' + sprintf(translate("%(label)s %(details)s"), {
|
||||
label: txtFormats.header[0] + translate("Gather Rates:") + txtFormats.header[1],
|
||||
details: rates.join(" ")
|
||||
});
|
||||
}
|
||||
|
||||
return txt;
|
||||
}
|
89
binaries/data/mods/public/gui/structree/helper.js
Normal file
89
binaries/data/mods/public/gui/structree/helper.js
Normal file
@ -0,0 +1,89 @@
|
||||
var g_TemplateData = {};
|
||||
var g_TechnologyData = {};
|
||||
|
||||
function loadTemplate(templateName)
|
||||
{
|
||||
if (!(templateName in g_TemplateData))
|
||||
{
|
||||
// We need to clone the template because we want to perform some translations.
|
||||
var data = clone(Engine.GetTemplate(templateName));
|
||||
translateObjectKeys(data, ["GenericName", "Tooltip"]);
|
||||
|
||||
g_TemplateData[templateName] = data;
|
||||
}
|
||||
|
||||
return g_TemplateData[templateName];
|
||||
}
|
||||
|
||||
function loadTechData(templateName)
|
||||
{
|
||||
if (!(templateName in g_TechnologyData))
|
||||
{
|
||||
var filename = "simulation/data/technologies/" + templateName + ".json";
|
||||
var data = Engine.ReadJSONFile(filename);
|
||||
translateObjectKeys(data, ["genericName", "tooltip"]);
|
||||
|
||||
g_TechnologyData[templateName] = data;
|
||||
}
|
||||
|
||||
return g_TechnologyData[templateName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a value from an entity's template
|
||||
*
|
||||
* @param templateName The template to retreive the value from
|
||||
* @param keypath The path to the value to be fetched. "Identity/GenericName"
|
||||
* is equivalent to {"Identity":{"GenericName":"FOOBAR"}}
|
||||
*
|
||||
* @return The content requested at the key-path defined, or a blank array if
|
||||
* not found
|
||||
*/
|
||||
function fetchValue(templateName, keypath)
|
||||
{
|
||||
var keys = keypath.split("/");
|
||||
var template = loadTemplate(templateName);
|
||||
|
||||
let k = 0;
|
||||
for (; k < keys.length-1; ++k)
|
||||
{
|
||||
if (template[keys[k]] === undefined)
|
||||
return [];
|
||||
|
||||
template = template[keys[k]];
|
||||
}
|
||||
if (template[keys[k]] === undefined)
|
||||
return [];
|
||||
|
||||
return template[keys[k]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch tokens from an entity's template
|
||||
* @return An array containing all tokens if found, else an empty array
|
||||
* @see fetchValue
|
||||
*/
|
||||
function fetchTokens(templateName, keypath)
|
||||
{
|
||||
var val = fetchValue(templateName, keypath);
|
||||
if (!("_string" in val))
|
||||
return [];
|
||||
|
||||
return val._string.split(" ");
|
||||
}
|
||||
|
||||
function depath(path)
|
||||
{
|
||||
return path.slice(path.lastIndexOf("/")+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is needed because getEntityCostTooltip in tooltip.js needs to get
|
||||
* the template data of the different wallSet pieces. In the session this
|
||||
* function does some caching, but here we do that in loadTemplate already.
|
||||
*/
|
||||
function GetTemplateData(templateName)
|
||||
{
|
||||
var template = loadTemplate(templateName);
|
||||
return GetTemplateDataHelper(template);
|
||||
}
|
333
binaries/data/mods/public/gui/structree/load.js
Normal file
333
binaries/data/mods/public/gui/structree/load.js
Normal file
@ -0,0 +1,333 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
23
binaries/data/mods/public/gui/structree/rows.xml
Normal file
23
binaries/data/mods/public/gui/structree/rows.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<object name="phase_rows">
|
||||
<repeat count="4" var="k">
|
||||
<object name="phase[k]">
|
||||
<repeat count="11" var="s">
|
||||
<object type="image" style="StructBox" name="phase[k]_struct[s]">
|
||||
<object type="text" style="StructNameSpecific" name="phase[k]_struct[s]_name"/>
|
||||
<object type="image" style="StructIcon" name="phase[k]_struct[s]_icon"
|
||||
sprite="stretched:pregame/shell/logo/wfg_logo_white.png"
|
||||
/>
|
||||
<repeat count="4" var="r">
|
||||
<object name="phase[k]_struct[s]_row[r]">
|
||||
<repeat count="16" var="p">
|
||||
<object type="image" style="ProdBox" name="phase[k]_struct[s]_row[r]_prod[p]"/>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
14
binaries/data/mods/public/gui/structree/setup.xml
Normal file
14
binaries/data/mods/public/gui/structree/setup.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<setup>
|
||||
<tooltip name="treeTooltip"
|
||||
anchor="top"
|
||||
buffer_zone="4"
|
||||
delay="50"
|
||||
font="sans-14"
|
||||
maxwidth="480"
|
||||
offset="16 24"
|
||||
sprite="bkTooltip"
|
||||
textcolor="white"
|
||||
/>
|
||||
</setup>
|
61
binaries/data/mods/public/gui/structree/sprites.xml
Normal file
61
binaries/data/mods/public/gui/structree/sprites.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<sprites>
|
||||
<sprite name="ProdBar">
|
||||
<image
|
||||
backcolor="136 136 136 102"
|
||||
size="0 0 100% 100%"
|
||||
/>
|
||||
</sprite>
|
||||
|
||||
<sprite name="bkTooltip">
|
||||
<image
|
||||
backcolor="0 0 0 192"
|
||||
size="0 0 100% 100%"
|
||||
/>
|
||||
|
||||
<!-- sides -->
|
||||
<image
|
||||
texture="global/border/line_horiz.png"
|
||||
texture_size="0 0 64 4"
|
||||
size="2 0 100%-2 2"
|
||||
/>
|
||||
<image
|
||||
texture="global/border/line_vert.png"
|
||||
texture_size="0 0 4 64"
|
||||
size="100%-2 2 100% 100%-2"
|
||||
/>
|
||||
<image
|
||||
texture="global/border/line_horiz.png"
|
||||
texture_size="0 0 64 4"
|
||||
size="2 100%-2 100%-2 100%"
|
||||
/>
|
||||
<image
|
||||
texture="global/border/line_vert.png"
|
||||
texture_size="0 0 4 64"
|
||||
size="0 2 2 100%-2"
|
||||
/>
|
||||
|
||||
<!-- corners -->
|
||||
<image
|
||||
texture="global/border/line_corner_top_right.png"
|
||||
texture_size="0 0 4 4"
|
||||
size="100%-2 0 100% 2"
|
||||
/>
|
||||
<image
|
||||
texture="global/border/line_corner_bottom_right.png"
|
||||
texture_size="0 0 4 4"
|
||||
size="100%-2 100%-2 100% 100%"
|
||||
/>
|
||||
<image
|
||||
texture="global/border/line_corner_bottom_left.png"
|
||||
texture_size="0 0 4 4"
|
||||
size="0 100%-2 2 100%"
|
||||
/>
|
||||
<image
|
||||
texture="global/border/line_corner_top_left.png"
|
||||
texture_size="0 0 4 4"
|
||||
size="0 0 2 2"
|
||||
/>
|
||||
</sprite>
|
||||
</sprites>
|
250
binaries/data/mods/public/gui/structree/structree.js
Normal file
250
binaries/data/mods/public/gui/structree/structree.js
Normal file
@ -0,0 +1,250 @@
|
||||
var g_ParsedData = {
|
||||
units: {},
|
||||
structures: {},
|
||||
techs: {},
|
||||
phases: {}
|
||||
};
|
||||
var g_Lists = {};
|
||||
var g_CivData = {};
|
||||
var g_SelectedCiv = "";
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the dropdown containing all the available civs
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
g_CivData = loadCivData(true);
|
||||
|
||||
if (!Object.keys(g_CivData).length)
|
||||
return;
|
||||
|
||||
var civList = [ { "name": civ.Name, "code": civ.Code } for each (civ in g_CivData) ];
|
||||
|
||||
// Alphabetically sort the list, ignoring case
|
||||
civList.sort(sortNameIgnoreCase);
|
||||
|
||||
var civListNames = [ civ.name for each (civ in civList) ];
|
||||
var civListCodes = [ civ.code for each (civ in civList) ];
|
||||
|
||||
// Set civ control
|
||||
var civSelection = Engine.GetGUIObjectByName("civSelection");
|
||||
civSelection.list = civListNames;
|
||||
civSelection.list_data = civListCodes;
|
||||
civSelection.selected = 0;
|
||||
}
|
||||
|
||||
function selectCiv(civCode)
|
||||
{
|
||||
if (civCode === g_SelectedCiv || !g_CivData[civCode])
|
||||
return;
|
||||
|
||||
g_SelectedCiv = civCode;
|
||||
|
||||
// If a buildList already exists, then this civ has already been parsed
|
||||
if (g_CivData[g_SelectedCiv].buildList)
|
||||
{
|
||||
draw();
|
||||
return;
|
||||
}
|
||||
|
||||
g_Lists.units = [];
|
||||
g_Lists.structures = [];
|
||||
g_Lists.techs = [];
|
||||
|
||||
// get initial units
|
||||
var startStructs = [];
|
||||
for (let entity of g_CivData[civCode].StartEntities)
|
||||
{
|
||||
if (entity.Template.slice(0, 5) == "units")
|
||||
g_Lists.units.push(entity.Template);
|
||||
else if (entity.Template.slice(0, 6) == "struct")
|
||||
{
|
||||
g_Lists.structures.push(entity.Template);
|
||||
startStructs.push(entity.Template);
|
||||
}
|
||||
}
|
||||
|
||||
// Load units and structures
|
||||
var unitCount = 0;
|
||||
do
|
||||
{
|
||||
for (let u of g_Lists.units)
|
||||
if (!g_ParsedData.units[u])
|
||||
g_ParsedData.units[u] = loadUnit(u);
|
||||
|
||||
unitCount = g_Lists.units.length;
|
||||
|
||||
for (let s of g_Lists.structures)
|
||||
if (!g_ParsedData.structures[s])
|
||||
g_ParsedData.structures[s] = loadStructure(s);
|
||||
|
||||
} while (unitCount < g_Lists.units.length);
|
||||
|
||||
// Load technologies
|
||||
var techPairs = {};
|
||||
for (let techcode of g_Lists.techs)
|
||||
{
|
||||
let realcode = depath(techcode);
|
||||
|
||||
if (realcode.slice(0,4) == "pair")
|
||||
techPairs[techcode] = loadTechnologyPair(techcode);
|
||||
else if (realcode.slice(0,5) == "phase")
|
||||
g_ParsedData.phases[techcode] = loadPhase(techcode);
|
||||
else
|
||||
g_ParsedData.techs[techcode] = loadTechnology(techcode);
|
||||
}
|
||||
|
||||
// Expand tech pairs
|
||||
for (let paircode in techPairs)
|
||||
{
|
||||
let pair = techPairs[paircode];
|
||||
for (let techcode of pair.techs)
|
||||
{
|
||||
let newTech = loadTechnology(techcode);
|
||||
|
||||
if (pair.req !== "")
|
||||
{
|
||||
if ("generic" in newTech.reqs)
|
||||
newTech.reqs.generic.concat(techPairs[pair.req].techs);
|
||||
else
|
||||
for (let civkey of Object.keys(newTech.reqs))
|
||||
newTech.reqs[civkey].concat(techPairs[pair.req].techs);
|
||||
}
|
||||
g_ParsedData.techs[techcode] = newTech;
|
||||
}
|
||||
}
|
||||
|
||||
// Establish phase order
|
||||
g_ParsedData.phaseList = unravelPhases(g_ParsedData.techs);
|
||||
for (let phasecode of g_ParsedData.phaseList)
|
||||
{
|
||||
let phaseInfo = loadTechData(phasecode);
|
||||
g_ParsedData.phases[phasecode] = loadPhase(phasecode);
|
||||
|
||||
if ("requirements" in phaseInfo)
|
||||
for (let op in phaseInfo.requirements)
|
||||
{
|
||||
let val = phaseInfo.requirements[op];
|
||||
if (op == "any")
|
||||
for (let v of val)
|
||||
{
|
||||
let k = Object.keys(v);
|
||||
k = k[0];
|
||||
v = v[k];
|
||||
if (k == "tech" && v in g_ParsedData.phases)
|
||||
g_ParsedData.phases[v].actualPhase = phasecode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Group production lists of structures by phase
|
||||
for (let structCode of g_Lists.structures)
|
||||
{
|
||||
let structInfo = g_ParsedData.structures[structCode];
|
||||
|
||||
// If this building is shared with another civ,
|
||||
// it may have already gone through the grouping process already
|
||||
if (!Array.isArray(structInfo.production.technology))
|
||||
continue;
|
||||
|
||||
// Expand tech pairs
|
||||
for (let prod of structInfo.production.technology)
|
||||
if (prod in techPairs)
|
||||
structInfo.production.technology.splice(
|
||||
structInfo.production.technology.indexOf(prod), 1,
|
||||
techPairs[prod].techs[0], techPairs[prod].techs[1]
|
||||
);
|
||||
|
||||
// Sort techs by phase
|
||||
let newProdTech = {};
|
||||
for (let prod of structInfo.production.technology)
|
||||
{
|
||||
let phase = "";
|
||||
|
||||
if (prod.slice(0,5) === "phase")
|
||||
{
|
||||
phase = g_ParsedData.phaseList.indexOf(g_ParsedData.phases[prod].actualPhase);
|
||||
if (phase > 0)
|
||||
phase = g_ParsedData.phaseList[phase - 1];
|
||||
}
|
||||
else if (g_SelectedCiv in g_ParsedData.techs[prod].reqs)
|
||||
{
|
||||
if (g_ParsedData.techs[prod].reqs[g_SelectedCiv].length > 0)
|
||||
phase = g_ParsedData.techs[prod].reqs[g_SelectedCiv][0];
|
||||
}
|
||||
else if ("generic" in g_ParsedData.techs[prod].reqs)
|
||||
{
|
||||
phase = g_ParsedData.techs[prod].reqs.generic[0];
|
||||
}
|
||||
|
||||
if (depath(phase).slice(0,5) !== "phase")
|
||||
{
|
||||
warn(prod+" doesn't have a specific phase set ("+structCode+")");
|
||||
phase = structInfo.phase;
|
||||
}
|
||||
|
||||
if (!(phase in newProdTech))
|
||||
newProdTech[phase] = [];
|
||||
|
||||
newProdTech[phase].push(prod);
|
||||
}
|
||||
|
||||
// Determine phase for units
|
||||
let newProdUnits = {};
|
||||
for (let prod of structInfo.production.units)
|
||||
{
|
||||
if (!(prod in g_ParsedData.units))
|
||||
{
|
||||
error(prod+" doesn't exist! ("+structCode+")");
|
||||
continue;
|
||||
}
|
||||
let unit = g_ParsedData.units[prod];
|
||||
let phase = "";
|
||||
|
||||
if (unit.phase !== false)
|
||||
phase = unit.phase;
|
||||
else if (unit.required !== undefined)
|
||||
{
|
||||
let reqs = g_ParsedData.techs[unit.required].reqs;
|
||||
if (g_SelectedCiv in reqs)
|
||||
phase = reqs[g_SelectedCiv][0];
|
||||
else
|
||||
phase = reqs.generic[0];
|
||||
}
|
||||
else if (structInfo.phase !== false)
|
||||
phase = structInfo.phase;
|
||||
else
|
||||
phase = g_ParsedData.phaseList[0];
|
||||
|
||||
if (!(phase in newProdUnits))
|
||||
newProdUnits[phase] = [];
|
||||
|
||||
newProdUnits[phase].push(prod);
|
||||
}
|
||||
|
||||
g_ParsedData.structures[structCode].production = {
|
||||
"technology": newProdTech,
|
||||
"units": newProdUnits
|
||||
};
|
||||
}
|
||||
|
||||
// Determine the buildList for the civ (grouped by phase)
|
||||
var buildList = {};
|
||||
for (let structCode of g_Lists.structures)
|
||||
{
|
||||
if (!g_ParsedData.structures[structCode].phase || startStructs.indexOf(structCode) > -1)
|
||||
g_ParsedData.structures[structCode].phase = g_ParsedData.phaseList[0];
|
||||
|
||||
let myPhase = g_ParsedData.structures[structCode].phase;
|
||||
|
||||
if (!(myPhase in buildList))
|
||||
buildList[myPhase] = [];
|
||||
buildList[myPhase].push(structCode);
|
||||
}
|
||||
|
||||
g_CivData[g_SelectedCiv].buildList = buildList;
|
||||
|
||||
// Draw tree
|
||||
draw();
|
||||
}
|
94
binaries/data/mods/public/gui/structree/structree.xml
Normal file
94
binaries/data/mods/public/gui/structree/structree.xml
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<objects>
|
||||
<script file="gui/common/functions_civinfo.js"/>
|
||||
<script file="gui/common/functions_utility.js"/>
|
||||
<script file="gui/common/tooltips.js"/>
|
||||
<script file="gui/structree/structree.js"/>
|
||||
<script file="gui/structree/draw.js"/>
|
||||
<script file="gui/structree/helper.js"/>
|
||||
<script file="gui/structree/load.js"/>
|
||||
|
||||
<!-- Add a translucent black background to fade out the menu page -->
|
||||
<object type="image" z="0" sprite="bkTranslucent"/>
|
||||
|
||||
<object type="image" style="ModernDialog" size="16 24 100%-16 100%-24">
|
||||
<object style="TitleText" type="text" size="50%-128 -18 50%+128 14">
|
||||
<translatableAttribute id="caption">Structure Tree</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<!-- Civ selection -->
|
||||
<object size="16 10 100%-16 30">
|
||||
<object
|
||||
name="civSelectionHeading"
|
||||
type="text"
|
||||
font="sans-bold-16"
|
||||
textcolor="white"
|
||||
text_align="left"
|
||||
size="100%-264 10 100%-160 48">
|
||||
<translatableAttribute id="caption">Civilization:</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object name="civSelection" type="dropdown" style="ModernDropDown" size="100%-160 8 100% 34">
|
||||
<action on="SelectionChange">selectCiv(this.list_data[this.selected]);</action>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<object
|
||||
name="civEmblem"
|
||||
type="image"
|
||||
size="6 6 96+6 96+6"
|
||||
sprite="stretched:pregame/shell/logo/wfg_logo_white.png"
|
||||
/>
|
||||
|
||||
<object
|
||||
name="civName"
|
||||
type="text"
|
||||
font="sans-bold-20"
|
||||
textcolor="white"
|
||||
text_align="left"
|
||||
text_valign="top"
|
||||
size="104 32 100%-8 96"
|
||||
/>
|
||||
|
||||
<object
|
||||
name="civHistory"
|
||||
type="text"
|
||||
font="sans-12"
|
||||
textcolor="white"
|
||||
text_align="left"
|
||||
text_valign="top"
|
||||
size="104 52 100%-8 100%"
|
||||
/>
|
||||
|
||||
<!-- Data display -->
|
||||
<object size="0 54+64 100% 100%-54">
|
||||
<repeat count="4" var="n">
|
||||
<object name="phase[n]_phase" type="image"/>
|
||||
<object name="phase[n]_bar">
|
||||
<repeat count="4" var="k">
|
||||
<object name="phase[n]_bar[k]" type="image" sprite="ProdBar">
|
||||
<object name="phase[n]_bar[k]_icon" type="image" size="2 2 20 20"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
|
||||
<object type="image" style="TreeDisplay" size="48+16+8 0 100%-16 100%">
|
||||
<include file="gui/structree/rows.xml"/>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
||||
<!-- Close dialog -->
|
||||
<object
|
||||
type="button"
|
||||
style="StoneButton"
|
||||
size="100%-164 100%-44 100%-16 100%-16"
|
||||
>
|
||||
<translatableAttribute id="caption">Close</translatableAttribute>
|
||||
<action on="Press">Engine.PopGuiPage();</action>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
</objects>
|
32
binaries/data/mods/public/gui/structree/styles.xml
Normal file
32
binaries/data/mods/public/gui/structree/styles.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<styles>
|
||||
<style name="TreeDisplay"
|
||||
sprite="ModernDarkBoxGold"
|
||||
scrollbar="true"
|
||||
scrollbar_style="ModernScrollBar"
|
||||
/>
|
||||
|
||||
<style name="StructNameSpecific"
|
||||
textcolor="white"
|
||||
font="sans-12"
|
||||
text_align="center"
|
||||
size="8 0 100%-8 20"
|
||||
/>
|
||||
|
||||
<style name="StructBox"
|
||||
sprite="ModernDarkBoxGold"
|
||||
size="4 4 68 68+16"
|
||||
/>
|
||||
|
||||
<style name="StructIcon"
|
||||
size="50%-24 8+16 50%+24 8+16+48"
|
||||
tooltip_style="treeTooltip"
|
||||
/>
|
||||
|
||||
<style name="ProdBox"
|
||||
size="0 0 20 20"
|
||||
sprite="stretched:pregame/shell/logo/wfg_logo_white.png"
|
||||
tooltip_style="treeTooltip"
|
||||
/>
|
||||
</styles>
|
Loading…
Reference in New Issue
Block a user