Add barter multiplier for barter prices. They can be altered by technologies or auras. Reviewed by mimo.

Differential Revision: https://code.wildfiregames.com/D478
This was SVN commit r19615.
This commit is contained in:
fatherbushido 2017-05-20 18:01:49 +00:00
parent d8490b8c2e
commit dc17836fe5
11 changed files with 156 additions and 34 deletions

View file

@ -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() {

View file

@ -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()

View file

@ -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;

View file

@ -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;

View file

@ -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(),

View file

@ -1,6 +1,16 @@
function Player() {}
Player.prototype.Schema =
"<element name='BarterMultiplier' a:help='Multipliers for barter prices.'>" +
"<interleave>" +
"<element name='Buy' a:help='Multipliers for the buy prices.'>" +
Resources.BuildSchema("positiveDecimal") +
"</element>" +
"<element name='Sell' a:help='Multipliers for the sell prices.'>" +
Resources.BuildSchema("positiveDecimal") +
"</element>" +
"</interleave>" +
"</element>" +
"<element name='SharedLosTech' a:help='Allies will share los when this technology is researched. Leave empty to never share LOS.'>" +
"<text/>" +
"</element>" +
@ -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)

View file

@ -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);

View file

@ -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": {

View file

@ -1,3 +1,19 @@
Resources = {
"GetCodes": () => ["food", "metal", "stone", "wood"],
"GetResource": () => ({}),
"BuildSchema": (type) => {
let schema = "";
for (let res of Resources.GetCodes())
schema +=
"<optional>" +
"<element name='" + res + "'>" +
"<ref name='" + type + "'/>" +
"</element>" +
"</optional>";
return "<interleave>" + schema + "</interleave>";
}
};
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
}
});

View file

@ -58,6 +58,20 @@
<Classes datatype="tokens">Player</Classes>
</Identity>
<Player>
<BarterMultiplier>
<Buy>
<food>1.0</food>
<wood>1.0</wood>
<stone>1.0</stone>
<metal>1.0</metal>
</Buy>
<Sell>
<food>1.0</food>
<wood>1.0</wood>
<stone>1.0</stone>
<metal>1.0</metal>
</Sell>
</BarterMultiplier>
<SharedLosTech>unlock_shared_los</SharedLosTech>
<SharedDropsitesTech>unlock_shared_dropsites</SharedDropsitesTech>
<SpyCostMultiplier>1.0</SpyCostMultiplier>

View file

@ -4,5 +4,19 @@
<SharedLosTech/>
<SharedDropsitesTech/>
<SpyCostMultiplier>1.0</SpyCostMultiplier>
<BarterMultiplier>
<Buy>
<food>1.0</food>
<wood>1.0</wood>
<stone>1.0</stone>
<metal>1.0</metal>
</Buy>
<Sell>
<food>1.0</food>
<wood>1.0</wood>
<stone>1.0</stone>
<metal>1.0</metal>
</Sell>
</BarterMultiplier>
</Player>
</Entity>