diff --git a/binaries/data/mods/public/simulation/ai/petra/baseManager.js b/binaries/data/mods/public/simulation/ai/petra/baseManager.js index 98c72bfadc..1cff50fef9 100644 --- a/binaries/data/mods/public/simulation/ai/petra/baseManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/baseManager.js @@ -467,7 +467,7 @@ m.BaseManager.prototype.checkResourceLevels = function(gameState, queues) }; /** Adds the estimated gather rates from this base to the currentRates */ -m.BaseManager.prototype.getGatherRates = function(gameState, currentRates) +m.BaseManager.prototype.addGatherRates = function(gameState, currentRates) { for (let res in currentRates) { diff --git a/binaries/data/mods/public/simulation/ai/petra/headquarters.js b/binaries/data/mods/public/simulation/ai/petra/headquarters.js index 5f8ba4d27c..29f03cea91 100644 --- a/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -22,9 +22,6 @@ m.HQ = function(Config) // Cache various quantities. this.turnCache = {}; - // Some resources objects (will be filled in init) - this.wantedRates = {}; - this.currentRates = {}; this.lastFailedGather = {}; this.firstBaseConfig = false; @@ -72,12 +69,6 @@ m.HQ.prototype.init = function(gameState, queues) this.navalMap = false; this.navalRegions = {}; - for (let res of Resources.GetCodes()) - { - this.wantedRates[res] = 0; - this.currentRates[res] = 0; - } - this.treasures = gameState.getEntities().filter(ent => { let type = ent.resourceSupplyType(); return type && type.generic == "treasure"; @@ -742,9 +733,9 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues) m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, requirements) { let units; - if (classes.indexOf("Hero") !== -1) + if (classes.indexOf("Hero") != -1) units = gameState.findTrainableUnits(classes, []); - else if (classes.indexOf("Siege") !== -1) // We do not want siege tower as AI does not know how to use it + else if (classes.indexOf("Siege") != -1) // We do not want siege tower as AI does not know how to use it units = gameState.findTrainableUnits(classes, ["SiegeTower"]); else // We do not want hero when not explicitely specified units = gameState.findTrainableUnits(classes, ["Hero"]); @@ -869,32 +860,38 @@ m.HQ.prototype.getTotalResourceLevel = function(gameState) }; /** - * returns the current gather rate + * Returns the current gather rate * This is not per-se exact, it performs a few adjustments ad-hoc to account for travel distance, stuffs like that. */ m.HQ.prototype.GetCurrentGatherRates = function(gameState) { - if (!this.turnCache.gatherRates) + if (!this.turnCache.currentRates) { - for (let res in this.currentRates) - this.currentRates[res] = 0.5 * this.GetTCResGatherer(res); + let currentRates = {}; + for (let res of Resources.GetCodes()) + currentRates[res] = 0.5 * this.GetTCResGatherer(res); for (let base of this.baseManagers) - base.getGatherRates(gameState, this.currentRates); + base.addGatherRates(gameState, currentRates); - for (let res in this.currentRates) - { - if (this.currentRates[res] < 0) - { - if (this.Config.debug > 0) - API3.warn("Petra: current rate for " + res + " < 0 with " + this.GetTCResGatherer(res) + " moved gatherers"); - this.currentRates[res] = 0; - } - } - this.turnCache.gatherRates = true; + for (let res of Resources.GetCodes()) + currentRates[res] = Math.max(currentRates[res], 0); + + this.turnCache.currentRates = currentRates; } - return this.currentRates; + return this.turnCache.currentRates; +}; + +/** + * Returns the wanted gather rate. + */ +m.HQ.prototype.GetWantedGatherRates = function(gameState) +{ + if (!this.turnCache.wantedRates) + this.turnCache.wantedRates = gameState.ai.queueManager.wantedGatherRates(gameState); + + return this.turnCache.wantedRates; }; /** @@ -907,18 +904,18 @@ m.HQ.prototype.GetCurrentGatherRates = function(gameState) */ m.HQ.prototype.pickMostNeededResources = function(gameState) { - this.wantedRates = gameState.ai.queueManager.wantedGatherRates(gameState); + let wantedRates = this.GetWantedGatherRates(gameState); let currentRates = this.GetCurrentGatherRates(gameState); let needed = []; - for (let res in this.wantedRates) - needed.push({ "type": res, "wanted": this.wantedRates[res], "current": currentRates[res] }); + for (let res in wantedRates) + needed.push({ "type": res, "wanted": wantedRates[res], "current": currentRates[res] }); needed.sort((a, b) => { let va = Math.max(0, a.wanted - a.current) / (a.current + 1); let vb = Math.max(0, b.wanted - b.current) / (b.current + 1); // If they happen to be equal (generally this means "0" aka no need), make it fair. - if (va === vb) + if (va == vb) return a.current - b.current; return vb - va; }); @@ -990,7 +987,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource, for (let j = 0; j < this.territoryMap.length; ++j) { - if (this.territoryMap.getOwnerIndex(j) !== 0) + if (this.territoryMap.getOwnerIndex(j) != 0) continue; // With enough room around to build the cc let i = this.territoryMap.getNonObstructedTile(j, radius, obstructions); @@ -1000,7 +997,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource, let index = gameState.ai.accessibility.landPassMap[i]; if (!this.landRegions[index]) continue; - if (proxyAccess && nbShips === 0 && proxyAccess !== index) + if (proxyAccess && nbShips == 0 && proxyAccess != index) continue; let norm = 0.5; // TODO adjust it, knowing that we will sum 5 maps @@ -1171,7 +1168,7 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState, template) for (let j = 0; j < this.territoryMap.length; ++j) { - if (this.territoryMap.getOwnerIndex(j) !== 0) + if (this.territoryMap.getOwnerIndex(j) != 0) continue; // with enough room around to build the cc let i = this.territoryMap.getNonObstructedTile(j, radius, obstructions); @@ -1310,7 +1307,7 @@ m.HQ.prototype.findMarketLocation = function(gameState, template) // do not try on the narrow border of our territory if (this.borderMap.map[j] & m.narrowFrontier_Mask) continue; - if (this.basesMap.map[j] === 0) // only in our territory + if (this.basesMap.map[j] == 0) // only in our territory continue; // with enough room around to build the market let i = this.territoryMap.getNonObstructedTile(j, radius, obstructions); @@ -1329,11 +1326,11 @@ m.HQ.prototype.findMarketLocation = function(gameState, template) { if (isNavalMarket && market.hasClass("NavalMarket")) { - if (m.getSeaAccess(gameState, market) !== gameState.ai.accessibility.getAccessValue(pos, true)) + if (m.getSeaAccess(gameState, market) != gameState.ai.accessibility.getAccessValue(pos, true)) continue; gainMultiplier = traderTemplatesGains.navalGainMultiplier; } - else if (m.getLandAccess(gameState, market) === index && + else if (m.getLandAccess(gameState, market) == index && !m.isLineInsideEnemyTerritory(gameState, market.position(), pos)) gainMultiplier = traderTemplatesGains.landGainMultiplier; else @@ -1348,7 +1345,7 @@ m.HQ.prototype.findMarketLocation = function(gameState, template) maxGainMult = gainMultiplier; } } - if (maxVal === 0) + if (maxVal == 0) continue; if (bestVal !== undefined && maxVal < bestVal) continue; @@ -1418,7 +1415,7 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template) if (wonderMode) { wonders = gameState.getOwnStructures().filter(API3.Filters.byClass("Wonder")).toEntityArray(); - wonderMode = wonders.length !== 0; + wonderMode = wonders.length != 0; if (wonderMode) wonderDistmin = (50 + wonders[0].footprintRadius()) * (50 + wonders[0].footprintRadius()); } @@ -1455,7 +1452,7 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template) if (this.borderMap.map[j] & m.largeFrontier_Mask && isTower) continue; } - if (this.basesMap.map[j] === 0) // inaccessible cell + if (this.basesMap.map[j] == 0) // inaccessible cell continue; // with enough room around to build the cc let i = this.territoryMap.getNonObstructedTile(j, radius, obstructions); @@ -1506,7 +1503,7 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template) break; } } - if (minDist < 0 || minDist === Math.min()) + if (minDist < 0 || minDist == Math.min()) continue; if (bestVal !== undefined && minDist > bestVal) continue; @@ -1807,7 +1804,7 @@ m.HQ.prototype.buildNewBase = function(gameState, queues, resource) let hasOwnCC = false; for (let ent of gameState.updatingGlobalCollection("allCCs", API3.Filters.byClass("CivCentre")).values()) { - if (ent.owner() !== PlayerID || ent.templateName() !== gameState.applyCiv("structures/{civ}_civil_centre")) + if (ent.owner() != PlayerID || ent.templateName() != gameState.applyCiv("structures/{civ}_civil_centre")) continue; hasOwnCC = true; break; @@ -2116,7 +2113,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions) if (!total.canAfford(new API3.Resources(template.cost()))) continue; templateFound = [trainable, template]; - if (template.hasClass("Ranged") === rangedWanted) + if (template.hasClass("Ranged") == rangedWanted) break; } if (!templateFound) @@ -2132,7 +2129,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions) { for (let q in queueManager.queues) { - if (q === "emergency") + if (q == "emergency") continue; queueManager.transferAccounts(cost, q, "emergency"); if (queueManager.canAfford("emergency", cost)) @@ -2181,7 +2178,7 @@ m.HQ.prototype.canBuild = function(gameState, structure) { // if no base, check that we can build outside our territory let buildTerritories = template.buildTerritories(); - if (buildTerritories && (!buildTerritories.length || buildTerritories.length === 1 && buildTerritories[0] === "own")) + if (buildTerritories && (!buildTerritories.length || buildTerritories.length == 1 && buildTerritories[0] == "own")) { this.buildManager.setUnbuildable(gameState, type, 180, "room"); return false; @@ -2253,7 +2250,7 @@ m.HQ.prototype.updateTerritories = function(gameState) if (this.borderMap.map[jx+width*jz] & m.outside_Mask) continue; let territoryOwner = this.territoryMap.getOwnerIndex(jx+width*jz); - if (territoryOwner !== PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner))) + if (territoryOwner != PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner))) { this.borderMap.map[j] |= m.narrowFrontier_Mask; break; @@ -2267,7 +2264,7 @@ m.HQ.prototype.updateTerritories = function(gameState) if (this.borderMap.map[jx+width*jz] & m.outside_Mask) continue; territoryOwner = this.territoryMap.getOwnerIndex(jx+width*jz); - if (territoryOwner !== PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner))) + if (territoryOwner != PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner))) onFrontier = true; } if (onFrontier && !(this.borderMap.map[j] & m.narrowFrontier_Mask)) @@ -2422,10 +2419,10 @@ m.HQ.prototype.assignGatherers = function() { for (let worker of base.workers.values()) { - if (worker.unitAIState().split(".")[1] !== "RETURNRESOURCE") + if (worker.unitAIState().split(".")[1] != "RETURNRESOURCE") continue; let orders = worker.unitAIOrderData(); - if (orders.length < 2 || !orders[1].target || orders[1].target !== worker.getMetadata(PlayerID, "supply")) + if (orders.length < 2 || !orders[1].target || orders[1].target != worker.getMetadata(PlayerID, "supply")) continue; this.AddTCGatherer(orders[1].target); } @@ -2468,7 +2465,7 @@ m.HQ.prototype.updateCaptureStrength = function(gameState) if (!ent.canCapture()) continue; let state = ent.unitAIState(); - if (!state || !state.split(".")[1] || state.split(".")[1] !== "COMBAT") + if (!state || !state.split(".")[1] || state.split(".")[1] != "COMBAT") continue; let orderData = ent.unitAIOrderData(); if (!orderData || !orderData.length || !orderData[0].target) @@ -2502,7 +2499,7 @@ m.HQ.prototype.updateCaptureStrength = function(gameState) let orderData = ent.unitAIOrderData(); if (!orderData || !orderData.length || !orderData[0].attackType) continue; - if ((orderData[0].attackType === "Capture") !== allowCapture) + if ((orderData[0].attackType == "Capture") !== allowCapture) ent.attack(targetId, allowCapture); } } @@ -2553,7 +2550,9 @@ m.HQ.prototype.AddTCResGatherer = function(resource) ++this.turnCache["resourceGatherer-" + resource]; else this.turnCache["resourceGatherer-" + resource] = 1; - this.turnCache.gatherRates = false; + + if (this.turnCache.currentRates) + this.turnCache.currentRates[resource] += 0.5; }; m.HQ.prototype.GetTCResGatherer = function(resource) @@ -2711,7 +2710,7 @@ m.HQ.prototype.update = function(gameState, queues, events) this.buildTemple(gameState, queues); } - if (gameState.ai.playedTurn % 30 === 0 && + if (gameState.ai.playedTurn % 30 == 0 && gameState.getPopulation() > 0.9 * gameState.getPopulationMax()) this.buildWonder(gameState, queues, false); } @@ -2760,8 +2759,6 @@ m.HQ.prototype.Serialize = function() let properties = { "phasing": this.phasing, "currentBase": this.currentBase, - "wantedRates": this.wantedRates, - "currentRates": this.currentRates, "lastFailedGather": this.lastFailedGather, "firstBaseConfig": this.firstBaseConfig, "supportRatio": this.supportRatio, diff --git a/binaries/data/mods/public/simulation/ai/petra/queueManager.js b/binaries/data/mods/public/simulation/ai/petra/queueManager.js index 6a157f2f0a..fc0c9dc919 100644 --- a/binaries/data/mods/public/simulation/ai/petra/queueManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/queueManager.js @@ -185,7 +185,7 @@ m.QueueManager.prototype.printQueues = function(gameState) API3.warn(p + ": " + uneval(this.accounts[p])); API3.warn("Current Resources: " + uneval(gameState.getResources())); API3.warn("Available Resources: " + uneval(this.getAvailableResources(gameState))); - API3.warn("Wanted Gather Rates: " + uneval(this.wantedGatherRates(gameState))); + API3.warn("Wanted Gather Rates: " + uneval(gameState.ai.HQ.GetWantedGatherRates(gameState))); API3.warn("Current Gather Rates: " + uneval(gameState.ai.HQ.GetCurrentGatherRates(gameState))); API3.warn("Most needed resources: " + uneval(gameState.ai.HQ.pickMostNeededResources(gameState))); API3.warn("------------------------------------"); diff --git a/binaries/data/mods/public/simulation/ai/petra/tradeManager.js b/binaries/data/mods/public/simulation/ai/petra/tradeManager.js index ec42639fbb..0878f6c642 100644 --- a/binaries/data/mods/public/simulation/ai/petra/tradeManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/tradeManager.js @@ -45,7 +45,7 @@ m.TradeManager.prototype.trainMoreTraders = function(gameState, queues) gameState.getOwnTrainingFacilities().forEach(function(ent) { for (let item of ent.trainingQueue()) { - if (!item.metadata || !item.metadata.role || item.metadata.role !== "trader") + if (!item.metadata || !item.metadata.role || item.metadata.role != "trader") continue; numTraders += item.count; if (item.metadata.sea !== undefined) @@ -71,7 +71,7 @@ m.TradeManager.prototype.trainMoreTraders = function(gameState, queues) gameState.ai.HQ.navalManager.seaTransportShips[this.tradeRoute.sea].forEach(function(ship) { if (already || !ship.hasClass("Trader")) return; - if (ship.getMetadata(PlayerID, "role") === "switchToTrader") + if (ship.getMetadata(PlayerID, "role") == "switchToTrader") { already = true; return; @@ -113,7 +113,7 @@ m.TradeManager.prototype.trainMoreTraders = function(gameState, queues) m.TradeManager.prototype.updateTrader = function(gameState, ent) { - if (ent.hasClass("Ship") && gameState.ai.playedTurn % 5 === 0 && + if (ent.hasClass("Ship") && gameState.ai.playedTurn % 5 == 0 && !ent.unitAIState().startsWith("INDIVIDUAL.GATHER") && m.gatherTreasure(gameState, ent, true)) return; @@ -141,7 +141,7 @@ m.TradeManager.prototype.updateTrader = function(gameState, ent) if (API3.SquareVectorDistance(route.target.position(), ent.position()) < API3.SquareVectorDistance(route.source.position(), ent.position())) nearerSource = false; - if (!ent.hasClass("Ship") && route.land !== access) + if (!ent.hasClass("Ship") && route.land != access) { if (nearerSource) gameState.ai.HQ.navalManager.requireTransport(gameState, ent, access, route.land, route.source.position()); @@ -162,18 +162,19 @@ m.TradeManager.prototype.updateTrader = function(gameState, ent) m.TradeManager.prototype.setTradingGoods = function(gameState) { let tradingGoods = {}; - for (let res in gameState.ai.HQ.wantedRates) + for (let res of Resources.GetCodes()) tradingGoods[res] = 0; // first, try to anticipate future needs let stocks = gameState.ai.HQ.getTotalResourceLevel(gameState); let mostNeeded = gameState.ai.HQ.pickMostNeededResources(gameState); + let wantedRates = gameState.ai.HQ.GetWantedGatherRates(gameState); let remaining = 100; let targetNum = this.Config.Economy.targetNumTraders; for (let res in stocks) { - if (res === "food") + if (res == "food") continue; - let wantedRate = gameState.ai.HQ.wantedRates[res]; + let wantedRate = wantedRates[res]; if (stocks[res] < 200) { tradingGoods[res] = wantedRate > 0 ? 20 : 10; @@ -339,9 +340,9 @@ m.TradeManager.prototype.checkEvents = function(gameState, events) let route = trader.getMetadata(PlayerID, "route"); if (!route) continue; - if (route.source === evt.entity) + if (route.source == evt.entity) route.source = evt.newentity; - else if (route.target === evt.entity) + else if (route.target == evt.entity) route.target = evt.newentity; else continue; @@ -516,9 +517,9 @@ m.TradeManager.prototype.checkRoutes = function(gameState, accessIndex) if (this.Config.chat) { let owner = this.tradeRoute.source.owner(); - if (owner === PlayerID) + if (owner == PlayerID) owner = this.tradeRoute.target.owner(); - if (owner !== PlayerID && !this.warnedAllies[owner]) + if (owner != PlayerID && !this.warnedAllies[owner]) { // Warn an ally that we have a trade route with him m.chatNewTradeRoute(gameState, owner); this.warnedAllies[owner] = true;