Move enums to own files in ai

This way they don't accidentally get mutated.
This commit is contained in:
phosit 2025-08-07 19:54:19 +02:00 committed by Phosit
parent 0a2bd6a5a4
commit 062be89694
11 changed files with 82 additions and 75 deletions

View file

@ -2,7 +2,8 @@ import * as filters from "simulation/ai/common-api/filters.js";
import { warn as aiWarn, SquareVectorDistance, VectorDistance } from "simulation/ai/common-api/utils.js";
import { AttackPlan } from "simulation/ai/petra/attackPlan.js";
import * as chat from "simulation/ai/petra/chatHelper.js";
import { Config, DIFFICULTY_VERY_EASY } from "simulation/ai/petra/config.js";
import { Config } from "simulation/ai/petra/config.js";
import * as difficulty from "simulation/ai/petra/difficultyLevel.js";
import { allowCapture, getLandAccess } from "simulation/ai/petra/entityExtend.js";
import { Worker } from "simulation/ai/petra/worker.js";
@ -435,7 +436,7 @@ AttackManager.prototype.update = function(gameState, queues, events)
}
// Check if we have some unused ranged siege unit which could do something useful while waiting
if (this.Config.difficulty > DIFFICULTY_VERY_EASY && gameState.ai.playedTurn % 5 == 0)
if (this.Config.difficulty > difficulty.VERY_EASY && gameState.ai.playedTurn % 5 == 0)
this.assignBombers(gameState);
};

View file

