mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Merge resource agnostic branch by s0600204, fixes #3934.
Remove all occurances of hardcoded resources in the simulation, GUI and AI code by specifying resources as JSON files in a new simulation subdirectory and accessing them through a globally defined prototype. This was SVN commit r18964.
This commit is contained in:
parent
7ff7fcd240
commit
52f311da2b
60 changed files with 881 additions and 598 deletions
98
binaries/data/mods/public/globalscripts/Resources.js
Normal file
98
binaries/data/mods/public/globalscripts/Resources.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
* Since the AI context can't access JSON functions, it gets passed an object
|
||||
* containing the information from `GuiInterface.js::GetSimulationState()`.
|
||||
*/
|
||||
function Resources()
|
||||
{
|
||||
let jsonFiles = [];
|
||||
// Simulation context
|
||||
if (Engine.FindJSONFiles)
|
||||
{
|
||||
jsonFiles = Engine.FindJSONFiles("resources", false);
|
||||
for (let file in jsonFiles)
|
||||
jsonFiles[file] = "resources/" + jsonFiles[file] + ".json";
|
||||
}
|
||||
// GUI context
|
||||
else if (Engine.BuildDirEntList)
|
||||
jsonFiles = Engine.BuildDirEntList("simulation/data/resources/", "*.json", false);
|
||||
else
|
||||
{
|
||||
error("Resources: JSON functions are not available");
|
||||
return;
|
||||
}
|
||||
|
||||
this.resourceData = [];
|
||||
this.resourceDataObj = {};
|
||||
this.resourceCodes = [];
|
||||
this.resourceNames = {};
|
||||
|
||||
for (let filename of jsonFiles)
|
||||
{
|
||||
let data = Engine.ReadJSONFile(filename);
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
if (data.code != data.code.toLowerCase())
|
||||
warn("Resource codes should use lower case: " + data.code);
|
||||
|
||||
// Treasures are supported for every specified resource
|
||||
if (data.code == "treasure")
|
||||
{
|
||||
error("Encountered resource with reserved keyword: " + data.code);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.resourceData.push(data);
|
||||
this.resourceDataObj[data.code] = data;
|
||||
this.resourceCodes.push(data.code);
|
||||
this.resourceNames[data.code] = data.name;
|
||||
for (let subres in data.subtypes)
|
||||
this.resourceNames[subres] = data.subtypes[subres]
|
||||
}
|
||||
|
||||
// Sort arrays by specified order
|
||||
let resSort = (a, b) =>
|
||||
a.order < b.order ? -1 :
|
||||
a.order > b.order ? +1 : 0;
|
||||
|
||||
this.resourceData.sort(resSort);
|
||||
this.resourceCodes.sort((a, b) => resSort(
|
||||
this.resourceData.find(resource => resource.code == a),
|
||||
this.resourceData.find(resource => resource.code == b)
|
||||
));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the objects defined in the JSON files for all availbale resources,
|
||||
* ordered as defined in these files.
|
||||
*/
|
||||
Resources.prototype.GetResources = function()
|
||||
{
|
||||
return this.resourceData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the object defined in the JSON file for the given resource.
|
||||
*/
|
||||
Resources.prototype.GetResource = function(type)
|
||||
{
|
||||
return this.resourceDataObj[type];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array containing all resource codes ordered as defined in the resource files.
|
||||
* For example ["food", "wood", "stone", "metal"].
|
||||
*/
|
||||
Resources.prototype.GetCodes = function()
|
||||
{
|
||||
return this.resourceCodes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object mapping resource codes to translatable resource names. Includes subtypes.
|
||||
* For example { "food": "Food", "fish": "Fish", "fruit": "Fruit", "metal": "Metal", ... }
|
||||
*/
|
||||
Resources.prototype.GetNames = function()
|
||||
{
|
||||
return this.resourceNames;
|
||||
};
|
||||
|
|
@ -75,8 +75,9 @@ function MatchesClassList(classes, match)
|
|||
* @param player An optional player id to get the technology modifications
|
||||
* of properties.
|
||||
* @param auraTemplates An object in the form of {key: {auraName: "", auraDescription: ""}}
|
||||
* @param resources An instance of the Resources prototype
|
||||
*/
|
||||
function GetTemplateDataHelper(template, player, auraTemplates)
|
||||
function GetTemplateDataHelper(template, player, auraTemplates, resources)
|
||||
{
|
||||
// Return data either from template (in tech tree) or sim state (ingame)
|
||||
let getEntityValue = function(tech_type) {
|
||||
|
|
@ -193,17 +194,9 @@ function GetTemplateDataHelper(template, player, auraTemplates)
|
|||
if (template.Cost)
|
||||
{
|
||||
ret.cost = {};
|
||||
if (template.Cost.Resources.food)
|
||||
ret.cost.food = getEntityValue("Cost/Resources/food");
|
||||
|
||||
if (template.Cost.Resources.wood)
|
||||
ret.cost.wood = getEntityValue("Cost/Resources/wood");
|
||||
|
||||
if (template.Cost.Resources.stone)
|
||||
ret.cost.stone = getEntityValue("Cost/Resources/stone");
|
||||
|
||||
if (template.Cost.Resources.metal)
|
||||
ret.cost.metal = getEntityValue("Cost/Resources/metal");
|
||||
for (let resCode of resources.GetCodes())
|
||||
if (template.Cost.Resources[resCode])
|
||||
ret.cost[resCode] = getEntityValue("Cost/Resources/" + resCode);
|
||||
|
||||
if (template.Cost.Population)
|
||||
ret.cost.population = getEntityValue("Cost/Population");
|
||||
|
|
@ -348,8 +341,9 @@ function GetTemplateDataHelper(template, player, auraTemplates)
|
|||
* Get information about a technology template.
|
||||
* @param template A valid template as obtained by loading the tech JSON file.
|
||||
* @param civ Civilization for which the specific name should be returned.
|
||||
* @param resources An instance of the Resources prototype.
|
||||
*/
|
||||
function GetTechnologyDataHelper(template, civ)
|
||||
function GetTechnologyDataHelper(template, civ, resources)
|
||||
{
|
||||
var ret = {};
|
||||
|
||||
|
|
@ -370,13 +364,9 @@ function GetTechnologyDataHelper(template, civ)
|
|||
|
||||
ret.icon = template.icon ? "technologies/" + template.icon : null;
|
||||
|
||||
ret.cost = {
|
||||
"food": template.cost ? +template.cost.food : 0,
|
||||
"wood": template.cost ? +template.cost.wood : 0,
|
||||
"metal": template.cost ? +template.cost.metal : 0,
|
||||
"stone": template.cost ? +template.cost.stone : 0,
|
||||
"time": template.researchTime ? +template.researchTime : 0,
|
||||
}
|
||||
ret.cost = { "time": template.researchTime ? +template.researchTime : 0 }
|
||||
for (let type of resources.GetCodes())
|
||||
ret.cost[type] = template.cost ? +template.cost[type] : 0;
|
||||
|
||||
ret.tooltip = template.tooltip;
|
||||
ret.requirementsTooltip = template.requirementsTooltip || "";
|
||||
|
|
|
|||
|
|
@ -245,3 +245,32 @@ function notifyUser(userName, msgText)
|
|||
|
||||
g_LastNickNotification = timeNow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Horizontally spaces objects within a parent
|
||||
*
|
||||
* @param margin The gap, in px, between the objects
|
||||
*/
|
||||
function horizontallySpaceObjects(parentName, margin=0)
|
||||
{
|
||||
let objects = Engine.GetGUIObjectByName(parentName).children;
|
||||
for (let i = 0; i < objects.length; ++i)
|
||||
{
|
||||
let size = objects[i].size;
|
||||
let width = size.right - size.left;
|
||||
size.left = i * (width + margin) + margin;
|
||||
size.right = (i + 1) * (width + margin);
|
||||
objects[i].size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide all children after a certain index
|
||||
*/
|
||||
function hideRemaining(parentName, start = 0)
|
||||
{
|
||||
let objects = Engine.GetGUIObjectByName(parentName).children;
|
||||
|
||||
for (let i = start; i < objects.length; ++i)
|
||||
objects[i].hidden = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +1,6 @@
|
|||
const localisedResourceNames = {
|
||||
"firstWord": {
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"food": translateWithContext("firstWord", "Food"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"meat": translateWithContext("firstWord", "Meat"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"metal": translateWithContext("firstWord", "Metal"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"ore": translateWithContext("firstWord", "Ore"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"rock": translateWithContext("firstWord", "Rock"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"ruins": translateWithContext("firstWord", "Ruins"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"stone": translateWithContext("firstWord", "Stone"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"treasure": translateWithContext("firstWord", "Treasure"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"tree": translateWithContext("firstWord", "Tree"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"wood": translateWithContext("firstWord", "Wood"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"fruit": translateWithContext("firstWord", "Fruit"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"grain": translateWithContext("firstWord", "Grain"),
|
||||
// Translation: Word as used at the beginning of a sentence or as a single-word sentence.
|
||||
"fish": translateWithContext("firstWord", "Fish"),
|
||||
},
|
||||
"withinSentence": {
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"food": translateWithContext("withinSentence", "Food"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"meat": translateWithContext("withinSentence", "Meat"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"metal": translateWithContext("withinSentence", "Metal"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"ore": translateWithContext("withinSentence", "Ore"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"rock": translateWithContext("withinSentence", "Rock"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"ruins": translateWithContext("withinSentence", "Ruins"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"stone": translateWithContext("withinSentence", "Stone"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"treasure": translateWithContext("withinSentence", "Treasure"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"tree": translateWithContext("withinSentence", "Tree"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"wood": translateWithContext("withinSentence", "Wood"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"fruit": translateWithContext("withinSentence", "Fruit"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"grain": translateWithContext("withinSentence", "Grain"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"fish": translateWithContext("withinSentence", "Fish"),
|
||||
}
|
||||
};
|
||||
|
||||
function getLocalizedResourceName(resourceCode, context)
|
||||
function getLocalizedResourceName(resourceName, context)
|
||||
{
|
||||
if (!localisedResourceNames[context])
|
||||
{
|
||||
warn("Internationalization: Unexpected context for resource type localization found: ‘" + context + "’. This context is not supported.");
|
||||
return resourceCode;
|
||||
}
|
||||
if (!localisedResourceNames[context][resourceCode])
|
||||
{
|
||||
warn("Internationalization: Unexpected resource type found with code ‘" + resourceCode + ". This resource type must be internationalized.");
|
||||
return resourceCode;
|
||||
}
|
||||
return localisedResourceNames[context][resourceCode];
|
||||
return translateWithContext(context, resourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -81,7 +12,7 @@ function getLocalizedResourceAmounts(resources)
|
|||
.filter(type => resources[type] > 0)
|
||||
.map(type => sprintf(translate("%(amount)s %(resourceType)s"), {
|
||||
"amount": resources[type],
|
||||
"resourceType": getLocalizedResourceName(type, "withinSentence")
|
||||
"resourceType": getLocalizedResourceName(g_ResourceData.GetResource(type).name, "withinSentence")
|
||||
}));
|
||||
|
||||
if (amounts.length > 1)
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ function getLootTooltip(template)
|
|||
template.trader && template.trader.goods
|
||||
);
|
||||
|
||||
const lootTypes = ["xp", "food", "wood", "stone", "metal"];
|
||||
const lootTypes = g_ResourceData.GetCodes().concat(["xp"]);
|
||||
let lootLabels = [];
|
||||
for (let type of lootTypes)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<object name="diplomacyDialogPanel"
|
||||
size="50%-300 50%-200 50%+300 50%+150"
|
||||
size="50%-260 50%-200 50%+260 50%+150"
|
||||
type="image"
|
||||
hidden="true"
|
||||
sprite="ModernDialog"
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
</object>
|
||||
|
||||
<object name="diplomacyHeader" size="32 32 100%-32 64">
|
||||
<object name="diplomacyHeaderName" size="0 0 150 100%" type="text" style="DiplomacyText" ghost="true">
|
||||
<object name="diplomacyHeaderName" size="0 0 140 100%" type="text" style="DiplomacyText" ghost="true" text_align="center">
|
||||
<translatableAttribute id="caption">Name</translatableAttribute>
|
||||
</object>
|
||||
<object name="diplomacyHeaderCiv" size="150 0 250 100%" type="text" style="DiplomacyText" ghost="true">
|
||||
|
|
@ -23,25 +23,25 @@
|
|||
<object name="diplomacyHeaderTheirs" size="300 0 360 100%" type="text" style="DiplomacyText" ghost="true">
|
||||
<translatableAttribute id="caption">Theirs</translatableAttribute>
|
||||
</object>
|
||||
<object name="diplomacyHeaderAlly" size="100%-180 0 100%-160 100%" type="text" style="DiplomacyText" tooltip_style="sessionToolTipBold">
|
||||
<object name="diplomacyHeaderAlly" size="360 0 380 100%" type="text" style="DiplomacyText" tooltip_style="sessionToolTipBold">
|
||||
<translatableAttribute id="caption">A</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Ally</translatableAttribute>
|
||||
</object>
|
||||
<object name="diplomacyHeaderNeutral" size="100%-160 0 100%-140 100%" type="text" style="DiplomacyText" tooltip_style="sessionToolTipBold">
|
||||
<object name="diplomacyHeaderNeutral" size="380 0 400 100%" type="text" style="DiplomacyText" tooltip_style="sessionToolTipBold">
|
||||
<translatableAttribute id="caption">N</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Neutral</translatableAttribute>
|
||||
</object>
|
||||
<object name="diplomacyHeaderEnemy" size="100%-140 0 100%-120 100%" type="text" style="DiplomacyText" tooltip_style="sessionToolTipBold">
|
||||
<object name="diplomacyHeaderEnemy" size="400 0 420 100%" type="text" style="DiplomacyText" tooltip_style="sessionToolTipBold">
|
||||
<translatableAttribute id="caption">E</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Enemy</translatableAttribute>
|
||||
</object>
|
||||
<object name="diplomacyHeaderTribute" size="100%-110 0 100% 100%" type="text" style="DiplomacyText">
|
||||
<object name="diplomacyHeaderTribute" size="430 0 100%-30 100%" type="text" style="DiplomacyText" text_align="center">
|
||||
<translatableAttribute id="caption">Tribute</translatableAttribute>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<object size="32 64 100%-32 384">
|
||||
<repeat count="16">
|
||||
<repeat count="16" var="n">
|
||||
<object name="diplomacyPlayer[n]" size="0 0 100% 20" type="image" hidden="false">
|
||||
<object name="diplomacyPlayerName[n]" size="0 0 150 100%" type="text" style="DiplomacyText" ghost="true"/>
|
||||
<object name="diplomacyPlayerCiv[n]" size="150 0 250 100%" type="text" style="DiplomacyText" ghost="true"/>
|
||||
|
|
@ -49,22 +49,17 @@
|
|||
<object name="diplomacyPlayerTheirs[n]" size="300 0 360 100%" type="text" style="DiplomacyText" ghost="true"/>
|
||||
|
||||
<!-- Diplomatic stance - selection -->
|
||||
<object name="diplomacyPlayerAlly[n]" size="100%-180 0 100%-160 100%" type="button" style="StoneButton" hidden="true"/>
|
||||
<object name="diplomacyPlayerNeutral[n]" size="100%-160 0 100%-140 100%" type="button" style="StoneButton" hidden="true"/>
|
||||
<object name="diplomacyPlayerEnemy[n]" size="100%-140 0 100%-120 100%" type="button" style="StoneButton" hidden="true"/>
|
||||
<object name="diplomacyPlayerAlly[n]" size="360 0 380 100%" type="button" style="StoneButton" hidden="true"/>
|
||||
<object name="diplomacyPlayerNeutral[n]" size="380 0 400 100%" type="button" style="StoneButton" hidden="true"/>
|
||||
<object name="diplomacyPlayerEnemy[n]" size="400 0 420 100%" type="button" style="StoneButton" hidden="true"/>
|
||||
|
||||
<!-- Tribute -->
|
||||
<object name="diplomacyPlayerTributeFood[n]" size="100%-110 0 100%-90 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
|
||||
<object name="diplomacyPlayerTributeFoodImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/food.png" ghost="true"/>
|
||||
</object>
|
||||
<object name="diplomacyPlayerTributeWood[n]" size="100%-90 0 100%-70 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
|
||||
<object name="diplomacyPlayerTributeWoodImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/wood.png" ghost="true"/>
|
||||
</object>
|
||||
<object name="diplomacyPlayerTributeStone[n]" size="100%-70 0 100%-50 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
|
||||
<object name="diplomacyPlayerTributeStoneImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/stone.png" ghost="true"/>
|
||||
</object>
|
||||
<object name="diplomacyPlayerTributeMetal[n]" size="100%-50 0 100%-30 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
|
||||
<object name="diplomacyPlayerTributeMetalImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/metal.png" ghost="true"/>
|
||||
<object size="430 0 100%-40 100%">
|
||||
<repeat count="8" var="r">
|
||||
<object name="diplomacyPlayer[n]_tribute[r]" size="0 0 20 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
|
||||
<object name="diplomacyPlayer[n]_tribute[r]_image" type="image" size="0 0 100% 100%" ghost="true"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
|
||||
<object name="diplomacyAttackRequest[n]" size="100%-20 0 100% 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
|
||||
|
|
|
|||
|
|
@ -22,9 +22,6 @@ const INITIAL_MENU_POSITION = "100%-164 " + MENU_TOP + " 100% " + MENU_BOTTOM;
|
|||
// Number of pixels per millisecond to move
|
||||
const MENU_SPEED = 1.2;
|
||||
|
||||
// Available resources in trade and tribute menu
|
||||
const RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
|
||||
// Trade menu: step for probability changes
|
||||
const STEP = 5;
|
||||
|
||||
|
|
@ -230,6 +227,20 @@ function closeChat()
|
|||
Engine.GetGUIObjectByName("chatDialogPanel").hidden = true;
|
||||
}
|
||||
|
||||
function resizeDiplomacyDialog()
|
||||
{
|
||||
let dialog = Engine.GetGUIObjectByName("diplomacyDialogPanel");
|
||||
let size = dialog.size;
|
||||
let width = size.right - size.left;
|
||||
|
||||
let tribSize = Engine.GetGUIObjectByName("diplomacyPlayer[0]_tribute[0]").size;
|
||||
width += g_ResourceData.GetCodes().length * (tribSize.right - tribSize.left);
|
||||
|
||||
size.left = -width / 2;
|
||||
size.right = width / 2;
|
||||
dialog.size = size;
|
||||
}
|
||||
|
||||
function initChatWindow()
|
||||
{
|
||||
let filters = prepareForDropdown(g_ChatHistoryFilters);
|
||||
|
|
@ -321,7 +332,6 @@ function openDiplomacy()
|
|||
diplomacyFormatTributeButtons(i, myself || playerInactive);
|
||||
diplomacyFormatAttackRequestButton(i, myself || playerInactive || isCeasefireActive || !hasAllies || !g_Players[i].isEnemy[g_ViewedPlayer]);
|
||||
}
|
||||
|
||||
Engine.GetGUIObjectByName("diplomacyDialogPanel").hidden = false;
|
||||
}
|
||||
|
||||
|
|
@ -372,16 +382,28 @@ function diplomacyFormatStanceButtons(i, hidden)
|
|||
|
||||
function diplomacyFormatTributeButtons(i, hidden)
|
||||
{
|
||||
for (let resource of RESOURCES)
|
||||
let resNames = g_ResourceData.GetNames();
|
||||
let resCodes = g_ResourceData.GetCodes();
|
||||
let r = 0;
|
||||
for (let resCode of resCodes)
|
||||
{
|
||||
let button = Engine.GetGUIObjectByName("diplomacyPlayerTribute"+resource[0].toUpperCase()+resource.substring(1)+"["+(i-1)+"]");
|
||||
let button = Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]_tribute["+r+"]");
|
||||
if (!button)
|
||||
{
|
||||
warn("Current GUI limits prevent displaying more than " + r + " tribute buttons!");
|
||||
break;
|
||||
}
|
||||
|
||||
Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]_tribute["+r+"]_image").sprite = "stretched:session/icons/resources/"+resCode+".png";
|
||||
button.hidden = hidden;
|
||||
setPanelObjectPosition(button, r, r+1, 0);
|
||||
++r;
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
button.enabled = controlsPlayer(g_ViewedPlayer);
|
||||
button.tooltip = formatTributeTooltip(i, resource, 100);
|
||||
button.onpress = (function(i, resource, button) {
|
||||
button.tooltip = formatTributeTooltip(i, resNames[resCode], 100);
|
||||
button.onPress = (function(i, resCode, button) {
|
||||
// Shift+click to send 500, shift+click+click to send 1000, etc.
|
||||
// See INPUT_MASSTRIBUTING in input.js
|
||||
let multiplier = 1;
|
||||
|
|
@ -394,24 +416,24 @@ function diplomacyFormatTributeButtons(i, hidden)
|
|||
}
|
||||
|
||||
let amounts = {};
|
||||
for (let type of RESOURCES)
|
||||
amounts[type] = 0;
|
||||
amounts[resource] = 100 * multiplier;
|
||||
for (let res of resCodes)
|
||||
amounts[res] = 0;
|
||||
amounts[resCode] = 100 * multiplier;
|
||||
|
||||
button.tooltip = formatTributeTooltip(i, resource, amounts[resource]);
|
||||
button.tooltip = formatTributeTooltip(i, resNames[resCode], amounts[resCode]);
|
||||
|
||||
// This is in a closure so that we have access to `player`, `amounts`, and `multiplier` without some
|
||||
// evil global variable hackery.
|
||||
g_FlushTributing = function() {
|
||||
Engine.PostNetworkCommand({ "type": "tribute", "player": i, "amounts": amounts });
|
||||
multiplier = 1;
|
||||
button.tooltip = formatTributeTooltip(i, resource, 100);
|
||||
button.tooltip = formatTributeTooltip(i, resNames[resCode], 100);
|
||||
};
|
||||
|
||||
if (!isBatchTrainPressed)
|
||||
g_FlushTributing();
|
||||
};
|
||||
})(i, resource, button);
|
||||
})(i, resCode, button);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -444,6 +466,20 @@ function toggleDiplomacy()
|
|||
openDiplomacy();
|
||||
}
|
||||
|
||||
function resizeTradeDialog()
|
||||
{
|
||||
let dialog = Engine.GetGUIObjectByName("tradeDialogPanel");
|
||||
let size = dialog.size;
|
||||
let width = size.right - size.left;
|
||||
|
||||
let tradeSize = Engine.GetGUIObjectByName("tradeResource[0]").size;
|
||||
width += g_ResourceData.GetCodes().length * (tradeSize.right - tradeSize.left);
|
||||
|
||||
size.left = -width / 2;
|
||||
size.right = width / 2;
|
||||
dialog.size = size;
|
||||
}
|
||||
|
||||
function openTrade()
|
||||
{
|
||||
closeOpenDialogs();
|
||||
|
|
@ -455,7 +491,7 @@ function openTrade()
|
|||
|
||||
var updateButtons = function()
|
||||
{
|
||||
for (var res in button)
|
||||
for (let res in button)
|
||||
{
|
||||
button[res].label.caption = proba[res] + "%";
|
||||
|
||||
|
|
@ -465,45 +501,55 @@ function openTrade()
|
|||
}
|
||||
};
|
||||
|
||||
var proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer);
|
||||
var button = {};
|
||||
var selec = RESOURCES[0];
|
||||
for (var i = 0; i < RESOURCES.length; ++i)
|
||||
{
|
||||
var buttonResource = Engine.GetGUIObjectByName("tradeResource["+i+"]");
|
||||
if (i > 0)
|
||||
{
|
||||
var size = Engine.GetGUIObjectByName("tradeResource["+(i-1)+"]").size;
|
||||
var width = size.right - size.left;
|
||||
size.left += width;
|
||||
size.right += width;
|
||||
Engine.GetGUIObjectByName("tradeResource["+i+"]").size = size;
|
||||
}
|
||||
var resource = RESOURCES[i];
|
||||
proba[resource] = (proba[resource] ? proba[resource] : 0);
|
||||
var buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]");
|
||||
var icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]");
|
||||
icon.sprite = "stretched:session/icons/resources/" + resource + ".png";
|
||||
var label = Engine.GetGUIObjectByName("tradeResourceText["+i+"]");
|
||||
var buttonUp = Engine.GetGUIObjectByName("tradeArrowUp["+i+"]");
|
||||
var buttonDn = Engine.GetGUIObjectByName("tradeArrowDn["+i+"]");
|
||||
var iconSel = Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]");
|
||||
button[resource] = { "up": buttonUp, "dn": buttonDn, "label": label, "sel": iconSel };
|
||||
let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer);
|
||||
let button = {};
|
||||
let resCodes = g_ResourceData.GetCodes();
|
||||
let selec = resCodes[0];
|
||||
hideRemaining("tradeResources", resCodes.length);
|
||||
Engine.GetGUIObjectByName("tradeHelp").hidden = false;
|
||||
|
||||
for (let i = 0; i < resCodes.length; ++i)
|
||||
{
|
||||
let tradeResource = Engine.GetGUIObjectByName("tradeResource["+i+"]");
|
||||
if (!tradeResource)
|
||||
{
|
||||
warn("Current GUI limits prevent displaying more than " + r + " resources in the trading goods selection dialog!");
|
||||
break;
|
||||
}
|
||||
|
||||
setPanelObjectPosition(tradeResource, i, i+1);
|
||||
|
||||
let resCode = resCodes[i];
|
||||
proba[resCode] = proba[resCode] || 0;
|
||||
|
||||
let icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]");
|
||||
icon.sprite = "stretched:session/icons/resources/" + resCode + ".png";
|
||||
|
||||
let buttonUp = Engine.GetGUIObjectByName("tradeArrowUp["+i+"]");
|
||||
let buttonDn = Engine.GetGUIObjectByName("tradeArrowDn["+i+"]");
|
||||
|
||||
button[resCode] = {
|
||||
"up": buttonUp,
|
||||
"dn": buttonDn,
|
||||
"label": Engine.GetGUIObjectByName("tradeResourceText["+i+"]"),
|
||||
"sel": Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]")
|
||||
};
|
||||
|
||||
let buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]");
|
||||
buttonResource.enabled = controlsPlayer(g_ViewedPlayer);
|
||||
buttonResource.onpress = (function(resource){
|
||||
return function() {
|
||||
if (Engine.HotkeyIsPressed("session.fulltradeswap"))
|
||||
{
|
||||
for (var ress of RESOURCES)
|
||||
proba[ress] = 0;
|
||||
for (let res of resCodes)
|
||||
proba[res] = 0;
|
||||
proba[resource] = 100;
|
||||
Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba});
|
||||
}
|
||||
selec = resource;
|
||||
updateButtons();
|
||||
};
|
||||
})(resource);
|
||||
})(resCode);
|
||||
|
||||
buttonUp.enabled = controlsPlayer(g_ViewedPlayer);
|
||||
buttonUp.onpress = (function(resource){
|
||||
|
|
@ -513,7 +559,7 @@ function openTrade()
|
|||
Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba});
|
||||
updateButtons();
|
||||
};
|
||||
})(resource);
|
||||
})(resCode);
|
||||
|
||||
buttonDn.enabled = controlsPlayer(g_ViewedPlayer);
|
||||
buttonDn.onpress = (function(resource){
|
||||
|
|
@ -523,14 +569,13 @@ function openTrade()
|
|||
Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba});
|
||||
updateButtons();
|
||||
};
|
||||
})(resource);
|
||||
})(resCode);
|
||||
}
|
||||
updateButtons();
|
||||
|
||||
let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer);
|
||||
Engine.GetGUIObjectByName("landTraders").caption = getIdleLandTradersText(traderNumber);
|
||||
Engine.GetGUIObjectByName("shipTraders").caption = getIdleShipTradersText(traderNumber);
|
||||
|
||||
Engine.GetGUIObjectByName("tradeDialogPanel").hidden = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,13 @@ function layoutSelectionMultiple()
|
|||
|
||||
function getResourceTypeDisplayName(resourceType)
|
||||
{
|
||||
let resourceCode = resourceType.generic;
|
||||
if (resourceCode == "treasure")
|
||||
return getLocalizedResourceName(resourceType.specific, "firstWord");
|
||||
else
|
||||
return getLocalizedResourceName(resourceCode, "firstWord");
|
||||
return getLocalizedResourceName(
|
||||
g_ResourceData.GetNames()[
|
||||
resourceType.generic == "treasure" ?
|
||||
resourceType.specific :
|
||||
resourceType.generic
|
||||
],
|
||||
"firstWord");
|
||||
}
|
||||
|
||||
// Updates the health bar of garrisoned units
|
||||
|
|
@ -182,15 +184,16 @@ function displaySingle(entState)
|
|||
"max": entState.resourceSupply.max
|
||||
});
|
||||
|
||||
let resourceType = getResourceTypeDisplayName(entState.resourceSupply.type);
|
||||
|
||||
let unitResourceBar = Engine.GetGUIObjectByName("resourceBar");
|
||||
let resourceSize = unitResourceBar.size;
|
||||
|
||||
resourceSize.rright = entState.resourceSupply.isInfinite ? 100 :
|
||||
100 * Math.max(0, Math.min(1, +entState.resourceSupply.amount / +entState.resourceSupply.max));
|
||||
unitResourceBar.size = resourceSize;
|
||||
Engine.GetGUIObjectByName("resourceLabel").caption = sprintf(translate("%(resource)s:"), { "resource": resourceType });
|
||||
|
||||
Engine.GetGUIObjectByName("resourceLabel").caption = sprintf(translate("%(resource)s:"), {
|
||||
"resource": getResourceTypeDisplayName(entState.resourceSupply.type)
|
||||
});
|
||||
Engine.GetGUIObjectByName("resourceStats").caption = resources;
|
||||
|
||||
if (entState.hitpoints)
|
||||
|
|
@ -406,7 +409,8 @@ function displayMultiple(entStates)
|
|||
if (Object.keys(totalCarrying).length)
|
||||
numberOfUnits.tooltip = sprintf(translate("%(label)s %(details)s\n"), {
|
||||
"label": headerFont(translate("Carrying:")),
|
||||
"details": bodyFont(RESOURCES.filter(res => !!totalCarrying[res]).map(
|
||||
"details": bodyFont(Object.keys(totalCarrying).filter(
|
||||
res => totalCarrying[res] != 0).map(
|
||||
res => sprintf(translate("%(type)s %(amount)s"),
|
||||
{ "type": costIcon(res), "amount": totalCarrying[res] })).join(" "))
|
||||
});
|
||||
|
|
@ -414,7 +418,8 @@ function displayMultiple(entStates)
|
|||
if (Object.keys(totalLoot).length)
|
||||
numberOfUnits.tooltip += sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": headerFont(translate("Loot:")),
|
||||
"details": bodyFont(Object.keys(totalLoot).map(
|
||||
"details": bodyFont(Object.keys(totalLoot).filter(
|
||||
res => totalLoot[res] != 0).map(
|
||||
res => sprintf(translate("%(type)s %(amount)s"),
|
||||
{ "type": costIcon(res), "amount": totalLoot[res] })).join(" "))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ let g_FormationsInfo = new Map();
|
|||
|
||||
let g_SelectionPanels = {};
|
||||
|
||||
let g_BarterSell;
|
||||
|
||||
g_SelectionPanels.Alert = {
|
||||
"getMaxNumberOfItems": function()
|
||||
{
|
||||
|
|
@ -104,8 +106,7 @@ g_SelectionPanels.Barter = {
|
|||
{
|
||||
if (unitEntStates.every(state => !state.barterMarket))
|
||||
return [];
|
||||
// ["food", "wood", "stone", "metal"]
|
||||
return BARTER_RESOURCES;
|
||||
return g_ResourceData.GetCodes();
|
||||
},
|
||||
"setupButton": function(data)
|
||||
{
|
||||
|
|
@ -125,6 +126,9 @@ g_SelectionPanels.Barter = {
|
|||
if (Engine.HotkeyIsPressed("session.massbarter"))
|
||||
amountToSell *= BARTER_BUNCH_MULTIPLIER;
|
||||
|
||||
if (!g_BarterSell)
|
||||
g_BarterSell = g_ResourceData.GetCodes()[0];
|
||||
|
||||
amount.Sell.caption = "-" + amountToSell;
|
||||
let prices;
|
||||
for (let state of data.unitEntStates)
|
||||
|
|
@ -136,7 +140,7 @@ g_SelectionPanels.Barter = {
|
|||
|
||||
amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell);
|
||||
|
||||
let resource = getLocalizedResourceName(data.item, "withinSentence");
|
||||
let resource = getLocalizedResourceName(g_ResourceData.GetNames()[data.item], "withinSentence");
|
||||
button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource });
|
||||
button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
const BARTER_RESOURCE_AMOUNT_TO_SELL = 100;
|
||||
const BARTER_BUNCH_MULTIPLIER = 5;
|
||||
const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
const BARTER_ACTIONS = ["Sell", "Buy"];
|
||||
const GATE_ACTIONS = ["lock", "unlock"];
|
||||
|
||||
// upgrade constants
|
||||
const UPGRADING_NOT_STARTED = -2;
|
||||
const UPGRADING_CHOSEN_OTHER = -1;
|
||||
|
||||
// ==============================================
|
||||
// BARTER HELPERS
|
||||
// Resources to sell on barter panel
|
||||
var g_BarterSell = "food";
|
||||
|
||||
function canMoveSelectionIntoFormation(formationTemplate)
|
||||
{
|
||||
if (!(formationTemplate in g_canMoveIntoFormation))
|
||||
|
|
|
|||
|
|
@ -1,24 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="unitBarterPanel"
|
||||
size="6 36 100% 100%"
|
||||
size="4 68 100% 100%"
|
||||
hidden="true"
|
||||
>
|
||||
<object ghost="true" style="resourceText" type="text" size="0 0 100% 20">
|
||||
<translatableAttribute id="tooltip">Exchange resources:</translatableAttribute>
|
||||
</object>
|
||||
<object size="0 32 100% 124">
|
||||
<repeat count="4">
|
||||
<!-- sell -->
|
||||
<object name="unitBarterSellButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">
|
||||
<object name="unitBarterSellIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
|
||||
<object name="unitBarterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
|
||||
<object name="unitBarterSellSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/>
|
||||
</object>
|
||||
<!-- buy -->
|
||||
<object name="unitBarterBuyButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">
|
||||
<object name="unitBarterBuyIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
|
||||
<object name="unitBarterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
<repeat count="4">
|
||||
|
||||
<!-- Sell -->
|
||||
<object name="unitBarterSellButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold" hidden="true">
|
||||
<object name="unitBarterSellIcon[n]" type="image" ghost="true" size="3 3 100%-3 100%-3"/>
|
||||
<object name="unitBarterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
|
||||
<object name="unitBarterSellSelection[n]" hidden="true" type="image" ghost="true" size="3 3 100%-3 100%-3" sprite="stretched:session/icons/corners.png"/>
|
||||
</object>
|
||||
|
||||
<!-- Buy -->
|
||||
<object name="unitBarterBuyButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold" hidden="true">
|
||||
<object name="unitBarterBuyIcon[n]" type="image" ghost="true" size="3 3 100%-3 100%-3"/>
|
||||
<object name="unitBarterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
|
||||
</object>
|
||||
|
||||
</repeat>
|
||||
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ var g_EntityStates = {};
|
|||
var g_TemplateData = {};
|
||||
var g_TemplateDataWithoutLocalization = {};
|
||||
var g_TechnologyData = {};
|
||||
var g_ResourceData = new Resources();
|
||||
|
||||
/**
|
||||
* Top coordinate of the research list.
|
||||
|
|
@ -274,7 +275,10 @@ function init(initData, hotloadData)
|
|||
let gameSpeedIdx = g_GameSpeeds.Speed.indexOf(Engine.GetSimRate());
|
||||
gameSpeed.selected = gameSpeedIdx != -1 ? gameSpeedIdx : g_GameSpeeds.Default;
|
||||
gameSpeed.onSelectionChange = function() { changeGameSpeed(+this.list_data[this.selected]); };
|
||||
|
||||
initMenuPosition();
|
||||
resizeDiplomacyDialog();
|
||||
resizeTradeDialog();
|
||||
|
||||
for (let slot in Engine.GetGUIObjectByName("unitHeroPanel").children)
|
||||
initGUIHeroes(slot);
|
||||
|
|
@ -496,10 +500,27 @@ function updateTopPanel()
|
|||
let viewPlayer = Engine.GetGUIObjectByName("viewPlayer");
|
||||
viewPlayer.hidden = !g_IsObserver && !g_DevSettings.changePerspective;
|
||||
|
||||
Engine.GetGUIObjectByName("food").hidden = !isPlayer;
|
||||
Engine.GetGUIObjectByName("wood").hidden = !isPlayer;
|
||||
Engine.GetGUIObjectByName("stone").hidden = !isPlayer;
|
||||
Engine.GetGUIObjectByName("metal").hidden = !isPlayer;
|
||||
let resCodes = g_ResourceData.GetCodes();
|
||||
let r = 0;
|
||||
for (let res of resCodes)
|
||||
{
|
||||
if (!Engine.GetGUIObjectByName("resource["+r+"]"))
|
||||
{
|
||||
warn("Current GUI limits prevent displaying more than " + r + " resources in the top panel!");
|
||||
break;
|
||||
}
|
||||
Engine.GetGUIObjectByName("resource["+r+"]_icon").sprite = "stretched:session/icons/resources/" + res + ".png";
|
||||
Engine.GetGUIObjectByName("resource["+r+"]").hidden = !isPlayer;
|
||||
++r;
|
||||
}
|
||||
horizontallySpaceObjects("resourceCounts", 5);
|
||||
hideRemaining("resourceCounts", r);
|
||||
|
||||
let resPop = Engine.GetGUIObjectByName("population");
|
||||
let resPopSize = resPop.size;
|
||||
resPopSize.left = Engine.GetGUIObjectByName("resource["+ (r-1) +"]").size.right;
|
||||
resPop.size = resPopSize;
|
||||
|
||||
Engine.GetGUIObjectByName("population").hidden = !isPlayer;
|
||||
Engine.GetGUIObjectByName("diplomacyButton1").hidden = !isPlayer;
|
||||
Engine.GetGUIObjectByName("tradeButton1").hidden = !isPlayer;
|
||||
|
|
@ -994,10 +1015,15 @@ function updatePlayerDisplay()
|
|||
if (!playerState)
|
||||
return;
|
||||
|
||||
for (let res of RESOURCES)
|
||||
let resCodes = g_ResourceData.GetCodes();
|
||||
let resNames = g_ResourceData.GetNames();
|
||||
for (let r = 0; r < resCodes.length; ++r)
|
||||
{
|
||||
Engine.GetGUIObjectByName("resource_" + res).caption = Math.floor(playerState.resourceCounts[res]);
|
||||
Engine.GetGUIObjectByName(res).tooltip = getLocalizedResourceName(res, "firstWord") + getAllyStatTooltip(res);
|
||||
if (!Engine.GetGUIObjectByName("resource["+r+"]"))
|
||||
break;
|
||||
let res = resCodes[r];
|
||||
Engine.GetGUIObjectByName("resource["+r+"]").tooltip = getLocalizedResourceName(resNames[res], "firstWord") + getAllyStatTooltip(res);
|
||||
Engine.GetGUIObjectByName("resource["+r+"]_count").caption = Math.floor(playerState.resourceCounts[res]);
|
||||
}
|
||||
|
||||
Engine.GetGUIObjectByName("resourcePop").caption = sprintf(translate("%(popCount)s/%(popLimit)s"), playerState);
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="food" size="10 0 100 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/food.png" ghost="true"/>
|
||||
<object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_food"/>
|
||||
</object>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="metal" size="280 0 370 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/metal.png" ghost="true"/>
|
||||
<object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_metal"/>
|
||||
</object>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="population" size="370 0 460 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -4 40 34" type="image" sprite="stretched:session/icons/resources/population.png" ghost="true"/>
|
||||
|
||||
<object name="population" size="0 0 50%-52 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -2 40 38" type="image" sprite="stretched:session/icons/resources/population.png" ghost="true"/>
|
||||
<object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourcePop"/>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="stone" size="190 0 280 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/stone.png" ghost="true"/>
|
||||
<object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_stone"/>
|
||||
</object>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="wood" size="100 0 190 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/wood.png" ghost="true"/>
|
||||
<object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_wood"/>
|
||||
</object>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<object size="0 0 50%-90-52 100%" name="resourceCounts">
|
||||
<repeat count="4">
|
||||
<object name="resource[n]" size="0 0 95 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -2 40 38" type="image" name="resource[n]_icon" ghost="true"/>
|
||||
<object size="34 0 100%-2 100%-2" type="text" style="resourceText" name="resource[n]_count"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="tradeDialogPanel"
|
||||
size="50%-250 50%-130 50%+250 50%+100"
|
||||
size="50%-134 50%-130 50%+134 50%+100"
|
||||
type="image"
|
||||
hidden="true"
|
||||
sprite="ModernDialog"
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
<translatableAttribute id="caption">Trading goods selection:</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object size="180 0 100% 100%">
|
||||
<repeat count="4">
|
||||
<object size="180 0 100% 100%" name="tradeResources">
|
||||
<repeat count="8">
|
||||
<object name="tradeResource[n]" size="0 0 58 32">
|
||||
<object name="tradeResourceButton[n]" size="4 0 36 100%" type="button" style="StoneButton">
|
||||
<object name="tradeResourceIcon[n]" type="image" ghost="true"/>
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ function draw()
|
|||
if (p>c)
|
||||
c = p;
|
||||
|
||||
hideRemaining("phase["+i+"]_struct["+s+"]_row["+r+"]_prod[", p, "]");
|
||||
hideRemaining("phase["+i+"]_struct["+s+"]_row["+r+"]", p);
|
||||
}
|
||||
|
||||
let size = thisEle.size;
|
||||
|
|
@ -136,13 +136,14 @@ function draw()
|
|||
phaEle.size = size;
|
||||
}
|
||||
++r;
|
||||
hideRemaining("phase["+i+"]_struct["+s+"]_row[", r, "]");
|
||||
hideRemaining("phase["+i+"]_struct["+s+"]_rows", r);
|
||||
++s;
|
||||
prodBarWidth += eleWidth + defMargin;
|
||||
}
|
||||
hideRemaining("phase["+i+"]_struct[", s, "]");
|
||||
let offset = getPositionOffset(i);
|
||||
|
||||
hideRemaining("phase["+i+"]", s);
|
||||
|
||||
let offset = getPositionOffset(i);
|
||||
// Resize phase bars
|
||||
for (let j = 1; j < phaseList.length - i; ++j)
|
||||
{
|
||||
|
|
@ -195,7 +196,7 @@ function draw()
|
|||
++p;
|
||||
}
|
||||
}
|
||||
hideRemaining("trainer["+t+"]_prod[", p, "]");
|
||||
hideRemaining("trainer["+t+"]_row", p);
|
||||
|
||||
let size = thisEle.size;
|
||||
size.right = size.left + Math.max(p*24, defWidth) + 4;
|
||||
|
|
@ -209,7 +210,7 @@ function draw()
|
|||
phaEle.size = size;
|
||||
++t;
|
||||
}
|
||||
hideRemaining("trainer[", t, "]");
|
||||
hideRemaining("trainers", t);
|
||||
|
||||
let size = Engine.GetGUIObjectByName("display_tree").size;
|
||||
size.right = t > 0 ? -124 : -4;
|
||||
|
|
@ -251,18 +252,6 @@ function getPositionOffset(idx)
|
|||
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).
|
||||
|
|
@ -299,7 +288,7 @@ function predraw()
|
|||
prodBarIcon.sprite = "stretched:session/portraits/"+g_ParsedData.phases[phaseList[i+j]].icon;
|
||||
}
|
||||
// Hide remaining prod bars
|
||||
hideRemaining("phase["+i+"]_bar[", j-1, "]");
|
||||
hideRemaining("phase["+i+"]_bars", j-1);
|
||||
|
||||
let s = 0;
|
||||
let ele = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]");
|
||||
|
|
@ -350,8 +339,8 @@ function predraw()
|
|||
g_DrawLimits[pha].structQuant = s;
|
||||
++i;
|
||||
}
|
||||
hideRemaining("phase[", i, "]");
|
||||
hideRemaining("phase[", i, "]_bar");
|
||||
hideRemaining("phase_rows", i);
|
||||
hideRemaining("phase_ident", i);
|
||||
|
||||
let t = 0;
|
||||
let ele = Engine.GetGUIObjectByName("trainer["+t+"]");
|
||||
|
|
|
|||
|
|
@ -91,5 +91,5 @@ function depath(path)
|
|||
function GetTemplateData(templateName)
|
||||
{
|
||||
var template = loadTemplate(templateName);
|
||||
return GetTemplateDataHelper(template, null, g_AuraData);
|
||||
return GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,28 +5,24 @@
|
|||
*/
|
||||
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.
|
||||
let rates = {};
|
||||
|
||||
// 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)
|
||||
for (let resource of g_ResourceData.GetResources())
|
||||
{
|
||||
let types = [resource.code];
|
||||
for (let subtype in resource.subtypes)
|
||||
// We ignore ruins as those are not that common and skew the results
|
||||
if (subtype !== "ruins")
|
||||
types.push(resource.code + "." + subtype);
|
||||
|
||||
let count, rate;
|
||||
[rate, count] = types[type].reduce(function(sum, t) {
|
||||
[rate, count] = types.reduce((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;
|
||||
rates[resource.code] = +(rate / count).toFixed(1);
|
||||
}
|
||||
|
||||
if (!Object.keys(rates).length)
|
||||
|
|
@ -41,7 +37,7 @@ function loadUnit(templateName)
|
|||
return null;
|
||||
var template = loadTemplate(templateName);
|
||||
|
||||
var unit = GetTemplateDataHelper(template, null, g_AuraData);
|
||||
var unit = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData);
|
||||
unit.phase = false;
|
||||
|
||||
if (unit.requiredTechnology)
|
||||
|
|
@ -94,7 +90,7 @@ function loadUnit(templateName)
|
|||
function loadStructure(templateName)
|
||||
{
|
||||
var template = loadTemplate(templateName);
|
||||
var structure = GetTemplateDataHelper(template, null, g_AuraData);
|
||||
var structure = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData);
|
||||
structure.phase = false;
|
||||
|
||||
if (structure.requiredTechnology)
|
||||
|
|
@ -180,7 +176,7 @@ function loadStructure(templateName)
|
|||
function loadTechnology(techName)
|
||||
{
|
||||
var template = loadTechData(techName);
|
||||
var tech = GetTechnologyDataHelper(template, g_SelectedCiv);
|
||||
var tech = GetTechnologyDataHelper(template, g_SelectedCiv, g_ResourceData);
|
||||
tech.reqs = {};
|
||||
|
||||
if (template.pair !== undefined)
|
||||
|
|
@ -243,7 +239,7 @@ function loadTechnology(techName)
|
|||
function loadPhase(phaseCode)
|
||||
{
|
||||
var template = loadTechData(phaseCode);
|
||||
var phase = GetTechnologyDataHelper(template, g_SelectedCiv);
|
||||
var phase = GetTechnologyDataHelper(template, g_SelectedCiv, g_ResourceData);
|
||||
|
||||
phase.actualPhase = phaseCode;
|
||||
if (template.replaces !== undefined)
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@
|
|||
<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="24" var="p">
|
||||
<object type="image" style="ProdBox" name="phase[k]_struct[s]_row[r]_prod[p]"/>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
<object name="phase[k]_struct[s]_rows">
|
||||
<repeat count="4" var="r">
|
||||
<object name="phase[k]_struct[s]_row[r]">
|
||||
<repeat count="24" var="p">
|
||||
<object type="image" style="ProdBox" name="phase[k]_struct[s]_row[r]_prod[p]"/>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ var g_Lists = {};
|
|||
var g_CivData = {};
|
||||
var g_SelectedCiv = "";
|
||||
var g_CallbackSet = false;
|
||||
var g_ResourceData = new Resources();
|
||||
|
||||
/**
|
||||
* Initialize the dropdown containing all the available civs
|
||||
|
|
|
|||
|
|
@ -64,16 +64,20 @@
|
|||
|
||||
<!-- Structure Tree display -->
|
||||
<object size="0 54+64 100%-124 100%-54" name="display_tree">
|
||||
<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 name="phase_ident">
|
||||
<repeat count="4" var="n">
|
||||
<object>
|
||||
<object name="phase[n]_phase" type="image"/>
|
||||
<object name="phase[n]_bars">
|
||||
<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>
|
||||
</repeat>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
|
||||
<object type="image" name="tree_display" style="TreeDisplay" size="48+16+8 0 100%-12 100%">
|
||||
<include file="gui/structree/rows.xml"/>
|
||||
|
|
@ -93,7 +97,7 @@
|
|||
<translatableAttribute id="caption">Trainer Units</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object type="image" style="TreeDisplay" size="0 24 100% 100%">
|
||||
<object type="image" style="TreeDisplay" size="0 24 100% 100%" name="trainers">
|
||||
<repeat count="3" var="t">
|
||||
<object type="image" style="StructBox" name="trainer[t]">
|
||||
<object type="text" style="StructNameSpecific" name="trainer[t]_name"/>
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ function calculateUnits(playerState, position)
|
|||
|
||||
function calculateResources(playerState, position)
|
||||
{
|
||||
let type = g_ResourcesTypes[position];
|
||||
let type = g_ResourceData.GetCodes()[position];
|
||||
|
||||
return formatIncome(
|
||||
playerState.statistics.resourcesGathered[type],
|
||||
|
|
@ -294,7 +294,7 @@ function calculateTotalResources(playerState)
|
|||
let totalGathered = 0;
|
||||
let totalUsed = 0;
|
||||
|
||||
for (let type of g_ResourcesTypes)
|
||||
for (let type of g_ResourceData.GetCodes())
|
||||
{
|
||||
totalGathered += playerState.statistics.resourcesGathered[type];
|
||||
totalUsed += playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type];
|
||||
|
|
@ -362,7 +362,7 @@ function calculateResourcesTeam(counters)
|
|||
|
||||
function calculateResourceExchanged(playerState, position)
|
||||
{
|
||||
let type = g_ResourcesTypes[position];
|
||||
let type = g_ResourceData.GetCodes()[position];
|
||||
|
||||
return formatIncome(
|
||||
playerState.statistics.resourcesBought[type],
|
||||
|
|
|
|||
|
|
@ -95,10 +95,11 @@ var g_ScorePanelsData = {
|
|||
"resources": {
|
||||
"headings": [
|
||||
{ "caption": translate("Player name"), "yStart": 26, "width": 200 },
|
||||
{ "caption": translate("Food"), "yStart": 34, "width": 100 },
|
||||
{ "caption": translate("Wood"), "yStart": 34, "width": 100 },
|
||||
{ "caption": translate("Stone"), "yStart": 34, "width": 100 },
|
||||
{ "caption": translate("Metal"), "yStart": 34, "width": 100 },
|
||||
...g_ResourceData.GetResources().map(res => ({
|
||||
"caption": translateWithContext("firstWord", res.name),
|
||||
"yStart": 34,
|
||||
"width": 100
|
||||
})),
|
||||
{ "caption": translate("Total"), "yStart": 34, "width": 110 },
|
||||
{
|
||||
"caption": sprintf(translate("Tributes \n(%(sent)s / %(received)s)"),
|
||||
|
|
@ -120,14 +121,15 @@ var g_ScorePanelsData = {
|
|||
"used": g_OutcomeColor + translate("Used") + '[/color]'
|
||||
}),
|
||||
"yStart": 16,
|
||||
"width": (100 * 4 + 110)
|
||||
}, // width = 510
|
||||
"width": 100 * g_ResourceData.GetCodes().length + 110
|
||||
},
|
||||
],
|
||||
"counters": [
|
||||
{ "width": 100, "fn": calculateResources, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateResources, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateResources, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateResources, "verticalOffset": 12 },
|
||||
...g_ResourceData.GetCodes().map(code => ({
|
||||
"fn": calculateResources,
|
||||
"verticalOffset": 12,
|
||||
"width": 100
|
||||
})),
|
||||
{ "width": 110, "fn": calculateTotalResources, "verticalOffset": 12 },
|
||||
{ "width": 121, "fn": calculateTributeSent, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateTreasureCollected, "verticalOffset": 12 },
|
||||
|
|
@ -138,19 +140,28 @@ var g_ScorePanelsData = {
|
|||
"market": {
|
||||
"headings": [
|
||||
{ "caption": translate("Player name"), "yStart": 26, "width": 200 },
|
||||
{ "caption": translate("Food exchanged"), "yStart": 16, "width": 100 },
|
||||
{ "caption": translate("Wood exchanged"), "yStart": 16, "width": 100 },
|
||||
{ "caption": translate("Stone exchanged"), "yStart": 16, "width": 100 },
|
||||
{ "caption": translate("Metal exchanged"), "yStart": 16, "width": 100 },
|
||||
...g_ResourceData.GetResources().map(res => {
|
||||
return {
|
||||
"caption":
|
||||
// Translation: use %(resourceWithinSentence)s if needed
|
||||
sprintf(translate("%(resourceFirstWord)s exchanged"), {
|
||||
"resourceFirstWord": translateWithContext("firstWord", res.name),
|
||||
"resourceWithinSentence": translateWithContext("withinSentence", res.name)
|
||||
}),
|
||||
"yStart": 16,
|
||||
"width": 100
|
||||
};
|
||||
}),
|
||||
{ "caption": translate("Barter efficiency"), "yStart": 16, "width": 100 },
|
||||
{ "caption": translate("Trade income"), "yStart": 16, "width": 100 }
|
||||
],
|
||||
"titleHeadings": [],
|
||||
"counters": [
|
||||
{ "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },
|
||||
...g_ResourceData.GetCodes().map(code => ({
|
||||
"width": 100,
|
||||
"fn": calculateResourceExchanged,
|
||||
"verticalOffset": 12
|
||||
})),
|
||||
{ "width": 100, "fn": calculateBarterEfficiency, "verticalOffset": 12 },
|
||||
{ "width": 100, "fn": calculateTradeIncome, "verticalOffset": 12 }
|
||||
],
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ const g_CapturedColor = '[color="255 255 157"]';
|
|||
|
||||
const g_BuildingsTypes = [ "total", "House", "Economic", "Outpost", "Military", "Fortress", "CivCentre", "Wonder" ];
|
||||
const g_UnitsTypes = [ "total", "Infantry", "Worker", "Cavalry", "Champion", "Hero", "Siege", "Ship", "Trader" ];
|
||||
const g_ResourcesTypes = [ "food", "wood", "stone", "metal" ];
|
||||
|
||||
// Colors used for gathered and traded resources
|
||||
const g_IncomeColor = '[color="201 255 200"]';
|
||||
|
|
@ -34,6 +33,7 @@ var g_PlayerCount = 0;
|
|||
// Count players without team (or all if teams are not displayed)
|
||||
var g_WithoutTeam = 0;
|
||||
var g_GameData;
|
||||
var g_ResourceData = new Resources();
|
||||
|
||||
function selectPanel(panel)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
"extractor": "json",
|
||||
"filemasks": [
|
||||
"gui/credits/texts/**.json"
|
||||
|
|
@ -314,6 +314,38 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"extractor": "json",
|
||||
"filemasks": [
|
||||
"simulation/data/resources/**.json"
|
||||
],
|
||||
"options": {
|
||||
"keywords": [
|
||||
"name",
|
||||
"subtypes"
|
||||
],
|
||||
"comments": [
|
||||
"Translation: Word as used at the beginning of a sentence or as a single-word sentence."
|
||||
],
|
||||
"context": "firstWord"
|
||||
}
|
||||
},
|
||||
{
|
||||
"extractor": "json",
|
||||
"filemasks": [
|
||||
"simulation/data/resources/**.json"
|
||||
],
|
||||
"options": {
|
||||
"keywords": [
|
||||
"name",
|
||||
"subtypes"
|
||||
],
|
||||
"comments": [
|
||||
"Translation: Word as used in the middle of a sentence (which may require using lowercase for your language)."
|
||||
],
|
||||
"context": "withinSentence"
|
||||
}
|
||||
},
|
||||
{
|
||||
"extractor": "txt",
|
||||
"filemasks": [
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ m.Resources = function(amounts = {}, population = 0)
|
|||
this.population = population > 0 ? population : 0;
|
||||
};
|
||||
|
||||
m.Resources.prototype.types = []; // This array will be filled in SharedScript.init
|
||||
// This array will be filled in SharedScript.init
|
||||
m.Resources.prototype.types = [];
|
||||
|
||||
m.Resources.prototype.reset = function()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -182,13 +182,10 @@ m.SharedScript.prototype.init = function(state, deserialization)
|
|||
this.accessibility.init(state, this.terrainAnalyzer);
|
||||
|
||||
// Setup resources
|
||||
this.resourceTypes = { "food": 0, "wood": 1, "stone": 2, "metal": 2 };
|
||||
this.resourceList = [];
|
||||
for (let res in this.resourceTypes)
|
||||
this.resourceList.push(res);
|
||||
m.Resources.prototype.types = this.resourceList;
|
||||
this.resourceInfo = state.resources;
|
||||
m.Resources.prototype.types = state.resources.codes;
|
||||
// Resource types: 0 = not used for resource maps
|
||||
// 1 = abondant resource with small amount each
|
||||
// 1 = abundant resource with small amount each
|
||||
// 2 = spare resource, but huge amount each
|
||||
// The following maps are defined in TerrainAnalysis.js and are used for some building placement (cc, dropsites)
|
||||
// They are updated by checking for create and destroy events for all resources
|
||||
|
|
@ -199,18 +196,6 @@ m.SharedScript.prototype.init = function(state, deserialization)
|
|||
this.ccResourceMaps = {}; // Contains maps showing the density of resources, optimized for CC placement.
|
||||
this.createResourceMaps();
|
||||
|
||||
/** Keep in sync with gui/common/l10n.js */
|
||||
this.resourceNames = {
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"food": markForTranslationWithContext("withinSentence", "Food"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"wood": markForTranslationWithContext("withinSentence", "Wood"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"metal": markForTranslationWithContext("withinSentence", "Metal"),
|
||||
// Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).
|
||||
"stone": markForTranslationWithContext("withinSentence", "Stone"),
|
||||
};
|
||||
|
||||
this.gameState = {};
|
||||
for (let i in this._players)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -383,9 +383,9 @@ m.Accessibility.prototype.floodFill = function(startIndex, value, onWater)
|
|||
/** creates a map of resource density */
|
||||
m.SharedScript.prototype.createResourceMaps = function()
|
||||
{
|
||||
for (let resource of this.resourceList)
|
||||
for (let resource of this.resourceInfo.codes)
|
||||
{
|
||||
if (this.resourceTypes[resource] !== 1 && this.resourceTypes[resource] !== 2)
|
||||
if (this.resourceInfo.aiInfluenceGroups[resource] === 0)
|
||||
continue;
|
||||
// if there is no resourceMap create one with an influence for everything with that resource
|
||||
if (this.resourceMaps[resource])
|
||||
|
|
@ -405,11 +405,11 @@ m.SharedScript.prototype.createResourceMaps = function()
|
|||
let cellSize = this.resourceMaps[resource].cellSize;
|
||||
let x = Math.floor(ent.position()[0] / cellSize);
|
||||
let z = Math.floor(ent.position()[1] / cellSize);
|
||||
let type = this.resourceTypes[resource];
|
||||
let strength = Math.floor(ent.resourceSupplyMax()/this.normalizationFactor[type]);
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[type]/cellSize, strength/2, "constant");
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[type]/cellSize, strength/2);
|
||||
this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[type]/cellSize, strength, "constant");
|
||||
let grp = this.resourceInfo.aiInfluenceGroups[resource];
|
||||
let strength = Math.floor(ent.resourceSupplyMax() / this.normalizationFactor[grp]);
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2, "constant");
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2);
|
||||
this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[grp] / cellSize, strength, "constant");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -420,9 +420,9 @@ m.SharedScript.prototype.createResourceMaps = function()
|
|||
*/
|
||||
m.SharedScript.prototype.updateResourceMaps = function(events)
|
||||
{
|
||||
for (let resource of this.resourceList)
|
||||
for (let resource of this.resourceInfo.codes)
|
||||
{
|
||||
if (this.resourceTypes[resource] !== 1 && this.resourceTypes[resource] !== 2)
|
||||
if (this.resourceInfo.aiInfluenceGroups[resource] === 0)
|
||||
continue;
|
||||
// if there is no resourceMap create one with an influence for everything with that resource
|
||||
if (this.resourceMaps[resource])
|
||||
|
|
@ -447,11 +447,11 @@ m.SharedScript.prototype.updateResourceMaps = function(events)
|
|||
let cellSize = this.resourceMaps[resource].cellSize;
|
||||
let x = Math.floor(ent.position()[0] / cellSize);
|
||||
let z = Math.floor(ent.position()[1] / cellSize);
|
||||
let type = this.resourceTypes[resource];
|
||||
let strength = -Math.floor(ent.resourceSupplyMax()/this.normalizationFactor[type]);
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[type]/cellSize, strength/2, "constant");
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[type]/cellSize, strength/2);
|
||||
this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[type]/cellSize, strength, "constant");
|
||||
let grp = this.resourceInfo.aiInfluenceGroups[resource];
|
||||
let strength = -Math.floor(ent.resourceSupplyMax() / this.normalizationFactor[grp]);
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2, "constant");
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2);
|
||||
this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[grp] / cellSize, strength, "constant");
|
||||
}
|
||||
for (let e of events.Create)
|
||||
{
|
||||
|
|
@ -466,11 +466,11 @@ m.SharedScript.prototype.updateResourceMaps = function(events)
|
|||
let cellSize = this.resourceMaps[resource].cellSize;
|
||||
let x = Math.floor(ent.position()[0] / cellSize);
|
||||
let z = Math.floor(ent.position()[1] / cellSize);
|
||||
let type = this.resourceTypes[resource];
|
||||
let strength = Math.floor(ent.resourceSupplyMax()/this.normalizationFactor[type]);
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[type]/cellSize, strength/2, "constant");
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[type]/cellSize, strength/2);
|
||||
this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[type]/cellSize, strength, "constant");
|
||||
let grp = this.resourceInfo.aiInfluenceGroups[resource];
|
||||
let strength = Math.floor(ent.resourceSupplyMax() / this.normalizationFactor[grp]);
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2, "constant");
|
||||
this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2);
|
||||
this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[grp] / cellSize, strength, "constant");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ m.BaseManager.prototype.init = function(gameState, state)
|
|||
this.dropsites = {};
|
||||
this.dropsiteSupplies = {};
|
||||
this.gatherers = {};
|
||||
for (let res of gameState.sharedScript.resourceList)
|
||||
for (let res of gameState.sharedScript.resourceInfo.codes)
|
||||
{
|
||||
this.dropsiteSupplies[res] = { "nearby": [], "medium": [], "faraway": [] };
|
||||
this.gatherers[res] = { "nextCheck": 0, "used": 0, "lost": 0 };
|
||||
|
|
@ -434,7 +434,7 @@ m.BaseManager.prototype.getResourceLevel = function (gameState, type, nearbyOnly
|
|||
/** check our resource levels and react accordingly */
|
||||
m.BaseManager.prototype.checkResourceLevels = function (gameState, queues)
|
||||
{
|
||||
for (let type of gameState.sharedScript.resourceList)
|
||||
for (let type of gameState.sharedScript.resourceInfo.codes)
|
||||
{
|
||||
if (type === "food")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ m.chatLaunchAttack = function(gameState, player, type)
|
|||
"message": "/allies "+ message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": ["_player_"],
|
||||
"parameters": {"_player_": player}
|
||||
"parameters": { "_player_": player }
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ m.chatAnswerRequestAttack = function(gameState, player, answer, other)
|
|||
"message": "/allies " + message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": ["_player_"],
|
||||
"parameters": {"_player_": player}
|
||||
"parameters": { "_player_": player }
|
||||
};
|
||||
if (other !== undefined)
|
||||
{
|
||||
|
|
@ -71,7 +71,7 @@ m.chatSentTribute = function(gameState, player)
|
|||
"message": "/allies " + message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": ["_player_"],
|
||||
"parameters": {"_player_": player}
|
||||
"parameters": { "_player_": player }
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -90,8 +90,8 @@ m.chatRequestTribute = function(gameState, resource)
|
|||
"type": "aichat",
|
||||
"message": "/allies " + message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": {"resource": "withinSentence"},
|
||||
"parameters": {"resource": gameState.sharedScript.resourceNames[resource]}
|
||||
"translateParameters": { "resource": "withinSentence" },
|
||||
"parameters": { "resource": gameState.sharedScript.resourceInfo.names[resource] }
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ m.chatNewTradeRoute = function(gameState, player)
|
|||
"message": "/allies " + message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": ["_player_"],
|
||||
"parameters": {"_player_": player}
|
||||
"parameters": { "_player_": player }
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,26 @@ m.Config = function(difficulty)
|
|||
"defensive": 0.5
|
||||
};
|
||||
|
||||
this.resources = ["food", "wood", "stone", "metal"];
|
||||
// See m.QueueManager.prototype.wantedGatherRates()
|
||||
this.queues =
|
||||
{
|
||||
"firstTurn": {
|
||||
"food": 10,
|
||||
"wood": 10,
|
||||
"default": 0
|
||||
},
|
||||
"short": {
|
||||
"food": 200,
|
||||
"wood": 200,
|
||||
"default": 100
|
||||
},
|
||||
"medium": {
|
||||
"default": 0
|
||||
},
|
||||
"long": {
|
||||
"default": 0
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
m.Config.prototype.setConfig = function(gameState)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ m.HQ.prototype.init = function(gameState, queues)
|
|||
this.navalMap = false;
|
||||
this.navalRegions = {};
|
||||
|
||||
for (let res of gameState.sharedScript.resourceList)
|
||||
for (let res of gameState.sharedScript.resourceInfo.codes)
|
||||
{
|
||||
this.wantedRates[res] = 0;
|
||||
this.currentRates[res] = 0;
|
||||
|
|
@ -654,7 +654,7 @@ m.HQ.prototype.bulkPickWorkers = function(gameState, baseRef, number)
|
|||
m.HQ.prototype.getTotalResourceLevel = function(gameState)
|
||||
{
|
||||
let total = {};
|
||||
for (let res of gameState.sharedScript.resourceList)
|
||||
for (let res of gameState.sharedScript.resourceInfo.codes)
|
||||
total[res] = 0;
|
||||
for (let base of this.baseManagers)
|
||||
for (let res in total)
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ m.QueueManager.prototype.wantedGatherRates = function(gameState)
|
|||
if (gameState.ai.playedTurn === 0)
|
||||
{
|
||||
let ret = {};
|
||||
for (let res of gameState.sharedScript.resourceList)
|
||||
ret[res] = (res === "food" || res === "wood" ) ? 10 : 0;
|
||||
for (let res of gameState.sharedScript.resourceInfo.codes)
|
||||
ret[res] = this.Config.queues.firstTurn[res] || this.Config.queues.firstTurn.default;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -97,11 +97,11 @@ m.QueueManager.prototype.wantedGatherRates = function(gameState)
|
|||
let totalShort = {};
|
||||
let totalMedium = {};
|
||||
let totalLong = {};
|
||||
for (let res of gameState.sharedScript.resourceList)
|
||||
for (let res of gameState.sharedScript.resourceInfo.codes)
|
||||
{
|
||||
totalShort[res] = (res === "food" || res === "wood" ) ? 200 : 100;
|
||||
totalMedium[res] = 0;
|
||||
totalLong[res] = 0;
|
||||
totalShort[res] = this.Config.queues.short[res] || this.Config.queues.short.default;
|
||||
totalMedium[res] = this.Config.queues.medium[res] || this.Config.queues.medium.default;
|
||||
totalLong[res] = this.Config.queues.long[res] || this.Config.queues.long.default;
|
||||
}
|
||||
let total;
|
||||
//queueArrays because it's faster.
|
||||
|
|
@ -133,7 +133,7 @@ m.QueueManager.prototype.wantedGatherRates = function(gameState)
|
|||
// global rates
|
||||
let rates = {};
|
||||
let diff;
|
||||
for (let res of gameState.sharedScript.resourceList)
|
||||
for (let res of gameState.sharedScript.resourceInfo.codes)
|
||||
{
|
||||
if (current[res] > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ m.ResearchManager.prototype.researchWantedTechs = function(gameState, techs)
|
|||
let cost = template.cost;
|
||||
let costMax = 0;
|
||||
for (let res in cost)
|
||||
costMax = Math.max(costMax, Math.max(cost[res]-available[res], 0));
|
||||
if (gameState.sharedScript.resourceInfo.codes.indexOf(res) != -1)
|
||||
costMax = Math.max(costMax, Math.max(cost[res]-available[res], 0));
|
||||
if (10*numWorkers < costMax)
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
// True price of 100 units of resource (for case if some resource is more worth).
|
||||
// The "true price" is a base price of 100 units of resource (for the case of some resources being of more worth than others).
|
||||
// With current bartering system only relative values makes sense
|
||||
// so if for example stone is two times more expensive than wood,
|
||||
// there will 2:1 exchange rate.
|
||||
const TRUE_PRICES = { "food": 100, "wood": 100, "stone": 100, "metal": 100 };
|
||||
|
||||
//
|
||||
// Constant part of price difference between true price and buy/sell price.
|
||||
// In percents.
|
||||
// Buy price equal to true price plus constant difference.
|
||||
|
|
@ -21,9 +20,6 @@ const DIFFERENCE_RESTORE = 0.5;
|
|||
// Interval of timer which slowly restore prices after deals
|
||||
const RESTORE_TIMER_INTERVAL = 5000;
|
||||
|
||||
// Array of resource names
|
||||
const RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
|
||||
function Barter() {}
|
||||
|
||||
Barter.prototype.Schema =
|
||||
|
|
@ -32,7 +28,7 @@ Barter.prototype.Schema =
|
|||
Barter.prototype.Init = function()
|
||||
{
|
||||
this.priceDifferences = {};
|
||||
for (var resource of RESOURCES)
|
||||
for (let resource of Resources.GetCodes())
|
||||
this.priceDifferences[resource] = 0;
|
||||
this.restoreTimer = undefined;
|
||||
};
|
||||
|
|
@ -40,10 +36,11 @@ Barter.prototype.Init = function()
|
|||
Barter.prototype.GetPrices = function()
|
||||
{
|
||||
var prices = { "buy": {}, "sell": {} };
|
||||
for (var resource of RESOURCES)
|
||||
for (let resource of Resources.GetCodes())
|
||||
{
|
||||
prices["buy"][resource] = TRUE_PRICES[resource] * (100 + CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
|
||||
prices["sell"][resource] = TRUE_PRICES[resource] * (100 - CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
|
||||
let truePrice = Resources.GetResource(resource).truePrice;
|
||||
prices.buy[resource] = truePrice * (100 + CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
|
||||
prices.sell[resource] = truePrice * (100 - CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
|
||||
}
|
||||
return prices;
|
||||
};
|
||||
|
|
@ -71,12 +68,13 @@ Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, reso
|
|||
warn("ExchangeResources: incorrect amount: " + uneval(amount));
|
||||
return;
|
||||
}
|
||||
if (RESOURCES.indexOf(resourceToSell) == -1)
|
||||
let availResources = Resources.GetCodes();
|
||||
if (availResources.indexOf(resourceToSell) == -1)
|
||||
{
|
||||
warn("ExchangeResources: incorrect resource to sell: " + uneval(resourceToSell));
|
||||
return;
|
||||
}
|
||||
if (RESOURCES.indexOf(resourceToBuy) == -1)
|
||||
if (availResources.indexOf(resourceToBuy) == -1)
|
||||
{
|
||||
warn("ExchangeResources: incorrect resource to buy: " + uneval(resourceToBuy));
|
||||
return;
|
||||
|
|
@ -135,7 +133,7 @@ Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, reso
|
|||
Barter.prototype.ProgressTimeout = function(data)
|
||||
{
|
||||
var needRestore = false;
|
||||
for (var resource of RESOURCES)
|
||||
for (let resource of Resources.GetCodes())
|
||||
{
|
||||
// Calculate value to restore, it should be limited to [-DIFFERENCE_RESTORE; DIFFERENCE_RESTORE] interval
|
||||
var differenceRestore = Math.min(DIFFERENCE_RESTORE, Math.max(-DIFFERENCE_RESTORE, this.priceDifferences[resource]));
|
||||
|
|
|
|||
|
|
@ -19,16 +19,11 @@ Cost.prototype.Schema =
|
|||
"<element name='PopulationBonus' a:help='Population cap increase while this entity exists'>" +
|
||||
"<data type='nonNegativeInteger'/>" +
|
||||
"</element>" +
|
||||
"<element name='BuildTime' a:help='Time taken to construct/train this unit (in seconds)'>" +
|
||||
"<element name='BuildTime' a:help='Time taken to construct/train this entity (in seconds)'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
"</element>" +
|
||||
"<element name='Resources' a:help='Resource costs to construct/train this unit'>" +
|
||||
"<interleave>" +
|
||||
"<element name='food'><data type='nonNegativeInteger'/></element>" +
|
||||
"<element name='wood'><data type='nonNegativeInteger'/></element>" +
|
||||
"<element name='stone'><data type='nonNegativeInteger'/></element>" +
|
||||
"<element name='metal'><data type='nonNegativeInteger'/></element>" +
|
||||
"</interleave>" +
|
||||
"<element name='Resources' a:help='Resource costs to construct/train this entity'>" +
|
||||
Resources.BuildSchema("nonNegativeDecimal") +
|
||||
"</element>";
|
||||
|
||||
Cost.prototype.Init = function()
|
||||
|
|
@ -70,8 +65,15 @@ Cost.prototype.GetResourceCosts = function(owner)
|
|||
let entityTemplate = cmpTemplateManager.GetTemplate(entityTemplateName);
|
||||
|
||||
let costs = {};
|
||||
for (let r in this.template.Resources)
|
||||
costs[r] = ApplyValueModificationsToTemplate("Cost/Resources/"+r, +this.template.Resources[r], owner, entityTemplate);
|
||||
let resCodes = Resources.GetCodes();
|
||||
|
||||
for (let res in this.template.Resources)
|
||||
{
|
||||
if (resCodes.indexOf(res) == -1)
|
||||
continue;
|
||||
costs[res] = ApplyValueModificationsToTemplate("Cost/Resources/"+res, +this.template.Resources[res], owner, entityTemplate);
|
||||
}
|
||||
|
||||
return costs;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,15 @@ GuiInterface.prototype.GetSimulationState = function()
|
|||
let cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter);
|
||||
ret.barterPrices = cmpBarter.GetPrices();
|
||||
|
||||
// Add Resource Codes, untranslated names and AI Analysis
|
||||
ret.resources = {
|
||||
"codes": Resources.GetCodes(),
|
||||
"names": Resources.GetNames(),
|
||||
"aiInfluenceGroups": {}
|
||||
};
|
||||
for (let res of ret.resources.codes)
|
||||
ret.resources.aiInfluenceGroups[res] = Resources.GetResource(res).aiAnalysisInfluenceGroup || 0;
|
||||
|
||||
// Add basic statistics to each player
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
|
|
@ -628,7 +637,7 @@ GuiInterface.prototype.GetTemplateData = function(player, extendedName)
|
|||
let aurasTemplate = {};
|
||||
|
||||
if (!template.Auras)
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate);
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate, Resources);
|
||||
|
||||
// Add aura name and description loaded from JSON file
|
||||
let auraNames = template.Auras._string.split(/\s+/);
|
||||
|
|
@ -646,7 +655,7 @@ GuiInterface.prototype.GetTemplateData = function(player, extendedName)
|
|||
aurasTemplate[name].auraName = auraTemplate.auraName || null;
|
||||
aurasTemplate[name].auraDescription = auraTemplate.auraDescription || null;
|
||||
}
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate);
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate, Resources);
|
||||
};
|
||||
|
||||
GuiInterface.prototype.GetTechnologyData = function(player, name)
|
||||
|
|
@ -661,7 +670,7 @@ GuiInterface.prototype.GetTechnologyData = function(player, name)
|
|||
}
|
||||
|
||||
let cmpPlayer = QueryPlayerIDInterface(player, IID_Player);
|
||||
return GetTechnologyDataHelper(template, cmpPlayer.GetCiv());
|
||||
return GetTechnologyDataHelper(template, cmpPlayer.GetCiv(), Resources);
|
||||
};
|
||||
|
||||
GuiInterface.prototype.IsTechnologyResearched = function(player, data)
|
||||
|
|
@ -1285,8 +1294,10 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
|
|||
|
||||
let result = {
|
||||
"pieces": [],
|
||||
"cost": { "food": 0, "wood": 0, "stone": 0, "metal": 0, "population": 0, "populationBonus": 0, "time": 0 },
|
||||
"cost": { "population": 0, "populationBonus": 0, "time": 0 },
|
||||
};
|
||||
for (let res of Resources.GetCodes())
|
||||
result.cost[res] = 0;
|
||||
|
||||
let previewEntities = [];
|
||||
if (end.pos)
|
||||
|
|
@ -1561,13 +1572,8 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
|
|||
// copied over, so we need to fetch it from the template instead).
|
||||
// TODO: we should really use a Cost object or at least some utility functions for this, this is mindless
|
||||
// boilerplate that's probably duplicated in tons of places.
|
||||
result.cost.food += tplData.cost.food;
|
||||
result.cost.wood += tplData.cost.wood;
|
||||
result.cost.stone += tplData.cost.stone;
|
||||
result.cost.metal += tplData.cost.metal;
|
||||
result.cost.population += tplData.cost.population;
|
||||
result.cost.populationBonus += tplData.cost.populationBonus;
|
||||
result.cost.time += tplData.cost.time;
|
||||
for (let res of Resources.GetCodes().concat("population", "populationBonus", "time"))
|
||||
result.cost[res] = tplData.cost[res];
|
||||
}
|
||||
|
||||
let canAfford = true;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
function Loot() {}
|
||||
|
||||
Loot.prototype.Schema =
|
||||
"<optional>" +
|
||||
"<element name='xp'><data type='nonNegativeInteger'/></element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='food'><data type='nonNegativeInteger'/></element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='wood'><data type='nonNegativeInteger'/></element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='stone'><data type='nonNegativeInteger'/></element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='metal'><data type='nonNegativeInteger'/></element>" +
|
||||
"</optional>";
|
||||
"<a:help>Specifies the loot credited when this entity is killed.</a:help>" +
|
||||
"<a:example>" +
|
||||
"<xp>35</xp>" +
|
||||
"<metal>10</metal>" +
|
||||
"</a:example>" +
|
||||
Resources.BuildSchema("nonNegativeInteger", ["xp"]);
|
||||
|
||||
Loot.prototype.Serialize = null; // we have no dynamic state to save
|
||||
|
||||
|
|
@ -26,12 +17,11 @@ Loot.prototype.GetXp = function()
|
|||
|
||||
Loot.prototype.GetResources = function()
|
||||
{
|
||||
return {
|
||||
"food": +(this.template.food || 0),
|
||||
"wood": +(this.template.wood || 0),
|
||||
"metal": +(this.template.metal || 0),
|
||||
"stone": +(this.template.stone || 0)
|
||||
};
|
||||
let ret = {};
|
||||
for (let res of Resources.GetCodes())
|
||||
ret[res] = +(this.template[res] || 0);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Loot, "Loot", Loot);
|
||||
|
|
|
|||
|
|
@ -24,12 +24,13 @@ Looter.prototype.Collect = function(targetEntity)
|
|||
);
|
||||
|
||||
// Loot resources as defined in the templates
|
||||
var resources = cmpLoot.GetResources();
|
||||
for (let type in resources)
|
||||
resources[type] = ApplyValueModificationsToEntity("Looter/Resource/"+type, resources[type], this.entity)
|
||||
+ (resourcesCarried[type] || 0);
|
||||
|
||||
// TODO: stop assuming that cmpLoot.GetResources() delivers all resource types (by defining them in a central location)
|
||||
let lootTemplate = cmpLoot.GetResources();
|
||||
let resources = {};
|
||||
for (let type of Resources.GetCodes())
|
||||
resources[type] =
|
||||
ApplyValueModificationsToEntity(
|
||||
"Looter/Resource/"+type, lootTemplate[type] || 0, this.entity) +
|
||||
(resourcesCarried[type] || 0);
|
||||
|
||||
// Transfer resources
|
||||
var cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
|
|
|
|||
|
|
@ -18,18 +18,8 @@ Player.prototype.Init = function()
|
|||
this.popBonuses = 0; // sum of population bonuses of player's entities
|
||||
this.maxPop = 300; // maximum population
|
||||
this.trainingBlocked = false; // indicates whether any training queue is currently blocked
|
||||
this.resourceCount = {
|
||||
"food": 300,
|
||||
"wood": 300,
|
||||
"metal": 300,
|
||||
"stone": 300
|
||||
};
|
||||
// goods for next trade-route and its proba in % (the sum of probas must be 100)
|
||||
this.tradingGoods = [
|
||||
{ "goods": "wood", "proba": 30 },
|
||||
{ "goods": "stone", "proba": 35 },
|
||||
{ "goods": "metal", "proba": 35 },
|
||||
];
|
||||
this.resourceCount = {};
|
||||
this.tradingGoods = []; // goods for next trade-route and its proba in % (the sum of probas must be 100)
|
||||
this.team = -1; // team number of the player, players on the same team will always have ally diplomatic status - also this is useful for team emblems, scoring, etc.
|
||||
this.teamsLocked = false;
|
||||
this.state = "active"; // game state - one of "active", "defeated", "won"
|
||||
|
|
@ -44,15 +34,25 @@ Player.prototype.Init = function()
|
|||
this.cheatsEnabled = false;
|
||||
this.cheatTimeMultiplier = 1;
|
||||
this.heroes = [];
|
||||
this.resourceNames = {
|
||||
"food": markForTranslation("Food"),
|
||||
"wood": markForTranslation("Wood"),
|
||||
"metal": markForTranslation("Metal"),
|
||||
"stone": markForTranslation("Stone"),
|
||||
};
|
||||
this.resourceNames = {};
|
||||
this.disabledTemplates = {};
|
||||
this.disabledTechnologies = {};
|
||||
this.startingTechnologies = [];
|
||||
|
||||
// Initial resources and trading goods probability in steps of 5
|
||||
let resCodes = Resources.GetCodes();
|
||||
let quotient = Math.floor(20 / resCodes.length);
|
||||
let remainder = 20 % resCodes.length;
|
||||
for (let i in resCodes)
|
||||
{
|
||||
let res = resCodes[i];
|
||||
this.resourceCount[res] = 300;
|
||||
this.resourceNames[res] = Resources.GetResource(res).name;
|
||||
this.tradingGoods.push({
|
||||
"goods": res,
|
||||
"proba": 5 * (quotient + (+i < remainder ? 1 : 0))
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.SetPlayerID = function(id)
|
||||
|
|
@ -197,14 +197,9 @@ Player.prototype.UnBlockTraining = function()
|
|||
|
||||
Player.prototype.SetResourceCounts = function(resources)
|
||||
{
|
||||
if (resources.food !== undefined)
|
||||
this.resourceCount.food = resources.food;
|
||||
if (resources.wood !== undefined)
|
||||
this.resourceCount.wood = resources.wood;
|
||||
if (resources.stone !== undefined)
|
||||
this.resourceCount.stone = resources.stone;
|
||||
if (resources.metal !== undefined)
|
||||
this.resourceCount.metal = resources.metal;
|
||||
for (let res in resources)
|
||||
if (this.resourceCount[res])
|
||||
this.resourceCount[res] = resources[res];
|
||||
};
|
||||
|
||||
Player.prototype.GetResourceCounts = function()
|
||||
|
|
@ -228,9 +223,7 @@ Player.prototype.AddResource = function(type, amount)
|
|||
Player.prototype.AddResources = function(amounts)
|
||||
{
|
||||
for (var type in amounts)
|
||||
{
|
||||
this.resourceCount[type] += +amounts[type];
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.GetNeededResources = function(amounts)
|
||||
|
|
@ -297,7 +290,8 @@ Player.prototype.SubtractResourcesOrNotify = function(amounts)
|
|||
|
||||
// Subtract the resources
|
||||
for (var type in amounts)
|
||||
this.resourceCount[type] -= amounts[type];
|
||||
if (this.resourceCount[type])
|
||||
this.resourceCount[type] -= amounts[type];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
@ -340,18 +334,30 @@ Player.prototype.GetTradingGoods = function()
|
|||
|
||||
Player.prototype.SetTradingGoods = function(tradingGoods)
|
||||
{
|
||||
var sumProba = 0;
|
||||
for (var resource in tradingGoods)
|
||||
sumProba += tradingGoods[resource];
|
||||
if (sumProba != 100) // consistency check
|
||||
let resCodes = Resources.GetCodes();
|
||||
let sumProba = 0;
|
||||
for (let resource in tradingGoods)
|
||||
{
|
||||
error("Player.js SetTradingGoods: " + uneval(tradingGoods));
|
||||
tradingGoods = { "food": 20, "wood":20, "stone":30, "metal":30 };
|
||||
if (resCodes.indexOf(resource) == -1)
|
||||
{
|
||||
error("Invalid trading goods: " + uneval(tradingGoods));
|
||||
return;
|
||||
}
|
||||
sumProba += tradingGoods[resource];
|
||||
}
|
||||
|
||||
if (sumProba != 100)
|
||||
{
|
||||
error("Invalid trading goods: " + uneval(tradingGoods));
|
||||
return;
|
||||
}
|
||||
|
||||
this.tradingGoods = [];
|
||||
for (var resource in tradingGoods)
|
||||
this.tradingGoods.push( {"goods": resource, "proba": tradingGoods[resource]} );
|
||||
for (let resource in tradingGoods)
|
||||
this.tradingGoods.push({
|
||||
"goods": resource,
|
||||
"proba": tradingGoods[resource]
|
||||
});
|
||||
};
|
||||
|
||||
Player.prototype.GetState = function()
|
||||
|
|
|
|||
|
|
@ -31,13 +31,7 @@ ProductionQueue.prototype.Schema =
|
|||
"</element>" +
|
||||
"</optional>" +
|
||||
"<element name='TechCostMultiplier' a:help='Multiplier to modify ressources cost and research time of technologies searched in this building.'>" +
|
||||
"<interleave>" +
|
||||
"<element name='food'><ref name='nonNegativeDecimal'/></element>" +
|
||||
"<element name='wood'><ref name='nonNegativeDecimal'/></element>" +
|
||||
"<element name='stone'><ref name='nonNegativeDecimal'/></element>" +
|
||||
"<element name='metal'><ref name='nonNegativeDecimal'/></element>" +
|
||||
"<element name='time'><ref name='nonNegativeDecimal'/></element>" +
|
||||
"</interleave>" +
|
||||
Resources.BuildSchema("nonNegativeDecimal", ["time"]) +
|
||||
"</element>";
|
||||
|
||||
ProductionQueue.prototype.Init = function()
|
||||
|
|
@ -260,7 +254,8 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
|
|||
// TODO: there should probably be a limit on the number of queued batches
|
||||
// TODO: there should be a way for the GUI to determine whether it's going
|
||||
// to be possible to add a batch (based on resource costs and length limits)
|
||||
var cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
let cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
let resCodes = Resources.GetCodes();
|
||||
|
||||
if (this.queue.length < MAX_QUEUE_SIZE)
|
||||
{
|
||||
|
|
@ -293,10 +288,12 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
|
|||
var buildTime = ApplyValueModificationsToTemplate("Cost/BuildTime", +template.Cost.BuildTime, cmpPlayer.GetPlayerID(), template);
|
||||
var time = timeMult * buildTime;
|
||||
|
||||
for (var r in template.Cost.Resources)
|
||||
for (let res in template.Cost.Resources)
|
||||
{
|
||||
costs[r] = ApplyValueModificationsToTemplate("Cost/Resources/"+r, +template.Cost.Resources[r], cmpPlayer.GetPlayerID(), template);
|
||||
totalCosts[r] = Math.floor(count * costs[r]);
|
||||
if (resCodes.indexOf(res) == -1)
|
||||
continue;
|
||||
costs[res] = ApplyValueModificationsToTemplate("Cost/Resources/"+res, +template.Cost.Resources[res], cmpPlayer.GetPlayerID(), template);
|
||||
totalCosts[res] = Math.floor(count * costs[res]);
|
||||
}
|
||||
|
||||
var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template);
|
||||
|
|
@ -337,6 +334,7 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
|
|||
var template = cmpDataTemplateManager.GetTechnologyTemplate(templateName);
|
||||
if (!template)
|
||||
return;
|
||||
|
||||
if (!this.GetTechnologiesList().some(tech =>
|
||||
tech &&
|
||||
(tech == templateName ||
|
||||
|
|
@ -346,13 +344,17 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
|
|||
error("This entity cannot research " + templateName);
|
||||
return;
|
||||
}
|
||||
var cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
|
||||
let techCostMultiplier = this.GetTechCostMultiplier();
|
||||
let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier();
|
||||
|
||||
var cost = {};
|
||||
let cost = {};
|
||||
for (let res in template.cost)
|
||||
cost[res] = Math.floor(techCostMultiplier[res] * template.cost[res]);
|
||||
{
|
||||
if (resCodes.indexOf(res) == -1)
|
||||
continue;
|
||||
cost[res] = Math.floor((techCostMultiplier[res] || 1) * template.cost[res]);
|
||||
}
|
||||
|
||||
// TrySubtractResources should report error to player (they ran out of resources)
|
||||
if (!cmpPlayer.TrySubtractResources(cost))
|
||||
|
|
@ -370,7 +372,7 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
|
|||
"player": cmpPlayer.GetPlayerID(),
|
||||
"count": 1,
|
||||
"technologyTemplate": templateName,
|
||||
"resources": deepcopy(template.cost), // need to copy to avoid serialization problems
|
||||
"resources": cost,
|
||||
"productionStarted": false,
|
||||
"timeTotal": time*1000,
|
||||
"timeRemaining": time*1000,
|
||||
|
|
@ -442,8 +444,10 @@ ProductionQueue.prototype.RemoveBatch = function(id)
|
|||
// Refund the resource cost for this batch
|
||||
var totalCosts = {};
|
||||
var cmpStatisticsTracker = QueryPlayerIDInterface(item.player, IID_StatisticsTracker);
|
||||
for each (var r in ["food", "wood", "stone", "metal"])
|
||||
for (let r of Resources.GetCodes())
|
||||
{
|
||||
if (!item.resources[r])
|
||||
continue;
|
||||
totalCosts[r] = Math.floor(item.count * item.resources[r]);
|
||||
if (cmpStatisticsTracker)
|
||||
cmpStatisticsTracker.IncreaseResourceUsedCounter(r, -totalCosts[r]);
|
||||
|
|
|
|||
|
|
@ -4,12 +4,7 @@ ResourceDropsite.prototype.Schema =
|
|||
"<element name='Types'>" +
|
||||
"<list>" +
|
||||
"<zeroOrMore>" +
|
||||
"<choice>" +
|
||||
"<value>food</value>" +
|
||||
"<value>wood</value>" +
|
||||
"<value>stone</value>" +
|
||||
"<value>metal</value>" +
|
||||
"</choice>" +
|
||||
Resources.BuildChoicesSchema() +
|
||||
"</zeroOrMore>" +
|
||||
"</list>" +
|
||||
"</element>" +
|
||||
|
|
@ -24,12 +19,14 @@ ResourceDropsite.prototype.Init = function()
|
|||
};
|
||||
|
||||
/**
|
||||
* Returns the list of resource types accepted by this dropsite.
|
||||
* Returns the list of resource types accepted by this dropsite,
|
||||
* as defined by it being referred to in the template and the resource being enabled.
|
||||
*/
|
||||
ResourceDropsite.prototype.GetTypes = function()
|
||||
{
|
||||
let types = ApplyValueModificationsToEntity("ResourceDropsite/Types", this.template.Types, this.entity);
|
||||
return types ? types.split(/\s+/) : [];
|
||||
let resources = Resources.GetCodes();
|
||||
return types.split(/\s+/).filter(type => resources.indexOf(type) != -1);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,35 +25,10 @@ ResourceGatherer.prototype.Schema =
|
|||
"<ref name='positiveDecimal'/>" +
|
||||
"</element>" +
|
||||
"<element name='Rates' a:help='Per-resource-type gather rate multipliers. If a resource type is not specified then it cannot be gathered by this unit'>" +
|
||||
"<interleave>" +
|
||||
"<optional><element name='food' a:help='Food gather rate (may be overridden by \"food.*\" subtypes)'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='wood' a:help='Wood gather rate'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='stone' a:help='Stone gather rate'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='metal' a:help='Metal gather rate'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='treasure' a:help='Treasure gather rate (only presense on value makes sense, size is only used to determine the delay before gathering, so it should be set to 1)'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='food.fish' a:help='Fish gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='food.fruit' a:help='Fruit gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='food.grain' a:help='Grain gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='food.meat' a:help='Meat gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='food.milk' a:help='Milk gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='wood.tree' a:help='Tree gather rate (overrides \"wood\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='wood.ruins' a:help='Tree gather rate (overrides \"wood\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='stone.rock' a:help='Rock gather rate (overrides \"stone\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='stone.ruins' a:help='Rock gather rate (overrides \"stone\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='metal.ore' a:help='Ore gather rate (overrides \"metal\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='treasure.food' a:help='Food treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='treasure.wood' a:help='Wood treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='treasure.stone' a:help='Stone treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"<optional><element name='treasure.metal' a:help='Metal treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" +
|
||||
"</interleave>" +
|
||||
Resources.BuildSchema("positiveDecimal", ["treasure"], true) +
|
||||
"</element>" +
|
||||
"<element name='Capacities' a:help='Per-resource-type maximum carrying capacity'>" +
|
||||
"<interleave>" +
|
||||
"<element name='food' a:help='Food capacity'><ref name='positiveDecimal'/></element>" +
|
||||
"<element name='wood' a:help='Wood capacity'><ref name='positiveDecimal'/></element>" +
|
||||
"<element name='stone' a:help='Stone capacity'><ref name='positiveDecimal'/></element>" +
|
||||
"<element name='metal' a:help='Metal capacity'><ref name='positiveDecimal'/></element>" +
|
||||
"</interleave>" +
|
||||
Resources.BuildSchema("positiveDecimal") +
|
||||
"</element>";
|
||||
|
||||
ResourceGatherer.prototype.Init = function()
|
||||
|
|
@ -137,6 +112,14 @@ ResourceGatherer.prototype.RecalculateGatherRatesAndCapacities = function()
|
|||
this.rates = {};
|
||||
for (let r in this.template.Rates)
|
||||
{
|
||||
let type = r.split(".");
|
||||
|
||||
if (type[0] != "treasure" && type.length > 1 && !Resources.GetResource(type[0]).subtypes[type[1]])
|
||||
{
|
||||
error("Resource subtype not found: " + type[0] + "." + type[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
let rate = ApplyValueModificationsToEntity("ResourceGatherer/Rates/" + r, +this.template.Rates[r], this.entity);
|
||||
this.rates[r] = rate * this.baseSpeed;
|
||||
}
|
||||
|
|
@ -174,7 +157,7 @@ ResourceGatherer.prototype.GetRange = function()
|
|||
|
||||
/**
|
||||
* Try to gather treasure
|
||||
* @return 'true' if treasure is successfully gathered and 'false' in the other case
|
||||
* @return 'true' if treasure is successfully gathered, otherwise 'false'
|
||||
*/
|
||||
ResourceGatherer.prototype.TryInstantGather = function(target)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,23 +12,8 @@ ResourceSupply.prototype.Schema =
|
|||
"<element name='Amount' a:help='Amount of resources available from this entity'>" +
|
||||
"<choice><data type='nonNegativeInteger'/><value>Infinity</value></choice>" +
|
||||
"</element>" +
|
||||
"<element name='Type' a:help='Type of resources'>" +
|
||||
"<choice>" +
|
||||
"<value>wood.tree</value>" +
|
||||
"<value>wood.ruins</value>" +
|
||||
"<value>stone.rock</value>" +
|
||||
"<value>stone.ruins</value>" +
|
||||
"<value>metal.ore</value>" +
|
||||
"<value>food.fish</value>" +
|
||||
"<value>food.fruit</value>" +
|
||||
"<value>food.grain</value>" +
|
||||
"<value>food.meat</value>" +
|
||||
"<value>food.milk</value>" +
|
||||
"<value>treasure.wood</value>" +
|
||||
"<value>treasure.stone</value>" +
|
||||
"<value>treasure.metal</value>" +
|
||||
"<value>treasure.food</value>" +
|
||||
"</choice>" +
|
||||
"<element name='Type' a:help='Type and Subtype of resource available from this entity'>" +
|
||||
Resources.BuildChoicesSchema(true, true) +
|
||||
"</element>" +
|
||||
"<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" +
|
||||
"<data type='nonNegativeInteger'/>" +
|
||||
|
|
@ -45,16 +30,23 @@ ResourceSupply.prototype.Init = function()
|
|||
this.amount = this.GetMaxAmount();
|
||||
|
||||
this.gatherers = []; // list of IDs for each players
|
||||
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); // system component so that's safe.
|
||||
var numPlayers = cmpPlayerManager.GetNumPlayers();
|
||||
for (var i = 0; i <= numPlayers; ++i) // use "<=" because we want Gaia too.
|
||||
let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); // system component so that's safe.
|
||||
let numPlayers = cmpPlayerManager.GetNumPlayers();
|
||||
for (let i = 0; i <= numPlayers; ++i) // use "<=" because we want Gaia too.
|
||||
this.gatherers.push([]);
|
||||
|
||||
this.infinite = !isFinite(+this.template.Amount);
|
||||
|
||||
[this.type,this.subType] = this.template.Type.split('.');
|
||||
this.cachedType = { "generic" : this.type, "specific" : this.subType };
|
||||
let [type, subtype] = this.template.Type.split('.');
|
||||
let resData = type === "treasure" ?
|
||||
{ "subtypes": Resources.GetNames() } :
|
||||
Resources.GetResource(type);
|
||||
|
||||
// Remove entity from gameworld if the resource supplied by this entity is disabled or not valid.
|
||||
if (!resData || !resData.subtypes[subtype])
|
||||
Engine.DestroyEntity(this.entity);
|
||||
|
||||
this.cachedType = { "generic": type, "specific": subtype };
|
||||
};
|
||||
|
||||
ResourceSupply.prototype.IsInfinite = function()
|
||||
|
|
|
|||
|
|
@ -3,28 +3,7 @@ function ResourceTrickle() {}
|
|||
ResourceTrickle.prototype.Schema =
|
||||
"<a:help>Controls the resource trickle ability of the unit.</a:help>" +
|
||||
"<element name='Rates' a:help='Trickle Rates'>" +
|
||||
"<interleave>" +
|
||||
"<optional>" +
|
||||
"<element name='food' a:help='Food given to the player every interval'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
"</element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='wood' a:help='Wood given to the player every interval'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
"</element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='stone' a:help='Stone given to the player every interval'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
"</element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='metal' a:help='Metal given to the player every interval'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
"</element>" +
|
||||
"</optional>" +
|
||||
"</interleave>" +
|
||||
Resources.BuildSchema("nonNegativeDecimal") +
|
||||
"</element>" +
|
||||
"<element name='Interval' a:help='Number of miliseconds must pass for the player to gain the next trickle.'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
|
|
@ -33,7 +12,7 @@ ResourceTrickle.prototype.Schema =
|
|||
ResourceTrickle.prototype.Init = function()
|
||||
{
|
||||
this.ComputeRates();
|
||||
// Call the timer
|
||||
|
||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
cmpTimer.SetInterval(this.entity, IID_ResourceTrickle, "Trickle", this.GetTimer(), this.GetTimer(), undefined);
|
||||
};
|
||||
|
|
@ -51,11 +30,16 @@ ResourceTrickle.prototype.GetRates = function()
|
|||
ResourceTrickle.prototype.ComputeRates = function()
|
||||
{
|
||||
this.rates = {};
|
||||
let resCodes = Resources.GetCodes();
|
||||
for (let resource in this.template.Rates)
|
||||
{
|
||||
if (resCodes.indexOf(resource) == -1)
|
||||
continue;
|
||||
|
||||
this.rates[resource] = ApplyValueModificationsToEntity("ResourceTrickle/Rates/"+resource, +this.template.Rates[resource], this.entity);
|
||||
}
|
||||
};
|
||||
|
||||
// Do the actual work here
|
||||
ResourceTrickle.prototype.Trickle = function(data, lateness)
|
||||
{
|
||||
// The player entity may also have a ResourceTrickle component
|
||||
|
|
@ -63,8 +47,7 @@ ResourceTrickle.prototype.Trickle = function(data, lateness)
|
|||
if (!cmpPlayer)
|
||||
return;
|
||||
|
||||
for (let resource in this.rates)
|
||||
cmpPlayer.AddResource(resource, this.rates[resource]);
|
||||
cmpPlayer.AddResources(this.rates);
|
||||
};
|
||||
|
||||
ResourceTrickle.prototype.OnValueModification = function(msg)
|
||||
|
|
|
|||
|
|
@ -122,30 +122,18 @@ StatisticsTracker.prototype.Init = function()
|
|||
this.buildingsCapturedValue = 0;
|
||||
|
||||
this.resourcesGathered = {
|
||||
"food": 0,
|
||||
"wood": 0,
|
||||
"metal": 0,
|
||||
"stone": 0,
|
||||
"vegetarianFood": 0
|
||||
};
|
||||
this.resourcesUsed = {
|
||||
"food": 0,
|
||||
"wood": 0,
|
||||
"metal": 0,
|
||||
"stone": 0
|
||||
};
|
||||
this.resourcesSold = {
|
||||
"food": 0,
|
||||
"wood": 0,
|
||||
"metal": 0,
|
||||
"stone": 0
|
||||
};
|
||||
this.resourcesBought = {
|
||||
"food": 0,
|
||||
"wood": 0,
|
||||
"metal": 0,
|
||||
"stone": 0
|
||||
};
|
||||
this.resourcesUsed = {};
|
||||
this.resourcesSold = {};
|
||||
this.resourcesBought = {};
|
||||
for (let res of Resources.GetCodes())
|
||||
{
|
||||
this.resourcesGathered[res] = 0;
|
||||
this.resourcesUsed[res] = 0;
|
||||
this.resourcesSold[res] = 0;
|
||||
this.resourcesBought[res] = 0;
|
||||
}
|
||||
|
||||
this.tributesSent = 0;
|
||||
this.tributesReceived = 0;
|
||||
|
|
@ -385,7 +373,8 @@ StatisticsTracker.prototype.IncreaseResourceGatheredCounter = function(type, amo
|
|||
*/
|
||||
StatisticsTracker.prototype.IncreaseResourceUsedCounter = function(type, amount)
|
||||
{
|
||||
this.resourcesUsed[type] += amount;
|
||||
if (typeof this.resourcesUsed[type] === "number")
|
||||
this.resourcesUsed[type] += amount;
|
||||
};
|
||||
|
||||
StatisticsTracker.prototype.IncreaseTreasuresCollectedCounter = function()
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
// Additional gain for ships for each garrisoned trader, in percents
|
||||
const GARRISONED_TRADER_ADDITION = 20;
|
||||
|
||||
// Array of resource names
|
||||
const RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
|
||||
function Trader() {}
|
||||
|
||||
Trader.prototype.Schema =
|
||||
|
|
|
|||
|
|
@ -29,10 +29,7 @@ Upgrade.prototype.Schema =
|
|||
"<element name='Cost' a:help='Resource cost to upgrade this unit'>" +
|
||||
"<oneOrMore>" +
|
||||
"<choice>" +
|
||||
"<element name='food'><data type='nonNegativeInteger'/></element>" +
|
||||
"<element name='wood'><data type='nonNegativeInteger'/></element>" +
|
||||
"<element name='stone'><data type='nonNegativeInteger'/></element>" +
|
||||
"<element name='metal'><data type='nonNegativeInteger'/></element>" +
|
||||
Resources.BuildSchema("nonNegativeInteger") +
|
||||
"</choice>" +
|
||||
"</oneOrMore>" +
|
||||
"</element>" +
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ Engine.LoadComponentScript("interfaces/Upgrade.js");
|
|||
Engine.LoadComponentScript("interfaces/BuildingAI.js");
|
||||
Engine.LoadComponentScript("GuiInterface.js");
|
||||
|
||||
Resources = {
|
||||
"GetCodes": () => ["food", "metal", "stone", "wood"],
|
||||
"GetNames": () => ({
|
||||
"food": "Food",
|
||||
"metal": "Metal",
|
||||
"stone": "Stone",
|
||||
"wood": "Wood"
|
||||
}),
|
||||
"GetResource": () => ({}),
|
||||
};
|
||||
|
||||
var cmp = ConstructComponent(SYSTEM_ENTITY, "GuiInterface");
|
||||
|
||||
|
||||
|
|
@ -333,7 +344,25 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
|||
timeElapsed: 0,
|
||||
gameType: "conquest",
|
||||
alliedVictory: false,
|
||||
barterPrices: {buy: {food: 150}, sell: {food: 25}}
|
||||
"barterPrices": {
|
||||
"buy": { "food": 150 },
|
||||
"sell": { "food": 25 }
|
||||
},
|
||||
"resources": {
|
||||
"codes": ["food", "metal", "stone", "wood"],
|
||||
"names": {
|
||||
"food": "Food",
|
||||
"metal": "Metal",
|
||||
"stone": "Stone",
|
||||
"wood": "Wood",
|
||||
},
|
||||
"aiInfluenceGroups": {
|
||||
"food": 0,
|
||||
"metal": 0,
|
||||
"stone": 0,
|
||||
"wood": 0,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
|
|
@ -453,7 +482,25 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
|||
timeElapsed: 0,
|
||||
gameType: "conquest",
|
||||
alliedVictory: false,
|
||||
barterPrices: {buy: {food: 150}, sell: {food: 25}}
|
||||
"barterPrices": {
|
||||
"buy": { "food": 150 },
|
||||
"sell": { "food": 25 }
|
||||
},
|
||||
"resources": {
|
||||
"codes": ["food", "metal", "stone", "wood"],
|
||||
"names": {
|
||||
"food": "Food",
|
||||
"metal": "Metal",
|
||||
"stone": "Stone",
|
||||
"wood": "Wood",
|
||||
},
|
||||
"aiInfluenceGroups": {
|
||||
"food": 0,
|
||||
"metal": 0,
|
||||
"stone": 0,
|
||||
"wood": 0,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ Engine.LoadComponentScript("interfaces/Player.js");
|
|||
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
|
||||
Engine.LoadComponentScript("Player.js");
|
||||
|
||||
Resources = {
|
||||
"GetCodes": () => ["food", "metal", "stone", "wood"],
|
||||
"GetResource": () => ({}),
|
||||
};
|
||||
|
||||
var cmpPlayer = ConstructComponent(10, "Player");
|
||||
|
||||
TS_ASSERT_EQUALS(cmpPlayer.GetPopulationCount(), 0);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"code": "food",
|
||||
"name": "Food",
|
||||
"order": 1,
|
||||
"subtypes": {
|
||||
"fish": "Fish",
|
||||
"fruit": "Fruit",
|
||||
"grain": "Grain",
|
||||
"meat": "Meat",
|
||||
"milk": "Milk"
|
||||
},
|
||||
"truePrice": 100,
|
||||
"aiAnalysisInfluenceGroup": 0
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"code": "metal",
|
||||
"name": "Metal",
|
||||
"order": 4,
|
||||
"subtypes": {
|
||||
"ore": "Ore"
|
||||
},
|
||||
"truePrice": 100,
|
||||
"aiAnalysisInfluenceGroup": 2
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"code": "stone",
|
||||
"name": "Stone",
|
||||
"order": 3,
|
||||
"subtypes": {
|
||||
"rock": "Rock",
|
||||
"ruins": "Ruins"
|
||||
},
|
||||
"truePrice": 100,
|
||||
"aiAnalysisInfluenceGroup": 2
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"code": "wood",
|
||||
"name": "Wood",
|
||||
"order": 2,
|
||||
"subtypes": {
|
||||
"tree": "Tree",
|
||||
"ruins": "Ruins"
|
||||
},
|
||||
"truePrice": 100,
|
||||
"aiAnalysisInfluenceGroup": 1
|
||||
}
|
||||
|
|
@ -148,7 +148,7 @@ function Cheat(input)
|
|||
cmpTechnologyManager.ResearchTechnology(techname);
|
||||
return;
|
||||
case "metaCheat":
|
||||
for (let resource of ["food", "wood", "metal", "stone"])
|
||||
for (let resource of Resources.GetCodes())
|
||||
Cheat({ "player": input.player, "action": "addresource", "text": resource, "parameter": input.parameter });
|
||||
Cheat({ "player": input.player, "action": "maxpopulation" });
|
||||
Cheat({ "player": input.player, "action": "changemaxpopulation" });
|
||||
|
|
|
|||
93
binaries/data/mods/public/simulation/helpers/Resources.js
Normal file
93
binaries/data/mods/public/simulation/helpers/Resources.js
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* Builds a RelaxRNG schema based on currently valid elements.
|
||||
*
|
||||
* To prevent validation errors, disabled resources are included in the schema.
|
||||
*
|
||||
* @param datatype - The datatype of the element
|
||||
* @param additional - Array of additional data elements. Time, xp, treasure, etc.
|
||||
* @param subtypes - If true, resource subtypes will be included as well.
|
||||
* @return RelaxNG schema string
|
||||
*/
|
||||
Resources.prototype.BuildSchema = function(datatype, additional = [], subtypes = false)
|
||||
{
|
||||
if (!datatype)
|
||||
return "";
|
||||
|
||||
switch (datatype)
|
||||
{
|
||||
case "decimal":
|
||||
case "nonNegativeDecimal":
|
||||
case "positiveDecimal":
|
||||
datatype = "<ref name='" + datatype + "'/>";
|
||||
break;
|
||||
|
||||
default:
|
||||
datatype = "<data type='" + datatype + "'/>";
|
||||
}
|
||||
|
||||
let resCodes = this.resourceData.map(resource => resource.code);
|
||||
let schema = "";
|
||||
for (let res of resCodes.concat(additional))
|
||||
schema +=
|
||||
"<optional>" +
|
||||
"<element name='" + res + "'>" +
|
||||
datatype +
|
||||
"</element>" +
|
||||
"</optional>";
|
||||
|
||||
if (!subtypes)
|
||||
return "<interleave>" + schema + "</interleave>";
|
||||
|
||||
for (let res of this.resourceData)
|
||||
for (let subtype in res.subtypes)
|
||||
schema +=
|
||||
"<optional>" +
|
||||
"<element name='" + res.code + "." + subtype + "'>" +
|
||||
datatype +
|
||||
"</element>" +
|
||||
"</optional>";
|
||||
|
||||
if (additional.indexOf("treasure") !== -1)
|
||||
for (let res of resCodes)
|
||||
schema +=
|
||||
"<optional>" +
|
||||
"<element name='" + "treasure." + res + "'>" +
|
||||
datatype +
|
||||
"</element>" +
|
||||
"</optional>";
|
||||
|
||||
return "<interleave>" + schema + "</interleave>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the value choices for a RelaxNG `<choice></choice>` object, based on currently valid resources.
|
||||
*
|
||||
* @oaram subtypes - If set to true, the choices returned will be resource subtypes, rather than main types
|
||||
* @param treasure - If set to true, the pseudo resource 'treasure' (or its subtypes) will be included
|
||||
* @return String of RelaxNG Schema `<choice/>` values.
|
||||
*/
|
||||
Resources.prototype.BuildChoicesSchema = function(subtypes = false, treasure = false)
|
||||
{
|
||||
let schema = "";
|
||||
|
||||
if (!subtypes)
|
||||
{
|
||||
let resCodes = this.resourceData.map(resource => resource.code);
|
||||
if (treasure)
|
||||
resCodes.push("treasure");
|
||||
for (let res of resCodes)
|
||||
schema += "<value>" + res + "</value>";
|
||||
}
|
||||
else
|
||||
for (let res of this.resourceData)
|
||||
{
|
||||
for (let subtype in res.subtypes)
|
||||
schema += "<value>" + res.code + "." + subtype + "</value>";
|
||||
if (treasure)
|
||||
schema += "<value>" + "treasure." + res.code + "</value>";
|
||||
}
|
||||
|
||||
return "<choice>" + schema + "</choice>";
|
||||
}
|
||||
|
||||
Resources = new Resources();
|
||||
Loading…
Reference in a new issue