Index: binaries/data/mods/public/simulation/ai/common-api/gamestate.js =================================================================== --- binaries/data/mods/public/simulation/ai/common-api/gamestate.js +++ binaries/data/mods/public/simulation/ai/common-api/gamestate.js @@ -35,6 +35,7 @@ let phaseData = {}; let phaseMap = {}; + for (let techName of techs) { if (!techName.startsWith("phase")) @@ -43,8 +44,9 @@ if (techData._definesPair) { - // Randomly pick a non-disabled choice from the phase-pair. - techName = pickRandom([techData._template.top, techData._template.bottom].filter(tech => !this.playerData.disabledTechnologies[tech])) || techData._template.top; + // TODO: let ai decide at runtime which one wants + // Cannot call pickrandom because this function is called on rejoin and that causes oos (reverting rP20750) + techName = this.playerData.disabledTechnologies[techData._template.bottom] ? techData._template.top : techData._template.bottom; let supersedes = techData._template.supersedes; techData = clone(this.getTemplate(techName)); Index: binaries/data/mods/public/simulation/ai/petra/_petrabot.js =================================================================== --- binaries/data/mods/public/simulation/ai/petra/_petrabot.js +++ binaries/data/mods/public/simulation/ai/petra/_petrabot.js @@ -55,7 +55,7 @@ this.queueManager.Deserialize(gameState, this.data.queueManager); this.queues = this.queueManager.queues; - this.HQ = new PETRA.HQ(this.Config); + this.HQ = new PETRA.HQ(this.Config, true); this.HQ.init(gameState, this.queues); this.HQ.Deserialize(gameState, this.data.HQ); Index: binaries/data/mods/public/simulation/ai/petra/attackManager.js =================================================================== --- binaries/data/mods/public/simulation/ai/petra/attackManager.js +++ binaries/data/mods/public/simulation/ai/petra/attackManager.js @@ -778,7 +778,7 @@ this.upcomingAttacks[key] = []; for (let dataAttack of data.upcomingAttacks[key]) { - let attack = new PETRA.AttackPlan(gameState, this.Config, dataAttack.properties.name); + let attack = new PETRA.AttackPlan(gameState, this.Config, dataAttack.properties.name, true); attack.Deserialize(gameState, dataAttack); attack.init(gameState); this.upcomingAttacks[key].push(attack); @@ -791,7 +791,7 @@ this.startedAttacks[key] = []; for (let dataAttack of data.startedAttacks[key]) { - let attack = new PETRA.AttackPlan(gameState, this.Config, dataAttack.properties.name); + let attack = new PETRA.AttackPlan(gameState, this.Config, dataAttack.properties.name, true); attack.Deserialize(gameState, dataAttack); attack.init(gameState); this.startedAttacks[key].push(attack); Index: binaries/data/mods/public/simulation/ai/petra/attackPlan.js =================================================================== --- binaries/data/mods/public/simulation/ai/petra/attackPlan.js +++ binaries/data/mods/public/simulation/ai/petra/attackPlan.js @@ -3,9 +3,10 @@ * It deals with everything in an attack, from picking a target to picking a path to it * To making sure units are built, and pushing elements to the queue manager otherwise * It also handles the actual attack, though much work is needed on that. + * When deserialized is true, do not call any random function inside constructor as that causes oos. */ -PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data) +PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data, deserialized) { this.Config = Config; this.name = uniqueID; @@ -168,31 +169,35 @@ this.neededShips = 3; } - // Put some randomness on the attack size - let variation = randFloat(0.8, 1.2); - // and lower priority and smaller sizes for easier difficulty levels + + // Lower priority for easier difficulty levels if (this.Config.difficulty < 2) - { priority *= 0.6; - variation *= 0.5; - } else if (this.Config.difficulty < 3) - { priority *= 0.8; - variation *= 0.8; - } - for (let cat in this.unitStat) - { - this.unitStat[cat].targetSize = Math.round(variation * this.unitStat[cat].targetSize); - this.unitStat[cat].minSize = Math.min(this.unitStat[cat].minSize, this.unitStat[cat].targetSize); - } - // change the sizes according to max population - this.neededShips = Math.ceil(this.Config.popScaling * this.neededShips); - for (let cat in this.unitStat) + if (!deserialized) { - this.unitStat[cat].targetSize = Math.round(this.Config.popScaling * this.unitStat[cat].targetSize); - this.unitStat[cat].minSize = Math.ceil(this.Config.popScaling * this.unitStat[cat].minSize); + // Put some randomness on the attack size + let variation = randFloat(0.8, 1.2); + // and lower sizes for easier difficulty levels + if (this.Config.difficulty < 2) + variation *= 0.5; + else if (this.Config.difficulty < 3) + variation *= 0.8; + + for (let cat in this.unitStat) + { + this.unitStat[cat].targetSize = Math.round(variation * this.unitStat[cat].targetSize); + this.unitStat[cat].minSize = Math.min(this.unitStat[cat].minSize, this.unitStat[cat].targetSize); + } + // change the sizes according to max population + this.neededShips = Math.ceil(this.Config.popScaling * this.neededShips); + for (let cat in this.unitStat) + { + this.unitStat[cat].targetSize = Math.round(this.Config.popScaling * this.unitStat[cat].targetSize); + this.unitStat[cat].minSize = Math.ceil(this.Config.popScaling * this.unitStat[cat].minSize); + } } // TODO: there should probably be one queue per type of training building Index: binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js =================================================================== --- binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js +++ binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js @@ -20,7 +20,7 @@ * sent through AIInterface. It is expected that the other player will change their diplomacy stance to the stance * that we suggested within a period of time, or else the request will be deleted from this.sentDiplomacyRequests. */ -PETRA.DiplomacyManager = function(Config) +PETRA.DiplomacyManager = function(Config, deserialized) { this.Config = Config; this.nextTributeUpdate = 90; @@ -31,7 +31,9 @@ this.betrayWeighting = 150; this.receivedDiplomacyRequests = new Map(); this.sentDiplomacyRequests = new Map(); - this.sentDiplomacyRequestLapseTime = 120 + randFloat(10, 100); + this.sentDiplomacyRequestLapseTime = 120; + if (!deserialized) + this.sentDiplomacyRequestLapseTime = 120 + randFloat(10, 100); }; /** Index: binaries/data/mods/public/simulation/ai/petra/headquarters.js =================================================================== --- binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -11,7 +11,7 @@ * -planning attacks -> attackManager * -picking new CC locations. */ -PETRA.HQ = function(Config) +PETRA.HQ = function(Config, deserialized) { this.Config = Config; this.phasing = 0; // existing values: 0 means no, i > 0 means phasing towards phase i @@ -42,7 +42,7 @@ this.tradeManager = new PETRA.TradeManager(this.Config); this.navalManager = new PETRA.NavalManager(this.Config); this.researchManager = new PETRA.ResearchManager(this.Config); - this.diplomacyManager = new PETRA.DiplomacyManager(this.Config); + this.diplomacyManager = new PETRA.DiplomacyManager(this.Config, deserialized); this.garrisonManager = new PETRA.GarrisonManager(this.Config); this.victoryManager = new PETRA.VictoryManager(this.Config); @@ -2885,7 +2885,7 @@ this.researchManager = new PETRA.ResearchManager(this.Config); this.researchManager.Deserialize(data.researchManager); - this.diplomacyManager = new PETRA.DiplomacyManager(this.Config); + this.diplomacyManager = new PETRA.DiplomacyManager(this.Config, true); this.diplomacyManager.Deserialize(data.diplomacyManager); this.garrisonManager = new PETRA.GarrisonManager(this.Config);