@ -1,7 +1,8 @@
import { EntityCollection } from "simulation/ai/common-api/entitycollection.js";
import * as filters from "simulation/ai/common-api/filters.js";
import { SquareVectorDistance, VectorDistance, warn as aiWarn } from "simulation/ai/common-api/utils.js";
import { Config, DIFFICULTY_EASY, DIFFICULTY_MEDIUM } from "simulation/ai/petra/config.js";
import { Config } from "simulation/ai/petra/config.js";
import * as difficulty from "simulation/ai/petra/difficultyLevel.js";
import { allowCapture, dumpEntity, getHolder, getLandAccess, isSiegeUnit, returnResources } from
"simulation/ai/petra/entityExtend.js";
import { TrainingPlan } from "simulation/ai/petra/queueplanTraining.js";
@ -179,18 +180,18 @@ export function AttackPlan(gameState, config, uniqueID, type = AttackPlan.TYPE_D
// Put some randomness on the attack size
let variation = randFloat(0.8, 1.2);
// and lower priority and smaller sizes for easier difficulty levels
if (this.Config.difficulty < DIFFICULTY_EASY)
if (this.Config.difficulty < difficulty.EASY)
{
priority *= 0.4;
variation *= 0.2;
}
else if (this.Config.difficulty < DIFFICULTY_MEDIUM)
else if (this.Config.difficulty < difficulty.MEDIUM)
{
priority *= 0.8;
variation *= 0.6;
}
if (this.Config.difficulty < DIFFICULTY_EASY)
if (this.Config.difficulty < difficulty.EASY)
{
for (const cat in this.unitStat)
{
@ -432,7 +433,7 @@ AttackPlan.prototype.addSiegeUnits = function(gameState)
this.siegeState = AttackPlan.SIEGE_ADDED;
let targetSize;
if (this.Config.difficulty < DIFFICULTY_MEDIUM)
if (this.Config.difficulty < difficulty.MEDIUM)
targetSize = this.type === AttackPlan.TYPE_HUGE_ATTACK ? Math.max(this.Config.difficulty, 1) : Math.max(this.Config.difficulty - 1, 0);
else
targetSize = this.type === AttackPlan.TYPE_HUGE_ATTACK ? this.Config.difficulty + 1 : this.Config.difficulty - 1;
@ -761,7 +762,7 @@ AttackPlan.prototype.assignUnits = function(gameState)
// Finally add also some workers for the higher difficulties,
// If Rush, assign all kind of workers, keeping only a minimum number of defenders
// Otherwise, assign only some idle workers if too much of them
if (this.Config.difficulty <= DIFFICULTY_EASY)
if (this.Config.difficulty <= difficulty.EASY)
return added;
let num = 0;

View file

@ -1,6 +1,7 @@
import * as filters from "simulation/ai/common-api/filters.js";
import { SquareVectorDistance, warn as aiWarn } from "simulation/ai/common-api/utils.js";
import { Config, DIFFICULTY_EASY, DIFFICULTY_MEDIUM } from "simulation/ai/petra/config.js";
import { Config } from "simulation/ai/petra/config.js";
import * as difficulty from "simulation/ai/petra/difficultyLevel.js";
import { getBestBase, getBuiltEntity, getLandAccess, isFastMoving, isNotWorthBuilding } from
"simulation/ai/petra/entityExtend.js";
import { createObstructionMap } from "simulation/ai/petra/mapModule.js";
@ -36,7 +37,7 @@ export function BaseManager(gameState, basesManager)
this.constructing = false;
// Defenders to train in this cc when its construction is finished
this.neededDefenders = this.Config.difficulty > DIFFICULTY_EASY ? 3 + 2*(this.Config.difficulty - 3) : 0;
this.neededDefenders = this.Config.difficulty > difficulty.EASY ? 3 + 2*(this.Config.difficulty - 3) : 0;
// vector for iterating, to check one use the HQ map.
this.territoryIndices = [];
@ -97,7 +98,7 @@ BaseManager.prototype.reset = function(gameState, state)
this.constructing = true;
else
this.constructing = false;
if (state !== BaseManager.STATE_CAPTURED || this.Config.difficulty < DIFFICULTY_MEDIUM)
if (state !== BaseManager.STATE_CAPTURED || this.Config.difficulty < difficulty.MEDIUM)
this.neededDefenders = 0;
else
this.neededDefenders = 3 + 2 * (this.Config.difficulty - 3);

View file

@ -1,18 +1,9 @@
import { warn as aiWarn } from "simulation/ai/common-api/utils.js";
import * as difficultyLevel from "simulation/ai/petra/difficultyLevel.js";
// These integers must be sequential
/* eslint-disable prefer-const -- Mods should be able to change them */
export let DIFFICULTY_SANDBOX = 0;
export let DIFFICULTY_VERY_EASY = 1;
export let DIFFICULTY_EASY = 2;
export let DIFFICULTY_MEDIUM = 3;
export let DIFFICULTY_HARD = 4;
export let DIFFICULTY_VERY_HARD = 5;
/* eslint-enable prefer-const */
export function Config(difficulty = DIFFICULTY_MEDIUM, behavior)
export function Config(difficulty = difficultyLevel.MEDIUM, behavior)
{
this.difficulty = difficulty;
this.difficulty = difficultyLevel;
// for instance "balanced", "aggressive" or "defensive"
this.behavior = behavior || "random";
@ -210,7 +201,7 @@ export function Config(difficulty = DIFFICULTY_MEDIUM, behavior)
Config.prototype.setConfig = function(gameState)
{
if (this.difficulty > DIFFICULTY_SANDBOX)
if (this.difficulty > difficultyLevel.SANDBOX)
{
// Setup personality traits according to the user choice:
// The parameter used to define the personality is basically the aggressivity or (1-defensiveness)
@ -253,14 +244,14 @@ Config.prototype.setConfig = function(gameState)
this.Military.fortressLapseTime = Math.round(this.Military.fortressLapseTime * (1.1 - 0.2 * this.personality.defensive));
this.priorities.defenseBuilding = Math.round(this.priorities.defenseBuilding * (0.9 + 0.2 * this.personality.defensive));
if (this.difficulty < DIFFICULTY_EASY)
if (this.difficulty < difficulty.EASY)
{
this.popScaling = 0.5;
this.Economy.supportRatio = 0.5;
this.Economy.provisionFields = 1;
this.Military.numSentryTowers = this.personality.defensive > this.personalityCut.strong ? 1 : 0;
}
else if (this.difficulty < DIFFICULTY_MEDIUM)
else if (this.difficulty < difficulty.MEDIUM)
{
this.popScaling = 0.7;
this.Economy.supportRatio = 0.4;
@ -269,7 +260,7 @@ Config.prototype.setConfig = function(gameState)
}
else
{
if (this.difficulty == DIFFICULTY_MEDIUM)
if (this.difficulty == difficulty.MEDIUM)
this.Military.numSentryTowers = 1;
else
this.Military.numSentryTowers = 2;
@ -287,9 +278,9 @@ Config.prototype.setConfig = function(gameState)
}
const maxPop = gameState.getPopulationMax();
if (this.difficulty < DIFFICULTY_EASY)
if (this.difficulty < difficulty.EASY)
this.Economy.targetNumWorkers = Math.max(1, Math.min(40, maxPop));
else if (this.difficulty < DIFFICULTY_MEDIUM)
else if (this.difficulty < difficulty.MEDIUM)
this.Economy.targetNumWorkers = Math.max(1, Math.min(60, Math.floor(maxPop/2)));
else
this.Economy.targetNumWorkers = Math.max(1, Math.min(120, Math.floor(maxPop/3)));
@ -315,7 +306,7 @@ Config.prototype.setConfig = function(gameState)
this.Economy.targetNumWorkers = Math.max(this.Economy.targetNumWorkers, this.Economy.popPhase2);
this.Economy.workPhase3 = Math.min(this.Economy.workPhase3, this.Economy.targetNumWorkers);
this.Economy.workPhase4 = Math.min(this.Economy.workPhase4, this.Economy.targetNumWorkers);
if (this.difficulty < DIFFICULTY_EASY)
if (this.difficulty < difficulty.EASY)
this.Economy.workPhase3 = Infinity; // prevent the phasing to city phase
this.emergencyValues = {

View file

@ -0,0 +1,9 @@
// These integers must be sequential
/* eslint-disable prefer-const -- Mods should be able to change them */
export let SANDBOX = 0;
export let VERY_EASY = 1;
export let EASY = 2;
export let MEDIUM = 3;
export let HARD = 4;
export let VERY_HARD = 5;
/* eslint-enable prefer-const */

View file

@ -5,15 +5,17 @@ import { AttackManager } from "simulation/ai/petra/attackManager.js";
import { AttackPlan } from "simulation/ai/petra/attackPlan.js";
import { BasesManager } from "simulation/ai/petra/basesManager.js";
import { BuildManager } from "simulation/ai/petra/buildManager.js";
import { Config, DIFFICULTY_SANDBOX, DIFFICULTY_EASY } from "simulation/ai/petra/config.js";
import { Config } from "simulation/ai/petra/config.js";
import { DefenseManager } from "simulation/ai/petra/defenseManager.js";
import * as difficulty from "simulation/ai/petra/difficultyLevel.js";
import { DiplomacyManager } from "simulation/ai/petra/diplomacyManager.js";
import { EmergencyManager } from "simulation/ai/petra/emergencyManager.js";
import { allowCapture, getAttackBonus, getLandAccess, getMaxStrength, isLineInsideEnemyTerritory,
setSeaAccess } from "simulation/ai/petra/entityExtend.js";
import { GarrisonManager } from "simulation/ai/petra/garrisonManager.js";
import { createBorderMap, createObstructionMap, createTerritoryMap, fullBorder_Mask, fullFrontier_Mask,
largeFrontier_Mask, narrowFrontier_Mask, outside_Mask } from "simulation/ai/petra/mapModule.js";
import * as mapMask from "simulation/ai/petra/mapMask.js";
import { createBorderMap, createObstructionMap, createTerritoryMap } from
"simulation/ai/petra/mapModule.js";
import { NavalManager } from "simulation/ai/petra/navalManager.js";
import { ConstructionPlan } from "simulation/ai/petra/queueplanBuilding.js";
import { TrainingPlan } from "simulation/ai/petra/queueplanTraining.js";
@ -261,7 +263,7 @@ Headquather.prototype.checkEvents = function(gameState, events)
}
// Then deals with decaying structures: destroy them if being lost to enemy (except in easier difficulties)
if (this.Config.difficulty < DIFFICULTY_EASY)
if (this.Config.difficulty < difficulty.EASY)
return;
for (const entId of this.decayingStructures)
{
@ -811,7 +813,7 @@ Headquather.prototype.findEconomicCCLocation = function(gameState, template, res
continue;
}
if (this.borderMap.map[j] & fullBorder_Mask) // disfavor the borders of the map
if (this.borderMap.map[j] & mapMask.fullBorder) // disfavor the borders of the map
norm *= 0.5;
let val = 2 * gameState.sharedScript.ccResourceMaps[resource].map[j];
@ -966,7 +968,7 @@ Headquather.prototype.findStrategicCCLocation = function(gameState, template)
currentVal += delta*delta;
}
// disfavor border of the map
if (this.borderMap.map[j] & fullBorder_Mask)
if (this.borderMap.map[j] & mapMask.fullBorder)
currentVal += 10000;
if (bestVal !== undefined && currentVal > bestVal)
@ -1047,7 +1049,7 @@ Headquather.prototype.findMarketLocation = function(gameState, template)
for (let j = 0; j < this.territoryMap.length; ++j)
{
// do not try on the narrow border of our territory
if (this.borderMap.map[j] & narrowFrontier_Mask)
if (this.borderMap.map[j] & mapMask.narrowFrontier)
continue;
if (this.baseAtIndex(j) == 0) // only in our territory
continue;
@ -1193,9 +1195,9 @@ Headquather.prototype.findDefensiveLocation = function(gameState, template)
if (!wonderMode)
{
// do not try if well inside or outside territory
if (!(this.borderMap.map[j] & fullFrontier_Mask))
if (!(this.borderMap.map[j] & mapMask.fullFrontier))
continue;
if (this.borderMap.map[j] & largeFrontier_Mask && isTower)
if (this.borderMap.map[j] & mapMask.largeFrontier && isTower)
continue;
}
if (this.baseAtIndex(j) == 0) // inaccessible cell
@ -1985,10 +1987,10 @@ Headquather.prototype.updateTerritories = function(gameState)
for (let j = 0; j < this.territoryMap.length; ++j)
{
if (this.borderMap.map[j] & outside_Mask)
if (this.borderMap.map[j] & mapMask.outside)
continue;
if (this.borderMap.map[j] & fullFrontier_Mask)
this.borderMap.map[j] &= ~fullFrontier_Mask; // reset the frontier
if (this.borderMap.map[j] & mapMask.fullFrontier)
this.borderMap.map[j] &= ~mapMask.fullFrontier; // reset the frontier
if (this.territoryMap.getOwnerIndex(j) != PlayerID)
this.basesManager.removeBaseFromTerritoryIndex(j);
@ -2006,12 +2008,12 @@ Headquather.prototype.updateTerritories = function(gameState)
let jz = iz + Math.round(insideSmall*a[1]);
if (jz < 0 || jz >= width)
continue;
if (this.borderMap.map[jx+width*jz] & outside_Mask)
if (this.borderMap.map[jx+width*jz] & mapMask.outside)
continue;
let territoryOwner = this.territoryMap.getOwnerIndex(jx+width*jz);
if (territoryOwner != PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner)))
{
this.borderMap.map[j] |= narrowFrontier_Mask;
this.borderMap.map[j] |= mapMask.narrowFrontier;
break;
}
jx = ix + Math.round(insideLarge*a[0]);
@ -2020,14 +2022,14 @@ Headquather.prototype.updateTerritories = function(gameState)
jz = iz + Math.round(insideLarge*a[1]);
if (jz < 0 || jz >= width)
continue;
if (this.borderMap.map[jx+width*jz] & outside_Mask)
if (this.borderMap.map[jx+width*jz] & mapMask.outside)
continue;
territoryOwner = this.territoryMap.getOwnerIndex(jx+width*jz);
if (territoryOwner != PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner)))
onFrontier = true;
}
if (onFrontier && !(this.borderMap.map[j] & narrowFrontier_Mask))
this.borderMap.map[j] |= largeFrontier_Mask;
if (onFrontier && !(this.borderMap.map[j] & mapMask.narrowFrontier))
this.borderMap.map[j] |= mapMask.largeFrontier;
if (this.basesManager.addTerritoryIndexToBase(gameState, j, passabilityMap))
expansion++;
@ -2322,7 +2324,7 @@ Headquather.prototype.update = function(gameState, queues, events)
if (gameState.ai.playedTurn % 3 == 0)
{
this.constructTrainingBuildings(gameState, queues);
if (this.Config.difficulty > DIFFICULTY_SANDBOX)
if (this.Config.difficulty > difficulty.SANDBOX)
this.buildDefenses(gameState, queues);
}
@ -2330,7 +2332,7 @@ Headquather.prototype.update = function(gameState, queues, events)
this.navalManager.update(gameState, queues, events);
if (this.Config.difficulty > DIFFICULTY_SANDBOX && (this.hasActiveBase() || !this.canBuildUnits))
if (this.Config.difficulty > difficulty.SANDBOX && (this.hasActiveBase() || !this.canBuildUnits))
this.attackManager.update(gameState, queues, events);
this.diplomacyManager.update(gameState, events);

View file

@ -0,0 +1,8 @@
/* eslint-disable prefer-const -- Mods should be able to change them */
export let outside = 1;
export let border = 2;
export let fullBorder = outside | border;
export let narrowFrontier = 4;
export let largeFrontier = 8;
export let fullFrontier = narrowFrontier | largeFrontier;
/* eslint-enable prefer-const */

View file

@ -1,6 +1,7 @@
import * as filters from "simulation/ai/common-api/filters.js";
import { InfoMap } from "simulation/ai/common-api/map-module.js";
import { getMapIndices } from "simulation/ai/common-api/utils.js";
import * as mapMask from "simulation/ai/petra/mapMask.js";
/** map functions */
@ -138,15 +139,6 @@ export function createTerritoryMap(gameState)
* - large border (inside our territory, exclusive of narrow) => bit 3
*/
/* eslint-disable prefer-const -- Mods should be able to change them */
export let outside_Mask = 1;
export let border_Mask = 2;
export let fullBorder_Mask = outside_Mask | border_Mask;
export let narrowFrontier_Mask = 4;
export let largeFrontier_Mask = 8;
export let fullFrontier_Mask = narrowFrontier_Mask | largeFrontier_Mask;
/* eslint-enable prefer-const */
export function createBorderMap(gameState)
{
const map = new InfoMap(gameState.sharedScript, "territory");
@ -165,13 +157,13 @@ export function createBorderMap(gameState)
const radius = dx*dx + dy*dy;
if (radius < radcut)
continue;
map.map[j] = outside_Mask;
map.map[j] = mapMask.outside;
const ind = getMapIndices(j, map, passabilityMap);
for (const k of ind)
{
if (passabilityMap.data[k] & obstructionMask)
continue;
map.map[j] = border_Mask;
map.map[j] = mapMask.border;
break;
}
}
@ -185,13 +177,13 @@ export function createBorderMap(gameState)
const iy = Math.floor(j/width);
if (ix < border || ix >= borderCut || iy < border || iy >= borderCut)
{
map.map[j] = outside_Mask;
map.map[j] = mapMask.outside;
const ind = getMapIndices(j, map, passabilityMap);
for (const k of ind)
{
if (passabilityMap.data[k] & obstructionMask)
continue;
map.map[j] = border_Mask;
map.map[j] = mapMask.border;
break;
}
}

View file

@ -3,8 +3,8 @@ import { InfoMap } from "simulation/ai/common-api/map-module.js";
import { ResourcesManager } from "simulation/ai/common-api/resources.js";
import { SquareVectorDistance, VectorDistance, warn as aiWarn } from "simulation/ai/common-api/utils.js";
import { getBuiltEntity, getLandAccess, getSeaAccess } from "simulation/ai/petra/entityExtend.js";
import { border_Mask, createObstructionMap, fullBorder_Mask, outside_Mask } from
"simulation/ai/petra/mapModule.js";
import * as mapMask from "simulation/ai/petra/mapMask.js";
import { createObstructionMap } from "simulation/ai/petra/mapModule.js";
import { QueuePlan } from "simulation/ai/petra/queueplan.js";
/**
@ -260,7 +260,7 @@ ConstructionPlan.prototype.findGoodPosition = function(gameState)
for (let j = 0; j < placement.map.length; ++j)
{
let value = placement.map[j] - gameState.sharedScript.resourceMaps.wood.map[j]/3;
if (HQ.borderMap.map[j] & fullBorder_Mask)
if (HQ.borderMap.map[j] & mapMask.fullBorder)
value /= 2; // we need space around farmstead, so disfavor map border
placement.set(j, value);
}
@ -282,9 +282,9 @@ ConstructionPlan.prototype.findGoodPosition = function(gameState)
placement.map[j] = 0;
else if (placement.map[j] > 0)
{
if (favorBorder && HQ.borderMap.map[j] & border_Mask)
if (favorBorder && HQ.borderMap.map[j] & mapMask.border)
placement.set(j, placement.map[j] + 50);
else if (disfavorBorder && !(HQ.borderMap.map[j] & fullBorder_Mask))
else if (disfavorBorder && !(HQ.borderMap.map[j] & mapMask.fullBorder))
placement.set(j, placement.map[j] + 10);
const x = (j % placement.width + 0.5) * cellSize;
@ -302,9 +302,9 @@ ConstructionPlan.prototype.findGoodPosition = function(gameState)
placement.map[j] = 0;
else if (placement.map[j] > 0)
{
if (favorBorder && HQ.borderMap.map[j] & border_Mask)
if (favorBorder && HQ.borderMap.map[j] & mapMask.border)
placement.set(j, placement.map[j] + 50);
else if (disfavorBorder && !(HQ.borderMap.map[j] & fullBorder_Mask))
else if (disfavorBorder && !(HQ.borderMap.map[j] & mapMask.fullBorder))
placement.set(j, placement.map[j] + 10);
const x = (j % placement.width + 0.5) * cellSize;
@ -496,7 +496,7 @@ ConstructionPlan.prototype.findDockPosition = function(gameState)
}
// Add a penalty if on the map border as ship movement will be difficult
if (gameState.ai.HQ.borderMap.map[j] & fullBorder_Mask)
if (gameState.ai.HQ.borderMap.map[j] & mapMask.fullBorder)
score += 20;
// Do a pre-selection, supposing we will have the best possible water
@ -825,7 +825,7 @@ ConstructionPlan.prototype.getFrontierProximity = function(gameState, j)
const jz = iz + Math.round(i*step*a[1]);
if (jz < 0 || jz >= width)
continue;
if (borderMap.map[jx+width*jz] & outside_Mask)
if (borderMap.map[jx+width*jz] & mapMask.outside)
continue;
territoryOwner = territoryMap.getOwnerIndex(jx+width*jz);
if (alliedVictory && gameState.isPlayerAlly(territoryOwner) || territoryOwner == PlayerID)

View file

@ -1,7 +1,8 @@
import * as filters from "simulation/ai/common-api/filters.js";
import { ResourcesManager } from "simulation/ai/common-api/resources.js";
import { SquareVectorDistance, warn as aiWarn } from "simulation/ai/common-api/utils.js";
import { Config, DIFFICULTY_SANDBOX } from "simulation/ai/petra/config.js";
import { Config } from "simulation/ai/petra/config.js";
import * as difficulty from "simulation/ai/petra/difficultyLevel.js";
import { gatherTreasure, getLandAccess, isFastMoving } from "simulation/ai/petra/entityExtend.js";
import { Headquather } from "simulation/ai/petra/headquarters.js";
import { ConstructionPlan } from "simulation/ai/petra/queueplanBuilding.js";
@ -35,7 +36,7 @@ Headquather.prototype.gameAnalysis = function(gameState)
// Sandbox difficulty should not try to expand
this.canExpand = this.Config.difficulty != DIFFICULTY_SANDBOX;
this.canExpand = this.Config.difficulty != difficulty.SANDBOX;
// If no base yet, check if we can construct one. If not, dispatch our units to possible tasks/attacks
this.canBuildUnits = true;
if (!gameState.getOwnStructures().filter(filters.byClass("CivCentre")).hasEntities())

View file

@ -1,7 +1,8 @@
import * as filters from "simulation/ai/common-api/filters.js";
import { SquareVectorDistance, warn as aiWarn } from "simulation/ai/common-api/utils.js";
import { newTradeRoute as chatNewTradeRoute } from "simulation/ai/petra/chatHelper.js";
import { Config, DIFFICULTY_VERY_EASY } from "simulation/ai/petra/config.js";
import { Config } from "simulation/ai/petra/config.js";
import * as difficulty from "simulation/ai/petra/difficultyLevel.js";
import { gatherTreasure, getBestBase, getLandAccess, getSeaAccess, isLineInsideEnemyTerritory } from
"simulation/ai/petra/entityExtend.js";
import { ConstructionPlan } from "simulation/ai/petra/queueplanBuilding.js";
@ -680,7 +681,7 @@ TradeManager.prototype.update = function(gameState, events, queues)
if (gameState.ai.HQ.canBarter && Resources.GetBarterableCodes().length)
this.performBarter(gameState);
if (this.Config.difficulty <= DIFFICULTY_VERY_EASY)
if (this.Config.difficulty <= difficulty.VERY_EASY)
return;
if (this.checkEvents(gameState, events)) // true if one market was built or destroyed