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 + +