diff --git a/binaries/data/mods/public/gui/session/menu.js b/binaries/data/mods/public/gui/session/menu.js
index 9d1ba9794b..492a6a2c35 100644
--- a/binaries/data/mods/public/gui/session/menu.js
+++ b/binaries/data/mods/public/gui/session/menu.js
@@ -773,7 +773,7 @@ function barterUpdateCommon(resourceCode, idx, prefix, player)
barterIcon.Buy.sprite = canBuyAny + "stretched:" + grayscale + "session/icons/resources/" + resourceCode + ".png";
barterAmount.Sell.caption = "-" + amountToSell;
- let prices = GetSimState().barterPrices;
+ let prices = GetSimState().players[player].barterPrices;
barterAmount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[resourceCode] * amountToSell);
barterButton.Buy.onPress = function() {
diff --git a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js
index 2bc676bc24..c876d0932a 100644
--- a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js
+++ b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js
@@ -19,7 +19,6 @@ m.GameState.prototype.init = function(SharedScript, state, player) {
this.entities = SharedScript.entities;
this.player = player;
this.playerData = SharedScript.playersData[this.player];
- this.barterPrices = SharedScript.barterPrices;
this.gameType = SharedScript.gameType;
this.alliedVictory = SharedScript.alliedVictory;
this.ceasefireActive = SharedScript.ceasefireActive;
@@ -66,7 +65,6 @@ m.GameState.prototype.update = function(SharedScript)
{
this.timeElapsed = SharedScript.timeElapsed;
this.playerData = SharedScript.playersData[this.player];
- this.barterPrices = SharedScript.barterPrices;
this.ceasefireActive = SharedScript.ceasefireActive;
};
@@ -122,7 +120,7 @@ m.GameState.prototype.getTimeElapsed = function()
m.GameState.prototype.getBarterPrices = function()
{
- return this.barterPrices;
+ return this.playerData.barterPrices;
};
m.GameState.prototype.getGameType = function()
diff --git a/binaries/data/mods/public/simulation/ai/common-api/shared.js b/binaries/data/mods/public/simulation/ai/common-api/shared.js
index 8c709db2d7..3c5791a594 100644
--- a/binaries/data/mods/public/simulation/ai/common-api/shared.js
+++ b/binaries/data/mods/public/simulation/ai/common-api/shared.js
@@ -142,7 +142,6 @@ m.SharedScript.prototype.init = function(state, deserialization)
this.circularMap = state.circularMap;
this.mapSize = state.mapSize;
this.gameType = state.gameType;
- this.barterPrices = state.barterPrices;
this.alliedVictory = state.alliedVictory;
this.ceasefireActive = state.ceasefireActive;
diff --git a/binaries/data/mods/public/simulation/components/Barter.js b/binaries/data/mods/public/simulation/components/Barter.js
index cb230caf25..30db99ca77 100644
--- a/binaries/data/mods/public/simulation/components/Barter.js
+++ b/binaries/data/mods/public/simulation/components/Barter.js
@@ -34,14 +34,16 @@ Barter.prototype.Init = function()
this.restoreTimer = undefined;
};
-Barter.prototype.GetPrices = function()
+Barter.prototype.GetPrices = function(playerEntity)
{
var prices = { "buy": {}, "sell": {} };
+ let cmpPlayer = Engine.QueryInterface(playerEntity, IID_Player);
+ let multiplier = cmpPlayer.GetBarterMultiplier();
for (let resource of Resources.GetCodes())
{
let truePrice = Resources.GetResource(resource).truePrice;
- prices.buy[resource] = truePrice * (100 + this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
- prices.sell[resource] = truePrice * (100 - this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
+ prices.buy[resource] = truePrice * (100 + this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) * multiplier.buy[resource] / 100;
+ prices.sell[resource] = truePrice * (100 - this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) * multiplier.sell[resource] / 100;
}
return prices;
};
@@ -87,7 +89,7 @@ Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, reso
}
var cmpPlayer = Engine.QueryInterface(playerEntity, IID_Player);
- var prices = this.GetPrices();
+ var prices = this.GetPrices(playerEntity);
var amountsToSubtract = {};
amountsToSubtract[resourceToSell] = amount;
if (cmpPlayer.TrySubtractResources(amountsToSubtract))
@@ -116,8 +118,7 @@ Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, reso
}
// Increase price difference for both exchange resources.
- // Overal price difference (constant + dynamic) can't exceed +-99%
- // so both buy/sell prices limited to [1%; 199%] interval.
+ // Overal price difference (dynamic +- constant) can't exceed +-99%.
this.priceDifferences[resourceToSell] -= this.DIFFERENCE_PER_DEAL * numberOfDeals;
this.priceDifferences[resourceToSell] = Math.min(99 - this.CONSTANT_DIFFERENCE, Math.max(this.CONSTANT_DIFFERENCE - 99, this.priceDifferences[resourceToSell]));
this.priceDifferences[resourceToBuy] += this.DIFFERENCE_PER_DEAL * numberOfDeals;
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
index 695765717b..a8f5278e3a 100644
--- a/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -124,10 +124,13 @@ GuiInterface.prototype.GetSimulationState = function()
"researchedTechs": cmpTechnologyManager ? cmpTechnologyManager.GetResearchedTechs() : null,
"classCounts": cmpTechnologyManager ? cmpTechnologyManager.GetClassCounts() : null,
"typeCountsByClass": cmpTechnologyManager ? cmpTechnologyManager.GetTypeCountsByClass() : null,
- "canBarter": Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).PlayerHasMarket(playerEnt)
+ "canBarter": Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).PlayerHasMarket(playerEnt),
+ "barterPrices": Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).GetPrices(playerEnt)
});
}
+
+
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpRangeManager)
ret.circularMap = cmpRangeManager.GetLosCircular();
@@ -153,8 +156,6 @@ GuiInterface.prototype.GetSimulationState = function()
ret.gameType = cmpEndGameManager.GetGameType();
ret.alliedVictory = cmpEndGameManager.GetAlliedVictory();
- ret.barterPrices = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).GetPrices();
-
// Add Resource Codes, untranslated names and AI Analysis
ret.resources = {
"codes": Resources.GetCodes(),
diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js
index 531f7932ec..0fe4397325 100644
--- a/binaries/data/mods/public/simulation/components/Player.js
+++ b/binaries/data/mods/public/simulation/components/Player.js
@@ -1,6 +1,16 @@
function Player() {}
Player.prototype.Schema =
+ "" +
+ "" +
+ "" +
+ Resources.BuildSchema("positiveDecimal") +
+ "" +
+ "" +
+ Resources.BuildSchema("positiveDecimal") +
+ "" +
+ "" +
+ "" +
"" +
"" +
"" +
@@ -47,6 +57,7 @@ Player.prototype.Init = function()
this.disabledTechnologies = {};
this.startingTechnologies = [];
this.spyCostMultiplier = +this.template.SpyCostMultiplier;
+ this.barterMultiplier = {"buy": this.template.BarterMultiplier.Buy, "sell": this.template.BarterMultiplier.Sell };
// Initial resources and trading goods probability in steps of 5
let resCodes = Resources.GetCodes();
@@ -164,6 +175,11 @@ Player.prototype.GetMaxPopulation = function()
return Math.round(ApplyValueModificationsToPlayer("Player/MaxPopulation", this.maxPop, this.entity, this.playerID));
};
+Player.prototype.GetBarterMultiplier = function()
+{
+ return this.barterMultiplier;
+};
+
Player.prototype.SetGatherRateMultiplier = function(value)
{
this.gatherRateMultiplier = value;
@@ -740,9 +756,18 @@ Player.prototype.OnDiplomacyChanged = function()
Player.prototype.OnValueModification = function(msg)
{
- if (msg.component != "Player" || msg.valueNames.indexOf("Player/SpyCostMultiplier") === -1)
+ if (msg.component != "Player")
return;
- this.spyCostMultiplier = ApplyValueModificationsToPlayer("Player/SpyCostMultiplier", +this.template.SpyCostMultiplier, this.entity, this.playerID);
+
+ if (msg.valueNames.indexOf("Player/SpyCostMultiplier") != -1)
+ this.spyCostMultiplier = ApplyValueModificationsToPlayer("Player/SpyCostMultiplier", +this.template.SpyCostMultiplier, this.entity, this.playerID);
+
+ if (msg.valueNames.toString().search("Player/BarterMultiplier") != -1)
+ for (let res in this.template.BarterMultiplier.Buy)
+ {
+ this.barterMultiplier.buy[res] = ApplyValueModificationsToEntity("Player/BarterMultiplier/Buy/"+res, +this.template.BarterMultiplier.Buy[res], this.entity);
+ this.barterMultiplier.sell[res] = ApplyValueModificationsToEntity("Player/BarterMultiplier/Sell/"+res, +this.template.BarterMultiplier.Sell[res], this.entity);
+ }
};
Player.prototype.SetCheatsEnabled = function(flag)
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Barter.js b/binaries/data/mods/public/simulation/components/tests/test_Barter.js
index 8faa8cf0ad..8cb719c445 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Barter.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Barter.js
@@ -20,6 +20,18 @@ const playerEnt = 11;
let timerActivated = false;
let bought = 0;
let sold = 0;
+let multiplier = {
+ "buy": {
+ "wood": 1.0,
+ "stone": 1.0,
+ "metal": 1.0
+ },
+ "sell": {
+ "wood": 1.0,
+ "stone": 1.0,
+ "metal": 1.0
+ }
+};
AddMock(SYSTEM_ENTITY, IID_Timer, {
"CancelTimer": id => { timerActivated = false; },
@@ -46,7 +58,8 @@ AddMock(playerEnt, IID_Player, {
"AddResource": (type, amount) => {
bought = amount;
return true;
- }
+ },
+ "GetBarterMultiplier": () => (multiplier)
});
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
@@ -61,17 +74,30 @@ AddMock(60, IID_Foundation, {});
// GetPrices
cmpBarter.priceDifferences = { "wood": 8, "stone": 0, "metal": 0 };
-TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices().buy, {
+TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerEnt).buy, {
"wood": truePrice * (100 + 8 + cmpBarter.CONSTANT_DIFFERENCE) / 100,
"stone": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) / 100,
"metal": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) / 100
});
-TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices().sell, {
+TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerEnt).sell, {
"wood": truePrice * (100 + 8 - cmpBarter.CONSTANT_DIFFERENCE) / 100,
"stone": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100,
"metal": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100
});
+multiplier.buy.stone = 2.0;
+TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerEnt).buy, {
+ "wood": truePrice * (100 + 8 + cmpBarter.CONSTANT_DIFFERENCE) / 100,
+ "stone": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) * 2.0 / 100,
+ "metal": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) / 100
+});
+TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerEnt).sell, {
+ "wood": truePrice * (100 + 8 - cmpBarter.CONSTANT_DIFFERENCE) / 100,
+ "stone": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100,
+ "metal": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100
+});
+multiplier.buy.stone = 1.0;
+
// PlayerHasMarket
TS_ASSERT(!cmpBarter.PlayerHasMarket(11));
@@ -119,7 +145,8 @@ timerActivated = false;
AddMock(playerEnt, IID_Player, {
"GetPlayerID": () => 1,
"TrySubtractResources": () => false,
- "AddResource": () => {}
+ "AddResource": () => {},
+ "GetBarterMultiplier": () => (multiplier)
});
cmpBarter.ExchangeResources(11, "wood", "stone", 100);
diff --git a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
index dfdf649087..fd0671fe82 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
@@ -299,6 +299,10 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
classCounts: {},
typeCountsByClass: {},
canBarter: false,
+ barterPrices: {
+ "buy": { "food": 150 },
+ "sell": { "food": 25 }
+ },
statistics: {
resourcesGathered: {
food: 100,
@@ -344,6 +348,10 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
classCounts: {},
typeCountsByClass: {},
canBarter: false,
+ barterPrices: {
+ "buy": { "food": 150 },
+ "sell": { "food": 25 }
+ },
statistics: {
resourcesGathered: {
food: 100,
@@ -360,10 +368,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
timeElapsed: 0,
gameType: "conquest",
alliedVictory: false,
- "barterPrices": {
- "buy": { "food": 150 },
- "sell": { "food": 25 }
- },
"resources": {
"codes": ["food", "metal", "stone", "wood"],
"names": {
@@ -417,6 +421,10 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
"classCounts": {},
"typeCountsByClass": {},
"canBarter": false,
+ "barterPrices": {
+ "buy": { "food": 150 },
+ "sell": { "food": 25 }
+ },
"statistics": {
"resourcesGathered": {
"food": 100,
@@ -485,6 +493,10 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
"classCounts": {},
"typeCountsByClass": {},
"canBarter": false,
+ "barterPrices": {
+ "buy": { "food": 150 },
+ "sell": { "food": 25 }
+ },
"statistics": {
"resourcesGathered": {
"food": 100,
@@ -524,10 +536,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
"timeElapsed": 0,
"gameType": "conquest",
"alliedVictory": false,
- "barterPrices": {
- "buy": { "food": 150 },
- "sell": { "food": 25 }
- },
"resources": {
"codes": ["food", "metal", "stone", "wood"],
"names": {
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Player.js b/binaries/data/mods/public/simulation/components/tests/test_Player.js
index 23563bf12e..880e0acedf 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Player.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Player.js
@@ -1,3 +1,19 @@
+Resources = {
+ "GetCodes": () => ["food", "metal", "stone", "wood"],
+ "GetResource": () => ({}),
+ "BuildSchema": (type) => {
+ let schema = "";
+ for (let res of Resources.GetCodes())
+ schema +=
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+ return "" + schema + "";
+ }
+};
+
Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/AuraManager.js");
@@ -5,11 +21,6 @@ Engine.LoadComponentScript("interfaces/Player.js");
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
Engine.LoadComponentScript("Player.js");
-Resources = {
- "GetCodes": () => ["food", "metal", "stone", "wood"],
- "GetResource": () => ({}),
-};
-
AddMock(SYSTEM_ENTITY, IID_TemplateManager, {
"GetTemplate": name => null,
"GetCurrentTemplateName" : ent => null
@@ -20,7 +31,19 @@ AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
});
var cmpPlayer = ConstructComponent(10, "Player", {
- "SpyCostMultiplier": 1
+ "SpyCostMultiplier": 1,
+ "BarterMultiplier": {
+ "Buy": {
+ "wood": 1.0,
+ "stone": 1.0,
+ "metal": 1.0
+ },
+ "Sell": {
+ "wood": 1.0,
+ "stone": 1.0,
+ "metal": 1.0
+ }
+ },
});
TS_ASSERT_EQUALS(cmpPlayer.GetPopulationCount(), 0);
@@ -40,3 +63,15 @@ diplo[1] = -1;
TS_ASSERT(cmpPlayer.IsAlly(1));
TS_ASSERT_EQUALS(cmpPlayer.GetSpyCostMultiplier(), 1);
+TS_ASSERT_UNEVAL_EQUALS(cmpPlayer.GetBarterMultiplier(), {
+ "buy": {
+ "wood": 1.0,
+ "stone": 1.0,
+ "metal": 1.0
+ },
+ "sell": {
+ "wood": 1.0,
+ "stone": 1.0,
+ "metal": 1.0
+ }
+});
diff --git a/binaries/data/mods/public/simulation/templates/special/player.xml b/binaries/data/mods/public/simulation/templates/special/player.xml
index f5398d86ed..5c7a89bdad 100644
--- a/binaries/data/mods/public/simulation/templates/special/player.xml
+++ b/binaries/data/mods/public/simulation/templates/special/player.xml
@@ -58,6 +58,20 @@
Player
+
+
+ 1.0
+ 1.0
+ 1.0
+ 1.0
+
+
+ 1.0
+ 1.0
+ 1.0
+ 1.0
+
+
unlock_shared_los
unlock_shared_dropsites
1.0
diff --git a/binaries/data/mods/public/simulation/templates/special/player_gaia.xml b/binaries/data/mods/public/simulation/templates/special/player_gaia.xml
index 936d2c4c11..af54c0e38b 100644
--- a/binaries/data/mods/public/simulation/templates/special/player_gaia.xml
+++ b/binaries/data/mods/public/simulation/templates/special/player_gaia.xml
@@ -4,5 +4,19 @@
1.0
+
+
+ 1.0
+ 1.0
+ 1.0
+ 1.0
+
+
+ 1.0
+ 1.0
+ 1.0
+ 1.0
+
+