Index: binaries/data/mods/public/globalscripts/Resources.js
===================================================================
--- binaries/data/mods/public/globalscripts/Resources.js
+++ binaries/data/mods/public/globalscripts/Resources.js
@@ -7,6 +7,13 @@
this.resourceDataObj = {};
this.resourceCodes = [];
this.resourceNames = {};
+ this.resourceTradable = {};
+ this.resourceTradableCodes = [];
+ this.resourceBarterable = {};
+ this.resourceBarterableCodes = [];
+ this.resourceTributable = {};
+ this.resourceTributableCodes = [];
+ this.resourceCurrency = undefined;
for (let filename of Engine.ListDirectoryFiles("simulation/data/resources/", "*.json", false))
{
@@ -28,6 +35,27 @@
this.resourceDataObj[data.code] = data;
this.resourceCodes.push(data.code);
this.resourceNames[data.code] = data.name;
+
+ // Specify whether resources can be exchanged
+ this.resourceTradable[data.code] = data.tradable;
+ if (data.tradable == true)
+ this.resourceTradableCodes.push(data.code);
+
+ this.resourceBarterable[data.code] = data.barterable;
+ if (data.barterable == true)
+ this.resourceBarterableCodes.push(data.code);
+
+ this.resourceTributable[data.code] = data.tributable;
+ if (data.tributable == true)
+ this.resourceTributableCodes.push(data.code);
+
+ if (data.isCurrency == true)
+ {
+ if (this.resourceCurrency)
+ warn("There is more than one currency defined, taking the last one.")
+ this.resourceCurrency = data.code;
+ }
+
for (let subres in data.subtypes)
this.resourceNames[subres] = data.subtypes[subres];
}
@@ -43,10 +71,32 @@
this.resourceData.find(resource => resource.code == b)
));
+ this.resourceTradableCodes.sort((a, b) => resSort(
+ this.resourceData.find(resource => resource.code == a),
+ this.resourceData.find(resource => resource.code == b)
+ ));
+
+ this.resourceBarterableCodes.sort((a, b) => resSort(
+ this.resourceData.find(resource => resource.code == a),
+ this.resourceData.find(resource => resource.code == b)
+ ));
+
+ this.resourceTributableCodes.sort((a, b) => resSort(
+ this.resourceData.find(resource => resource.code == a),
+ this.resourceData.find(resource => resource.code == b)
+ ));
+
deepfreeze(this.resourceData);
deepfreeze(this.resourceDataObj);
deepfreeze(this.resourceCodes);
deepfreeze(this.resourceNames);
+ deepfreeze(this.resourceTradableCodes);
+ deepfreeze(this.resourceTradable);
+ deepfreeze(this.resourceBarterableCodes);
+ deepfreeze(this.resourceBarterable);
+ deepfreeze(this.resourceTributableCodes);
+ deepfreeze(this.resourceTributable);
+// deepfreeze(this.resourceCurrency);
}
/**
@@ -83,3 +133,66 @@
{
return this.resourceNames;
};
+
+/**
+ * Returns an array with tradable resource codes.
+ * @return {string[]} data of the form [ "food", "metal", ... ]
+ */
+Resources.prototype.GetTradableCodes = function()
+{
+ return this.resourceTradableCodes;
+};
+
+/**
+ * Returns an object mapping resource codes whether it is tradable or not.
+ * @return {object} data of the form { "food": "true", "metal": "false", ... }
+ */
+Resources.prototype.GetTradable = function()
+{
+ return this.resourceTradable;
+};
+
+/**
+ * Returns an array with barterable resource codes.
+ * @return {string[]} data of the form [ "food", "metal", ... ]
+ */
+Resources.prototype.GetBarterableCodes = function()
+{
+ return this.resourceBarterableCodes;
+};
+
+/**
+ * Returns an object mapping resource codes whether it is barterable or not.
+ * @return {object} data of the form { "food": "true", "metal": "false", ... }
+ */
+Resources.prototype.GetBarterable = function()
+{
+ return this.resourceBarterable;
+};
+
+/**
+ * Returns an array with tributable resource codes.
+ * @return {string[]} data of the form [ "food", "metal", ... ]
+ */
+Resources.prototype.GetTributableCodes = function()
+{
+ return this.resourceTributableCodes;
+};
+
+/**
+ * Returns an object mapping resource codes whether it is tributable or not.
+ * @return {object} data of the form { "food": "true", "metal": "false", ... }
+ */
+Resources.prototype.GetTributable = function()
+{
+ return this.resourceTributable;
+};
+
+/**
+ * Returns the resource that is the currency.
+ * @return {string} "resource"
+ */
+Resources.prototype.GetCurrency = function()
+{
+ return this.resourceCurrency;
+};
Index: binaries/data/mods/public/gui/session/menu.js
===================================================================
--- binaries/data/mods/public/gui/session/menu.js
+++ binaries/data/mods/public/gui/session/menu.js
@@ -290,7 +290,7 @@
let size = dialog.size;
let tribSize = Engine.GetGUIObjectByName("diplomacyPlayer[0]_tribute[0]").size;
- let widthOffset = g_ResourceData.GetCodes().length * (tribSize.right - tribSize.left) / 2;
+ let widthOffset = g_ResourceData.GetTributableCodes().length * (tribSize.right - tribSize.left) / 2;
size.left -= widthOffset;
size.right += widthOffset;
@@ -491,7 +491,7 @@
function diplomacyFormatTributeButtons(i, hidden)
{
- let resCodes = g_ResourceData.GetCodes();
+ let resCodes = g_ResourceData.GetTributableCodes();
let r = 0;
for (let resCode of resCodes)
{
@@ -638,7 +638,7 @@
let width = size.right - size.left;
let tradeSize = Engine.GetGUIObjectByName("tradeResource[0]").size;
- width += g_ResourceData.GetCodes().length * (tradeSize.right - tradeSize.left);
+ width += g_ResourceData.GetTradableCodes().length * (tradeSize.right - tradeSize.left);
size.left = -width / 2;
size.right = width / 2;
@@ -656,8 +656,9 @@
let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer);
let button = {};
- let resCodes = g_ResourceData.GetCodes();
- let currTradeSelection = resCodes[0];
+ let resTradeCodes = g_ResourceData.GetTradableCodes();
+ let resBarterCodes = g_ResourceData.GetBarterableCodes();
+ let currTradeSelection = resTradeCodes[0];
let updateTradeButtons = function()
{
@@ -671,12 +672,13 @@
}
};
- hideRemaining("tradeResources", resCodes.length);
+ hideRemaining("tradeResources", resTradeCodes.length);
Engine.GetGUIObjectByName("tradeHelp").hidden = false;
- for (let i = 0; i < resCodes.length; ++i)
+ // Barter:
+ for (let i = 0; i < resBarterCodes.length; ++i)
{
- let resCode = resCodes[i];
+ let resBarterCode = resBarterCodes[i];
let barterResource = Engine.GetGUIObjectByName("barterResource[" + i + "]");
if (!barterResource)
@@ -685,11 +687,14 @@
break;
}
- // Barter:
- barterOpenCommon(resCode, i, "barter");
+ barterOpenCommon(resBarterCode, i, "barter");
setPanelObjectPosition(barterResource, i, i + 1);
+ }
+ // Trade:
+ for (let i = 0; i < resTradeCodes.length; ++i)
+ {
+ let resTradeCode = resTradeCodes[i];
- // Trade:
let tradeResource = Engine.GetGUIObjectByName("tradeResource[" + i + "]");
if (!tradeResource)
{
@@ -700,19 +705,19 @@
setPanelObjectPosition(tradeResource, i, i + 1);
let icon = Engine.GetGUIObjectByName("tradeResourceIcon[" + i + "]");
- icon.sprite = "stretched:session/icons/resources/" + resCode + ".png";
+ icon.sprite = "stretched:session/icons/resources/" + resTradeCode + ".png";
let buttonUp = Engine.GetGUIObjectByName("tradeArrowUp[" + i + "]");
let buttonDn = Engine.GetGUIObjectByName("tradeArrowDn[" + i + "]");
- button[resCode] = {
+ button[resTradeCode] = {
"up": buttonUp,
"dn": buttonDn,
"label": Engine.GetGUIObjectByName("tradeResourceText[" + i + "]"),
"sel": Engine.GetGUIObjectByName("tradeResourceSelection[" + i + "]")
};
- proba[resCode] = proba[resCode] || 0;
+ proba[resTradeCode] = proba[resTradeCode] || 0;
let buttonResource = Engine.GetGUIObjectByName("tradeResourceButton[" + i + "]");
buttonResource.enabled = controlsPlayer(g_ViewedPlayer);
@@ -720,7 +725,7 @@
return () => {
if (Engine.HotkeyIsPressed("session.fulltradeswap"))
{
- for (let res of resCodes)
+ for (let res of resTradeCodes)
proba[res] = 0;
proba[resource] = 100;
Engine.PostNetworkCommand({ "type": "set-trading-goods", "tradingGoods": proba });
@@ -728,7 +733,7 @@
currTradeSelection = resource;
updateTradeButtons();
};
- })(resCode);
+ })(resTradeCode);
buttonUp.enabled = controlsPlayer(g_ViewedPlayer);
buttonUp.onPress = (resource => {
@@ -738,7 +743,7 @@
Engine.PostNetworkCommand({ "type": "set-trading-goods", "tradingGoods": proba });
updateTradeButtons();
};
- })(resCode);
+ })(resTradeCode);
buttonDn.enabled = controlsPlayer(g_ViewedPlayer);
buttonDn.onPress = (resource => {
@@ -748,7 +753,7 @@
Engine.PostNetworkCommand({ "type": "set-trading-goods", "tradingGoods": proba });
updateTradeButtons();
};
- })(resCode);
+ })(resTradeCode);
}
updateTradeButtons();
@@ -765,7 +770,7 @@
function initBarterButtons()
{
- g_BarterSell = g_ResourceData.GetCodes()[0];
+ g_BarterSell = g_ResourceData.GetBarterableCodes()[0];
}
/**
@@ -855,7 +860,11 @@
});
};
- barterButton.Buy.hidden = isSelected;
+ if (g_BarterSell == g_ResourceData.GetCurrency() || !g_ResourceData.GetCurrency())
+ barterButton.Buy.hidden = isSelected;
+ else
+ barterButton.Buy.hidden = resourceCode != g_ResourceData.GetCurrency();
+
barterButton.Buy.enabled = controlsPlayer(player);
barterButton.Sell.hidden = false;
selectionIcon.hidden = !isSelected;
@@ -873,7 +882,9 @@
Engine.GetGUIObjectByName("barterHelp").hidden = !canBarter;
if (canBarter)
- g_ResourceData.GetCodes().forEach((resCode, i) => { barterUpdateCommon(resCode, i, "barter", g_ViewedPlayer) });
+ g_ResourceData.GetBarterableCodes().forEach((resCode, i) => {
+ barterUpdateCommon(resCode, i, "barter", g_ViewedPlayer);
+ });
}
function getIdleLandTradersText(traderNumber)
Index: binaries/data/mods/public/gui/session/selection_panels.js
===================================================================
--- binaries/data/mods/public/gui/session/selection_panels.js
+++ binaries/data/mods/public/gui/session/selection_panels.js
@@ -84,9 +84,9 @@
"getItems": function(unitEntStates)
{
// If more than `rowLength` resources, don't display icons.
- if (unitEntStates.every(state => !state.isBarterMarket) || g_ResourceData.GetCodes().length > this.rowLength)
+ if (unitEntStates.every(state => !state.isBarterMarket) || g_ResourceData.GetBarterableCodes().length > this.rowLength)
return [];
- return g_ResourceData.GetCodes();
+ return g_ResourceData.GetBarterableCodes();
},
"setupButton": function(data)
{
Index: binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js
+++ binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js
@@ -80,6 +80,9 @@
let toSend = false;
for (let res in allyResources)
{
+ // Do not send resources which are untributable
+ if (!Resources.GetTributable[res])
+ continue;
if (donor && availableResources[res] > 200 && allyResources[res] < 0.2 * availableResources[res])
{
tribute[res] = Math.floor(0.3*availableResources[res] - allyResources[res]);
@@ -402,17 +405,28 @@
}
else
{
- response = "acceptWithTribute";
- requiredTribute = gameState.ai.HQ.pickMostNeededResources(gameState)[0];
- requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * (requestType === "ally" ? 10 : 5));
- this.receivedDiplomacyRequests.set(player, {
- "status": "waitingForTribute",
- "wanted": requiredTribute.wanted,
- "type": requiredTribute.type,
- "warnTime": gameState.ai.elapsedTime + 60,
- "sentWarning": false,
- "requestType": requestType
- });
+ // Try to request a tribute.
+ // If a resource is not tributable, do not request it.
+ // If no resources are tributable, decline.
+ requiredTribute = gameState.ai.HQ.pickMostNeededResources(gameState).find(res => Resources.GetTributableCodes().some(res2 => res2 == res.type));
+ if (requiredTribute)
+ {
+ response = "acceptWithTribute";
+ requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * (requestType === "ally" ? 10 : 5));
+ this.receivedDiplomacyRequests.set(player, {
+ "status": "waitingForTribute",
+ "wanted": requiredTribute.wanted,
+ "type": requiredTribute.type,
+ "warnTime": gameState.ai.elapsedTime + 60,
+ "sentWarning": false,
+ "requestType": requestType
+ });
+ }
+ else
+ {
+ this.receivedDiplomacyRequests.set(player, { "requestType": requestType, "status": "declinedRequest" });
+ response = "decline";
+ }
}
m.chatAnswerRequestDiplomacy(gameState, player, requestType, response, requiredTribute);
};
Index: binaries/data/mods/public/simulation/ai/petra/tradeManager.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/tradeManager.js
+++ binaries/data/mods/public/simulation/ai/petra/tradeManager.js
@@ -162,7 +162,7 @@
m.TradeManager.prototype.setTradingGoods = function(gameState)
{
let tradingGoods = {};
- for (let res of Resources.GetCodes())
+ for (let res of Resources.GetTradableCodes())
tradingGoods[res] = 0;
// first, try to anticipate future needs
let stocks = gameState.ai.HQ.getTotalResourceLevel(gameState);
@@ -230,7 +230,7 @@
let getBarterRate = (prices, buy, sell) => Math.round(100 * prices.sell[sell] / prices.buy[buy]);
// loop through each missing resource checking if we could barter and help finishing a queue quickly.
- for (let buy of Resources.GetCodes())
+ for (let buy of Resources.GetBarterableCodes())
{
// Check if our rate allows to gather it fast enough
if (needs[buy] == 0 || needs[buy] < rates[buy] * 30)
@@ -239,10 +239,15 @@
// Pick the best resource to barter.
let bestToSell;
let bestRate = 0;
- for (let sell of Resources.GetCodes())
+ for (let sell of Resources.GetBarterableCodes())
{
if (sell == buy)
continue;
+
+ // Do not sell non-currency for non-currency if a currency is defined
+ if (Resources.GetCurrency() && sell != Resources.GetCurrency() && buy != Resources.GetCurrency())
+ continue;
+
// Do not sell if we need it or do not have enough buffer
if (needs[sell] > 0 || available[sell] < 500)
continue;
@@ -295,7 +300,7 @@
return false;
let bestToBuy;
let bestChoice = 0;
- for (let buy of Resources.GetCodes())
+ for (let buy of Resources.GetBarterableCodes())
{
if (buy == "food")
continue;
Index: binaries/data/mods/public/simulation/components/Barter.js
===================================================================
--- binaries/data/mods/public/simulation/components/Barter.js
+++ binaries/data/mods/public/simulation/components/Barter.js
@@ -29,7 +29,7 @@
Barter.prototype.Init = function()
{
this.priceDifferences = {};
- for (let resource of Resources.GetCodes())
+ for (let resource of Resources.GetBarterableCodes())
this.priceDifferences[resource] = 0;
this.restoreTimer = undefined;
};
@@ -38,7 +38,7 @@
{
var prices = { "buy": {}, "sell": {} };
let multiplier = QueryPlayerIDInterface(playerID).GetBarterMultiplier();
- for (let resource of Resources.GetCodes())
+ for (let resource of Resources.GetBarterableCodes())
{
let truePrice = Resources.GetResource(resource).truePrice;
prices.buy[resource] = truePrice * (100 + this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) * multiplier.buy[resource] / 100;
@@ -69,7 +69,7 @@
return;
}
- let availResources = Resources.GetCodes();
+ let availResources = Resources.GetBarterableCodes();
if (availResources.indexOf(resourceToSell) == -1)
{
warn("ExchangeResources: incorrect resource to sell: " + uneval(resourceToSell));
@@ -136,7 +136,7 @@
Barter.prototype.ProgressTimeout = function(data)
{
var needRestore = false;
- for (let resource of Resources.GetCodes())
+ for (let resource of Resources.GetBarterableCodes())
{
// Calculate value to restore, it should be limited to [-DIFFERENCE_RESTORE; DIFFERENCE_RESTORE] interval
var differenceRestore = Math.min(this.DIFFERENCE_RESTORE, Math.max(-this.DIFFERENCE_RESTORE, this.priceDifferences[resource]));
Index: binaries/data/mods/public/simulation/components/Player.js
===================================================================
--- binaries/data/mods/public/simulation/components/Player.js
+++ binaries/data/mods/public/simulation/components/Player.js
@@ -80,15 +80,21 @@
"sell": clone(this.template.BarterMultiplier.Sell)
};
- // Initial resources and trading goods probability in steps of 5
+ // Initial resources
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;
+ }
+ // Trading goods probability in steps of 5
+ let resTradeCodes = Resources.GetTradableCodes();
+ let quotient = Math.floor(20 / resTradeCodes.length);
+ let remainder = 20 % resTradeCodes.length;
+ for (let i in resTradeCodes)
+ {
+ let res = resTradeCodes[i];
this.tradingGoods.push({
"goods": res,
"proba": 5 * (quotient + (+i < remainder ? 1 : 0))
@@ -411,7 +417,7 @@
Player.prototype.GetTradingGoods = function()
{
- var tradingGoods = {};
+ let tradingGoods = {};
for (let resource of this.tradingGoods)
tradingGoods[resource.goods] = resource.proba;
@@ -420,7 +426,7 @@
Player.prototype.SetTradingGoods = function(tradingGoods)
{
- let resCodes = Resources.GetCodes();
+ let resCodes = Resources.GetTradableCodes();
let sumProba = 0;
for (let resource in tradingGoods)
{
@@ -434,7 +440,7 @@
if (sumProba != 100)
{
- error("Invalid trading goods: " + uneval(tradingGoods));
+ error("Invalid trading goods probability: " + uneval(sumProba));
return;
}
@@ -866,7 +872,7 @@
return;
for (let resCode in amounts)
- if (Resources.GetCodes().indexOf(resCode) == -1 ||
+ if (Resources.GetTributableCodes().indexOf(resCode) == -1 ||
!Number.isInteger(amounts[resCode]) ||
amounts[resCode] < 0)
{
Index: binaries/data/mods/public/simulation/components/tests/test_Barter.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Barter.js
+++ binaries/data/mods/public/simulation/components/tests/test_Barter.js
@@ -10,7 +10,7 @@
const truePrice = 110;
Resources = {
- "GetCodes": () => ["wood", "stone", "metal"],
+ "GetBarterableCodes": () => ["wood", "stone", "metal"],
"GetResource": (resource) => ({ "truePrice": truePrice })
};
Index: binaries/data/mods/public/simulation/components/tests/test_Player.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Player.js
+++ binaries/data/mods/public/simulation/components/tests/test_Player.js
@@ -1,6 +1,5 @@
Resources = {
"GetCodes": () => ["food", "metal", "stone", "wood"],
- "GetResource": () => ({}),
"BuildSchema": (type) => {
let schema = "";
for (let res of Resources.GetCodes())
@@ -11,6 +10,43 @@
"" +
"";
return "" + schema + "";
+ },
+ "GetTradableCodes": () => ["food", "metal", "stone", "wood"],
+ "GetResource": () => ({}),
+ "BuildSchema": (type) => {
+ let schema = "";
+ for (let res of Resources.GetTradableCodes())
+ schema +=
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+ return "" + schema + "";
+ },
+ "GetBarterableCodes": () => ["food", "metal", "stone", "wood"],
+ "BuildSchema": (type) => {
+ let schema = "";
+ for (let res of Resources.GetBarterableCodes())
+ schema +=
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+ return "" + schema + "";
+ },
+ "GetTributableCodes": () => ["food", "metal", "stone", "wood"],
+ "BuildSchema": (type) => {
+ let schema = "";
+ for (let res of Resources.GetTributableCodes())
+ schema +=
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+ return "" + schema + "";
}
};
Index: binaries/data/mods/public/simulation/data/resources/food.json
===================================================================
--- binaries/data/mods/public/simulation/data/resources/food.json
+++ binaries/data/mods/public/simulation/data/resources/food.json
@@ -10,5 +10,9 @@
"meat": "Meat"
},
"truePrice": 100,
- "aiAnalysisInfluenceGroup": "ignore"
+ "aiAnalysisInfluenceGroup": "ignore",
+ "tradable": true,
+ "barterable": true,
+ "tributable": true,
+ "isCurrency": false
}
Index: binaries/data/mods/public/simulation/data/resources/metal.json
===================================================================
--- binaries/data/mods/public/simulation/data/resources/metal.json
+++ binaries/data/mods/public/simulation/data/resources/metal.json
@@ -7,5 +7,9 @@
"ore": "Ore"
},
"truePrice": 100,
- "aiAnalysisInfluenceGroup": "sparse"
+ "aiAnalysisInfluenceGroup": "sparse",
+ "tradable": true,
+ "barterable": true,
+ "tributable": true,
+ "isCurrency": false
}
Index: binaries/data/mods/public/simulation/data/resources/stone.json
===================================================================
--- binaries/data/mods/public/simulation/data/resources/stone.json
+++ binaries/data/mods/public/simulation/data/resources/stone.json
@@ -8,5 +8,9 @@
"ruins": "Ruins"
},
"truePrice": 100,
- "aiAnalysisInfluenceGroup": "sparse"
+ "aiAnalysisInfluenceGroup": "sparse",
+ "tradable": true,
+ "barterable": true,
+ "tributable": true,
+ "isCurrency": false
}
Index: binaries/data/mods/public/simulation/data/resources/wood.json
===================================================================
--- binaries/data/mods/public/simulation/data/resources/wood.json
+++ binaries/data/mods/public/simulation/data/resources/wood.json
@@ -8,5 +8,9 @@
"ruins": "Ruins"
},
"truePrice": 100,
- "aiAnalysisInfluenceGroup": "abundant"
+ "aiAnalysisInfluenceGroup": "abundant",
+ "tradable": true,
+ "barterable": true,
+ "tributable": true,
+ "isCurrency": false
}