Changeset View
Standalone View
binaries/data/mods/public/simulation/ai/petra/tradeManager.js
Show First 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | else | ||||
ent.tradeRoute(route.source, route.target); | ent.tradeRoute(route.source, route.target); | ||||
ent.setMetadata(PlayerID, "route", this.routeEntToId(route)); | ent.setMetadata(PlayerID, "route", this.routeEntToId(route)); | ||||
Engine.ProfileStop(); | Engine.ProfileStop(); | ||||
}; | }; | ||||
m.TradeManager.prototype.setTradingGoods = function(gameState) | m.TradeManager.prototype.setTradingGoods = function(gameState) | ||||
{ | { | ||||
let tradingGoods = {}; | let tradingGoods = {}; | ||||
for (let res of Resources.GetCodes()) | let resTradeCodes = Resources.GetCodes("tradable"); | ||||
for (let res of resTradeCodes) | |||||
tradingGoods[res] = 0; | tradingGoods[res] = 0; | ||||
// first, try to anticipate future needs | // first, try to anticipate future needs | ||||
let stocks = gameState.ai.HQ.getTotalResourceLevel(gameState); | let stocks = gameState.ai.HQ.getTotalResourceLevel(gameState); | ||||
Silier: this needs to filter tradable resources here or in loop below | |||||
let mostNeeded = gameState.ai.HQ.pickMostNeededResources(gameState); | let mostNeeded = gameState.ai.HQ.pickMostNeededResources(gameState, "tradable"); | ||||
Done Inline Actionsneed to get most needed traidable Silier: need to get most needed traidable | |||||
Done Inline ActionsNot sure how to filter through object. I'll look into it tomorrow hopefully. Freagarach: Not sure how to filter through object. I'll look into it tomorrow hopefully. | |||||
let wantedRates = gameState.ai.HQ.GetWantedGatherRates(gameState); | let wantedRates = gameState.ai.HQ.GetWantedGatherRates(gameState); | ||||
let remaining = 100; | let remaining = 100; | ||||
let targetNum = this.Config.Economy.targetNumTraders; | let targetNum = this.Config.Economy.targetNumTraders; | ||||
for (let res in stocks) | for (let res of resTradeCodes) | ||||
Done Inline Actionsof Silier: of | |||||
Done Inline ActionsYeah, it was too late yesterday. Freagarach: Yeah, it was too late yesterday. | |||||
{ | { | ||||
if (res == "food") | if (res == "food") | ||||
continue; | continue; | ||||
let wantedRate = wantedRates[res]; | let wantedRate = wantedRates[res]; | ||||
if (stocks[res] < 200) | if (stocks[res] < 200) | ||||
{ | { | ||||
tradingGoods[res] = wantedRate > 0 ? 20 : 10; | tradingGoods[res] = wantedRate > 0 ? 20 : 10; | ||||
targetNum += Math.min(5, 3 + Math.ceil(wantedRate/30)); | targetNum += Math.min(5, 3 + Math.ceil(wantedRate/30)); | ||||
Show All 13 Lines | m.TradeManager.prototype.setTradingGoods = function(gameState) | ||||
this.targetNumTraders = Math.round(this.Config.popScaling * targetNum); | this.targetNumTraders = Math.round(this.Config.popScaling * targetNum); | ||||
// then add what is needed now | // then add what is needed now | ||||
let mainNeed = Math.floor(remaining * 70 / 100); | let mainNeed = Math.floor(remaining * 70 / 100); | ||||
let nextNeed = remaining - mainNeed; | let nextNeed = remaining - mainNeed; | ||||
tradingGoods[mostNeeded[0].type] += mainNeed; | tradingGoods[mostNeeded[0].type] += mainNeed; | ||||
if (mostNeeded[1].wanted > 0) | if (mostNeeded[1].wanted > 0) | ||||
SilierUnsubmitted Done Inline Actionsmostneeded[0/1] does not have to exists Silier: mostneeded[0/1] does not have to exists | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsI'll check for more as well. Freagarach: I'll check for more as well. | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsmostNeeded[0] Has to exist because this function is not called when there are no tradable resources. Can we rely on that? Freagarach: `mostNeeded[0]` Has to exist because this function is not called when there are no tradable… | |||||
SilierUnsubmitted Done Inline Actionstechnically but need to check all calls where is this function called and add comment as description of this function to not call when no tradable resources, anyway that could be early return and no one would have problems in the future calling this on 0 resources Silier: technically but need to check all calls where is this function called and add comment as… | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsOkay, thanks! I'll add more early returns in functions then :) Freagarach: Okay, thanks! I'll add more early returns in functions then :) | |||||
tradingGoods[mostNeeded[1].type] += nextNeed; | tradingGoods[mostNeeded[1].type] += nextNeed; | ||||
else | else | ||||
tradingGoods[mostNeeded[0].type] += nextNeed; | tradingGoods[mostNeeded[0].type] += nextNeed; | ||||
Engine.PostCommand(PlayerID, { "type": "set-trading-goods", "tradingGoods": tradingGoods }); | Engine.PostCommand(PlayerID, { "type": "set-trading-goods", "tradingGoods": tradingGoods }); | ||||
if (this.Config.debug > 2) | if (this.Config.debug > 2) | ||||
API3.warn(" trading goods set to " + uneval(tradingGoods)); | API3.warn(" trading goods set to " + uneval(tradingGoods)); | ||||
}; | }; | ||||
Show All 13 Lines | m.TradeManager.prototype.performBarter = function(gameState) | ||||
let rates = gameState.ai.HQ.GetCurrentGatherRates(gameState); | let rates = gameState.ai.HQ.GetCurrentGatherRates(gameState); | ||||
let barterPrices = gameState.getBarterPrices(); | let barterPrices = gameState.getBarterPrices(); | ||||
// calculates conversion rates | // calculates conversion rates | ||||
let getBarterRate = (prices, buy, sell) => Math.round(100 * prices.sell[sell] / prices.buy[buy]); | 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. | // loop through each missing resource checking if we could barter and help finishing a queue quickly. | ||||
for (let buy of Resources.GetCodes()) | let resBarterCodes = Resources.GetCodes("barterable"); | ||||
for (let buy of resBarterCodes) | |||||
{ | { | ||||
// Check if our rate allows to gather it fast enough | // Check if our rate allows to gather it fast enough | ||||
if (needs[buy] == 0 || needs[buy] < rates[buy] * 30) | if (needs[buy] == 0 || needs[buy] < rates[buy] * 30) | ||||
continue; | continue; | ||||
// Pick the best resource to barter. | // Pick the best resource to barter. | ||||
let bestToSell; | let bestToSell; | ||||
let bestRate = 0; | let bestRate = 0; | ||||
for (let sell of Resources.GetCodes()) | for (let sell of resBarterCodes) | ||||
Done Inline Actionsyou could cache that codes as you are going to call it n^2 times Silier: you could cache that codes as you are going to call it n^2 times | |||||
{ | { | ||||
if (sell == buy) | if (sell == buy) | ||||
continue; | continue; | ||||
// Do not sell if we need it or do not have enough buffer | // Do not sell if we need it or do not have enough buffer | ||||
if (needs[sell] > 0 || available[sell] < 500) | if (needs[sell] > 0 || available[sell] < 500) | ||||
continue; | continue; | ||||
let barterRateMin; | let barterRateMin; | ||||
if (sell == "food") | if (sell == "food") | ||||
Done Inline ActionsI think it can be simplified as !GetCodes("currency").some(x => x == sell || x => x == buy) Stan: I think it can be simplified as
```lang=js
!GetCodes("currency").some(x => x == sell || x =>… | |||||
{ | { | ||||
barterRateMin = 30; | barterRateMin = 30; | ||||
if (available[sell] > 40000) | if (available[sell] > 40000) | ||||
barterRateMin = 0; | barterRateMin = 0; | ||||
else if (available[sell] > 15000) | else if (available[sell] > 15000) | ||||
barterRateMin = 5; | barterRateMin = 5; | ||||
else if (available[sell] > 1000) | else if (available[sell] > 1000) | ||||
barterRateMin = 10; | barterRateMin = 10; | ||||
Show All 26 Lines | if (bestToSell !== undefined) | ||||
" rate buy " + rates[buy] + " available sell " + available[bestToSell] + | " rate buy " + rates[buy] + " available sell " + available[bestToSell] + | ||||
" available buy " + available[buy] + " barterRate " + bestRate + | " available buy " + available[buy] + " barterRate " + bestRate + | ||||
" amount " + amount); | " amount " + amount); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// now do contingency bartering, selling food to buy finite resources (and annoy our ennemies by increasing prices) | // now do contingency bartering, selling food to buy finite resources (and annoy our ennemies by increasing prices) | ||||
if (available.food < 1000 || needs.food > 0) | if (available.food < 1000 || needs.food > 0 || resBarterCodes.indexOf("food") == -1) | ||||
Done Inline ActionsYou mean here? This should fix that, since the idea of all code below is to barter food, I can just as well check here ;) Freagarach: You mean here? This should fix that, since the idea of all code below is to barter food, I can… | |||||
return false; | return false; | ||||
let bestToBuy; | let bestToBuy; | ||||
let bestChoice = 0; | let bestChoice = 0; | ||||
for (let buy of Resources.GetCodes()) | for (let buy of resBarterCodes) | ||||
{ | { | ||||
if (buy == "food") | if (buy == "food") | ||||
continue; | continue; | ||||
let barterRateMin = 80; | let barterRateMin = 80; | ||||
if (available[buy] < 5000 && available.food > 5000) | if (available[buy] < 5000 && available.food > 5000) | ||||
barterRateMin -= 20 - Math.floor(available[buy]/250); | barterRateMin -= 20 - Math.floor(available[buy]/250); | ||||
let barterRate = getBarterRate(barterPrices, buy, "food"); | let barterRate = getBarterRate(barterPrices, buy, "food"); | ||||
Done Inline Actionsfood set not bartable ? Silier: food set not bartable ? | |||||
if (barterRate < barterRateMin) | if (barterRate < barterRateMin) | ||||
continue; | continue; | ||||
let choice = barterRate / (100 + available[buy]); | let choice = barterRate / (100 + available[buy]); | ||||
if (choice > bestChoice) | if (choice > bestChoice) | ||||
{ | { | ||||
bestChoice = choice; | bestChoice = choice; | ||||
bestToBuy = buy; | bestToBuy = buy; | ||||
} | } | ||||
} | } | ||||
if (bestToBuy !== undefined) | if (bestToBuy !== undefined) | ||||
{ | { | ||||
let amount = available.food > 5000 ? 500 : 100; | let amount = available.food > 5000 ? 500 : 100; | ||||
barterers[0].barter(bestToBuy, "food", amount); | barterers[0].barter(bestToBuy, "food", amount); | ||||
Done Inline Actionswhat if food is set as not bartable Silier: what if food is set as not bartable | |||||
if (this.Config.debug > 2) | if (this.Config.debug > 2) | ||||
API3.warn("Contingency bartering: sold food for " + bestToBuy + | API3.warn("Contingency bartering: sold food for " + bestToBuy + | ||||
" available sell " + available.food + " available buy " + available[bestToBuy] + | " available sell " + available.food + " available buy " + available[bestToBuy] + | ||||
" barterRate " + getBarterRate(barterPrices, bestToBuy, "food") + | " barterRate " + getBarterRate(barterPrices, bestToBuy, "food") + | ||||
" amount " + amount); | " amount " + amount); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* fills the best trade route in this.tradeRoute and the best potential route in this.potentialTradeRoute | * fills the best trade route in this.tradeRoute and the best potential route in this.potentialTradeRoute | ||||
* If an index is given, it returns the best route with this index or the best land route if index is a land index | * If an index is given, it returns the best route with this index or the best land route if index is a land index | ||||
*/ | */ | ||||
m.TradeManager.prototype.checkRoutes = function(gameState, accessIndex) | m.TradeManager.prototype.checkRoutes = function(gameState, accessIndex) | ||||
{ | { | ||||
// If we cannot trade, do not bother checking routes. | |||||
if (!Resources.GetCodes("tradable").length) | |||||
{ | |||||
this.tradeRoute = undefined; | |||||
this.potentialTradeRoute = undefined; | |||||
return false; | |||||
} | |||||
let market1 = gameState.updatingCollection("OwnMarkets", API3.Filters.byClass("Market"), gameState.getOwnStructures()); | let market1 = gameState.updatingCollection("OwnMarkets", API3.Filters.byClass("Market"), gameState.getOwnStructures()); | ||||
let market2 = gameState.updatingCollection("diplo-ExclusiveAllyMarkets", API3.Filters.byClass("Market"), gameState.getExclusiveAllyEntities()); | let market2 = gameState.updatingCollection("diplo-ExclusiveAllyMarkets", API3.Filters.byClass("Market"), gameState.getExclusiveAllyEntities()); | ||||
if (market1.length + market2.length < 2) // We have to wait ... markets will be built soon | if (market1.length + market2.length < 2) // We have to wait ... markets will be built soon | ||||
{ | { | ||||
this.tradeRoute = undefined; | this.tradeRoute = undefined; | ||||
this.potentialTradeRoute = undefined; | this.potentialTradeRoute = undefined; | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 195 Lines • ▼ Show 20 Lines | m.TradeManager.prototype.prospectForNewMarket = function(gameState, queues) | ||||
let plan = new m.ConstructionPlan(gameState, "structures/{civ}_market"); | let plan = new m.ConstructionPlan(gameState, "structures/{civ}_market"); | ||||
if (!this.tradeRoute) | if (!this.tradeRoute) | ||||
plan.queueToReset = "economicBuilding"; | plan.queueToReset = "economicBuilding"; | ||||
queues.economicBuilding.addPlan(plan); | queues.economicBuilding.addPlan(plan); | ||||
}; | }; | ||||
m.TradeManager.prototype.isNewMarketWorth = function(expectedGain) | m.TradeManager.prototype.isNewMarketWorth = function(expectedGain) | ||||
{ | { | ||||
if (!Resources.GetCodes("tradable").length) | |||||
return false; | |||||
if (expectedGain < this.minimalGain) | if (expectedGain < this.minimalGain) | ||||
return false; | return false; | ||||
if (this.potentialTradeRoute && expectedGain < 2*this.potentialTradeRoute.gain && | if (this.potentialTradeRoute && expectedGain < 2*this.potentialTradeRoute.gain && | ||||
expectedGain < this.potentialTradeRoute.gain + 20) | expectedGain < this.potentialTradeRoute.gain + 20) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
}; | }; | ||||
m.TradeManager.prototype.update = function(gameState, events, queues) | m.TradeManager.prototype.update = function(gameState, events, queues) | ||||
{ | { | ||||
if (gameState.ai.HQ.canBarter) | if (gameState.ai.HQ.canBarter && Resources.GetCodes("barterable").length) | ||||
this.performBarter(gameState); | this.performBarter(gameState); | ||||
if (this.Config.difficulty <= 1) | if (this.Config.difficulty <= 1) | ||||
return; | return; | ||||
if (this.checkEvents(gameState, events)) // true if one market was built or destroyed | if (this.checkEvents(gameState, events)) // true if one market was built or destroyed | ||||
{ | { | ||||
this.traders.forEach(ent => { this.checkTrader(gameState, ent); }); | this.traders.forEach(ent => { this.checkTrader(gameState, ent); }); | ||||
▲ Show 20 Lines • Show All 82 Lines • Show Last 20 Lines |
this needs to filter tradable resources here or in loop below