diff --git a/binaries/data/mods/public/simulation/ai/aegis/aegis.js b/binaries/data/mods/public/simulation/ai/aegis/aegis.js index fdeaa0c530..d02b714cd2 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/aegis.js +++ b/binaries/data/mods/public/simulation/ai/aegis/aegis.js @@ -1,28 +1,33 @@ + +var AEGIS = (function() { +var m = {}; + // "local" global variables for stuffs that will need a unique ID // Note that since order of loading is alphabetic, this means this file must go before any other file using them. -var uniqueIDBOPlans = 0; // training/building/research plans -var uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map -var uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. +m.playerGlobals = []; +m.DebugEnabled = false; -function AegisBot(settings) { - BaseAI.call(this, settings); +m.AegisBot = function AegisBot(settings) { + API3.BaseAI.call(this, settings); - Config.updateDifficulty(settings.difficulty); + this.Config = new m.Config(); + + this.Config.updateDifficulty(settings.difficulty); this.turn = 0; this.playedTurn = 0; - - this.priorities = Config.priorities; + + this.priorities = this.Config.priorities; // this.queues can only be modified by the queue manager or things will go awry. this.queues = {}; for (i in this.priorities) - this.queues[i] = new Queue(); + this.queues[i] = new m.Queue(); - this.queueManager = new QueueManager(this.queues, this.priorities); + this.queueManager = new m.QueueManager(this.Config, this.queues, this.priorities); - this.HQ = new HQ(); + this.HQ = new m.HQ(this.Config); this.firstTime = true; @@ -30,34 +35,39 @@ function AegisBot(settings) { this.defcon = 5; this.defconChangeTime = -10000000; -} +}; -AegisBot.prototype = new BaseAI(); +m.AegisBot.prototype = new API3.BaseAI(); + +m.AegisBot.prototype.CustomInit = function(gameState, sharedScript) { + + m.playerGlobals[PlayerID] = {}; + m.playerGlobals[PlayerID].uniqueIDBOPlans = 0; // training/building/research plans + m.playerGlobals[PlayerID].uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map + m.playerGlobals[PlayerID].uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. -AegisBot.prototype.CustomInit = function(gameState, sharedScript) { - this.HQ.init(gameState,sharedScript.events,this.queues); - debug ("Initialized with the difficulty " + Config.difficulty); + m.debug ("Initialized with the difficulty " + this.Config.difficulty); - var ents = gameState.getEntities().filter(Filters.byOwner(PlayerID)); + var ents = gameState.getEntities().filter(API3.Filters.byOwner(this.player)); var myKeyEntities = ents.filter(function(ent) { return ent.hasClass("CivCentre"); }); if (myKeyEntities.length == 0){ - myKeyEntities = gameState.getEntities().filter(Filters.byOwner(PlayerID)); + myKeyEntities = gameState.getEntities().filter(API3.Filters.byOwner(this.player)); } - var filter = Filters.byClass("CivCentre"); - var enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(PlayerID))).filter(filter); + var filter = API3.Filters.byClass("CivCentre"); + var enemyKeyEntities = gameState.getEntities().filter(API3.Filters.not(API3.Filters.byOwner(this.player))).filter(filter); if (enemyKeyEntities.length == 0){ - enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(PlayerID))); + enemyKeyEntities = gameState.getEntities().filter(API3.Filters.not(API3.Filters.byOwner(this.player))); } this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position()); - this.pathFinder = new aStarPath(gameState, false, true); + this.pathFinder = new API3.aStarPath(gameState, false, true); this.pathsToMe = []; this.pathInfo = { "angle" : 0, "needboat" : true, "mkeyPos" : myKeyEntities.toEntityArray()[0].position(), "ekeyPos" : enemyKeyEntities.toEntityArray()[0].position() }; @@ -65,7 +75,7 @@ AegisBot.prototype.CustomInit = function(gameState, sharedScript) { var pos = [this.pathInfo.mkeyPos[0] + 150*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 150*Math.sin(this.pathInfo.angle)]; var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 2, 2);// uncomment for debug:*/, 300000, gameState); - //Engine.DumpImage("initialPath" + PlayerID + ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255); + //Engine.DumpImage("initialPath" + this.player + ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255); if (path !== undefined && path[1] !== undefined && path[1] == false) { // path is viable and doesn't require boating. @@ -80,7 +90,8 @@ AegisBot.prototype.CustomInit = function(gameState, sharedScript) { this.chooseRandomStrategy(); } -AegisBot.prototype.OnUpdate = function(sharedScript) { +m.AegisBot.prototype.OnUpdate = function(sharedScript) { + if (this.gameFinished){ return; } @@ -120,7 +131,7 @@ AegisBot.prototype.OnUpdate = function(sharedScript) { { if (this.pathInfo.needboat) { - debug ("Assuming this is a water map"); + m.debug ("Assuming this is a water map"); this.HQ.waterMap = true; } delete this.pathFinder; @@ -132,27 +143,27 @@ AegisBot.prototype.OnUpdate = function(sharedScript) { var cityPhase = this.gameState.cityPhase(); // try going up phases. // TODO: softcode this. - if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40 + if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40 && this.gameState.findResearchers(townPhase,true).length != 0 && this.queues.majorTech.length() === 0 - && this.gameState.getOwnEntities().filter(Filters.byClass("Village")).length > 5) + && this.gameState.getOwnEntities().filter(API3.Filters.byClass("Village")).length > 5) { this.queueManager.pauseQueue("villager", true); this.queueManager.pauseQueue("citizenSoldier", true); this.queueManager.pauseQueue("house", true); - this.queues.majorTech.addItem(new ResearchPlan(this.gameState, townPhase,0,-1,true)); // we rush the town phase. - debug ("Trying to reach town phase"); + this.queues.majorTech.addItem(new m.ResearchPlan(this.gameState, townPhase,0,-1,true)); // we rush the town phase. + m.debug ("Trying to reach town phase"); } - else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > (Config.Economy.cityPhase*1000) + else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.cityPhase*1000) && this.gameState.getOwnEntitiesByRole("worker").length > 85 && this.gameState.findResearchers(cityPhase, true).length != 0 && this.queues.majorTech.length() === 0) { - debug ("Trying to reach city phase"); - this.queues.majorTech.addItem(new ResearchPlan(this.gameState, cityPhase)); + m.debug ("Trying to reach city phase"); + this.queues.majorTech.addItem(new m.ResearchPlan(this.gameState, cityPhase)); } // defcon cooldown if (this.defcon < 5 && this.gameState.timeSinceDefconChange() > 20000) { this.defcon++; - debug ("updefconing to " +this.defcon); + m.debug ("updefconing to " +this.defcon); if (this.defcon >= 4 && this.HQ.hasGarrisonedFemales) this.HQ.ungarrisonAll(this.gameState); } @@ -210,24 +221,24 @@ AegisBot.prototype.OnUpdate = function(sharedScript) { this.turn++; }; -AegisBot.prototype.chooseRandomStrategy = function() +m.AegisBot.prototype.chooseRandomStrategy = function() { // deactivated for now. this.strategy = "normal"; // rarely and if we can assume it's not a water map. - if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && Config.difficulty == 2) + if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && this.Config.difficulty == 2) { this.strategy = "rush"; // going to rush. this.HQ.targetNumWorkers = 0; - Config.Economy.townPhase = 480; - Config.Economy.cityPhase = 900; - Config.Economy.farmsteadStartTime = 600; - Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2. + this.Config.Economy.townPhase = 480; + this.Config.Economy.cityPhase = 900; + this.Config.Economy.farmsteadStartTime = 600; + this.Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2. } }; -/*AegisBot.prototype.Deserialize = function(data, sharedScript) +/*m.AegisBot.prototype.Deserialize = function(data, sharedScript) { }; @@ -237,21 +248,24 @@ AegisBot.prototype.Serialize = function() return {}; };*/ -function debug(output){ - if (Config.debug){ +m.debug = function(output){ + if (m.DebugEnabled){ if (typeof output === "string"){ warn(output); }else{ warn(uneval(output)); } } -} +}; -function copyPrototype(descendant, parent) { +m.copyPrototype = function(descendant, parent) { var sConstructor = parent.toString(); var aMatch = sConstructor.match( /\s*function (.*)\(/ ); if ( aMatch != null ) { descendant.prototype[aMatch[1]] = parent; } for (var m in parent.prototype) { descendant.prototype[m] = parent.prototype[m]; } -} +}; + +return m; +}()); diff --git a/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js b/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js index f2a9c5716a..a0ef0194fe 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js +++ b/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js @@ -1,3 +1,6 @@ +var AEGIS = function(m) +{ + /* This is an attack plan (despite the name, it's a relic of older times). * It deals with everything in an attack, from picking a target to picking a path to it * To making sure units rae built, and pushing elements to the queue manager otherwise @@ -6,8 +9,9 @@ * There is a basic support for naval expeditions here. */ -function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { +m.CityAttack = function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy, type , targetFinder) { + this.Config = Config; //This is the list of IDs of the units in the plan this.idList=[]; @@ -33,14 +37,14 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { return false; } - var CCs = gameState.getOwnEntities().filter(Filters.byClass("CivCentre")); + var CCs = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")); if (CCs.length === 0) { this.failed = true; return false; } - debug ("Target (" + PlayerID +") = " +this.targetPlayer); + m.debug ("Target (" + PlayerID +") = " +this.targetPlayer); this.targetFinder = targetFinder || this.defaultTargetFinder; this.type = type || "normal"; this.name = uniqueID; @@ -50,7 +54,7 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { this.maxPreparationTime = 210*1000; // in this case we want to have the attack ready by the 13th minute. Countdown. Minimum 2 minutes. - if (type !== "superSized" && Config.difficulty >= 1) + if (type !== "superSized" && this.Config.difficulty >= 1) this.maxPreparationTime = 780000 - gameState.getTimeElapsed() < 120000 ? 120000 : 780000 - gameState.getTimeElapsed(); this.pausingStart = 0; @@ -120,7 +124,7 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { return (strength[0] > 15 || strength[1] > 15); };*/ - var filter = Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID)); + var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)); this.unitCollection = gameState.getOwnEntities().filter(filter); this.unitCollection.registerUpdates(); this.unitCollection.length; @@ -136,7 +140,7 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { var cat = unitCat; var Unit = this.unitStat[cat]; - filter = Filters.and(Filters.byClassesAnd(Unit["classes"]),Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID))); + filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID))); this.unit[cat] = gameState.getOwnEntities().filter(filter); this.unit[cat].registerUpdates(); this.unit[cat].length; @@ -186,7 +190,7 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { this.anyNotMinimal = true; // used for support plans - var myFortresses = gameState.getOwnTrainingFacilities().filter(Filters.byClass("GarrisonFortress")); + var myFortresses = gameState.getOwnTrainingFacilities().filter(API3.Filters.byClass("GarrisonFortress")); if (myFortresses.length !== 0) { // make this our rallypoint @@ -237,11 +241,11 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { this.assignUnits(gameState); - //debug ("Before"); + //m.debug ("Before"); //Engine.DumpHeap(); // get a good path to an estimated target. - this.pathFinder = new aStarPath(gameState,false,false, this.targetPlayer); + this.pathFinder = new API3.aStarPath(gameState,false,false, this.targetPlayer); //Engine.DumpImage("widthmap.png", this.pathFinder.widthMap, this.pathFinder.width,this.pathFinder.height,255); this.pathWidth = 6; // prefer a path far from entities. This will avoid units getting stuck in trees and also results in less straight paths. @@ -249,21 +253,21 @@ function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) { this.onBoat = false; // tells us if our units are loaded on boats. this.needsShip = false; - //debug ("after"); + //m.debug ("after"); //Engine.DumpHeap(); return true; }; -CityAttack.prototype.getName = function(){ +m.CityAttack.prototype.getName = function(){ return this.name; }; -CityAttack.prototype.getType = function(){ +m.CityAttack.prototype.getType = function(){ return this.type; }; // Returns true if the attack can be executed at the current time // Basically his checks we have enough units. // We run a count of our units. -CityAttack.prototype.canStart = function(gameState){ +m.CityAttack.prototype.canStart = function(gameState){ for (var unitCat in this.unitStat) { var Unit = this.unitStat[unitCat]; if (this.unit[unitCat].length < Unit["minSize"]) @@ -273,27 +277,27 @@ CityAttack.prototype.canStart = function(gameState){ // TODO: check if our target is valid and a few other stuffs (good moment to attack?) }; -CityAttack.prototype.isStarted = function(){ +m.CityAttack.prototype.isStarted = function(){ if ((this.state !== "unexecuted")) - debug ("Attack plan already started"); + m.debug ("Attack plan already started"); return !(this.state == "unexecuted"); }; -CityAttack.prototype.isPaused = function(){ +m.CityAttack.prototype.isPaused = function(){ return this.paused; }; -CityAttack.prototype.setPaused = function(gameState, boolValue){ +m.CityAttack.prototype.setPaused = function(gameState, boolValue){ if (!this.paused && boolValue === true) { this.pausingStart = gameState.getTimeElapsed(); this.paused = true; - debug ("Pausing attack plan " +this.name); + m.debug ("Pausing attack plan " +this.name); } else if (this.paused && boolValue === false) { this.totalPausingTime += gameState.getTimeElapsed() - this.pausingStart; this.paused = false; - debug ("Unpausing attack plan " +this.name); + m.debug ("Unpausing attack plan " +this.name); } }; -CityAttack.prototype.mustStart = function(gameState){ +m.CityAttack.prototype.mustStart = function(gameState){ if (this.isPaused() || this.path === undefined) return false; var MaxReachedEverywhere = true; @@ -309,14 +313,14 @@ CityAttack.prototype.mustStart = function(gameState){ }; // Adds a build order. If resetQueue is true, this will reset the queue. -CityAttack.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue) { +m.CityAttack.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue) { if (!this.isStarted()) { - debug ("Adding a build order for " + name); + m.debug ("Adding a build order for " + name); // no minsize as we don't want the plan to fail at the last minute though. this.unitStat[name] = unitStats; var Unit = this.unitStat[name]; - var filter = Filters.and(Filters.byClassesAnd(Unit["classes"]),Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID))); + var filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID))); this.unit[name] = gameState.getOwnEntities().filter(filter); this.unit[name].registerUpdates(); this.buildOrder.push([0, Unit["classes"], this.unit[name], Unit, name]); @@ -330,7 +334,7 @@ CityAttack.prototype.addBuildOrder = function(gameState, name, unitStats, resetQ // Three returns possible: 1 is "keep going", 0 is "failed plan", 2 is "start" // 3 is a special case: no valid path returned. Right now I stop attacking alltogether. -CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { +m.CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { var self = this; if (this.path == undefined || this.target == undefined || this.path === "toBeContinued") { @@ -342,14 +346,14 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { targets = this.defaultTargetFinder(gameState, HQ); if (targets.length !== 0) { - debug ("Aiming for " + targets); + m.debug ("Aiming for " + targets); // picking a target var maxDist = -1; var index = 0; for (var i in targets._entities) { // we're sure it has a position has TargetFinder already checks that. - var dist = SquareVectorDistance(targets._entities[i].position(), this.rallyPoint); + var dist = API3.SquareVectorDistance(targets._entities[i].position(), this.rallyPoint); if (dist < maxDist || maxDist === -1) { maxDist = dist; @@ -385,11 +389,11 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { // Basically we'll add it as a new class to train compulsorily, and we'll recompute our path. if (!gameState.ai.HQ.waterMap) { - debug ("This is actually a water map."); + m.debug ("This is actually a water map."); gameState.ai.HQ.waterMap = true; return 0; } - debug ("We need a ship."); + m.debug ("We need a ship."); this.needsShip = true; this.pathWidth = 3; this.pathSampling = 3; @@ -400,7 +404,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { { // my pathfinder returns arrays in arrays in arrays. var waypointPos = this.path[i][0]; - var territory = Map.createTerritoryMap(gameState); + var territory = m.createTerritoryMap(gameState); if (territory.getOwner(waypointPos) !== PlayerID || this.path[i][1] === true) { // if we're suddenly out of our territory or this is the point where we change transportation method. @@ -426,7 +430,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { { // my pathfinder returns arrays in arrays in arrays. var waypointPos = this.path[i][0]; - var territory = Map.createTerritoryMap(gameState); + var territory = m.createTerritoryMap(gameState); if (territory.getOwner(waypointPos) !== PlayerID || this.path[i][1] === true) { // if we're suddenly out of our territory or this is the point where we change transportation method. @@ -511,7 +515,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { if (this.buildOrder[0][0] < 1 && queue.length() <= 5) { var template = HQ.findBestTrainableSoldier(gameState, this.buildOrder[0][1], this.buildOrder[0][3]["interests"] ); - //debug ("tried " + uneval(this.buildOrder[0][1]) +", and " + template); + //m.debug ("tried " + uneval(this.buildOrder[0][1]) +", and " + template); // HACK (TODO replace) : if we have no trainable template... Then we'll simply remove the buildOrder, effectively removing the unit from the plan. if (template === undefined) { // TODO: this is a complete hack. @@ -523,9 +527,9 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { if (gameState.getTimeElapsed() > 1800000) max *= 2; if (gameState.getTemplate(template).hasClass("CitizenSoldier")) - queue.addItem( new TrainingPlan(gameState,template, { "role" : "worker", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) ); + queue.addItem( new m.TrainingPlan(gameState,template, { "role" : "worker", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) ); else - queue.addItem( new TrainingPlan(gameState,template, { "role" : "attack", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) ); + queue.addItem( new m.TrainingPlan(gameState,template, { "role" : "attack", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) ); } } } @@ -546,7 +550,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { this.targetPos = target.position(); count++; if (count > 1000){ - debug("No target with a valid position found"); + m.debug("No target with a valid position found"); return false; } } @@ -559,7 +563,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { if (path !== "toBeContinued") { this.startedPathing = false; this.path = path; - debug("Pathing ended"); + m.debug("Pathing ended"); } } */ @@ -567,7 +571,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { Engine.ProfileStop(); // can happen for now if (this.buildOrder.length === 0) { - debug ("Ending plan: no build orders"); + m.debug ("Ending plan: no build orders"); return 0; // will abort the plan, should return something else } return 1; @@ -583,7 +587,7 @@ CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { return 0; return 0; }; -CityAttack.prototype.assignUnits = function(gameState){ +m.CityAttack.prototype.assignUnits = function(gameState){ var self = this; // TODO: assign myself units that fit only, right now I'm getting anything. @@ -604,14 +608,14 @@ CityAttack.prototype.assignUnits = function(gameState){ }; // this sends a unit by ID back to the "rally point" -CityAttack.prototype.ToRallyPoint = function(gameState,id) +m.CityAttack.prototype.ToRallyPoint = function(gameState,id) { // Move back to nearest rallypoint gameState.getEntityById(id).move(this.rallyPoint[0],this.rallyPoint[1]); } // this sends all units back to the "rally point" by entity collections. // It doesn't disturb ones that could be currently defending, even if the plan is not (yet) paused. -CityAttack.prototype.AllToRallyPoint = function(gameState, evenWorkers) { +m.CityAttack.prototype.AllToRallyPoint = function(gameState, evenWorkers) { var self = this; if (evenWorkers) { for (var unitCat in this.unit) { @@ -634,7 +638,7 @@ CityAttack.prototype.AllToRallyPoint = function(gameState, evenWorkers) { } // Default target finder aims for conquest critical targets -CityAttack.prototype.defaultTargetFinder = function(gameState, HQ){ +m.CityAttack.prototype.defaultTargetFinder = function(gameState, HQ){ var targets = undefined; targets = HQ.enemyWatchers[this.targetPlayer].getEnemyBuildings(gameState, "CivCentre",true); @@ -650,13 +654,13 @@ CityAttack.prototype.defaultTargetFinder = function(gameState, HQ){ } // no buildings, attack anything conquest critical, even units (it's assuming it won't move). if (targets.length == 0) { - targets = gameState.getEnemyEntities().filter(Filters.and( Filters.byOwner(this.targetPlayer),Filters.byClass("ConquestCritical"))); + targets = gameState.getEnemyEntities().filter(API3.Filters.and( API3.Filters.byOwner(this.targetPlayer),API3.Filters.byClass("ConquestCritical"))); } return targets; }; // tupdate -CityAttack.prototype.raidingTargetFinder = function(gameState, HQ, Target){ +m.CityAttack.prototype.raidingTargetFinder = function(gameState, HQ, Target){ var targets = undefined; if (Target == "villager") { @@ -684,7 +688,7 @@ CityAttack.prototype.raidingTargetFinder = function(gameState, HQ, Target){ // Executes the attack plan, after this is executed the update function will be run every turn // If we're here, it's because we have in our IDlist enough units. // now the IDlist units are treated turn by turn -CityAttack.prototype.StartAttack = function(gameState, HQ){ +m.CityAttack.prototype.StartAttack = function(gameState, HQ){ // check we have a target and a path. if (this.targetPos && this.path !== undefined) { @@ -701,19 +705,19 @@ CityAttack.prototype.StartAttack = function(gameState, HQ){ this.unitCollection.move(this.path[0][0][0], this.path[0][0][1]); this.unitCollection.setStance("aggressive"); - this.unitCollection.filter(Filters.byClass("Siege")).setStance("defensive"); + this.unitCollection.filter(API3.Filters.byClass("Siege")).setStance("defensive"); this.state = "walking"; } else { gameState.ai.gameFinished = true; - debug ("I do not have any target. So I'll just assume I won the game."); + m.debug ("I do not have any target. So I'll just assume I won the game."); return false; } return true; }; // Runs every turn after the attack is executed -CityAttack.prototype.update = function(gameState, HQ, events){ +m.CityAttack.prototype.update = function(gameState, HQ, events){ var self = this; Engine.ProfileStart("Update Attack"); @@ -750,7 +754,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0 && attacker.owner() != PlayerID) { - var territoryMap = Map.createTerritoryMap(gameState); + var territoryMap = m.createTerritoryMap(gameState); if ( +territoryMap.point(attacker.position()) - 64 === +this.targetPlayer) { attackedNB++; @@ -769,7 +773,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ } } if (attackedNB > 4) { - debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); + m.debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); // we must assume we've arrived at the end of the trail. this.state = "arrived"; } @@ -799,7 +803,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ var enemy = enemySoldiers[j]; if (enemy.position() === undefined) // likely garrisoned continue; - if (inRange(enemy.position(), attacker.position(), 1000) && this.threatList.indexOf(enemy.id()) === -1) + if (m.inRange(enemy.position(), attacker.position(), 1000) && this.threatList.indexOf(enemy.id()) === -1) this.threatList.push(enemy.id()); } this.threatList.push(e.msg.attacker); @@ -844,16 +848,16 @@ CityAttack.prototype.update = function(gameState, HQ, events){ } // basically haven't moved an inch: very likely stuck) - if (SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0) { + if (API3.SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0) { // check for stuck siege units - var sieges = this.unitCollection.filter(Filters.byClass("Siege")); + var sieges = this.unitCollection.filter(API3.Filters.byClass("Siege")); var farthest = 0; var farthestEnt = -1; sieges.forEach (function (ent) { - if (SquareVectorDistance(ent.position(),self.position) > farthest) + if (API3.SquareVectorDistance(ent.position(),self.position) > farthest) { - farthest = SquareVectorDistance(ent.position(),self.position); + farthest = API3.SquareVectorDistance(ent.position(),self.position); farthestEnt = ent; } }); @@ -863,42 +867,42 @@ CityAttack.prototype.update = function(gameState, HQ, events){ if (gameState.ai.playedTurn % 5 === 0) this.position5TurnsAgo = this.position; - if (this.lastPosition && SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) { + if (this.lastPosition && API3.SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) { this.unitCollection.moveIndiv(this.path[0][0][0], this.path[0][0][1]); // We're stuck, presumably. Check if there are no walls just close to us. If so, we're arrived, and we're gonna tear down some serious stone. - var walls = gameState.getEnemyEntities().filter(Filters.and(Filters.byOwner(this.targetPlayer), Filters.byClass("StoneWall"))); + var walls = gameState.getEnemyEntities().filter(API3.Filters.and(API3.Filters.byOwner(this.targetPlayer), API3.Filters.byClass("StoneWall"))); var nexttoWalls = false; walls.forEach( function (ent) { - if (!nexttoWalls && SquareVectorDistance(self.position, ent.position()) < 800) + if (!nexttoWalls && API3.SquareVectorDistance(self.position, ent.position()) < 800) nexttoWalls = true; }); // there are walls but we can attack - if (nexttoWalls && this.unitCollection.filter(Filters.byCanAttack("StoneWall")).length !== 0) + if (nexttoWalls && this.unitCollection.filter(API3.Filters.byCanAttack("StoneWall")).length !== 0) { - debug ("Attack Plan " +this.type +" " +this.name +" has met walls and is not happy."); + m.debug ("Attack Plan " +this.type +" " +this.name +" has met walls and is not happy."); this.state = "arrived"; } else if (nexttoWalls) { // abort plan. - debug ("Attack Plan " +this.type +" " +this.name +" has met walls and gives up."); + m.debug ("Attack Plan " +this.type +" " +this.name +" has met walls and gives up."); Engine.ProfileStop(); return 0; } } // check if our land units are close enough from the next waypoint. - if (SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) < 7500 || - SquareVectorDistance(this.unitCollection.getCentrePosition(), this.path[0][0]) < 650) { - if (this.unitCollection.filter(Filters.byClass("Siege")).length !== 0 - && SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) >= 7500 - && SquareVectorDistance(this.unitCollection.filter(Filters.byClass("Siege")).getCentrePosition(), this.path[0][0]) >= 650) + if (API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) < 7500 || + API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.path[0][0]) < 650) { + if (this.unitCollection.filter(API3.Filters.byClass("Siege")).length !== 0 + && API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) >= 7500 + && API3.SquareVectorDistance(this.unitCollection.filter(API3.Filters.byClass("Siege")).getCentrePosition(), this.path[0][0]) >= 650) { } else { for (var i = 0; i < this.path.length; ++i) { - debug ("path waypoint " + i + "," + this.path[i][1] + " at " + uneval(this.path[i][0])); + m.debug ("path waypoint " + i + "," + this.path[i][1] + " at " + uneval(this.path[i][0])); } - debug ("position is " + this.unitCollection.getCentrePosition()); + m.debug ("position is " + this.unitCollection.getCentrePosition()); // okay so here basically two cases. The first one is "we need a boat at this point". // the second one is "we need to unload at this point". The third is "normal". @@ -908,7 +912,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ if (this.path.length > 0){ this.unitCollection.move(this.path[0][0][0], this.path[0][0][1]); } else { - debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); + m.debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); // we must assume we've arrived at the end of the trail. this.state = "arrived"; } @@ -917,15 +921,15 @@ CityAttack.prototype.update = function(gameState, HQ, events){ // TODO: make this require an escort later on. this.path.shift(); if (this.path.length === 0) { - debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); + m.debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); // we must assume we've arrived at the end of the trail. this.state = "arrived"; } else { /* - var plan = new TransportPlan(gameState, this.unitCollection.toIdArray(), this.path[0][0], false); + var plan = new m.TransportPlan(gameState, this.unitCollection.toIdArray(), this.path[0][0], false); this.tpPlanID = plan.ID; HQ.navalManager.transportPlans.push(plan); - debug ("Transporting over sea"); + m.debug ("Transporting over sea"); this.state = "transporting"; */ // TODO: fix this above @@ -962,7 +966,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ }); var targetList = []; enemyCitizens.forEach( function (enemy) { - if (inRange(enemy.position(), units.getCentrePosition(), 2500) && targetList.indexOf(enemy.id()) === -1) + if (m.inRange(enemy.position(), units.getCentrePosition(), 2500) && targetList.indexOf(enemy.id()) === -1) targetList.push(enemy.id()); }); if (targetList.length > 0) @@ -989,7 +993,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0 && attacker.owner() != PlayerID) { if (ourUnit.hasClass("Siege")) { - var collec = this.unitCollection.filterNearest(ourUnit.position(), 8).filter(Filters.not(Filters.byClass("Siege"))).toEntityArray(); + var collec = this.unitCollection.filterNearest(ourUnit.position(), 8).filter(API3.Filters.not(API3.Filters.byClass("Siege"))).toEntityArray(); if (collec.length !== 0) { collec[0].attack(attacker.id()); @@ -1018,7 +1022,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ this.unitCollUpdateArray = this.unitCollection.toIdArray(); } else { // some stuffs for locality and speed - var territoryMap = Map.createTerritoryMap(gameState); + var territoryMap = m.createTerritoryMap(gameState); var timeElapsed = gameState.getTimeElapsed(); // Let's check a few units each time we update. Currently 10 @@ -1057,7 +1061,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ if (!enemy.position() || (enemy.hasClass("StoneWall") && ent.canAttackClass("StoneWall"))) { return false; } - if (SquareVectorDistance(enemy.position(),ent.position()) > 3000) { + if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 3000) { return false; } return true; @@ -1070,7 +1074,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ } if (!enemy.hasClass("Support")) return false; - if (SquareVectorDistance(enemy.position(),ent.position()) > 10000) { + if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 10000) { return false; } return true; @@ -1081,7 +1085,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ if (!enemy.position()) { return false; } - if (SquareVectorDistance(enemy.position(),ent.position()) > 10000) { + if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 10000) { return false; } return true; @@ -1118,19 +1122,19 @@ CityAttack.prototype.update = function(gameState, HQ, events){ { var rand = Math.floor(Math.random() * mStruct.length*0.1); ent.attack(mStruct[+rand].id()); - //debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); + //m.debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); } - } else if (SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ - //debug ("Siege units moving to " + uneval(self.targetPos)); + } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ + //m.debug ("Siege units moving to " + uneval(self.targetPos)); ent.move(self.targetPos[0],self.targetPos[1]); } } else { if (mUnit.length !== 0) { var rand = Math.floor(Math.random() * mUnit.length*0.99); ent.attack(mUnit[(+rand)].id()); - //debug ("Units attacking a unit from " +mUnit[+rand].owner() + " , " +mUnit[+rand].templateName()); - } else if (SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ - //debug ("Units moving to " + uneval(self.targetPos)); + //m.debug ("Units attacking a unit from " +mUnit[+rand].owner() + " , " +mUnit[+rand].templateName()); + } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ + //m.debug ("Units moving to " + uneval(self.targetPos)); ent.move(self.targetPos[0],self.targetPos[1]); } else if (mStruct.length !== 0) { mStruct.sort(function (structa,structb) { //}){ @@ -1156,7 +1160,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ { var rand = Math.floor(Math.random() * mStruct.length*0.1); ent.attack(mStruct[+rand].id()); - //debug ("Units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); + //m.debug ("Units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); } } } @@ -1172,8 +1176,8 @@ CityAttack.prototype.update = function(gameState, HQ, events){ targets = this.defaultTargetFinder(gameState, HQ); } if (targets.length) { - debug ("Seems like our target has been destroyed. Switching."); - debug ("Aiming for " + targets); + m.debug ("Seems like our target has been destroyed. Switching."); + m.debug ("Aiming for " + targets); // picking a target this.targetPos = undefined; var count = 0; @@ -1183,7 +1187,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ this.targetPos = this.target.position(); count++; if (count > 1000){ - debug("No target with a valid position found"); + m.debug("No target with a valid position found"); Engine.ProfileStop(); return false; } @@ -1215,7 +1219,7 @@ CityAttack.prototype.update = function(gameState, HQ, events){ return this.unitCollection.length; }; -CityAttack.prototype.totalCountUnits = function(gameState){ +m.CityAttack.prototype.totalCountUnits = function(gameState){ var totalcount = 0; for (var i in this.idList) { @@ -1224,7 +1228,7 @@ CityAttack.prototype.totalCountUnits = function(gameState){ return totalcount; }; // reset any units -CityAttack.prototype.Abort = function(gameState){ +m.CityAttack.prototype.Abort = function(gameState){ this.unitCollection.forEach(function(ent) { ent.setMetadata(PlayerID, "role",undefined); ent.setMetadata(PlayerID, "subrole",undefined); @@ -1238,3 +1242,6 @@ CityAttack.prototype.Abort = function(gameState){ gameState.ai.queueManager.removeQueue("plan_" + this.name); gameState.ai.queueManager.removeQueue("plan_" + this.name + "_champ"); }; + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js index 097716890d..46d7e394b5 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js @@ -1,3 +1,5 @@ +var AEGIS = function(m) +{ /* Base Manager * Handles lower level economic stuffs. * Some tasks: @@ -10,9 +12,10 @@ -updating whatever needs updating, keeping track of stuffs (rebuilding needs…) */ -var BaseManager = function() { +m.BaseManager = function(Config) { + this.Config = Config; this.farmingFields = false; - this.ID = uniqueIDBases++; + this.ID = m.playerGlobals[PlayerID].uniqueIDBases++; // anchor building: seen as the main building of the base. Needs to have territorial influence this.anchor = undefined; @@ -31,13 +34,13 @@ var BaseManager = function() { this.territoryIndices = []; }; -BaseManager.prototype.init = function(gameState, events, unconstructed){ +m.BaseManager.prototype.init = function(gameState, events, unconstructed){ this.constructing = unconstructed; // entitycollections - this.units = gameState.getOwnEntities().filter(Filters.and(Filters.byClass("Unit"),Filters.byMetadata(PlayerID, "base", this.ID))); - this.buildings = gameState.getOwnEntities().filter(Filters.and(Filters.byClass("Structure"),Filters.byMetadata(PlayerID, "base", this.ID))); + this.units = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Unit"),API3.Filters.byMetadata(PlayerID, "base", this.ID))); + this.buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byMetadata(PlayerID, "base", this.ID))); - this.workers = this.units.filter(Filters.byMetadata(PlayerID,"role","worker")); + this.workers = this.units.filter(API3.Filters.byMetadata(PlayerID,"role","worker")); this.workers.allowQuickIter(); this.buildings.allowQuickIter(); @@ -62,7 +65,7 @@ BaseManager.prototype.init = function(gameState, events, unconstructed){ this.bigRadius = { 'food':70*70,'wood':200*200,'stone':200*200,'metal':200*200 }; }; -BaseManager.prototype.assignEntity = function(unit){ +m.BaseManager.prototype.assignEntity = function(unit){ unit.setMetadata(PlayerID, "base", this.ID); this.units.updateEnt(unit); this.workers.updateEnt(unit); @@ -73,7 +76,7 @@ BaseManager.prototype.assignEntity = function(unit){ this.territoryBuildings.push(unit.id()); }; -BaseManager.prototype.setAnchor = function(anchorEntity) { +m.BaseManager.prototype.setAnchor = function(anchorEntity) { if (!anchorEntity.hasClass("Structure") || !anchorEntity.hasTerritoryInfluence()) { warn("Error: Aegis' base " + this.ID + " has been assigned an anchor building that has no territorial influence. Please report this on the forum.") @@ -90,7 +93,7 @@ BaseManager.prototype.setAnchor = function(anchorEntity) { } // affects the HQ map. -BaseManager.prototype.initTerritory = function(HQ, gameState) { +m.BaseManager.prototype.initTerritory = function(HQ, gameState) { if (!this.anchor) warn ("Error: Aegis tried to initialize the territory of base " + this.ID + " without assigning it an anchor building first"); var radius = Math.round((this.anchor.territoryInfluenceRadius() / 4.0) * 1.25); @@ -122,7 +125,7 @@ BaseManager.prototype.initTerritory = function(HQ, gameState) { } } -BaseManager.prototype.initGatheringFunctions = function(HQ, gameState, specTypes) { +m.BaseManager.prototype.initGatheringFunctions = function(HQ, gameState, specTypes) { // init our gathering functions. var types = ["food","wood","stone","metal"]; if (specTypes !== undefined) @@ -136,7 +139,7 @@ BaseManager.prototype.initGatheringFunctions = function(HQ, gameState, specTypes var type = types[i]; // TODO: set us as "X" gatherer - this.buildings.filter(Filters.isDropsite(type)).forEach(function(ent) { self.initializeDropsite(gameState, ent,type) }); + this.buildings.filter(API3.Filters.isDropsite(type)).forEach(function(ent) { self.initializeDropsite(gameState, ent,type) }); if (this.getResourceLevel(gameState, type, "all") > 1000) this.willGather[type] = 1; @@ -151,13 +154,13 @@ BaseManager.prototype.initGatheringFunctions = function(HQ, gameState, specTypes if (needFarm) this.willGather["food"] = 1; } - debug ("food" + this.willGather["food"]); - debug (this.willGather["wood"]); - debug (this.willGather["stone"]); - debug (this.willGather["metal"]); + m.debug ("food" + this.willGather["food"]); + m.debug (this.willGather["wood"]); + m.debug (this.willGather["stone"]); + m.debug (this.willGather["metal"]); } -BaseManager.prototype.checkEvents = function (gameState, events, queues) { +m.BaseManager.prototype.checkEvents = function (gameState, events, queues) { for (i in events) { if (events[i].type == "Destroy") @@ -185,10 +188,10 @@ BaseManager.prototype.checkEvents = function (gameState, events, queues) { if (ent.hasClass("CivCentre")) { // TODO: might want to tell the queue manager to pause other stuffs if we are the only base. - queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true }, 0 , -1,ent.position())); + queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true }, 0 , -1,ent.position())); } else { // TODO - queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true },0,-1,ent.position())); + queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true },0,-1,ent.position())); } } } @@ -238,7 +241,7 @@ BaseManager.prototype.checkEvents = function (gameState, events, queues) { }; // If no specific dropsite, it'll assign to the closest -BaseManager.prototype.assignResourceToDP = function (gameState, supply, specificDP) { +m.BaseManager.prototype.assignResourceToDP = function (gameState, supply, specificDP) { var type = supply.resourceSupplyType()["generic"]; if (type == "treasure") type = supply.resourceSupplyType()["specific"]; @@ -249,7 +252,7 @@ BaseManager.prototype.assignResourceToDP = function (gameState, supply, specific for (i in this.dropsites) { var dp = gameState.getEntityById(i); - var distance = SquareVectorDistance(supply.position(), dp.position()); + var distance = API3.SquareVectorDistance(supply.position(), dp.position()); if (distance < dist && distance < this.bigRadius[type]) { closest = dp.id(); @@ -267,7 +270,7 @@ BaseManager.prototype.assignResourceToDP = function (gameState, supply, specific // TODO: ought to recount immediatly. } -BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { +m.BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { var count = 0, farCount = 0; var self = this; @@ -278,7 +281,7 @@ BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { resources.filter( function (supply) { //}){ if (!supply.position() || !ent.position()) return; - var distance = SquareVectorDistance(supply.position(), ent.position()); + var distance = API3.SquareVectorDistance(supply.position(), ent.position()); if (supply.getMetadata(PlayerID, "linked-dropsite") == undefined || supply.getMetadata(PlayerID, "linked-dropsite-dist") > distance) { if (distance < self.bigRadius[type]) { @@ -294,19 +297,19 @@ BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { } }); // This one is both for the nearby and the linked - var filter = Filters.byMetadata(PlayerID, "linked-dropsite", ent.id()); + var filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite", ent.id()); var collection = resources.filter(filter); collection.registerUpdates(); - filter = Filters.byMetadata(PlayerID, "linked-dropsite-close",true); + filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite-close",true); var collection2 = collection.filter(filter); collection2.registerUpdates(); - filter = Filters.byMetadata(PlayerID, "linked-dropsite-nearby",true); + filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite-nearby",true); var collection3 = collection.filter(filter); collection3.registerUpdates(); - filter = Filters.byMetadata(PlayerID, "linked-to-dropsite", ent.id()); + filter = API3.Filters.byMetadata(PlayerID, "linked-to-dropsite", ent.id()); var WkCollection = this.workers.filter(filter); WkCollection.registerUpdates(); @@ -318,51 +321,51 @@ BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { // TODO: get workers on those resources and do something with them. } - if (Config.debug) + if (m.DebugEnabled) { // Make resources glow wildly if (type == "food") { self.dropsites[ent.id()][type][2].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]}); }); self.dropsites[ent.id()][type][1].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]}); }); self.dropsites[ent.id()][type][0].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); }); } if (type == "wood") { self.dropsites[ent.id()][type][2].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]}); }); self.dropsites[ent.id()][type][1].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]}); }); self.dropsites[ent.id()][type][0].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); }); } if (type == "stone") { self.dropsites[ent.id()][type][2].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]}); }); self.dropsites[ent.id()][type][1].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]}); }); self.dropsites[ent.id()][type][0].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]}); }); } if (type == "metal") { self.dropsites[ent.id()][type][2].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]}); }); self.dropsites[ent.id()][type][1].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]}); }); self.dropsites[ent.id()][type][0].forEach(function(ent){ - Engine.PostCommand({"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]}); + Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]}); }); } } @@ -371,7 +374,7 @@ BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { // completely and "safely" remove a dropsite from our list. // this also removes any linked resource and so on. // TODO: should re-add the resources to another dropsite. -BaseManager.prototype.scrapDropsite = function (gameState, ent) { +m.BaseManager.prototype.scrapDropsite = function (gameState, ent) { if (this.dropsites[ent.id()] === undefined) return true; @@ -398,7 +401,7 @@ BaseManager.prototype.scrapDropsite = function (gameState, ent) { }; // Returns the position of the best place to build a new dropsite for the specified resource -BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){ +m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){ var storeHousePlate = gameState.getTemplate(gameState.applyCiv("structures/{civ}_storehouse")); @@ -407,15 +410,15 @@ BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){ // Then checks for a good spot in the territory. If none, and town/city phase, checks outside // The AI will currently not build a CC if it wouldn't connect with an existing CC. - var territory = Map.createTerritoryMap(gameState); + var territory = m.createTerritoryMap(gameState); - var obstructions = Map.createObstructionMap(gameState,this.accessIndex,storeHousePlate); + var obstructions = m.createObstructionMap(gameState,this.accessIndex,storeHousePlate); obstructions.expandInfluences(); // copy the resource map as initialization. - var friendlyTiles = new Map(gameState.sharedScript, gameState.sharedScript.resourceMaps[resource].map, true); + var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.resourceMaps[resource].map, true); - var DPFoundations = gameState.getOwnFoundations().filter(Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse"))); + var DPFoundations = gameState.getOwnFoundations().filter(API3.Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse"))); // TODO: might be better to check dropsites someplace else. // loop over this in this.terrytoryindices. It's usually a little too much, but it's always enough. @@ -434,25 +437,25 @@ BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){ { var pos = [j%friendlyTiles.width, Math.floor(j/friendlyTiles.width)]; var dpPos = gameState.getEntityById(i).position(); - if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) + if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) { friendlyTiles.map[j] = 0; continue; - } else if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) + } else if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) friendlyTiles.map[j] /= 2; } for (var i in DPFoundations._entities) { var pos = [j%friendlyTiles.width, Math.floor(j/friendlyTiles.width)]; var dpPos = gameState.getEntityById(i).position(); - if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) + if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) friendlyTiles.map[j] = 0; - else if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) + else if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) friendlyTiles.map[j] /= 2; } } - if (Config.debug) + if (m.DebugEnabled) friendlyTiles.dumpIm("DP_" + resource + "_" + gameState.getTimeElapsed() + ".png"); var best = friendlyTiles.findBestTile(2, obstructions); // try to find a spot to place a DP. @@ -469,7 +472,7 @@ BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){ }; // update the resource level of a dropsite. -BaseManager.prototype.updateDropsite = function (gameState, ent, type) { +m.BaseManager.prototype.updateDropsite = function (gameState, ent, type) { if (this.dropsites[ent.id()] === undefined || this.dropsites[ent.id()][type] === undefined) return undefined; // should initialize it first. @@ -490,7 +493,7 @@ BaseManager.prototype.updateDropsite = function (gameState, ent, type) { }; // Updates dropsites. -BaseManager.prototype.updateDropsites = function (gameState) { +m.BaseManager.prototype.updateDropsites = function (gameState) { // for each dropsite, recalculate for (i in this.dropsites) { @@ -507,7 +510,7 @@ BaseManager.prototype.updateDropsites = function (gameState) { // we're assuming Max - 3 for metal/stone mines, and 20 for any dropsite that has wood. // TODO: for wood might want to count the trees too. // TODO: this returns "future" worker capacity, might want to have a current one. -BaseManager.prototype.getWorkerCapacity = function (gameState, type) { +m.BaseManager.prototype.getWorkerCapacity = function (gameState, type) { var count = 0; if (type == "food") return 1000000; // TODO: perhaps return something sensible here. @@ -530,12 +533,12 @@ BaseManager.prototype.getWorkerCapacity = function (gameState, type) { // TODO: ought to be cached or something probably // Returns the amount of resource left -BaseManager.prototype.getResourceLevel = function (gameState, type, searchType, threshold) { +m.BaseManager.prototype.getResourceLevel = function (gameState, type, searchType, threshold) { var count = 0; if (searchType == "all") { // return all resources in the base area. - gameState.getResourceSupplies(type).filter(Filters.byTerritory(gameState.ai.HQ.basesMap, this.ID)).forEach( function (ent) { //}){ + gameState.getResourceSupplies(type).filter(API3.Filters.byTerritory(gameState.ai.HQ.basesMap, this.ID)).forEach( function (ent) { //}){ count += ent.resourceSupplyAmount(); }); return count; @@ -574,7 +577,7 @@ BaseManager.prototype.getResourceLevel = function (gameState, type, searchType, }; // check our resource levels and react accordingly -BaseManager.prototype.checkResourceLevels = function (gameState,queues) { +m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) { for (type in this.willGather) { if (this.willGather[type] === 0) @@ -589,9 +592,9 @@ BaseManager.prototype.checkResourceLevels = function (gameState,queues) { if (!this.isFarming && count < 1600 && queues.field.length === 0) { // tell the queue manager we'll be trying to build fields shortly. - for (var i = 0; i < Config.Economy.initialFields;++i) + for (var i = 0; i < this.Config.Economy.initialFields;++i) { - var plan = new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }); + var plan = new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }); plan.isGo = function() { return false; }; // don't start right away. queues.field.addItem(plan); } @@ -604,7 +607,7 @@ BaseManager.prototype.checkResourceLevels = function (gameState,queues) { if (this.isFarming) { var numFarms = 0; - this.buildings.filter(Filters.byClass("Field")).forEach(function (field) { + this.buildings.filter(API3.Filters.byClass("Field")).forEach(function (field) { if (field.resourceSupplyAmount() > 400) numFarms++; }); @@ -615,7 +618,7 @@ BaseManager.prototype.checkResourceLevels = function (gameState,queues) { // let's see if we need to push new farms. if (numFd < 2) if (numFarms < Math.round(this.gatherersByType(gameState, "food").length / 4.6) || numFarms < Math.round(this.workers.length / 15.0)) - queues.field.addItem(new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID })); + queues.field.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID })); // TODO: refine count to only count my base. } } else if (queues.dropsites.length() === 0 && gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_storehouse")) === 0) { @@ -626,12 +629,12 @@ BaseManager.prototype.checkResourceLevels = function (gameState,queues) { var pos = this.findBestDropsiteLocation(gameState, type); if (!pos) { - debug ("Found no right position for a " + type + " dropsite, going into \"noSpot\" mode"); + m.debug ("Found no right position for a " + type + " dropsite, going into \"noSpot\" mode"); this.willGather[type] = 2; // won't build // TODO: tell the HQ we'll be needing a new base for this resource, or tell it we've ran out of resource Z. } else { - debug ("planning new dropsite for " + type); - queues.dropsites.addItem(new ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : this.ID }, 0, -1, pos)); + m.debug ("planning new dropsite for " + type); + queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : this.ID }, 0, -1, pos)); } } } @@ -640,13 +643,13 @@ BaseManager.prototype.checkResourceLevels = function (gameState,queues) { }; // let's return the estimated gather rates. -BaseManager.prototype.getGatherRates = function(gameState, currentRates) { +m.BaseManager.prototype.getGatherRates = function(gameState, currentRates) { }; -BaseManager.prototype.assignRolelessUnits = function(gameState) { +m.BaseManager.prototype.assignRolelessUnits = function(gameState) { // TODO: make this cleverer. - var roleless = this.units.filter(Filters.not(Filters.byHasMetadata(PlayerID, "role"))); + var roleless = this.units.filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "role"))); var self = this; roleless.forEach(function(ent) { if (ent.hasClass("Worker") || ent.hasClass("CitizenSoldier")) { @@ -660,7 +663,7 @@ BaseManager.prototype.assignRolelessUnits = function(gameState) { // If the numbers of workers on the resources is unbalanced then set some of workers to idle so // they can be reassigned by reassignIdleWorkers. // TODO: actually this probably should be in the HQ. -BaseManager.prototype.setWorkersIdleByPriority = function(gameState){ +m.BaseManager.prototype.setWorkersIdleByPriority = function(gameState){ var self = this; if (gameState.currentPhase() < 2 && gameState.getTimeElapsed() < 360000) return; // not in the first phase or the first 6 minutes. @@ -685,7 +688,7 @@ BaseManager.prototype.setWorkersIdleByPriority = function(gameState){ this.gatherersByType(gameState,types.types[i]).forEach( function (ent) { //}){ if (nb > 0) { - //debug ("Moving " +ent.id() + " from " + types.types[i]); + //m.debug ("Moving " +ent.id() + " from " + types.types[i]); nb--; // TODO: might want to direct assign. ent.stopMoving(); @@ -693,16 +696,16 @@ BaseManager.prototype.setWorkersIdleByPriority = function(gameState){ } }); } - //debug (currentRates); + //m.debug (currentRates); }; // TODO: work on this. -BaseManager.prototype.reassignIdleWorkers = function(gameState) { +m.BaseManager.prototype.reassignIdleWorkers = function(gameState) { var self = this; // Search for idle workers, and tell them to gather resources based on demand - var filter = Filters.or(Filters.byMetadata(PlayerID,"subrole","idle"), Filters.not(Filters.byHasMetadata(PlayerID,"subrole"))); + var filter = API3.Filters.or(API3.Filters.byMetadata(PlayerID,"subrole","idle"), API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"subrole"))); var idleWorkers = gameState.updatingCollection("idle-workers-base-" + this.ID, filter, this.workers); if (idleWorkers.length) { @@ -713,7 +716,7 @@ BaseManager.prototype.reassignIdleWorkers = function(gameState) { } if (ent.hasClass("Worker")) { var types = gameState.ai.HQ.pickMostNeededResources(gameState); - //debug ("assigning " +ent.id() + " to " + types[0]); + //m.debug ("assigning " +ent.id() + " to " + types[0]); ent.setMetadata(PlayerID, "subrole", "gatherer"); ent.setMetadata(PlayerID, "gather-type", types[0]); @@ -734,21 +737,21 @@ BaseManager.prototype.reassignIdleWorkers = function(gameState) { } }; -BaseManager.prototype.workersBySubrole = function(gameState, subrole) { - return gameState.updatingCollection("subrole-" + subrole +"-base-" + this.ID, Filters.byMetadata(PlayerID, "subrole", subrole), this.workers, true); +m.BaseManager.prototype.workersBySubrole = function(gameState, subrole) { + return gameState.updatingCollection("subrole-" + subrole +"-base-" + this.ID, API3.Filters.byMetadata(PlayerID, "subrole", subrole), this.workers, true); }; -BaseManager.prototype.gatherersByType = function(gameState, type) { - return gameState.updatingCollection("workers-gathering-" + type +"-base-" + this.ID, Filters.byMetadata(PlayerID, "gather-type", type), this.workersBySubrole(gameState, "gatherer")); +m.BaseManager.prototype.gatherersByType = function(gameState, type) { + return gameState.updatingCollection("workers-gathering-" + type +"-base-" + this.ID, API3.Filters.byMetadata(PlayerID, "gather-type", type), this.workersBySubrole(gameState, "gatherer")); }; // returns an entity collection of workers. // They are idled immediatly and their subrole set to idle. -BaseManager.prototype.pickBuilders = function(gameState, number) { - var collec = new EntityCollection(gameState.sharedScript); +m.BaseManager.prototype.pickBuilders = function(gameState, number) { + var collec = new API3.EntityCollection(gameState.sharedScript); // TODO: choose better. - var workers = this.workers.filter(Filters.not(Filters.byClass("Cavalry"))).toEntityArray(); + var workers = this.workers.filter(API3.Filters.not(API3.Filters.byClass("Cavalry"))).toEntityArray(); workers.sort(function (a,b) { var vala = 0, valb = 0; if (a.getMetadata(PlayerID,"subrole") == "builder") @@ -770,7 +773,8 @@ BaseManager.prototype.pickBuilders = function(gameState, number) { return collec; } -BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { +m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { + // If we have some foundations, and we don't have enough builder-workers, // try reassigning some other workers who are nearby @@ -778,21 +782,21 @@ BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { var self = this; - var foundations = this.buildings.filter(Filters.and(Filters.isFoundation(),Filters.not(Filters.byClass("Field")))).toEntityArray(); + var foundations = this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(),API3.Filters.not(API3.Filters.byClass("Field")))).toEntityArray(); var damagedBuildings = this.buildings.filter(function (ent) { if (ent.needsRepair() && ent.getMetadata(PlayerID, "plan") == undefined) { return true; } return false; }).toEntityArray(); // Check if nothing to build if (!foundations.length && !damagedBuildings.length){ return; } - var workers = this.workers.filter(Filters.not(Filters.byClass("Cavalry"))); + var workers = this.workers.filter(API3.Filters.not(API3.Filters.byClass("Cavalry"))); var builderWorkers = this.workersBySubrole(gameState, "builder"); - var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter(Filters.isIdle()); + var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter(API3.Filters.isIdle()); // if we're constructing and we have the foundations to our base anchor, only try building that. - if (this.constructing == true && this.buildings.filter(Filters.and(Filters.isFoundation(), Filters.byMetadata(PlayerID, "baseAnchor", true))).length !== 0) + if (this.constructing == true && this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(), API3.Filters.byMetadata(PlayerID, "baseAnchor", true))).length !== 0) { - foundations = this.buildings.filter(Filters.byMetadata(PlayerID, "baseAnchor", true)).toEntityArray(); + foundations = this.buildings.filter(API3.Filters.byMetadata(PlayerID, "baseAnchor", true)).toEntityArray(); var tID = foundations[0].id(); workers.forEach(function (ent) { //}){ var target = ent.getMetadata(PlayerID, "target-foundation"); @@ -832,7 +836,7 @@ BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length; - var targetNB = Config.Economy.targetNumBuilders; // TODO: dynamic that. + var targetNB = this.Config.Economy.targetNumBuilders; // TODO: dynamic that. if (target.hasClass("CivCentre") || target.buildTime() > 150 || target.hasClass("House")) targetNB *= 2; if (target.getMetadata(PlayerID, "baseAnchor") == true) @@ -844,7 +848,7 @@ BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { var addedToThis = 0; idleBuilderWorkers.forEach(function(ent) { - if (ent.position() && SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB) + if (ent.position() && API3.SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB) { addedWorkers++; addedToThis++; @@ -876,7 +880,7 @@ BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { } else if (noRepair && !target.hasClass("CivCentre")) continue; - var territory = Map.createTerritoryMap(gameState); + var territory = m.createTerritoryMap(gameState); if (territory.getOwner(target.position()) !== PlayerID || territory.getOwner([target.position()[0] + 5, target.position()[1]]) !== PlayerID) continue; @@ -900,7 +904,7 @@ BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { } }; -BaseManager.prototype.update = function(gameState, queues, events) { +m.BaseManager.prototype.update = function(gameState, queues, events) { Engine.ProfileStart("Base update - base " + this.ID); var self = this; @@ -957,10 +961,14 @@ BaseManager.prototype.update = function(gameState, queues, events) { Engine.ProfileStart("Run Workers"); this.workers.forEach(function(ent) { if (!ent.getMetadata(PlayerID, "worker-object")) - ent.setMetadata(PlayerID, "worker-object", new Worker(ent)); + ent.setMetadata(PlayerID, "worker-object", new m.Worker(ent)); ent.getMetadata(PlayerID, "worker-object").update(self, gameState); }); Engine.ProfileStop(); Engine.ProfileStop(); }; + +return m; + +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/config.js b/binaries/data/mods/public/simulation/ai/aegis/config.js index 789999fcf9..41a5d4dc82 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/config.js +++ b/binaries/data/mods/public/simulation/ai/aegis/config.js @@ -1,6 +1,11 @@ -// Baseconfig is the highest difficulty. -var baseConfig = { - "Military" : { +var AEGIS = function(m) +{ + +m.Config = function() { + this.difficulty = 2; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. + // overriden by the GUI + + this.Military = { "fortressLapseTime" : 540, // Time to wait between building 2 fortresses "defenceBuildingTime" : 600, // Time to wait before building towers or fortresses "attackPlansStartTime" : 0, // time to wait before attacking. Start as soon as possible (first barracks) @@ -8,8 +13,8 @@ var baseConfig = { "popForBarracks1" : 15, "popForBarracks2" : 95, "timeForBlacksmith" : 900, - }, - "Economy" : { + }; + this.Economy = { "townPhase" : 180, // time to start trying to reach town phase (might be a while after. Still need the requirements + ress ) "cityPhase" : 840, // time to start trying to reach city phase "popForMarket" : 80, @@ -19,19 +24,21 @@ var baseConfig = { "targetNumBuilders" : 1.5, // Base number of builders per foundation. "femaleRatio" : 0.4, // percent of females among the workforce. "initialFields" : 2 - }, + }; // Note: attack settings are set directly in attack_plan.js // defence - "Defence" : { + this.Defence = + { "defenceRatio" : 5, // see defence.js for more info. "armyCompactSize" : 700, // squared. Half-diameter of an army. "armyBreakawaySize" : 900 // squared. - }, + }; // military - "buildings" : { + this.buildings = + { "moderate" : { "default" : [ "structures/{civ}_barracks" ] }, @@ -51,10 +58,11 @@ var baseConfig = { "default" : [ "structures/{civ}_fortress" ], "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ] } - }, + }; // qbot - "priorities" : { // Note these are dynamic, you are only setting the initial values + this.priorities = + { // Note these are dynamic, you are only setting the initial values "house" : 350, "villager" : 40, "citizenSoldier" : 60, @@ -67,49 +75,46 @@ var baseConfig = { "majorTech" : 700, "minorTech" : 50, "civilCentre" : 400 - }, - "difficulty" : 2, // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. - "debug" : false + }; }; -var Config = { - "debug": false, - "difficulty" : 2, // overriden by the GUI - updateDifficulty: function(difficulty) +//Config.prototype = new BaseConfig(); + +m.Config.prototype.updateDifficulty = function(difficulty) +{ + this.difficulty = difficulty; + // changing settings based on difficulty. + if (this.difficulty === 1) { - Config.difficulty = difficulty; - // changing settings based on difficulty. - if (Config.difficulty === 1) - { - Config.Military.defenceBuildingTime = 1200; - Config.Military.attackPlansStartTime = 960; - Config.Military.popForBarracks1 = 35; - Config.Military.popForBarracks2 = 150; // shouldn't reach it - Config.Military.popForBlacksmith = 150; // shouldn't reach it + this.Military.defenceBuildingTime = 1200; + this.Military.attackPlansStartTime = 960; + this.Military.popForBarracks1 = 35; + this.Military.popForBarracks2 = 150; // shouldn't reach it + this.Military.popForBlacksmith = 150; // shouldn't reach it - Config.Economy.cityPhase = 1800; - Config.Economy.popForMarket = 80; - Config.Economy.techStartTime = 600; - Config.Economy.femaleRatio = 0.6; - Config.Economy.initialFields = 1; - // Config.Economy.targetNumWorkers will be set by AI scripts. - } - else if (Config.difficulty === 0) - { - Config.Military.defenceBuildingTime = 450; - Config.Military.attackPlansStartTime = 9600000; // never - Config.Military.popForBarracks1 = 60; - Config.Military.popForBarracks2 = 150; // shouldn't reach it - Config.Military.popForBlacksmith = 150; // shouldn't reach it + this.Economy.cityPhase = 1800; + this.Economy.popForMarket = 80; + this.Economy.techStartTime = 600; + this.Economy.femaleRatio = 0.6; + this.Economy.initialFields = 1; + // Config.Economy.targetNumWorkers will be set by AI scripts. + } + else if (this.difficulty === 0) + { + this.Military.defenceBuildingTime = 450; + this.Military.attackPlansStartTime = 9600000; // never + this.Military.popForBarracks1 = 60; + this.Military.popForBarracks2 = 150; // shouldn't reach it + this.Military.popForBlacksmith = 150; // shouldn't reach it - Config.Economy.cityPhase = 240000; - Config.Economy.popForMarket = 200; - Config.Economy.techStartTime = 1800; - Config.Economy.femaleRatio = 0.2; - Config.Economy.initialFields = 1; - // Config.Economy.targetNumWorkers will be set by AI scripts. - } + this.Economy.cityPhase = 240000; + this.Economy.popForMarket = 200; + this.Economy.techStartTime = 1800; + this.Economy.femaleRatio = 0.2; + this.Economy.initialFields = 1; + // Config.Economy.targetNumWorkers will be set by AI scripts. } }; -Config.__proto__ = baseConfig; +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/data.json b/binaries/data/mods/public/simulation/ai/aegis/data.json index 4aeb576372..0ec1529b25 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/data.json +++ b/binaries/data/mods/public/simulation/ai/aegis/data.json @@ -1,6 +1,7 @@ { "name": "Aegis Bot", "description": "Wraitii's improvement of qBot. It is more reliable and generally a better player. Note that it doesn't support saved games yet, and there may be other bugs. Please report issues to Wildfire Games (see the link in the main menu).", + "moduleName" : "AEGIS", "constructor": "AegisBot", "useShared": true } diff --git a/binaries/data/mods/public/simulation/ai/aegis/defence.js b/binaries/data/mods/public/simulation/ai/aegis/defence.js index be768c3a41..f666daf66d 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/defence.js +++ b/binaries/data/mods/public/simulation/ai/aegis/defence.js @@ -1,6 +1,9 @@ +var AEGIS = function(m) +{ + // directly imported from Marilyn, with slight modifications to work with qBot. -function Defence(){ +m.Defence = function(Config){ this.defenceRatio = Config.Defence.defenceRatio;// How many defenders we want per attacker. Need to balance fewer losses vs. lost economy // note: the choice should be a no-brainer most of the time: better deflect the attack. // This is also sometimes forcebly overcome by the defense manager. @@ -48,36 +51,36 @@ function Defence(){ // 1: Huge army in the base, outnumbering us. -Defence.prototype.update = function(gameState, events, HQ){ +m.Defence.prototype.update = function(gameState, events, HQ){ Engine.ProfileStart("Defence Manager"); // a litlle cache-ing if (!this.idleDefs) { - var filter = Filters.and(Filters.byMetadata(PlayerID, "role", "defence"), Filters.isIdle()); + var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "role", "defence"), API3.Filters.isIdle()); this.idleDefs = gameState.getOwnEntities().filter(filter); this.idleDefs.registerUpdates(); } if (!this.defenders) { - var filter = Filters.byMetadata(PlayerID, "role", "defence"); + var filter = API3.Filters.byMetadata(PlayerID, "role", "defence"); this.defenders = gameState.getOwnEntities().filter(filter); this.defenders.registerUpdates(); } /*if (!this.listedEnemyCollection) { - var filter = Filters.byMetadata(PlayerID, "listed-enemy", true); + var filter = API3.Filters.byMetadata(PlayerID, "listed-enemy", true); this.listedEnemyCollection = gameState.getEnemyEntities().filter(filter); this.listedEnemyCollection.registerUpdates(); } - this.myBuildings = gameState.getOwnEntities().filter(Filters.byClass("Structure")).toEntityArray(); - this.myUnits = gameState.getOwnEntities().filter(Filters.byClass("Unit")); + this.myBuildings = gameState.getOwnEntities().filter(API3.Filters.byClass("Structure")).toEntityArray(); + this.myUnits = gameState.getOwnEntities().filter(API3.Filters.byClass("Unit")); */ - var filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), Filters.byOwner(PlayerID)); + var filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(PlayerID)); this.myUnits = gameState.updatingGlobalCollection("player-" +PlayerID + "-soldiers", filter); - filter = Filters.and(Filters.byClass("Structure"), Filters.byOwner(PlayerID)); + filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(PlayerID)); this.myBuildings = gameState.updatingGlobalCollection("player-" +PlayerID + "-structures", filter); - this.territoryMap = Map.createTerritoryMap(gameState); // used by many func + this.territoryMap = m.createTerritoryMap(gameState); // used by many func // First step: we deal with enemy armies, those are the highest priority. this.defendFromEnemies(gameState, events, HQ); @@ -118,7 +121,7 @@ Defence.prototype.reevaluateDangerousArmies = function(gameState, armies) { } for (var o in this.myBuildings) { // if the armies out of my buildings LOS (with a little more, because we're cheating right now and big armies could go undetected) - if (inRange(pos, this.myBuildings[o].position(),this.myBuildings[o].visionRange()*this.myBuildings[o].visionRange() + 2500)) { + if (m.inRange(pos, this.myBuildings[o].position(),this.myBuildings[o].visionRange()*this.myBuildings[o].visionRange() + 2500)) { stillDangerousArmies[i] = armies[i]; break; } @@ -138,7 +141,7 @@ Defence.prototype.evaluateArmies = function(gameState, armies) { }*/ // Incorporates an entity in an army. If no army fits, it creates a new one around this one. // an army is basically an entity collection. -Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { +m.Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { if (entity.position() === undefined) return; if (this.enemyArmy[entity.owner()] === undefined) @@ -151,7 +154,7 @@ Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { if (army.getCentrePosition() === undefined) { } else { - if (SquareVectorDistance(army.getCentrePosition(), entity.position()) < this.armyCompactSize) + if (API3.SquareVectorDistance(army.getCentrePosition(), entity.position()) < this.armyCompactSize) { entity.setMetadata(PlayerID, "inArmy", armyIndex); army.addEnt(entity); @@ -163,11 +166,11 @@ Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { if (HQ) { var self = this; - var close = HQ.enemyWatchers[entity.owner()].enemySoldiers.filter(Filters.byDistance(entity.position(), self.armyCompactSize)); + var close = HQ.enemyWatchers[entity.owner()].enemySoldiers.filter(API3.Filters.byDistance(entity.position(), self.armyCompactSize)); if (!minNBForArmy || close.length >= minNBForArmy) { // if we're here, we need to create an army for it, and freeze it to make sure no unit will be added automatically - var newArmy = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(entity.owner())]); + var newArmy = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(entity.owner())]); newArmy.addEnt(entity); newArmy.freeze(); newArmy.registerUpdates(); @@ -184,7 +187,7 @@ Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { } } else { // if we're here, we need to create an army for it, and freeze it to make sure no unit will be added automatically - var newArmy = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(entity.owner())]); + var newArmy = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(entity.owner())]); newArmy.addEnt(entity); newArmy.freeze(); newArmy.registerUpdates(); @@ -195,12 +198,12 @@ Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { return; } // Returns if a unit should be seen as dangerous or not. -Defence.prototype.evaluateRawEntity = function(gameState, entity) { +m.Defence.prototype.evaluateRawEntity = function(gameState, entity) { if (entity.position && +this.territoryMap.point(entity.position) - 64 === +PlayerID && entity._template.Attack !== undefined) return true; return false; } -Defence.prototype.evaluateEntity = function(gameState, entity) { +m.Defence.prototype.evaluateEntity = function(gameState, entity) { if (!entity.position()) return false; if (this.territoryMap.point(entity.position()) - 64 === entity.owner() || entity.attackTypes() === undefined) @@ -210,20 +213,20 @@ Defence.prototype.evaluateEntity = function(gameState, entity) { { if (!this.myBuildings._entities[i].hasClass("ConquestCritical")) continue; - if (SquareVectorDistance(this.myBuildings._entities[i].position(), entity.position()) < 6000) + if (API3.SquareVectorDistance(this.myBuildings._entities[i].position(), entity.position()) < 6000) return true; } return false; } // returns false if the unit is in its territory -Defence.prototype.reevaluateEntity = function(gameState, entity) { +m.Defence.prototype.reevaluateEntity = function(gameState, entity) { if ( (entity.position() && +this.territoryMap.point(entity.position()) - 64 === +entity.owner()) || entity.attackTypes() === undefined) return false; return true; } // This deals with incoming enemy armies, setting the defcon if needed. It will take new soldiers, and assign them to attack // TODO: still is still pretty dumb, it could use improvements. -Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { +m.Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { var self = this; // New, faster system will loop for enemy soldiers, and also females on occasions ( TODO ) @@ -313,7 +316,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { } else { army.forEach(function (ent) { //}){ // check if the unit is a breakaway - if (ent.position() && SquareVectorDistance(position, ent.position()) > self.armyBreakawaySize) + if (ent.position() && API3.SquareVectorDistance(position, ent.position()) > self.armyBreakawaySize) { ent.setMetadata(PlayerID, "inArmy", undefined); army.removeEnt(ent); @@ -322,12 +325,12 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { } else { // check if we have registered that unit already. if (self.listOfEnemies[ent.id()] === undefined) { - self.listOfEnemies[ent.id()] = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(ent.owner())]); + self.listOfEnemies[ent.id()] = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(ent.owner())]); self.listOfEnemies[ent.id()].freeze(); self.listOfEnemies[ent.id()].addEnt(ent); self.listOfEnemies[ent.id()].registerUpdates(); - self.attackerCache[ent.id()] = self.myUnits.filter(Filters.byTargetedEntity(ent.id())); + self.attackerCache[ent.id()] = self.myUnits.filter(API3.Filters.byTargetedEntity(ent.id())); self.attackerCache[ent.id()].registerUpdates(); nbOfAttackers++; self.nbAttackers++; @@ -373,7 +376,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { if (this.nbAttackers === 0 && this.nbDefenders === 0) { // Release all our units - this.myUnits.filter(Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ + this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ defender.stopMoving(); if (defender.getMetadata(PlayerID, "formerrole")) defender.setMetadata(PlayerID, "role", defender.getMetadata(PlayerID, "formerrole") ); @@ -387,7 +390,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { return; } else if (this.nbAttackers === 0 && this.nbDefenders !== 0) { // Release all our units - this.myUnits.filter(Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ + this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ defender.stopMoving(); if (defender.getMetadata(PlayerID, "formerrole")) defender.setMetadata(PlayerID, "role", defender.getMetadata(PlayerID, "formerrole") ); @@ -404,8 +407,8 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { HQ.ungarrisonAll(gameState); } - //debug ("total number of attackers:"+ this.nbAttackers); - //debug ("total number of defenders:"+ this.nbDefenders); + //m.debug ("total number of attackers:"+ this.nbAttackers); + //m.debug ("total number of defenders:"+ this.nbDefenders); // If I'm here, I have a list of enemy units, and a list of my units attacking it (in absolute terms, I could use a list of any unit attacking it). // now I'll list my idle defenders, then my idle soldiers that could defend. @@ -419,8 +422,8 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { } // we're having too many. Release those that attack units already dealt with, or idle ones. - if (this.myUnits.filter(Filters.byMetadata(PlayerID, "role","defence")).length > nbOfAttackers*this.defenceRatio*1.2) { - this.myUnits.filter(Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ + if (this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).length > nbOfAttackers*this.defenceRatio*1.2) { + this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ if ( defender.isIdle() || (defender.unitAIOrderData() && defender.unitAIOrderData()["target"])) { if ( defender.isIdle() || (self.attackerCache[defender.unitAIOrderData()["target"]] && self.attackerCache[defender.unitAIOrderData()["target"]].length > 3)) { // okay release me. @@ -437,9 +440,9 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { } - var nonDefenders = this.myUnits.filter(Filters.or(Filters.not(Filters.byMetadata(PlayerID, "role","defence")),Filters.isIdle())); - nonDefenders = nonDefenders.filter(Filters.not(Filters.byClass("Female"))); - nonDefenders = nonDefenders.filter(Filters.not(Filters.byMetadata(PlayerID, "subrole","attacking"))); + var nonDefenders = this.myUnits.filter(API3.Filters.or(API3.Filters.not(API3.Filters.byMetadata(PlayerID, "role","defence")),API3.Filters.isIdle())); + nonDefenders = nonDefenders.filter(API3.Filters.not(API3.Filters.byClass("Female"))); + nonDefenders = nonDefenders.filter(API3.Filters.not(API3.Filters.byMetadata(PlayerID, "subrole","attacking"))); var defenceRatio = this.defenceRatio; if (newEnemies.length + this.nbAttackers > (this.nbDefenders + nonDefenders.length) * 0.8 && this.nbAttackers > 9) @@ -448,8 +451,8 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { if (newEnemies.length + this.nbAttackers > (this.nbDefenders + nonDefenders.length) * 1.5 && this.nbAttackers > 5) gameState.setDefcon(1); - //debug ("newEnemies.length "+ newEnemies.length); - //debug ("nonDefenders.length "+ nonDefenders.length); + //m.debug ("newEnemies.length "+ newEnemies.length); + //m.debug ("nonDefenders.length "+ nonDefenders.length); if (gameState.defcon() > 3) HQ.unpauseAllPlans(gameState); @@ -457,7 +460,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { if ( (nonDefenders.length + this.nbDefenders > newEnemies.length + this.nbAttackers) || this.nbDefenders + nonDefenders.length < 4) { - var buildings = gameState.getOwnEntities().filter(Filters.byCanGarrison()).toEntityArray(); + var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); buildings.forEach( function (struct) { if (struct.garrisoned() && struct.garrisoned().length) struct.unloadAll(); @@ -513,7 +516,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { { var ent = nonDefenders._entities[id]; if (ent.position()) - data.push([id, ent, SquareVectorDistance(enemy.position(), ent.position())]); + data.push([id, ent, API3.SquareVectorDistance(enemy.position(), ent.position())]); } // refine the defenders we want. Since it's the distance squared, it has the effect // of tending to always prefer closer units, though this refinement should change it slighty. @@ -547,13 +550,13 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { for each (var val in data.slice(0, Math.min(nonDefenders._length, defRatio - assigned))) ret[val[0]] = val[1]; - var defs = new EntityCollection(nonDefenders._ai, ret); + var defs = new API3.EntityCollection(nonDefenders._ai, ret); // successfully sorted defs.forEach(function (defender) { //}){ if (defender.getMetadata(PlayerID, "plan") != undefined && (gameState.defcon() < 4 || defender.getMetadata(PlayerID,"subrole") == "walking")) HQ.pausePlan(gameState, defender.getMetadata(PlayerID, "plan")); - //debug ("Against " +enemy.id() + " Assigning " + defender.id()); + //m.debug ("Against " +enemy.id() + " Assigning " + defender.id()); if (defender.getMetadata(PlayerID, "role") == "worker" || defender.getMetadata(PlayerID, "role") == "attack") defender.setMetadata(PlayerID, "formerrole", defender.getMetadata(PlayerID, "role")); defender.setMetadata(PlayerID, "role","defence"); @@ -571,8 +574,8 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { /*if (gameState.defcon() <= 3) { // let's try to garrison neighboring females. - var buildings = gameState.getOwnEntities().filter(Filters.byCanGarrison()).toEntityArray(); - var females = gameState.getOwnEntities().filter(Filters.byClass("Support")); + var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); + var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support")); var cache = {}; var garrisoned = false; @@ -580,7 +583,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { garrisoned = false; if (ent.position()) { - if (SquareVectorDistance(ent.position(), enemy.position()) < 3500) + if (API3.SquareVectorDistance(ent.position(), enemy.position()) < 3500) { for (var i in buildings) { @@ -611,7 +614,7 @@ Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { // this processes the attackmessages // So that a unit that gets attacked will not be completely dumb. // warning: huge levels of indentation coming. -Defence.prototype.MessageProcess = function(gameState,events, HQ) { +m.Defence.prototype.MessageProcess = function(gameState,events, HQ) { var self = this; for (var key in events){ @@ -646,12 +649,12 @@ Defence.prototype.MessageProcess = function(gameState,events, HQ) { if (territory === PlayerID) { // anyway we'll register the animal as dangerous, and attack it (note: only on our territory. Don't care otherwise). - this.listOfWantedUnits[attacker.id()] = new EntityCollection(gameState.sharedScript); + this.listOfWantedUnits[attacker.id()] = new API3.EntityCollection(gameState.sharedScript); this.listOfWantedUnits[attacker.id()].addEnt(attacker); this.listOfWantedUnits[attacker.id()].freeze(); this.listOfWantedUnits[attacker.id()].registerUpdates(); - var filter = Filters.byTargetedEntity(attacker.id()); + var filter = API3.Filters.byTargetedEntity(attacker.id()); this.WantedUnitsAttacker[attacker.id()] = this.myUnits.filter(filter); this.WantedUnitsAttacker[attacker.id()].registerUpdates(); } @@ -666,7 +669,7 @@ Defence.prototype.MessageProcess = function(gameState,events, HQ) { // Right now, to make the AI less gameable, we'll mark any surrounding resource as inaccessible. // usual tower range is 80. Be on the safe side. - var close = gameState.getResourceSupplies("wood").filter(Filters.byDistance(attacker.position(), 90)); + var close = gameState.getResourceSupplies("wood").filter(API3.Filters.byDistance(attacker.position(), 90)); close.forEach(function (supply) { //}){ supply.setMetadata(PlayerID, "inaccessible", true); }); @@ -683,7 +686,7 @@ Defence.prototype.MessageProcess = function(gameState,events, HQ) { if (this.reevaluateEntity(gameState, attacker)) { var position = attacker.position(); - var close = HQ.enemyWatchers[attacker.owner()].enemySoldiers.filter(Filters.byDistance(position, self.armyCompactSize)); + var close = HQ.enemyWatchers[attacker.owner()].enemySoldiers.filter(API3.Filters.byDistance(position, self.armyCompactSize)); if (close.length > 2 || ourUnit.hasClass("Support") || attacker.hasClass("Siege")) { @@ -692,7 +695,7 @@ Defence.prototype.MessageProcess = function(gameState,events, HQ) { armyID = attacker.getMetadata(PlayerID, "inArmy"); close.forEach(function (ent) { //}){ - if (SquareVectorDistance(position, ent.position()) < self.armyCompactSize) + if (API3.SquareVectorDistance(position, ent.position()) < self.armyCompactSize) { ent.setMetadata(PlayerID, "inArmy", armyID); self.enemyArmy[ent.owner()][armyID].addEnt(ent); @@ -708,7 +711,7 @@ Defence.prototype.MessageProcess = function(gameState,events, HQ) { // let's try to garrison this support unit. if (ourUnit.position()) { - var buildings = gameState.getOwnEntities().filter(Filters.byCanGarrison()).filterNearest(ourUnit.position(),4).toEntityArray(); + var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).filterNearest(ourUnit.position(),4).toEntityArray(); var garrisoned = false; for (var i in buildings) { @@ -742,7 +745,7 @@ Defence.prototype.MessageProcess = function(gameState,events, HQ) { }; // nice sets of closing brackets, isn't it? // At most, this will put defcon to 4 -Defence.prototype.DealWithWantedUnits = function(gameState, events, HQ) { +m.Defence.prototype.DealWithWantedUnits = function(gameState, events, HQ) { //if (gameState.defcon() < 3) // return; @@ -841,3 +844,6 @@ Defence.prototype.DealWithWantedUnits = function(gameState, events, HQ) { } return; } + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js b/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js index 0256e48433..873ca49527 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js +++ b/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js @@ -1,32 +1,35 @@ +var AEGIS = function(m) +{ + /* * A class that keeps track of enemy buildings, units, and pretty much anything I can think of (still a LOT TODO here) * Only watches one enemy, you'll need one per enemy. * Note: pretty much unused in the current version. */ -var enemyWatcher = function(gameState, playerToWatch) { +m.enemyWatcher = function(gameState, playerToWatch) { this.watched = playerToWatch; // using global entity collections, shared by any AI that knows the name of this. - var filter = Filters.and(Filters.byClass("Structure"), Filters.byOwner(this.watched)); + var filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(this.watched)); this.enemyBuildings = gameState.updatingGlobalCollection("player-" +this.watched + "-structures", filter); - filter = Filters.and(Filters.byClass("Unit"), Filters.byOwner(this.watched)); + filter = API3.Filters.and(API3.Filters.byClass("Unit"), API3.Filters.byOwner(this.watched)); this.enemyUnits = gameState.updatingGlobalCollection("player-" +this.watched + "-units", filter); - filter = Filters.and(Filters.byClass("Worker"), Filters.byOwner(this.watched)); + filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched)); this.enemyCivilians = gameState.updatingGlobalCollection("player-" +this.watched + "-civilians", filter); - filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), Filters.byOwner(this.watched)); + filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched)); this.enemySoldiers = gameState.updatingGlobalCollection("player-" +this.watched + "-soldiers", filter); - filter = Filters.and(Filters.byClass("Worker"), Filters.byOwner(this.watched)); + filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched)); this.enemyCivilians = gameState.getEnemyEntities().filter(filter); this.enemyCivilians.registerUpdates(); - filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), Filters.byOwner(this.watched)); + filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched)); this.enemySoldiers = gameState.getEnemyEntities().filter(filter); this.enemySoldiers.registerUpdates(); @@ -40,15 +43,15 @@ var enemyWatcher = function(gameState, playerToWatch) { this.dangerousArmies = []; }; -enemyWatcher.prototype.getAllEnemySoldiers = function() { +m.enemyWatcher.prototype.getAllEnemySoldiers = function() { return this.enemySoldiers; }; -enemyWatcher.prototype.getAllEnemyBuildings = function() { +m.enemyWatcher.prototype.getAllEnemyBuildings = function() { return this.enemyBuildings; }; -enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, OneTime) { - var filter = Filters.byClass(specialClass); +m.enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, OneTime) { + var filter = API3.Filters.byClass(specialClass); if (OneTime && gameState.getGEC("player-" +this.watched + "-structures-" +specialClass)) return gameState.getGEC("player-" +this.watched + "-structures-" +specialClass); @@ -57,55 +60,55 @@ enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, One return gameState.updatingGlobalCollection("player-" +this.watched + "-structures-" +specialClass, filter, gameState.getGEC("player-" +this.watched + "-structures")); }; -enemyWatcher.prototype.getDangerousArmies = function() { +m.enemyWatcher.prototype.getDangerousArmies = function() { var toreturn = {}; for (var i in this.dangerousArmies) toreturn[this.dangerousArmies[i]] = this.armies[this.dangerousArmies[i]]; return toreturn; }; -enemyWatcher.prototype.getSafeArmies = function() { +m.enemyWatcher.prototype.getSafeArmies = function() { var toreturn = {}; for (var i in this.armies) if (this.dangerousArmies.indexOf(i) == -1) toreturn[i] = this.armies[i]; return toreturn; }; -enemyWatcher.prototype.resetDangerousArmies = function() { +m.enemyWatcher.prototype.resetDangerousArmies = function() { this.dangerousArmies = []; }; -enemyWatcher.prototype.setAsDangerous = function(armyID) { +m.enemyWatcher.prototype.setAsDangerous = function(armyID) { if (this.dangerousArmies.indexOf(armyID) === -1) this.dangerousArmies.push(armyID); }; -enemyWatcher.prototype.isDangerous = function(armyID) { +m.enemyWatcher.prototype.isDangerous = function(armyID) { if (this.dangerousArmies.indexOf(armyID) === -1) return false; return true; }; // returns [id, army] -enemyWatcher.prototype.getArmyFromMember = function(memberID) { +m.enemyWatcher.prototype.getArmyFromMember = function(memberID) { for (var i in this.armies) { if (this.armies[i].toIdArray().indexOf(memberID) !== -1) return [i,this.armies[i]]; } return undefined; }; -enemyWatcher.prototype.isPartOfDangerousArmy = function(memberID) { +m.enemyWatcher.prototype.isPartOfDangerousArmy = function(memberID) { var armyID = this.getArmyFromMember(memberID)[0]; if (this.isDangerous(armyID)) return true; return false; }; -enemyWatcher.prototype.cleanDebug = function() { +m.enemyWatcher.prototype.cleanDebug = function() { for (var armyID in this.armies) { var army = this.armies[armyID]; - debug ("Army " +armyID); - debug (army.length +" members, centered around " +army.getCentrePosition()); + m.debug ("Army " +armyID); + m.debug (army.length +" members, centered around " +army.getCentrePosition()); } } // this will monitor any unmonitored soldier. -enemyWatcher.prototype.detectArmies = function(gameState){ +m.enemyWatcher.prototype.detectArmies = function(gameState){ //this.cleanDebug(); var self = this; @@ -121,7 +124,7 @@ enemyWatcher.prototype.detectArmies = function(gameState){ var armyID = gameState.player + "" + self.totalNBofArmies; self.totalNBofArmies++, enemy.setMetadata(PlayerID, "EnemyWatcherArmy",armyID); - var filter = Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID); + var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID); var army = self.enemySoldiers.filter(filter); self.armies[armyID] = army; self.armies[armyID].registerUpdates(); @@ -140,7 +143,7 @@ enemyWatcher.prototype.detectArmies = function(gameState){ }; // this will merge any two army who are too close together. The distance for "army" is fairly big. // note: this doesn't actually merge two entity collections... It simply changes the unit metadatas, and will clear the empty entity collection -enemyWatcher.prototype.mergeArmies = function(){ +m.enemyWatcher.prototype.mergeArmies = function(){ for (var army in this.armies) { var firstArmy = this.armies[army]; if (firstArmy.length !== 0) { @@ -149,7 +152,7 @@ enemyWatcher.prototype.mergeArmies = function(){ if (otherArmy !== army && this.armies[otherArmy].length !== 0) { var secondArmy = this.armies[otherArmy]; // we're not self merging, so we check if the two armies are close together - if (inRange(firstAPos,secondArmy.getApproximatePosition(4), 4000 ) ) { + if (m.inRange(firstAPos,secondArmy.getApproximatePosition(4), 4000 ) ) { // okay so we merge the two together // if the other one was dangerous and we weren't, we're now. @@ -166,7 +169,7 @@ enemyWatcher.prototype.mergeArmies = function(){ } this.ScrapEmptyArmies(); }; -enemyWatcher.prototype.ScrapEmptyArmies = function(){ +m.enemyWatcher.prototype.ScrapEmptyArmies = function(){ var removelist = []; for (var army in this.armies) { if (this.armies[army].length === 0) { @@ -181,10 +184,10 @@ enemyWatcher.prototype.ScrapEmptyArmies = function(){ } }; // splits any unit too far from the centerposition -enemyWatcher.prototype.splitArmies = function(gameState){ +m.enemyWatcher.prototype.splitArmies = function(gameState){ var self = this; - var map = Map.createTerritoryMap(gameState); + var map = m.createTerritoryMap(gameState); for (var armyID in this.armies) { var army = this.armies[armyID]; @@ -197,14 +200,14 @@ enemyWatcher.prototype.splitArmies = function(gameState){ if (enemy.position() === undefined) return; - if (!inRange(enemy.position(),centre, 3500) ) { + if (!m.inRange(enemy.position(),centre, 3500) ) { var newArmyID = gameState.player + "" + self.totalNBofArmies; if (self.dangerousArmies.indexOf(armyID) !== -1) self.dangerousArmies.push(newArmyID); self.totalNBofArmies++, enemy.setMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); - var filter = Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); + var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); var newArmy = self.enemySoldiers.filter(filter); self.armies[newArmyID] = newArmy; self.armies[newArmyID].registerUpdates(); @@ -213,3 +216,7 @@ enemyWatcher.prototype.splitArmies = function(gameState){ }); } }; + + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/entity-extend.js b/binaries/data/mods/public/simulation/ai/aegis/entity-extend.js index 382b32b869..90773f38fe 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/entity-extend.js +++ b/binaries/data/mods/public/simulation/ai/aegis/entity-extend.js @@ -1,5 +1,8 @@ +var AEGIS = function(m) +{ + // returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too. -function getMaxStrength(ent, againstClass) +m.getMaxStrength = function(ent, againstClass) { var strength = 0.0; var attackTypes = ent.attackTypes(); @@ -61,3 +64,6 @@ function getMaxStrength(ent, againstClass) } return strength * hp; }; + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/entitycollection-extend.js b/binaries/data/mods/public/simulation/ai/aegis/entitycollection-extend.js index 9aff32f42c..065bf83c0b 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/entitycollection-extend.js +++ b/binaries/data/mods/public/simulation/ai/aegis/entitycollection-extend.js @@ -1,4 +1,7 @@ -function EntityCollectionFromIds(gameState, idList){ +var AEGIS = function(m) +{ + +m.EntityCollectionFromIds = function(gameState, idList){ var ents = {}; for (var i in idList){ var id = idList[i]; @@ -6,5 +9,8 @@ function EntityCollectionFromIds(gameState, idList){ ents[id] = gameState.entities._entities[id]; } } - return new EntityCollection(gameState.sharedScript, ents); + return new API3.EntityCollection(gameState.sharedScript, ents); } + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/headquarters.js b/binaries/data/mods/public/simulation/ai/aegis/headquarters.js index f8bc055711..b948ed6ca2 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/aegis/headquarters.js @@ -1,3 +1,5 @@ +var AEGIS = function(m) +{ /* Headquarters * Deal with high level logic for the AI. Most of the interesting stuff gets done here. * Some tasks: @@ -12,11 +14,13 @@ -picking new CC locations. */ -var HQ = function() { - this.targetNumBuilders = Config.Economy.targetNumBuilders; // number of workers we want building stuff +m.HQ = function(Config) { - this.dockStartTime = Config.Economy.dockStartTime * 1000; - this.techStartTime = Config.Economy.techStartTime * 1000; + this.Config = Config; + this.targetNumBuilders = this.Config.Economy.targetNumBuilders; // number of workers we want building stuff + + this.dockStartTime = this.Config.Economy.dockStartTime * 1000; + this.techStartTime = this.Config.Economy.techStartTime * 1000; this.dockFailed = false; // sanity check this.waterMap = false; // set by the aegis.js file. @@ -27,15 +31,15 @@ var HQ = function() { this.baseManagers = {}; // this means we'll have about a big third of women, and thus we can maximize resource gathering rates. - this.femaleRatio = Config.Economy.femaleRatio; + this.femaleRatio = this.Config.Economy.femaleRatio; this.fortressStartTime = 0; - this.fortressLapseTime = Config.Military.fortressLapseTime * 1000; - this.defenceBuildingTime = Config.Military.defenceBuildingTime * 1000; - this.attackPlansStartTime = Config.Military.attackPlansStartTime * 1000; - this.defenceManager = new Defence(); + this.fortressLapseTime = this.Config.Military.fortressLapseTime * 1000; + this.defenceBuildingTime = this.Config.Military.defenceBuildingTime * 1000; + this.attackPlansStartTime = this.Config.Military.attackPlansStartTime * 1000; + this.defenceManager = new m.Defence(this.Config); - this.navalManager = new NavalManager(); + this.navalManager = new m.NavalManager(); this.TotalAttackNumber = 0; this.upcomingAttacks = { "CityAttack" : [] }; @@ -43,49 +47,49 @@ var HQ = function() { }; // More initialisation for stuff that needs the gameState -HQ.prototype.init = function(gameState, events, queues){ +m.HQ.prototype.init = function(gameState, events, queues){ // initialize base map. Each pixel is a base ID, or 0 if none - this.basesMap = new Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length)); + this.basesMap = new API3.Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length)); this.basesMap.setMaxVal(255); - if (Config.Economy.targetNumWorkers) - this.targetNumWorkers = Config.Economy.targetNumWorkers; + if (this.Config.Economy.targetNumWorkers) + this.targetNumWorkers = this.Config.Economy.targetNumWorkers; else if (this.targetNumWorkers === undefined) - this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+(Config.difficulty)*0.125,0.3))), 1); + this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+(this.Config.difficulty)*0.125,0.3))), 1); // Let's get our initial situation here. // TODO: improve on this. // TODO: aknowledge bases, assign workers already. - var ents = gameState.getEntities().filter(Filters.byOwner(PlayerID)); + var ents = gameState.getEntities().filter(API3.Filters.byOwner(PlayerID)); var workersNB = 0; var hasScout = false; var treasureAmount = { 'food': 0, 'wood': 0, 'stone': 0, 'metal': 0 }; var hasCC = false; - if (ents.filter(Filters.byClass("CivCentre")).length > 0) + if (ents.filter(API3.Filters.byClass("CivCentre")).length > 0) hasCC = true; - workersNB = ents.filter(Filters.byClass("Worker")).length; - if (ents.filter(Filters.byClass("Cavalry")).length > 0) + workersNB = ents.filter(API3.Filters.byClass("Worker")).length; + if (ents.filter(API3.Filters.byClass("Cavalry")).length > 0) hasScout = true; // tODO: take multiple CCs into account. if (hasCC) { - var CC = ents.filter(Filters.byClass("CivCentre")).toEntityArray()[0]; + var CC = ents.filter(API3.Filters.byClass("CivCentre")).toEntityArray()[0]; for (i in treasureAmount) gameState.getResourceSupplies(i).forEach( function (ent) { - if (ent.resourceSupplyType().generic === "treasure" && SquareVectorDistance(ent.position(), CC.position()) < 5000) + if (ent.resourceSupplyType().generic === "treasure" && API3.SquareVectorDistance(ent.position(), CC.position()) < 5000) treasureAmount[i] += ent.resourceSupplyMax(); }); - this.baseManagers[1] = new BaseManager(); + this.baseManagers[1] = new m.BaseManager(this.Config); this.baseManagers[1].init(gameState, events); this.baseManagers[1].setAnchor(CC); this.baseManagers[1].initTerritory(this, gameState); this.baseManagers[1].initGatheringFunctions(this, gameState); - if (Config.debug) + if (m.DebugEnabled) this.basesMap.dumpIm("basesMap.png"); var self = this; @@ -105,14 +109,14 @@ HQ.prototype.init = function(gameState, events, queues){ var pos = this.baseManagers[1].findBestDropsiteLocation(gameState, "wood"); if (pos) { - queues.dropsites.addItem(new ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : 1 }, 0, -1, pos)); - queues.minorTech.addItem(new ResearchPlan(gameState, "gather_capacity_wheelbarrow")); + queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : 1 }, 0, -1, pos)); + queues.minorTech.addItem(new m.ResearchPlan(gameState, "gather_capacity_wheelbarrow")); } } } - var map = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map); - if (Config.debug) + var map = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map); + if (m.DebugEnabled) map.dumpIm("map_CC_Wood.png"); //this.reassignIdleWorkers(gameState); @@ -125,22 +129,22 @@ HQ.prototype.init = function(gameState, events, queues){ // load units and buildings from the config files - if (civ in Config.buildings.moderate){ - this.bModerate = Config.buildings.moderate[civ]; + if (civ in this.Config.buildings.moderate){ + this.bModerate = this.Config.buildings.moderate[civ]; }else{ - this.bModerate = Config.buildings.moderate['default']; + this.bModerate = this.Config.buildings.moderate['default']; } - if (civ in Config.buildings.advanced){ - this.bAdvanced = Config.buildings.advanced[civ]; + if (civ in this.Config.buildings.advanced){ + this.bAdvanced = this.Config.buildings.advanced[civ]; }else{ - this.bAdvanced = Config.buildings.advanced['default']; + this.bAdvanced = this.Config.buildings.advanced['default']; } - if (civ in Config.buildings.fort){ - this.bFort = Config.buildings.fort[civ]; + if (civ in this.Config.buildings.fort){ + this.bFort = this.Config.buildings.fort[civ]; }else{ - this.bFort = Config.buildings.fort['default']; + this.bFort = this.Config.buildings.fort['default']; } for (var i in this.bAdvanced){ @@ -156,7 +160,7 @@ HQ.prototype.init = function(gameState, events, queues){ } var enemies = gameState.getEnemyEntities(); - var filter = Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]); + var filter = API3.Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]); this.enemySoldiers = enemies.filter(filter); // TODO: cope with diplomacy changes this.enemySoldiers.registerUpdates(); @@ -167,13 +171,13 @@ HQ.prototype.init = function(gameState, events, queues){ this.ennWatcherIndex = []; for (var i = 1; i <= 8; i++) if (PlayerID != i && gameState.isPlayerEnemy(i)) { - this.enemyWatchers[i] = new enemyWatcher(gameState, i); + this.enemyWatchers[i] = new m.enemyWatcher(gameState, i); this.ennWatcherIndex.push(i); this.defenceManager.enemyArmy[i] = []; } }; -HQ.prototype.checkEvents = function (gameState, events, queues) { +m.HQ.prototype.checkEvents = function (gameState, events, queues) { for (i in events) { if (events[i].type == "Destroy") @@ -193,8 +197,8 @@ HQ.prototype.checkEvents = function (gameState, events, queues) { if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1) { // Okay so let's try to create a new base around this. - var bID = uniqueIDBases; - this.baseManagers[bID] = new BaseManager(); + var bID = m.playerGlobals[PlayerID].uniqueIDBases; + this.baseManagers[bID] = new m.BaseManager(this.Config); this.baseManagers[bID].init(gameState, events, true); this.baseManagers[bID].setAnchor(ent); this.baseManagers[bID].initTerritory(this, gameState); @@ -243,7 +247,7 @@ HQ.prototype.checkEvents = function (gameState, events, queues) { // TODO: This should probably be changed to favor a more mixed approach for better defense. // (or even to adapt based on estimated enemy strategy). // TODO: this should probably set which base it wants them in. -HQ.prototype.trainMoreWorkers = function(gameState, queues) { +m.HQ.prototype.trainMoreWorkers = function(gameState, queues) { // Count the workers in the world and in progress var numFemales = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("units/{civ}_support_female_citizen")); numFemales += queues.villager.countQueuedUnitsWithClass("Support"); @@ -293,14 +297,14 @@ HQ.prototype.trainMoreWorkers = function(gameState, queues) { // base "0" means "auto" if (template === gameState.applyCiv("units/{civ}_support_female_citizen")) - queues.villager.addItem(new TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size )); + queues.villager.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size )); else - queues.citizenSoldier.addItem(new TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size)); + queues.citizenSoldier.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size)); } }; // picks the best template based on parameters and classes -HQ.prototype.findBestTrainableUnit = function(gameState, classes, parameters) { +m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, parameters) { var units = gameState.findTrainableUnits(classes); if (units.length === 0) @@ -317,8 +321,8 @@ HQ.prototype.findBestTrainableUnit = function(gameState, classes, parameters) { bTopParam = param[1]; } if (param[0] == "strength") { - aTopParam += getMaxStrength(a[1]) * param[1]; - bTopParam += getMaxStrength(b[1]) * param[1]; + aTopParam += m.getMaxStrength(a[1]) * param[1]; + bTopParam += m.getMaxStrength(b[1]) * param[1]; } if (param[0] == "speed") { aTopParam += a[1].walkSpeed() * param[1]; @@ -343,7 +347,7 @@ HQ.prototype.findBestTrainableUnit = function(gameState, classes, parameters) { }; // picks the best template based on parameters and classes -HQ.prototype.findBestTrainableSoldier = function(gameState, classes, parameters) { +m.HQ.prototype.findBestTrainableSoldier = function(gameState, classes, parameters) { var units = gameState.findTrainableUnits(classes); if (units.length === 0) @@ -361,12 +365,12 @@ HQ.prototype.findBestTrainableSoldier = function(gameState, classes, parameters) bTopParam = param[1]; } if (param[0] == "strength") { - aTopParam += getMaxStrength(a[1]) * param[1]; - bTopParam += getMaxStrength(b[1]) * param[1]; + aTopParam += m.getMaxStrength(a[1]) * param[1]; + bTopParam += m.getMaxStrength(b[1]) * param[1]; } if (param[0] == "siegeStrength") { - aTopParam += getMaxStrength(a[1], "Structure") * param[1]; - bTopParam += getMaxStrength(b[1], "Structure") * param[1]; + aTopParam += m.getMaxStrength(a[1], "Structure") * param[1]; + bTopParam += m.getMaxStrength(b[1], "Structure") * param[1]; } if (param[0] == "speed") { aTopParam += a[1].walkSpeed() * param[1]; @@ -394,7 +398,7 @@ HQ.prototype.findBestTrainableSoldier = function(gameState, classes, parameters) // Tries to research any available tech // Only one at once. Also does military tech (selection is completely random atm) // TODO: Lots, lots, lots here. -HQ.prototype.tryResearchTechs = function(gameState, queues) { +m.HQ.prototype.tryResearchTechs = function(gameState, queues) { if (queues.minorTech.length() === 0) { var possibilities = gameState.findAvailableTech(); @@ -402,15 +406,16 @@ HQ.prototype.tryResearchTechs = function(gameState, queues) { return; // randomly pick one. No worries about pairs in that case. var p = Math.floor((Math.random()*possibilities.length)); - queues.minorTech.addItem(new ResearchPlan(gameState, possibilities[p][0])); + queues.minorTech.addItem(new m.ResearchPlan(gameState, possibilities[p][0])); } } // We're given a worker and a resource type // We'll assign the worker for the best base for that resource type. // TODO: improve choice alogrithm -HQ.prototype.switchWorkerBase = function(gameState, worker, type) { +m.HQ.prototype.switchWorkerBase = function(gameState, worker, type) { var bestBase = 0; + for (var i in this.baseManagers) { if (this.baseManagers[i].willGather[type] >= 1) @@ -435,12 +440,12 @@ HQ.prototype.switchWorkerBase = function(gameState, worker, type) { // returns an entity collection of workers through BaseManager.pickBuilders // TODO: better the choice algo. // TODO: also can't get over multiple bases right now. -HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number) { +m.HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number) { var accessIndex = this.baseManagers[newBaseID].accessIndex; if (!accessIndex) return false; // sorting bases by whether they are on the same accessindex or not. - var baseBest = AssocArraytoArray(this.baseManagers).sort(function (a,b) { + var baseBest = m.AssocArraytoArray(this.baseManagers).sort(function (a,b) { if (a.accessIndex === accessIndex && b.accessIndex !== accessIndex) return -1; else if (b.accessIndex === accessIndex && a.accessIndex !== accessIndex) @@ -459,7 +464,7 @@ HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number) { // 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. -HQ.prototype.GetCurrentGatherRates = function(gameState) { +m.HQ.prototype.GetCurrentGatherRates = function(gameState) { var self = this; var currentRates = {}; @@ -474,7 +479,7 @@ HQ.prototype.GetCurrentGatherRates = function(gameState) { // Pick the resource which most needs another worker -HQ.prototype.pickMostNeededResources = function(gameState) { +m.HQ.prototype.pickMostNeededResources = function(gameState) { var self = this; this.wantedRates = gameState.ai.queueManager.wantedGatherRates(gameState); @@ -517,7 +522,7 @@ HQ.prototype.pickMostNeededResources = function(gameState) { // If all the CC's are destroyed then build a new one // TODO: rehabilitate. -HQ.prototype.buildNewCC= function(gameState, queues) { +m.HQ.prototype.buildNewCC= function(gameState, queues) { var numCCs = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_civil_centre")); numCCs += queues.civilCentre.length(); @@ -529,14 +534,14 @@ HQ.prototype.buildNewCC= function(gameState, queues) { this.baseNeed["wood"] = 50; this.baseNeed["stone"] = 50; this.baseNeed["metal"] = 50; - queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre")); + queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre")); } return (gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_civil_centre"), true) == 0 && gameState.currentPhase() > 1); }; // Returns the best position to build a new Civil Centre // Whose primary function would be to reach new resources of type "resource". -HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ +m.HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ var CCPlate = gameState.getTemplate("structures/{civ}_civil_centre"); @@ -545,16 +550,16 @@ HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ // Then checks for a good spot in the territory. If none, and town/city phase, checks outside // The AI will currently not build a CC if it wouldn't connect with an existing CC. - var territory = Map.createTerritoryMap(gameState); + var territory = m.createTerritoryMap(gameState); - var obstructions = Map.createObstructionMap(gameState, 0); + var obstructions = m.createObstructionMap(gameState, 0); obstructions.expandInfluences(); // copy the resource map as initialization. - var friendlyTiles = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true); + var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true); friendlyTiles.setMaxVal(255); - var ents = gameState.getOwnEntities().filter(Filters.byClass("CivCentre")).toEntityArray(); - var eEnts = gameState.getEnemyEntities().filter(Filters.byClass("CivCentre")).toEntityArray(); + var ents = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); + var eEnts = gameState.getEnemyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); var dps = gameState.getOwnDropsites().toEntityArray(); @@ -576,7 +581,7 @@ HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ var entPos = ents[i].position(); entPos = [entPos[0]/4.0,entPos[1]/4.0]; - var dist = SquareVectorDistance(entPos, pos); + var dist = API3.SquareVectorDistance(entPos, pos); if (dist < 2120) { canBuild = false; @@ -598,7 +603,7 @@ HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ var entPos = eEnts[i].position(); entPos = [entPos[0]/4.0,entPos[1]/4.0]; // 7100 works well as a limit. - if (SquareVectorDistance(entPos, pos) < 2500) + if (API3.SquareVectorDistance(entPos, pos) < 2500) { canBuild = false; continue; @@ -620,11 +625,11 @@ HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ continue; } dpPos = [dpPos[0]/4.0,dpPos[1]/4.0]; - if (SquareVectorDistance(dpPos, pos) < 100) + if (API3.SquareVectorDistance(dpPos, pos) < 100) { friendlyTiles.map[j] = 0; continue; - } else if (SquareVectorDistance(dpPos, pos) < 400) + } else if (API3.SquareVectorDistance(dpPos, pos) < 400) friendlyTiles.map[j] /= 2; } @@ -645,7 +650,7 @@ HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ var best = friendlyTiles.findBestTile(6, obstructions); var bestIdx = best[0]; - if (Config.debug) + if (m.DebugEnabled) { friendlyTiles.map[bestIdx] = 270; friendlyTiles.dumpIm("cc_placement_base_" + gameState.getTimeElapsed() + "_" + resource + "_" + best[1] + ".png",301); @@ -659,44 +664,44 @@ HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ var x = ((bestIdx % friendlyTiles.width) + 0.5) * gameState.cellSize; var z = (Math.floor(bestIdx / friendlyTiles.width) + 0.5) * gameState.cellSize; - debug ("Best for value " + best[1] + " at " + uneval([x,z])); + m.debug ("Best for value " + best[1] + " at " + uneval([x,z])); return [x,z]; }; -HQ.prototype.buildTemple = function(gameState, queues){ +m.HQ.prototype.buildTemple = function(gameState, queues){ if (gameState.currentPhase() >= 2 ) { if (queues.economicBuilding.countQueuedUnits() === 0 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_temple")) === 0){ - queues.economicBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_temple", { "base" : 1 })); + queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_temple", { "base" : 1 })); } } }; -HQ.prototype.buildMarket = function(gameState, queues){ - if (gameState.getPopulation() > Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) { +m.HQ.prototype.buildMarket = function(gameState, queues){ + if (gameState.getPopulation() > this.Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) { if (queues.economicBuilding.countQueuedUnitsWithClass("BarterMarket") === 0 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market")) === 0){ //only ever build one storehouse/CC/market at a time - queues.economicBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_market", { "base" : 1 })); + queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_market", { "base" : 1 })); } } }; // Build a farmstead to go to town phase faster and prepare for research. Only really active on higher diff mode. -HQ.prototype.buildFarmstead = function(gameState, queues){ - if (gameState.getPopulation() > Config.Economy.popForFarmstead) { +m.HQ.prototype.buildFarmstead = function(gameState, queues){ + if (gameState.getPopulation() > this.Config.Economy.popForFarmstead) { // achtung: "DropsiteFood" does not refer to CCs. if (queues.economicBuilding.countQueuedUnitsWithClass("DropsiteFood") === 0 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_farmstead")) === 0){ //only ever build one storehouse/CC/market at a time - queues.economicBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_farmstead", { "base" : 1 })); + queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_farmstead", { "base" : 1 })); } } }; // TODO: generic this, probably per-base -HQ.prototype.buildDock = function(gameState, queues){ +m.HQ.prototype.buildDock = function(gameState, queues){ if (!this.waterMap || this.dockFailed) return; if (gameState.getTimeElapsed() > this.dockStartTime) { @@ -710,7 +715,7 @@ HQ.prototype.buildDock = function(gameState, queues){ if (tp !== "") { var remaining = this.navalManager.getUnconnectedSeas(gameState, this.baseManagers[1].accessIndex); - queues.economicBuilding.addItem(new ConstructionPlan(gameState, tp, { "base" : 1, "sea" : remaining[0] })); + queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, tp, { "base" : 1, "sea" : remaining[0] })); } } } @@ -719,7 +724,7 @@ HQ.prototype.buildDock = function(gameState, queues){ // if Aegis has resources it doesn't need, it'll try to barter it for resources it needs // once per turn because the info doesn't update between a turn and I don't want to fix it. // Not sure how efficient it is but it seems to be sane, at least. -HQ.prototype.tryBartering = function(gameState){ +m.HQ.prototype.tryBartering = function(gameState){ var done = false; if (gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_market"), true) >= 1) { @@ -732,7 +737,7 @@ HQ.prototype.tryBartering = function(gameState){ if ( (ress[buy] < 400) || needs[buy] > 0) { // if we need that other resource/ have too little of it var markets = gameState.getOwnEntitiesByType(gameState.applyCiv("structures/{civ}_market"), true).toEntityArray(); markets[0].barter(buy,sell,100); - //debug ("bartered " +sell +" for " + buy + ", value 100"); + //m.debug ("bartered " +sell +" for " + buy + ", value 100"); done = true; } } @@ -743,7 +748,7 @@ HQ.prototype.tryBartering = function(gameState){ // build more houses if needed. // kinda ugly, lots of special cases to both build enough houses but not tooo many… -HQ.prototype.buildMoreHouses = function(gameState,queues) { +m.HQ.prototype.buildMoreHouses = function(gameState,queues) { if (gameState.getPopulationLimit() < gameState.getPopulationMax()) { @@ -751,7 +756,9 @@ HQ.prototype.buildMoreHouses = function(gameState,queues) { if (numPlanned < 3 || (numPlanned < 5 && gameState.getPopulation() > 80)) { - var plan = new ConstructionPlan(gameState, "structures/{civ}_house", { "base" : 1 }); + var plan = new m.ConstructionPlan(gameState, "structures/{civ}_house", { "base" : 1 }); + // make the difficulty available to the isGo function without having to pass it as argument + var difficulty = this.Config.difficulty; // change the starting condition to "less than 15 slots left". plan.isGo = function (gameState) { var HouseNb = gameState.countEntitiesByType(gameState.applyCiv("foundation|structures/{civ}_house"), true); @@ -761,9 +768,9 @@ HQ.prototype.buildMoreHouses = function(gameState,queues) { freeSlots = gameState.getPopulationLimit() + HouseNb*5 - gameState.getPopulation(); else freeSlots = gameState.getPopulationLimit() + HouseNb*10 - gameState.getPopulation(); - if (gameState.getPopulation() > 55 && Config.difficulty > 1) + if (gameState.getPopulation() > 55 && difficulty > 1) return (freeSlots <= 21); - else if (gameState.getPopulation() >= 20 && Config.difficulty !== 0) + else if (gameState.getPopulation() >= 20 && difficulty !== 0) return (freeSlots <= 16); else return (freeSlots <= 10); @@ -774,19 +781,20 @@ HQ.prototype.buildMoreHouses = function(gameState,queues) { }; // checks if we have bases for all resource types (bar food for now) or if we need to expand. -HQ.prototype.checkBasesRessLevel = function(gameState,queues) { +m.HQ.prototype.checkBasesRessLevel = function(gameState,queues) { if (gameState.currentPhase() === 1 && !gameState.isResearching(gameState.townPhase())) return; var count = { "wood" : 0, "stone" : 0, "metal" : 0 } var capacity = { "wood" : 0, "stone" : 0, "metal" : 0 } var need = { "wood" : true, "stone" : true, "metal" : true }; var posss = []; + for (i in this.baseManagers) { var base = this.baseManagers[i]; for (type in count) { - if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max(Config.difficulty,2)) + if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max(this.Config.difficulty,2)) count[type]++; capacity[type] += base.getWorkerCapacity(gameState, type); if (base.willGather[type] !== 2) @@ -796,7 +804,7 @@ HQ.prototype.checkBasesRessLevel = function(gameState,queues) { for (type in count) { if (count[type] === 0 || need[type] - || capacity[type] < gameState.getOwnEntities().filter(Filters.and(Filters.byMetadata(PlayerID, "subrole", "gatherer"), Filters.byMetadata(PlayerID, "gather-type", type))).length * 1.05) + || capacity[type] < gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byMetadata(PlayerID, "subrole", "gatherer"), API3.Filters.byMetadata(PlayerID, "gather-type", type))).length * 1.05) { // plan a new base. if (gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_civil_centre")) === 0 && queues.civilCentre.length() === 0) { @@ -809,7 +817,7 @@ HQ.prototype.checkBasesRessLevel = function(gameState,queues) { this.outOf[type] = true; } else { // base "-1" means new base. - queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre",{ "base" : -1 }, 0, -1, pos)); + queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre",{ "base" : -1 }, 0, -1, pos)); } } } @@ -819,9 +827,9 @@ HQ.prototype.checkBasesRessLevel = function(gameState,queues) { // Deals with building fortresses and towers. // Currently build towers next to every useful dropsites. // TODO: Fortresses are placed randomly atm. -HQ.prototype.buildDefences = function(gameState, queues){ +m.HQ.prototype.buildDefences = function(gameState, queues){ - var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(Filters.not(Filters.byHasMetadata(PlayerID,"plan"))).length; + var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"plan"))).length; if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv('structures/{civ}_defense_tower')) + queues.defenceBuilding.length() < gameState.getEntityLimits()["DefenseTower"] && queues.defenceBuilding.length() < 4 && gameState.currentPhase() > 1) { @@ -836,7 +844,7 @@ HQ.prototype.buildDefences = function(gameState, queues){ { var position = dpEnt.position(); if (position) { - queues.defenceBuilding.addItem(new ConstructionPlan(gameState, 'structures/{civ}_defense_tower', { "base" : i }, 0 , -1, position)); + queues.defenceBuilding.addItem(new m.ConstructionPlan(gameState, 'structures/{civ}_defense_tower', { "base" : i }, 0 , -1, position)); } dpEnt.setMetadata(PlayerID, "defenseTower", true); } @@ -855,8 +863,8 @@ HQ.prototype.buildDefences = function(gameState, queues){ { if (!this.fortressStartTime) this.fortressStartTime = gameState.getTimeElapsed(); - queues.defenceBuilding.addItem(new ConstructionPlan(gameState, this.bFort[0], { "base" : 1 })); - debug ("Building a fortress"); + queues.defenceBuilding.addItem(new m.ConstructionPlan(gameState, this.bFort[0], { "base" : 1 })); + m.debug ("Building a fortress"); } } if (gameState.countEntitiesByType(gameState.applyCiv(this.bFort[i]), true) >= 1) { @@ -877,13 +885,13 @@ HQ.prototype.buildDefences = function(gameState, queues){ } }; -HQ.prototype.buildBlacksmith = function(gameState, queues){ - if (gameState.getTimeElapsed() > Config.Military.timeForBlacksmith*1000) { +m.HQ.prototype.buildBlacksmith = function(gameState, queues){ + if (gameState.getTimeElapsed() > this.Config.Military.timeForBlacksmith*1000) { if (queues.militaryBuilding.length() === 0 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_blacksmith")) === 0) { var tp = gameState.getTemplate(gameState.applyCiv("structures/{civ}_blacksmith")); if (tp.available(gameState)) - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_blacksmith", { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_blacksmith", { "base" : 1 })); } } }; @@ -892,32 +900,32 @@ HQ.prototype.buildBlacksmith = function(gameState, queues){ // They are mostly defined by Config.js. This is unreliable since changes could be done easily. // TODO: We need to determine these dynamically. Also doesn't build fortresses since the above function does that. // TODO: building placement is bad. Choice of buildings is also fairly dumb. -HQ.prototype.constructTrainingBuildings = function(gameState, queues) { +m.HQ.prototype.constructTrainingBuildings = function(gameState, queues) { Engine.ProfileStart("Build buildings"); - var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(Filters.not(Filters.byHasMetadata(PlayerID, "plan"))).length; + var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "plan"))).length; - if (workersNumber > Config.Military.popForBarracks1) { + if (workersNumber > this.Config.Military.popForBarracks1) { if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) + queues.militaryBuilding.length() < 1) { - debug ("Trying to build barracks"); - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); + m.debug ("Trying to build barracks"); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); } } - if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > Config.Military.popForBarracks2) + if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > this.Config.Military.popForBarracks2) if (queues.militaryBuilding.length() < 1) - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); if (gameState.countEntitiesByType(gameState.applyCiv(this.bModerate[0]), true) === 2 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 3 && workersNumber > 125) if (queues.militaryBuilding.length() < 1) { - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); if (gameState.civ() == "gaul" || gameState.civ() == "brit" || gameState.civ() == "iber") { - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); } } //build advanced military buildings - if (workersNumber >= Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){ + if (workersNumber >= this.Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){ if (queues.militaryBuilding.length() === 0){ var inConst = 0; for (var i in this.bAdvanced) @@ -925,7 +933,7 @@ HQ.prototype.constructTrainingBuildings = function(gameState, queues) { if (inConst == 0 && this.bAdvanced && this.bAdvanced.length !== 0) { var i = Math.floor(Math.random() * this.bAdvanced.length); if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i])) < 1){ - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); } } } @@ -939,8 +947,8 @@ HQ.prototype.constructTrainingBuildings = function(gameState, queues) { if (inConst == 1) { var i = Math.floor(Math.random() * this.bAdvanced.length); if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i])) < 1){ - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); - queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); + queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); } } } @@ -949,9 +957,9 @@ HQ.prototype.constructTrainingBuildings = function(gameState, queues) { }; // TODO: use pop(). Currently unused as this is too gameable. -HQ.prototype.garrisonAllFemales = function(gameState) { - var buildings = gameState.getOwnEntities().filter(Filters.byCanGarrison()).toEntityArray(); - var females = gameState.getOwnEntities().filter(Filters.byClass("Support")); +m.HQ.prototype.garrisonAllFemales = function(gameState) { + var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); + var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support")); var cache = {}; @@ -974,16 +982,16 @@ HQ.prototype.garrisonAllFemales = function(gameState) { }); this.hasGarrisonedFemales = true; }; -HQ.prototype.ungarrisonAll = function(gameState) { +m.HQ.prototype.ungarrisonAll = function(gameState) { this.hasGarrisonedFemales = false; - var buildings = gameState.getOwnEntities().filter(Filters.and(Filters.byClass("Structure"),Filters.byCanGarrison())).toEntityArray(); + var buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byCanGarrison())).toEntityArray(); buildings.forEach( function (struct) { if (struct.garrisoned() && struct.garrisoned().length) struct.unloadAll(); }); }; -HQ.prototype.pausePlan = function(gameState, planName) { +m.HQ.prototype.pausePlan = function(gameState, planName) { for (var attackType in this.upcomingAttacks) { for (var i in this.upcomingAttacks[attackType]) { var attack = this.upcomingAttacks[attackType][i]; @@ -999,7 +1007,7 @@ HQ.prototype.pausePlan = function(gameState, planName) { } } } -HQ.prototype.unpausePlan = function(gameState, planName) { +m.HQ.prototype.unpausePlan = function(gameState, planName) { for (var attackType in this.upcomingAttacks) { for (var i in this.upcomingAttacks[attackType]) { var attack = this.upcomingAttacks[attackType][i]; @@ -1015,7 +1023,7 @@ HQ.prototype.unpausePlan = function(gameState, planName) { } } } -HQ.prototype.pauseAllPlans = function(gameState) { +m.HQ.prototype.pauseAllPlans = function(gameState) { for (var attackType in this.upcomingAttacks) { for (var i in this.upcomingAttacks[attackType]) { var attack = this.upcomingAttacks[attackType][i]; @@ -1029,7 +1037,7 @@ HQ.prototype.pauseAllPlans = function(gameState) { } } } -HQ.prototype.unpauseAllPlans = function(gameState) { +m.HQ.prototype.unpauseAllPlans = function(gameState) { for (var attackType in this.upcomingAttacks) { for (var i in this.upcomingAttacks[attackType]) { var attack = this.upcomingAttacks[attackType][i]; @@ -1047,7 +1055,7 @@ HQ.prototype.unpauseAllPlans = function(gameState) { // Some functions are run every turn // Others once in a while -HQ.prototype.update = function(gameState, queues, events) { +m.HQ.prototype.update = function(gameState, queues, events) { Engine.ProfileStart("Headquarters update"); this.checkEvents(gameState,events,queues); @@ -1057,7 +1065,7 @@ HQ.prototype.update = function(gameState, queues, events) { this.trainMoreWorkers(gameState, queues); // sandbox doesn't expand. - if (Config.difficulty !== 0) + if (this.Config.difficulty !== 0) this.checkBasesRessLevel(gameState, queues); this.buildMoreHouses(gameState,queues); @@ -1065,7 +1073,7 @@ HQ.prototype.update = function(gameState, queues, events) { if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2) this.tryResearchTechs(gameState,queues); - if (Config.difficulty > 1) + if (this.Config.difficulty > 1) this.tryBartering(gameState); this.buildFarmstead(gameState, queues); @@ -1087,7 +1095,7 @@ HQ.prototype.update = function(gameState, queues, events) { for (i in this.baseManagers) { this.baseManagers[i].checkEvents(gameState, events, queues) - if ( ( (+i + gameState.ai.playedTurn) % (uniqueIDBases - 1)) === 0) + if ( ( (+i + gameState.ai.playedTurn) % (m.playerGlobals[PlayerID].uniqueIDBases - 1)) === 0) this.baseManagers[i].update(gameState, queues, events); } @@ -1113,10 +1121,10 @@ HQ.prototype.update = function(gameState, queues, events) { if (updateStep === 1 || attack.isPaused() ) { // just chillin' } else if (updateStep === 0 || updateStep === 3) { - debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" aborted."); + m.debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" aborted."); if (updateStep === 3) { this.attackPlansEncounteredWater = true; - debug("No attack path found. Aborting."); + m.debug("No attack path found. Aborting."); } attack.Abort(gameState, this); this.upcomingAttacks[attackType].splice(i--,1); @@ -1130,7 +1138,7 @@ HQ.prototype.update = function(gameState, queues, events) { chatText = "I'm starting an attack against " + gameState.sharedScript.playersData[attack.targetPlayer].name + "."; gameState.ai.chatTeam(chatText); - debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName()); + m.debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName()); attack.StartAttack(gameState,this); this.startedAttacks[attackType].push(attack); this.upcomingAttacks[attackType].splice(i--,1); @@ -1145,7 +1153,7 @@ HQ.prototype.update = function(gameState, queues, events) { chatText = "I'm starting an attack against " + gameState.sharedScript.playersData[attack.targetPlayer].name + "."; gameState.ai.chatTeam(chatText); - debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName()); + m.debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName()); this.startedAttacks[attackType].push(attack); this.upcomingAttacks[attackType].splice(i--,1); } @@ -1160,7 +1168,7 @@ HQ.prototype.update = function(gameState, queues, events) { { var remaining = attack.update(gameState,this,events); if (remaining == 0 || remaining == undefined) { - debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" is now finished."); + m.debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" is now finished."); attack.Abort(gameState); this.startedAttacks[attackType].splice(i--,1); } @@ -1174,14 +1182,14 @@ HQ.prototype.update = function(gameState, queues, events) { if (gameState.ai.strategy === "rush" && this.startedAttacks["CityAttack"].length !== 0) { // and then we revert. gameState.ai.strategy = "normal"; - Config.Economy.femaleRatio = 0.4; + this.Config.Economy.femaleRatio = 0.4; gameState.ai.modules.economy.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*0.55), 1); } else if (gameState.ai.strategy === "rush" && this.upcomingAttacks["CityAttack"].length === 0) { - Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1, "rush") + Lalala = new m.CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "rush") this.TotalAttackNumber++; this.upcomingAttacks["CityAttack"].push(Lalala); - debug ("Starting a little something"); + m.debug ("Starting a little something"); } else if (gameState.ai.strategy !== "rush" && !this.waterMap) { // creating plans after updating because an aborted plan might be reused in that case. @@ -1193,22 +1201,22 @@ HQ.prototype.update = function(gameState, queues, events) { } else { // basically only the first plan, really. if (this.upcomingAttacks["CityAttack"].length == 0 && gameState.getTimeElapsed() < 12*60000) { - var Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1); + var Lalala = new m.CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1); if (Lalala.failed) { this.attackPlansEncounteredWater = true; // hack } else { - debug ("Military Manager: Creating the plan " +this.TotalAttackNumber); + m.debug ("Military Manager: Creating the plan " +this.TotalAttackNumber); this.TotalAttackNumber++; this.upcomingAttacks["CityAttack"].push(Lalala); } - } else if (this.upcomingAttacks["CityAttack"].length == 0 && Config.difficulty !== 0) { - var Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1, "superSized"); + } else if (this.upcomingAttacks["CityAttack"].length == 0 && this.Config.difficulty !== 0) { + var Lalala = new m.CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "superSized"); if (Lalala.failed) { this.attackPlansEncounteredWater = true; // hack } else { - debug ("Military Manager: Creating the super sized plan " +this.TotalAttackNumber); + m.debug ("Military Manager: Creating the super sized plan " +this.TotalAttackNumber); this.TotalAttackNumber++; this.upcomingAttacks["CityAttack"].push(Lalala); } @@ -1221,12 +1229,12 @@ HQ.prototype.update = function(gameState, queues, events) { // very old relic. This should be reimplemented someday so the code stays here. if (this.HarassRaiding && this.preparingRaidNumber + this.startedRaidNumber < 1 && gameState.getTimeElapsed() < 780000) { - var Lalala = new CityAttack(gameState, this,this.totalStartedAttackNumber, -1, "harass_raid"); + var Lalala = new m.CityAttack(gameState, this,this.totalStartedAttackNumber, -1, "harass_raid"); if (!Lalala.createSupportPlans(gameState, this, )) { - debug ("Military Manager: harrassing plan not a valid option"); + m.debug ("Military Manager: harrassing plan not a valid option"); this.HarassRaiding = false; } else { - debug ("Military Manager: Creating the harass raid plan " +this.totalStartedAttackNumber); + m.debug ("Military Manager: Creating the harass raid plan " +this.totalStartedAttackNumber); this.totalStartedAttackNumber++; this.preparingRaidNumber++; @@ -1243,7 +1251,7 @@ HQ.prototype.update = function(gameState, queues, events) { this.buildDropsites(gameState, queues); Engine.ProfileStop(); - if (Config.difficulty !== 0) + if (this.Config.difficulty !== 0) this.tryBartering(gameState); this.buildFarmstead(gameState, queues); @@ -1255,3 +1263,7 @@ HQ.prototype.update = function(gameState, queues, events) { */ Engine.ProfileStop(); // Heaquarters update }; + +return m; + +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/map-module.js b/binaries/data/mods/public/simulation/ai/aegis/map-module.js index 9cd8070ffd..a62bce4003 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/map-module.js +++ b/binaries/data/mods/public/simulation/ai/aegis/map-module.js @@ -1,6 +1,10 @@ -// other map functions +var AEGIS = function(m) +{ -Map.createObstructionMap = function(gameState, accessIndex, template){ +// other map functions +m.TERRITORY_PLAYER_MASK = 0x3F; + +m.createObstructionMap = function(gameState, accessIndex, template){ var passabilityMap = gameState.getMap(); var territoryMap = gameState.ai.territoryMap; @@ -31,7 +35,7 @@ Map.createObstructionMap = function(gameState, accessIndex, template){ for (var y = 0; y < passabilityMap.height; ++y) { var i = x + y*passabilityMap.width; - var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK); + var tilePlayer = (territoryMap.data[i] & m.TERRITORY_PLAYER_MASK); if (gameState.ai.myIndex !== gameState.ai.accessibility.landPassMap[i]) { @@ -88,7 +92,7 @@ Map.createObstructionMap = function(gameState, accessIndex, template){ var obstructionTiles = new Uint8Array(passabilityMap.data.length); for (var i = 0; i < passabilityMap.data.length; ++i) { - var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK); + var tilePlayer = (territoryMap.data[i] & m.TERRITORY_PLAYER_MASK); var invalidTerritory = ( (!buildOwn && tilePlayer == playerID) || (!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) || @@ -105,7 +109,7 @@ Map.createObstructionMap = function(gameState, accessIndex, template){ } } - var map = new Map(gameState.sharedScript, obstructionTiles); + var map = new API3.Map(gameState.sharedScript, obstructionTiles); map.setMaxVal(255); if (template && template.buildDistance()){ @@ -126,17 +130,19 @@ Map.createObstructionMap = function(gameState, accessIndex, template){ }; - -Map.createTerritoryMap = function(gameState) { +m.createTerritoryMap = function(gameState) { var map = gameState.ai.territoryMap; - var ret = new Map(gameState.sharedScript, map.data); + var ret = new API3.Map(gameState.sharedScript, map.data); ret.getOwner = function(p) { - return this.point(p) & TERRITORY_PLAYER_MASK; + return this.point(p) & m.TERRITORY_PLAYER_MASK; } ret.getOwnerIndex = function(p) { - return this.map[p] & TERRITORY_PLAYER_MASK; + return this.map[p] & m.TERRITORY_PLAYER_MASK; } return ret; }; + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js b/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js index fb36c4a713..e8f48dbb42 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js @@ -1,3 +1,6 @@ +var AEGIS = function(m) +{ + /* Naval Manager Will deal with anything ships. -Basically trade over water (with fleets and goals commissioned by the economy manager) @@ -9,7 +12,7 @@ Does not build them though, that's for the base manager to handle. */ -var NavalManager = function() { +m.NavalManager = function() { // accessibility zones for which we have a dock. // Connexion is described as [landindex] = [seaIndexes]; // technically they also exist for sea zones but I don't care. @@ -32,16 +35,16 @@ var NavalManager = function() { }; // More initialisation for stuff that needs the gameState -NavalManager.prototype.init = function(gameState, events, queues) { +m.NavalManager.prototype.init = function(gameState, events, queues) { // finished docks - this.docks = gameState.getOwnEntities().filter(Filters.and(Filters.byClass("Dock"), Filters.not(Filters.isFoundation()))); + this.docks = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Dock"), API3.Filters.not(API3.Filters.isFoundation()))); this.docks.allowQuickIter(); this.docks.registerUpdates(); - this.ships = gameState.getOwnEntities().filter(Filters.byClass("Ship")); + this.ships = gameState.getOwnEntities().filter(API3.Filters.byClass("Ship")); // note: those two can overlap (some transport ships are warships too and vice-versa). - this.tpShips = this.ships.filter(Filters.byCanGarrison()); - this.warships = this.ships.filter(Filters.byClass("Warship")); + this.tpShips = this.ships.filter(API3.Filters.byCanGarrison()); + this.warships = this.ships.filter(API3.Filters.byClass("Warship")); this.ships.registerUpdates(); this.tpShips.registerUpdates(); @@ -52,19 +55,19 @@ NavalManager.prototype.init = function(gameState, events, queues) { if (gameState.ai.accessibility.regionType[i] !== "water") { // push dummies - this.seaShips.push(new EntityCollection(gameState.sharedScript)); - this.seaTpShips.push(new EntityCollection(gameState.sharedScript)); - this.seaWarships.push(new EntityCollection(gameState.sharedScript)); + this.seaShips.push(new API3.EntityCollection(gameState.sharedScript)); + this.seaTpShips.push(new API3.EntityCollection(gameState.sharedScript)); + this.seaWarships.push(new API3.EntityCollection(gameState.sharedScript)); this.wantedTpShips.push(0); this.wantedWarships.push(0); } else { - var collec = this.ships.filter(Filters.byStaticMetadata(PlayerID, "sea", i)); + var collec = this.ships.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); collec.registerUpdates(); this.seaShips.push(collec); - collec = this.tpShips.filter(Filters.byStaticMetadata(PlayerID, "sea", i)); + collec = this.tpShips.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); collec.registerUpdates(); this.seaTpShips.push(collec); - var collec = this.warships.filter(Filters.byStaticMetadata(PlayerID, "sea", i)); + var collec = this.warships.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); collec.registerUpdates(); this.seaWarships.push(collec); @@ -76,7 +79,7 @@ NavalManager.prototype.init = function(gameState, events, queues) { } }; -NavalManager.prototype.getUnconnectedSeas = function (gameState, region) { +m.NavalManager.prototype.getUnconnectedSeas = function (gameState, region) { var seas = gameState.ai.accessibility.regionLinks[region] if (seas.length === 0) return []; @@ -89,7 +92,7 @@ NavalManager.prototype.getUnconnectedSeas = function (gameState, region) { }; // returns true if there is a path from A to B and we have docks. -NavalManager.prototype.canReach = function (gameState, regionA, regionB) { +m.NavalManager.prototype.canReach = function (gameState, regionA, regionB) { var path = gameState.ai.accessibility.getTrajectToIndex(regionA, regionB); if (!path) { @@ -100,7 +103,7 @@ NavalManager.prototype.canReach = function (gameState, regionA, regionB) { if (gameState.ai.accessibility.regionType[path[i]] == "land") if (this.accessibleSeas.indexOf(path[i+1]) === -1) { - debug ("cannot reach because of " + path[i+1]); + m.debug ("cannot reach because of " + path[i+1]); return false; // we wn't be able to board on that sea } } @@ -108,7 +111,7 @@ NavalManager.prototype.canReach = function (gameState, regionA, regionB) { }; -NavalManager.prototype.checkEvents = function (gameState, queues, events) { +m.NavalManager.prototype.checkEvents = function (gameState, queues, events) { for (i in events) { if (events[i].type == "Destroy") @@ -137,19 +140,19 @@ NavalManager.prototype.checkEvents = function (gameState, queues, events) { } }; -NavalManager.prototype.addPlan = function(plan) { +m.NavalManager.prototype.addPlan = function(plan) { this.transportPlans.push(plan); }; // will create a plan at the end of the turn. // many units can call this separately and end up in the same plan // which can be useful. -NavalManager.prototype.askForTransport = function(entity, startPos, endPos) { +m.NavalManager.prototype.askForTransport = function(entity, startPos, endPos) { this.askedPlans.push([entity, startPos, endPos]); }; // creates aforementionned plans -NavalManager.prototype.createPlans = function(gameState) { +m.NavalManager.prototype.createPlans = function(gameState) { var startID = {}; for (i in this.askedPlans) @@ -172,13 +175,13 @@ NavalManager.prototype.createPlans = function(gameState) { for (var i in startID) for (var k in startID[i]) { - var tpPlan = new TransportPlan(gameState, startID[i][k].units, startID[i][k].dest, false) + var tpPlan = new m.TransportPlan(gameState, startID[i][k].units, startID[i][k].dest, false) this.transportPlans.push (tpPlan); } }; // TODO: work on this. -NavalManager.prototype.maintainFleet = function(gameState, queues, events) { +m.NavalManager.prototype.maintainFleet = function(gameState, queues, events) { // check if we have enough transport ships. // check per region. for (var i = 0; i < this.seaShips.length; ++i) @@ -188,13 +191,13 @@ NavalManager.prototype.maintainFleet = function(gameState, queues, events) { && tpNb + queues.ships.length() === 0 && gameState.getTemplate(gameState.applyCiv("units/{civ}_ship_bireme")).available(gameState)) { // TODO: check our dock can build the wanted ship types, for Carthage. - queues.ships.addItem(new TrainingPlan(gameState, "units/{civ}_ship_bireme", { "sea" : i }, 1, 0, -1, 1 )); + queues.ships.addItem(new m.TrainingPlan(gameState, "units/{civ}_ship_bireme", { "sea" : i }, 1, 0, -1, 1 )); } } }; // bumps up the number of ships we want if we need more. -NavalManager.prototype.checkLevels = function(gameState, queues) { +m.NavalManager.prototype.checkLevels = function(gameState, queues) { if (queues.ships.length() !== 0) return; for (var i = 0; i < this.transportPlans.length; ++i) @@ -214,7 +217,7 @@ NavalManager.prototype.checkLevels = function(gameState, queues) { }; // assigns free ships to plans that need some -NavalManager.prototype.assignToPlans = function(gameState, queues, events) { +m.NavalManager.prototype.assignToPlans = function(gameState, queues, events) { for (var i = 0; i < this.transportPlans.length; ++i) { var plan = this.transportPlans[i]; @@ -228,7 +231,7 @@ NavalManager.prototype.assignToPlans = function(gameState, queues, events) { { if (!ship.getMetadata(PlayerID, "tpplan")) { - debug ("Assigning ship " + ship.id() + " to plan" + plan.ID); + m.debug ("Assigning ship " + ship.id() + " to plan" + plan.ID); plan.assignShip(gameState, ship); return true; } @@ -239,7 +242,7 @@ NavalManager.prototype.assignToPlans = function(gameState, queues, events) { return false; }; -NavalManager.prototype.checkActivePlan = function(ID) { +m.NavalManager.prototype.checkActivePlan = function(ID) { for (var i = 0; i < this.transportPlans.length; ++i) if (this.transportPlans[i].ID === ID) return true; @@ -249,7 +252,7 @@ NavalManager.prototype.checkActivePlan = function(ID) { // Some functions are run every turn // Others once in a while -NavalManager.prototype.update = function(gameState, queues, events) { +m.NavalManager.prototype.update = function(gameState, queues, events) { Engine.ProfileStart("Naval Manager update"); this.checkEvents(gameState, queues, events); @@ -286,3 +289,6 @@ NavalManager.prototype.update = function(gameState, queues, events) { } Engine.ProfileStop(); }; + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/plan-transport.js b/binaries/data/mods/public/simulation/ai/aegis/plan-transport.js index 73592956cf..f7800f746d 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/plan-transport.js +++ b/binaries/data/mods/public/simulation/ai/aegis/plan-transport.js @@ -1,3 +1,6 @@ +var AEGIS = function(m) +{ + /* Describes a transport plan Constructor assign units (units is an ID array, or an ID), a destionation (position, ingame), and a wanted escort size. @@ -15,10 +18,10 @@ // TODO: finish the support of multiple accessibility indexes. // TODO: this doesn't check we can actually reach in the init, which we might want? -var TransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) { +m.TransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) { var self = this; - this.ID = uniqueIDTPlans++; + this.ID = m.playerGlobals[PlayerID].uniqueIDTPlans++; var unitsID = []; if (units.length !== undefined) @@ -26,7 +29,7 @@ var TransportPlan = function(gameState, units, destination, allAtOnce, escortSiz else unitsID = [units]; - this.units = EntityCollectionFromIds(gameState, unitsID); + this.units = m.EntityCollectionFromIds(gameState, unitsID); this.units.forEach(function (ent) { //}){ ent.setMetadata(PlayerID, "tpplan", self.ID); ent.setMetadata(PlayerID, "formerRole", ent.getMetadata(PlayerID, "role")); @@ -36,8 +39,8 @@ var TransportPlan = function(gameState, units, destination, allAtOnce, escortSiz this.units.freeze(); this.units.registerUpdates(); - debug ("Starting a new plan with ID " + this.ID + " to " + destination); - debug ("units are " + uneval (units)); + m.debug ("Starting a new plan with ID " + this.ID + " to " + destination); + m.debug ("units are " + uneval (units)); this.destination = destination; this.destinationIndex = gameState.ai.accessibility.getAccessValue(destination); @@ -70,7 +73,7 @@ var TransportPlan = function(gameState, units, destination, allAtOnce, escortSiz }; // count available slots -TransportPlan.prototype.countFreeSlots = function(onlyTrulyFree) +m.TransportPlan.prototype.countFreeSlots = function(onlyTrulyFree) { var slots = 0; this.transportShips.forEach(function (ent) { //}){ @@ -80,12 +83,12 @@ TransportPlan.prototype.countFreeSlots = function(onlyTrulyFree) }); } -TransportPlan.prototype.assignShip = function(gameState, ship) +m.TransportPlan.prototype.assignShip = function(gameState, ship) { ship.setMetadata(PlayerID,"tpplan", this.ID); } -TransportPlan.prototype.releaseAll = function(gameState) +m.TransportPlan.prototype.releaseAll = function(gameState) { this.ships.forEach(function (ent) { ent.setMetadata(PlayerID,"tpplan", undefined) }); this.units.forEach(function (ent) { @@ -96,25 +99,25 @@ TransportPlan.prototype.releaseAll = function(gameState) }); } -TransportPlan.prototype.releaseAllShips = function(gameState) +m.TransportPlan.prototype.releaseAllShips = function(gameState) { this.ships.forEach(function (ent) { ent.setMetadata(PlayerID,"tpplan", undefined) }); } -TransportPlan.prototype.needTpShips = function() +m.TransportPlan.prototype.needTpShips = function() { if ((this.allAtOnce && this.countFreeSlots() >= this.units.length) || this.transportShips.length > 0) return false; return true; } -TransportPlan.prototype.needEscortShips = function() +m.TransportPlan.prototype.needEscortShips = function() { return !((this.onlyIfOK && this.escortShips.length < this.escortSize) || !this.onlyIfOK); } // returns the zone for which we are needing our ships -TransportPlan.prototype.neededShipsZone = function() +m.TransportPlan.prototype.neededShipsZone = function() { if (!this.seaZone) return false; @@ -134,7 +137,7 @@ TransportPlan.prototype.neededShipsZone = function() > there is the possibility that we'll be moving units on land, but that's basically a restart too, with more clearing. Grouping Path is basically the same with "grouping" and we never unboard (unless there is a need to) */ -TransportPlan.prototype.carryOn = function(gameState, navalManager) +m.TransportPlan.prototype.carryOn = function(gameState, navalManager) { if (this.state === "unstarted") { @@ -171,7 +174,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) // let's get our index this turn. this.startIndex = unitIndexes[0]; - debug ("plan " + this.ID + " from " + this.startIndex); + m.debug ("plan " + this.ID + " from " + this.startIndex); return true; } @@ -190,7 +193,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) } // we have a path, register the first sea zone. this.seaZone = this.path[1]; - debug ("Plan " + this.ID + " over seazone " + this.seaZone); + m.debug ("Plan " + this.ID + " over seazone " + this.seaZone); } // if we currently have no baoarding spot, try and find one. if (!this.boardingSpot) @@ -206,10 +209,10 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) var passabilityMap = gameState.getMap(); var territoryMap = gameState.ai.territoryMap; var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction") | gameState.getPassabilityClassMask("building-shore"); - var obstructions = new Map(gameState.sharedScript); + var obstructions = new API3.Map(gameState.sharedScript); // wanted map. - var friendlyTiles = new Map(gameState.sharedScript); + var friendlyTiles = new API3.Map(gameState.sharedScript); for (var j = 0; j < friendlyTiles.length; ++j) { @@ -248,7 +251,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) // we have the spot we want to board at. this.boardingSpot = [x,z]; - debug ("Plan " + this.ID + " new boarding spot is " + this.boardingSpot); + m.debug ("Plan " + this.ID + " new boarding spot is " + this.boardingSpot); } // if all at once we need to be full, else we just need enough escort ships. @@ -262,7 +265,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) this.garrisonShipID = -1; - debug ("Boarding"); + m.debug ("Boarding"); this.state = "boarding"; } return true; @@ -300,12 +303,12 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) // check if we need to move our units and ships closer together var stillMoving = false; - if (SquareVectorDistance(this.ships.getCentrePosition(),this.boardingSpot) > 1600) + if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.boardingSpot) > 1600) { this.ships.move(this.boardingSpot[0],this.boardingSpot[1]); stillMoving = true; // wait till ships are in position } - if (SquareVectorDistance(this.units.getCentrePosition(),this.boardingSpot) > 1600) + if (API3.SquareVectorDistance(this.units.getCentrePosition(),this.boardingSpot) > 1600) { this.units.move(this.boardingSpot[0],this.boardingSpot[1]); stillMoving = true; // wait till units are in position @@ -365,10 +368,10 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) var passabilityMap = gameState.getMap(); var territoryMap = gameState.ai.territoryMap; var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction") | gameState.getPassabilityClassMask("building-shore"); - var obstructions = new Map(gameState.sharedScript); + var obstructions = new API3.Map(gameState.sharedScript); // wanted map. - var friendlyTiles = new Map(gameState.sharedScript); + var friendlyTiles = new API3.Map(gameState.sharedScript); var wantedIndex = -1; @@ -377,7 +380,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) this.path.splice(0,2); wantedIndex = this.path[0]; } else { - debug ("too short at " +uneval(this.path)); + m.debug ("too short at " +uneval(this.path)); return false; // Incomputable } @@ -431,7 +434,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) return false; // check if we need to move ships - if (SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) + if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) { this.ships.move(this.unboardingSpot[0],this.unboardingSpot[1]); } else { @@ -447,7 +450,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) return false; // check if we need to move ships - if (SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) + if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) { this.ships.move(this.unboardingSpot[0],this.unboardingSpot[1]); } else { @@ -455,7 +458,7 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) // TODO: improve on this. if (this.path.length > 1) { - debug ("plan " + this.ID + " going back for more"); + m.debug ("plan " + this.ID + " going back for more"); // basically reset. delete this.boardingSpot; delete this.unboardingSpot; @@ -463,10 +466,13 @@ TransportPlan.prototype.carryOn = function(gameState, navalManager) this.releaseAllShips(); return true; } - debug ("plan " + this.ID + " is finished"); + m.debug ("plan " + this.ID + " is finished"); return false; } } return true; } + +return m; +}(AEGIS); diff --git a/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js b/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js index e40593bc98..b831cef1aa 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js @@ -1,3 +1,6 @@ +var AEGIS = function(m) +{ + // This takes the input queues and picks which items to fund with resources until no more resources are left to distribute. // // Currently this manager keeps accounts for each queue, split between the 4 main resources @@ -17,7 +20,8 @@ // // This system should be improved. It's probably not flexible enough. -var QueueManager = function(queues, priorities) { +m.QueueManager = function(Config, queues, priorities) { + this.Config = Config; this.queues = queues; this.priorities = priorities; this.account = {}; @@ -28,7 +32,7 @@ var QueueManager = function(queues, priorities) { this.queueArrays = []; for (var p in this.queues) { this.account[p] = 0; - this.accounts[p] = new Resources(); + this.accounts[p] = new API3.Resources(); this.queueArrays.push([p,this.queues[p]]); } this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); @@ -36,7 +40,7 @@ var QueueManager = function(queues, priorities) { this.curItemQueue = []; }; -QueueManager.prototype.getAvailableResources = function(gameState, noAccounts) { +m.QueueManager.prototype.getAvailableResources = function(gameState, noAccounts) { var resources = gameState.getResources(); if (noAccounts) return resources; @@ -46,16 +50,16 @@ QueueManager.prototype.getAvailableResources = function(gameState, noAccounts) { return resources; }; -QueueManager.prototype.getTotalAccountedResources = function(gameState) { - var resources = new Resources(); +m.QueueManager.prototype.getTotalAccountedResources = function(gameState) { + var resources = new API3.Resources(); for (var key in this.queues) { resources.add(this.accounts[key]); } return resources; }; -QueueManager.prototype.currentNeeds = function(gameState) { - var needs = new Resources(); +m.QueueManager.prototype.currentNeeds = function(gameState) { + var needs = new API3.Resources(); // get out current resources, not removing accounts. var current = this.getAvailableResources(gameState, true); //queueArrays because it's faster. @@ -82,8 +86,8 @@ QueueManager.prototype.currentNeeds = function(gameState) { }; }; -QueueManager.prototype.futureNeeds = function(gameState) { - var needs = new Resources(); +m.QueueManager.prototype.futureNeeds = function(gameState) { + var needs = new API3.Resources(); // get out current resources, not removing accounts. var current = this.getAvailableResources(gameState, true); //queueArrays because it's faster. @@ -108,7 +112,7 @@ QueueManager.prototype.futureNeeds = function(gameState) { }; // calculate the gather rates we'd want to be able to use all elements in our queues -QueueManager.prototype.wantedGatherRates = function(gameState) { +m.QueueManager.prototype.wantedGatherRates = function(gameState) { var rates = { "food" : 0, "wood" : 0, "stone" : 0, "metal" : 0 }; var qTime = gameState.getTimeElapsed(); var qCosts = { "food" : 0, "wood" : 0, "stone" : 0, "metal" : 0 }; @@ -143,7 +147,9 @@ QueueManager.prototype.wantedGatherRates = function(gameState) { // estimate time based on priority + cost + nb // TODO: work on this. for (type in qCosts) + { qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name])); + } qTime += 30000; } else { // TODO: work on this. @@ -165,7 +171,7 @@ QueueManager.prototype.wantedGatherRates = function(gameState) { return rates; }; -/*QueueManager.prototype.logNeeds = function(gameState) { +/*m.QueueManager.prototype.logNeeds = function(gameState) { if (!this.totor) { this.totor = []; @@ -255,34 +261,34 @@ QueueManager.prototype.wantedGatherRates = function(gameState) { }; */ -QueueManager.prototype.printQueues = function(gameState){ - debug("QUEUES"); +m.QueueManager.prototype.printQueues = function(gameState){ + m.debug("QUEUES"); for (var i in this.queues){ var qStr = ""; var q = this.queues[i]; if (q.queue.length > 0) - debug((i + ":")); + m.debug((i + ":")); for (var j in q.queue){ qStr = " " + q.queue[j].type + " "; if (q.queue[j].number) qStr += "x" + q.queue[j].number; - debug (qStr); + m.debug (qStr); } } - debug ("Accounts"); + m.debug ("Accounts"); for (var p in this.accounts) { - debug(p + ": " + uneval(this.accounts[p])); + m.debug(p + ": " + uneval(this.accounts[p])); } - debug("Needed Resources:" + uneval(this.futureNeeds(gameState,false))); - debug ("Wanted Gather Rates:" + uneval(this.wantedGatherRates(gameState))); - debug ("Current Resources:" + uneval(gameState.getResources())); - debug ("Available Resources:" + uneval(this.getAvailableResources(gameState))); + m.debug("Needed Resources:" + uneval(this.futureNeeds(gameState,false))); + m.debug ("Wanted Gather Rates:" + uneval(this.wantedGatherRates(gameState))); + m.debug ("Current Resources:" + uneval(gameState.getResources())); + m.debug ("Available Resources:" + uneval(this.getAvailableResources(gameState))); }; // nice readable HTML version. -QueueManager.prototype.HTMLprintQueues = function(gameState){ - if (!Config.debug) +m.QueueManager.prototype.HTMLprintQueues = function(gameState){ + if (!m.DebugEnabled) return; log("