diff --git a/binaries/data/mods/public/gui/aiconfig/aiconfig.xml b/binaries/data/mods/public/gui/aiconfig/aiconfig.xml index 4d6678441f..c5fbb9d78f 100644 --- a/binaries/data/mods/public/gui/aiconfig/aiconfig.xml +++ b/binaries/data/mods/public/gui/aiconfig/aiconfig.xml @@ -10,7 +10,7 @@ - + AI Configuration @@ -33,7 +33,7 @@ - + Cancel diff --git a/binaries/data/mods/public/simulation/ai/petra/data.json b/binaries/data/mods/public/simulation/ai/petra/data.json index b05136bb05..643976b93d 100644 --- a/binaries/data/mods/public/simulation/ai/petra/data.json +++ b/binaries/data/mods/public/simulation/ai/petra/data.json @@ -1,6 +1,6 @@ { "name": "Petra Bot", - "description": "Started as a fork of Aegis bot, Petra is the most stable AI available. It supports naval maps and is generally more challenging. Please report issues to Wildfire Games (see the link in the main menu).", + "description": "Petra is the default 0AD AI bot. Please report issues to Wildfire Games (see the link in the main menu).\n\nThe AI has a malus-bonus on resource stockpiling (either gathering rate or trade gain) varying from 0.5 for Sandbox to 1.6 for Very Hard (Medium = 1.0). In addition, the Sandbox level does not expand nor attack.", "moduleName" : "PETRA", "constructor": "PetraBot", "useShared": true diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js index 05e5752a66..0465e252b5 100644 --- a/binaries/data/mods/public/simulation/components/Player.js +++ b/binaries/data/mods/public/simulation/components/Player.js @@ -36,6 +36,7 @@ Player.prototype.Init = function() this.controlAllUnits = false; this.isAI = false; this.gatherRateMultiplier = 1; + this.tradeRateMultiplier = 1; this.cheatsEnabled = false; this.cheatTimeMultiplier = 1; this.heroes = []; @@ -156,6 +157,16 @@ Player.prototype.GetGatherRateMultiplier = function() return this.gatherRateMultiplier; }; +Player.prototype.SetTradeRateMultiplier = function(value) +{ + this.tradeRateMultiplier = value; +}; + +Player.prototype.GetTradeRateMultiplier = function() +{ + return this.tradeRateMultiplier; +}; + Player.prototype.GetHeroes = function() { return this.heroes; diff --git a/binaries/data/mods/public/simulation/helpers/InitGame.js b/binaries/data/mods/public/simulation/helpers/InitGame.js index 9d98d079ec..3c0324d126 100644 --- a/binaries/data/mods/public/simulation/helpers/InitGame.js +++ b/binaries/data/mods/public/simulation/helpers/InitGame.js @@ -42,6 +42,8 @@ function InitGame(settings) cmpRangeManager.ExploreAllTiles(i); } + // Sandbox, Very Easy, Easy, Medium, Hard, Very Hard + let rate = [ 0.50, 0.64, 0.80, 1.00, 1.25, 1.56 ]; let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); let cmpAIManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIManager); for (let i = 1; i < settings.PlayerData.length; ++i) @@ -50,10 +52,12 @@ function InitGame(settings) cmpPlayer.SetCheatsEnabled(!!settings.CheatsEnabled); if (settings.PlayerData[i] && settings.PlayerData[i].AI && settings.PlayerData[i].AI != "") { - cmpAIManager.AddPlayer(settings.PlayerData[i].AI, i, +settings.PlayerData[i].AIDiff); + let AIDiff = +settings.PlayerData[i].AIDiff; + cmpAIManager.AddPlayer(settings.PlayerData[i].AI, i, AIDiff); cmpPlayer.SetAI(true); - // Sandbox: 50%, very easy: 50%, easy: 66%, Medium: 100%, hard: 133%, very hard: 166% - cmpPlayer.SetGatherRateMultiplier(Math.max(0.5,(+settings.PlayerData[i].AIDiff)/3.0)); + AIDiff = Math.min(AIDiff, rate.length - 1); + cmpPlayer.SetGatherRateMultiplier(rate[AIDiff]); + cmpPlayer.SetTradeRateMultiplier(rate[AIDiff]); } if (settings.PopulationCap) cmpPlayer.SetMaxPopulation(settings.PopulationCap); diff --git a/binaries/data/mods/public/simulation/helpers/TraderGain.js b/binaries/data/mods/public/simulation/helpers/TraderGain.js index 35275a21c8..d259979f68 100644 --- a/binaries/data/mods/public/simulation/helpers/TraderGain.js +++ b/binaries/data/mods/public/simulation/helpers/TraderGain.js @@ -11,14 +11,15 @@ function CalculateTraderGain(firstMarket, secondMarket, template, trader) var cmpFirstMarketPosition = Engine.QueryInterface(firstMarket, IID_Position); var cmpSecondMarketPosition = Engine.QueryInterface(secondMarket, IID_Position); - if (!cmpFirstMarketPosition || !cmpFirstMarketPosition.IsInWorld() || !cmpSecondMarketPosition || !cmpSecondMarketPosition.IsInWorld()) + if (!cmpFirstMarketPosition || !cmpFirstMarketPosition.IsInWorld() || + !cmpSecondMarketPosition || !cmpSecondMarketPosition.IsInWorld()) return null; var firstMarketPosition = cmpFirstMarketPosition.GetPosition2D(); var secondMarketPosition = cmpSecondMarketPosition.GetPosition2D(); // Calculate ordinary Euclidean distance between markets. // We don't use pathfinder, because ordinary distance looks more fair. - var distance = Math.sqrt(Math.pow(firstMarketPosition.x - secondMarketPosition.x, 2) + Math.pow(firstMarketPosition.y - secondMarketPosition.y, 2)); + var distance = firstMarketPosition.distanceTo(secondMarketPosition); // We calculate gain as square of distance to encourage trading between remote markets gain.traderGain = Math.pow(distance * DISTANCE_FACTOR, 2); if (template && template.GainMultiplier) @@ -28,12 +29,10 @@ function CalculateTraderGain(firstMarket, secondMarket, template, trader) else // called from the gui with modifications already applied gain.traderGain *= template.GainMultiplier; } - gain.traderGain = Math.round(gain.traderGain); // If trader undefined, the trader owner is supposed to be the same as the first market - if (trader) - var cmpOwnership = Engine.QueryInterface(trader, IID_Ownership); - else - var cmpOwnership = Engine.QueryInterface(firstMarket, IID_Ownership); + var cmpOwnership = trader ? Engine.QueryInterface(trader, IID_Ownership) : Engine.QueryInterface(firstMarket, IID_Ownership); + if (!cmpOwnership) + return null; gain.traderOwner = cmpOwnership.GetOwner(); // If markets belong to different players, add gain from international trading @@ -41,13 +40,28 @@ function CalculateTraderGain(firstMarket, secondMarket, template, trader) var ownerSecondMarket = Engine.QueryInterface(secondMarket, IID_Ownership).GetOwner(); if (ownerFirstMarket != ownerSecondMarket) { - var internationalGain1 = ApplyValueModificationsToEntity("Trade/International", INTERNATIONAL_TRADING_ADDITION, firstMarket); - gain.market1Gain = Math.round(gain.traderGain * internationalGain1 / 100); + gain.market1Gain = gain.traderGain * ApplyValueModificationsToEntity("Trade/International", INTERNATIONAL_TRADING_ADDITION, firstMarket) / 100; gain.market1Owner = ownerFirstMarket; - var internationalGain2 = ApplyValueModificationsToEntity("Trade/International", INTERNATIONAL_TRADING_ADDITION, secondMarket); - gain.market2Gain = Math.round(gain.traderGain * internationalGain2 / 100); + gain.market2Gain = gain.traderGain * ApplyValueModificationsToEntity("Trade/International", INTERNATIONAL_TRADING_ADDITION, secondMarket) / 100; gain.market2Owner = ownerSecondMarket; + } + // Add potential trade multipliers and roundings + var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); + var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(gain.traderOwner), IID_Player); + if (cmpPlayer) + gain.traderGain *= cmpPlayer.GetTradeRateMultiplier(); + gain.traderGain = Math.round(gain.traderGain); + + if (ownerFirstMarket != ownerSecondMarket) + { + if ((cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(gain.market1Owner), IID_Player))) + gain.market1Gain *= cmpPlayer.GetTradeRateMultiplier(); + gain.market1Gain = Math.round(gain.market1Gain); + + if ((cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(gain.market2Owner), IID_Player))) + gain.market2Gain *= cmpPlayer.GetTradeRateMultiplier(); + gain.market2Gain = Math.round(gain.market2Gain); } return gain;