Ticket #2322: AI_in_one_global_v1.0.diff
File AI_in_one_global_v1.0.diff, 308.8 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/simulation/ai/qbot/defence.js
1 function Defence( ){1 function Defence(Config){ 2 2 this.ACQUIRE_DIST = Config.defence.acquireDistance; 3 3 this.RELEASE_DIST = Config.defence.releaseDistance; 4 4 -
binaries/data/mods/public/simulation/ai/qbot/attackMoveToLocation.js
1 function AttackMoveToLocation(gameState, militaryManager, minAttackSize, maxAttackSize, targetFinder){ 1 function AttackMoveToLocation(gameState, Config, militaryManager, minAttackSize, maxAttackSize, targetFinder){ 2 3 this.Config = Config; 2 4 this.minAttackSize = minAttackSize || Config.attack.minAttackSize; 3 5 this.maxAttackSize = maxAttackSize || Config.attack.maxAttackSize; 4 6 this.idList=[]; … … 17 19 var enemyCount = militaryManager.measureEnemyCount(gameState); 18 20 19 21 // We require our army to be >= this strength 20 var targetStrength = enemyStrength * Config.attack.enemyRatio;22 var targetStrength = enemyStrength * this.Config.attack.enemyRatio; 21 23 22 24 var availableCount = militaryManager.countAvailableUnits(); 23 25 var availableStrength = militaryManager.measureAvailableStrength(); -
binaries/data/mods/public/simulation/ai/qbot/entity-extend.js
3 3 }; 4 4 5 5 Entity.prototype.garrison = function(target) { 6 Engine.PostCommand( {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});6 Engine.PostCommand(PlayerID, {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false}); 7 7 return this; 8 8 }; 9 9 10 10 Entity.prototype.attack = function(unitId) 11 11 { 12 Engine.PostCommand( {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});12 Engine.PostCommand(PlayerID, {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false}); 13 13 return this; 14 }; 15 Kein Zeilenumbruch am Ende der Datei 14 }; -
binaries/data/mods/public/simulation/ai/qbot/economy.js
357 357 // Make resources glow wildly 358 358 if (resource == "food"){ 359 359 ent.getMetadata("nearby-resources-" + resource).forEach(function(ent){ 360 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]});360 Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); 361 361 }); 362 362 } 363 363 if (resource == "wood"){ 364 364 ent.getMetadata("nearby-resources-" + resource).forEach(function(ent){ 365 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]});365 Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); 366 366 }); 367 367 } 368 368 if (resource == "metal"){ 369 369 ent.getMetadata("nearby-resources-" + resource).forEach(function(ent){ 370 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0,10]});370 Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0,10]}); 371 371 }); 372 372 }*/ 373 373 }); -
binaries/data/mods/public/simulation/ai/qbot/worker.js
34 34 35 35 this.startApproachingResourceTime = gameState.getTimeElapsed(); 36 36 37 //Engine.PostCommand( {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [10,0,0]});37 //Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [10,0,0]}); 38 38 }else{ 39 39 // If we haven't reached the resource in 2 minutes twice in a row and none of the resource has been 40 40 // gathered then mark it as inaccessible. … … 61 61 this.ent.repair(target); 62 62 } 63 63 64 //Engine.PostCommand( {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [0,10,0]});64 //Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [0,10,0]}); 65 65 } 66 66 67 67 Engine.ProfileStart("Update Gatherer Counts"); … … 248 248 }else{ 249 249 return type.generic; 250 250 } 251 }; 252 Kein Zeilenumbruch am Ende der Datei 251 }; -
binaries/data/mods/public/simulation/ai/qbot/entitycollection-extend.js
7 7 unitId = unit; 8 8 } 9 9 10 Engine.PostCommand( {"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});10 Engine.PostCommand(PlayerID, {"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false}); 11 11 return this; 12 12 }; 13 13 … … 37 37 }else{ 38 38 return [sumPos[0]/count, sumPos[1]/count]; 39 39 } 40 }; 41 Kein Zeilenumbruch am Ende der Datei 40 }; -
binaries/data/mods/public/simulation/ai/qbot/military.js
6 6 * 7 7 */ 8 8 9 var MilitaryAttackManager = function() { 9 var MilitaryAttackManager = function(Config) { 10 11 this.Config = Config 10 12 // these use the structure soldiers[unitId] = true|false to register the units 11 13 this.attackManagers = [AttackMoveToLocation]; 12 14 this.availableAttacks = []; … … 16 18 this.attackCount = 0; 17 19 this.lastAttackTime = 0; 18 20 19 this.defenceManager = new Defence( );21 this.defenceManager = new Defence(Config); 20 22 }; 21 23 22 24 MilitaryAttackManager.prototype.init = function(gameState) { … … 24 26 25 27 // load units and buildings from the config files 26 28 27 if (civ in Config.buildings.moderate){28 this.bModerate = Config.buildings.moderate[civ];29 if (civ in this.Config.buildings.moderate){ 30 this.bModerate = this.Config.buildings.moderate[civ]; 29 31 }else{ 30 this.bModerate = Config.buildings.moderate['default'];32 this.bModerate = this.Config.buildings.moderate['default']; 31 33 } 32 34 33 if (civ in Config.buildings.advanced){34 this.bAdvanced = Config.buildings.advanced[civ];35 if (civ in this.Config.buildings.advanced){ 36 this.bAdvanced = this.Config.buildings.advanced[civ]; 35 37 }else{ 36 this.bAdvanced = Config.buildings.advanced['default'];38 this.bAdvanced = this.Config.buildings.advanced['default']; 37 39 } 38 40 39 if (civ in Config.buildings.fort){40 this.bFort = Config.buildings.fort[civ];41 if (civ in this.Config.buildings.fort){ 42 this.bFort = this.Config.buildings.fort[civ]; 41 43 }else{ 42 this.bFort = Config.buildings.fort['default'];44 this.bFort = this.Config.buildings.fort['default']; 43 45 } 44 46 45 47 for (var i in this.bAdvanced){ … … 54 56 }; 55 57 // TODO: figure out how to make this generic 56 58 for (var i in this.attackManagers){ 57 this.availableAttacks[i] = new this.attackManagers[i](gameState, this );59 this.availableAttacks[i] = new this.attackManagers[i](gameState, this.Config, this); 58 60 } 59 61 60 62 var enemies = gameState.getEnemyEntities(); … … 435 437 this.currentAttacks.push(this.availableAttacks[i]); 436 438 //debug("Attacking!"); 437 439 } 438 this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this ));440 this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this.Config, this)); 439 441 } 440 442 Engine.ProfileStop(); 441 443 -
binaries/data/mods/public/simulation/ai/qbot/config.js
1 var baseConfig = { 2 "attack" : { 1 function Config() { 2 this.debug = false 3 4 this.attack = { 3 5 "minAttackSize" : 20, // attackMoveToLocation 4 6 "maxAttackSize" : 60, // attackMoveToLocation 5 7 "enemyRatio" : 1.5, // attackMoveToLocation 6 8 "groupSize" : 10 // military 7 } ,9 }; 8 10 9 11 // defence 10 "defence" :{12 this.defence = { 11 13 "acquireDistance" : 220, 12 14 "releaseDistance" : 250, 13 15 "groupRadius" : 20, 14 16 "groupBreakRadius" : 40, 15 17 "groupMergeRadius" : 10, 16 18 "defenderRatio" : 2 17 } ,19 }; 18 20 19 21 // military 20 "buildings" :{22 this.buildings = { 21 23 "moderate" : { 22 24 "default" : [ "structures/{civ}_barracks" ] 23 25 }, … … 37 39 "default" : [ "structures/{civ}_fortress" ], 38 40 "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ] 39 41 } 40 } ,42 }; 41 43 42 44 // qbot 43 "priorities" :{ // Note these are dynamic, you are only setting the initial values45 this.priorities = { // Note these are dynamic, you are only setting the initial values 44 46 "house" : 500, 45 47 "citizenSoldier" : 100, 46 48 "villager" : 100, … … 51 53 "militaryBuilding" : 50, 52 54 "defenceBuilding" : 17, 53 55 "civilCentre" : 1000 54 }, 55 56 "debug" : false 56 }; 57 57 }; 58 58 59 var Config = {60 "debug": false61 };62 63 Config.__proto__ = baseConfig;64 Kein Zeilenumbruch am Ende der Datei -
binaries/data/mods/public/simulation/ai/qbot/qbot.js
1 var g_debugEnabled = false; 1 2 2 3 function QBotAI(settings) { 3 4 BaseAI.call(this, settings); … … 4 5 5 6 this.turn = 0; 6 7 8 this.Config = new Config(); 9 7 10 this.modules = { 8 11 "economy": new EconomyManager(), 9 "military": new MilitaryAttackManager( ),12 "military": new MilitaryAttackManager(this.Config), 10 13 "housing": new HousingManager() 11 14 }; 12 15 16 13 17 // this.queues cannot be modified past initialisation or queue-manager will break 14 18 this.queues = { 15 19 house : new Queue(), … … 26 30 27 31 this.productionQueues = []; 28 32 29 this.priorities = Config.priorities;33 this.priorities = this.Config.priorities; 30 34 31 35 this.queueManager = new QueueManager(this.queues, this.priorities); 32 36 … … 161 165 }; 162 166 163 167 function debug(output){ 164 if ( Config.debug){168 if (g_debugEnabled){ 165 169 if (typeof output === "string"){ 166 170 warn(output); 167 171 }else{ -
binaries/data/mods/public/simulation/ai/common-api-v2/base.js
1 var PlayerID = -1; 2 1 3 function BaseAI(settings) 2 4 { 3 5 if (!settings) … … 112 114 return null; 113 115 }; 114 116 115 BaseAI.prototype.HandleMessage = function(state )117 BaseAI.prototype.HandleMessage = function(state, playerID) 116 118 { 119 PlayerID = playerID; 117 120 if (!this._entities) 118 121 { 119 122 // Do a (shallow) clone of all the initial entity properties (in order … … 237 240 238 241 BaseAI.prototype.chat = function(message) 239 242 { 240 Engine.PostCommand( {"type": "chat", "message": message});243 Engine.PostCommand(PlayerID, {"type": "chat", "message": message}); 241 244 }; 242 245 243 246 BaseAI.prototype.registerUpdatingEntityCollection = function(entCollection) -
binaries/data/mods/public/simulation/ai/common-api-v2/entity.js
372 372 373 373 move: function(x, z, queued) { 374 374 queued = queued || false; 375 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued});375 Engine.PostCommand(PlayerID, {"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued}); 376 376 return this; 377 377 }, 378 378 379 379 garrison: function(target) { 380 Engine.PostCommand( {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});380 Engine.PostCommand(PlayerID, {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false}); 381 381 return this; 382 382 }, 383 383 384 384 attack: function(unitId) { 385 Engine.PostCommand( {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});385 Engine.PostCommand(PlayerID, {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false}); 386 386 return this; 387 387 }, 388 388 389 389 gather: function(target, queued) { 390 390 queued = queued || false; 391 Engine.PostCommand( {"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued});391 Engine.PostCommand(PlayerID, {"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued}); 392 392 return this; 393 393 }, 394 394 395 395 repair: function(target, queued) { 396 396 queued = queued || false; 397 Engine.PostCommand( {"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued});397 Engine.PostCommand(PlayerID, {"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued}); 398 398 return this; 399 399 }, 400 400 401 401 returnResources: function(target, queued) { 402 402 queued = queued || false; 403 Engine.PostCommand( {"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued});403 Engine.PostCommand(PlayerID, {"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued}); 404 404 return this; 405 405 }, 406 406 407 407 destroy: function() { 408 Engine.PostCommand( {"type": "delete-entities", "entities": [this.id()]});408 Engine.PostCommand(PlayerID, {"type": "delete-entities", "entities": [this.id()]}); 409 409 return this; 410 410 }, 411 411 … … 423 423 return this; 424 424 } 425 425 426 Engine.PostCommand( {426 Engine.PostCommand(PlayerID, { 427 427 "type": "train", 428 428 "entities": [this.id()], 429 429 "template": type, … … 437 437 // TODO: verify this unit can construct this, just for internal 438 438 // sanity-checking and error reporting 439 439 440 Engine.PostCommand( {440 Engine.PostCommand(PlayerID, { 441 441 "type": "construct", 442 442 "entities": [this.id()], 443 443 "template": template, -
binaries/data/mods/public/simulation/ai/common-api-v2/entitycollection.js
109 109 EntityCollection.prototype.move = function(x, z, queued) 110 110 { 111 111 queued = queued || false; 112 Engine.PostCommand( {"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});112 Engine.PostCommand(PlayerID, {"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued}); 113 113 return this; 114 114 }; 115 115 116 116 EntityCollection.prototype.destroy = function() 117 117 { 118 Engine.PostCommand( {"type": "delete-entities", "entities": this.toIdArray()});118 Engine.PostCommand(PlayerID, {"type": "delete-entities", "entities": this.toIdArray()}); 119 119 return this; 120 120 }; 121 121 -
binaries/data/mods/public/simulation/ai/common-api-v3/map-module.js
1 var API3 = function(m) 2 { 3 1 4 /* The map module. 2 5 * Copied with changes from QuantumState's original for qBot, it's a component for storing 8 bit values. 3 6 */ … … 2 5 3 const TERRITORY_PLAYER_MASK = 0x3F; 4 5 function Map(sharedScript, originalMap, actualCopy){ 6 // The function needs to be named too because of the copyConstructor functionality 7 m.Map = function Map(sharedScript, originalMap, actualCopy){ 6 8 // get the map to find out the correct dimensions … … 25 27 this.cellSize = 4; 26 28 } 27 29 28 Map.prototype.setMaxVal = function(val){30 m.Map.prototype.setMaxVal = function(val){ 29 31 this.maxVal = val; 30 32 }; 31 33 32 Map.prototype.gamePosToMapPos = function(p){34 m.Map.prototype.gamePosToMapPos = function(p){ 33 35 return [Math.floor(p[0]/this.cellSize), Math.floor(p[1]/this.cellSize)]; 34 36 }; 35 37 36 Map.prototype.point = function(p){38 m.Map.prototype.point = function(p){ 37 39 var q = this.gamePosToMapPos(p); 38 40 return this.map[q[0] + this.width * q[1]]; 39 41 }; 40 Map.prototype.addInfluence = function(cx, cy, maxDist, strength, type) {42 m.Map.prototype.addInfluence = function(cx, cy, maxDist, strength, type) { 41 43 strength = strength ? +strength : +maxDist; 42 44 type = type ? type : 'linear'; 43 45 … … 90 92 } 91 93 }; 92 94 93 Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type) {95 m.Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type) { 94 96 strength = strength ? +strength : +maxDist; 95 97 type = type ? type : 'constant'; 96 98 … … 145 147 }; 146 148 147 149 // doesn't check for overflow. 148 Map.prototype.setInfluence = function(cx, cy, maxDist, value) {150 m.Map.prototype.setInfluence = function(cx, cy, maxDist, value) { 149 151 value = value ? value : 0; 150 152 151 153 var x0 = Math.max(0, cx - maxDist); … … 166 168 } 167 169 }; 168 170 169 Map.prototype.sumInfluence = function(cx, cy, radius){171 m.Map.prototype.sumInfluence = function(cx, cy, radius){ 170 172 var x0 = Math.max(0, cx - radius); 171 173 var y0 = Math.max(0, cy - radius); 172 174 var x1 = Math.min(this.width, cx + radius); … … 192 194 * neighbours' values. (If the grid is initialised with 0s and 65535s or 255s, the 193 195 * result of each cell is its Manhattan distance to the nearest 0.) 194 196 */ 195 Map.prototype.expandInfluences = function(maximum, map) {197 m.Map.prototype.expandInfluences = function(maximum, map) { 196 198 var grid = this.map; 197 199 if (map !== undefined) 198 200 grid = map; … … 252 254 } 253 255 }; 254 256 255 Map.prototype.findBestTile = function(radius, obstructionTiles){257 m.Map.prototype.findBestTile = function(radius, obstructionTiles){ 256 258 // Find the best non-obstructed tile 257 259 var bestIdx = 0; 258 260 var bestVal = -1; … … 269 271 return [bestIdx, bestVal]; 270 272 }; 271 273 // Multiplies current map by the parameter map pixelwise 272 Map.prototype.multiply = function(map, onlyBetter, divider, maxMultiplier){274 m.Map.prototype.multiply = function(map, onlyBetter, divider, maxMultiplier){ 273 275 for (var i = 0; i < this.length; ++i){ 274 276 if (map.map[i]/divider > 1) 275 277 this.map[i] = Math.min(maxMultiplier*this.map[i], this.map[i] * (map.map[i]/divider)); 276 278 } 277 279 }; 278 280 // add to current map by the parameter map pixelwise 279 Map.prototype.add = function(map){281 m.Map.prototype.add = function(map){ 280 282 for (var i = 0; i < this.length; ++i) { 281 283 if (this.map[i] + map.map[i] < 0) 282 284 this.map[i] = 0; … … 287 289 } 288 290 }; 289 291 290 Map.prototype.dumpIm = function(name, threshold){292 m.Map.prototype.dumpIm = function(name, threshold){ 291 293 name = name ? name : "default.png"; 292 294 threshold = threshold ? threshold : this.maxVal; 293 295 Engine.DumpImage(name, this.map, this.width, this.height, threshold); 294 296 }; 297 298 return m; 299 300 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/class.js
1 var API3 = function(m) 2 { 1 3 /** 2 4 * Provides a nicer syntax for defining classes, 3 5 * with support for OO-style inheritance. … … 2 4 */ 3 function Class(data)5 m.Class = function(data) 4 6 { … … 34 36 print((new B).foo+" "+(new B).bar+"\n"); 35 37 print((new C).foo+" "+(new C).bar+"\n"); 36 38 //*/ 39 40 return m; 41 42 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/filters.js
1 var Filters = { 1 var API3 = function(m) 2 { 3 4 m.Filters = { 2 5 byType: function(type){ 3 6 return {"func" : function(ent){ 4 7 return ent.templateName() === type; … … 169 172 if (ent.position() === undefined){ 170 173 return false; 171 174 }else{ 172 return ( SquareVectorDistance(startPoint, ent.position()) < dist*dist);175 return (m.SquareVectorDistance(startPoint, ent.position()) < dist*dist); 173 176 } 174 177 }, 175 178 "dynamicProperties": ['position']}; … … 181 184 if (!ent.position()){ 182 185 return false; 183 186 }else{ 184 return ( SquareVectorDistance(startPoint, ent.position()) < dist*dist);187 return (m.SquareVectorDistance(startPoint, ent.position()) < dist*dist); 185 188 } 186 189 }, 187 190 "dynamicProperties": []}; … … 238 241 "dynamicProperties": []}; 239 242 } 240 243 }; 244 245 return m; 246 247 }(API3); 248 -
binaries/data/mods/public/simulation/ai/common-api-v3/entity.js
1 var EntityTemplate = Class({ 1 var API3 = function(m) 2 { 2 3 4 m.EntityTemplate = m.Class({ 5 3 6 // techModifications should be the tech modifications of only one player. 4 7 // gamestates handle "GetTemplate" and should push the player's 5 8 // while entities should push the owner's … … 447 450 448 451 449 452 450 var Entity =Class({451 _super: EntityTemplate,453 m.Entity = m.Class({ 454 _super: m.EntityTemplate, 452 455 453 456 _init: function(sharedAI, entity) 454 457 { … … 576 579 return this._entity.resourceCarrying; 577 580 }, 578 581 579 garrisoned: function() { return new EntityCollection(this._ai, this._entity.garrisoned); },582 garrisoned: function() { return new m.EntityCollection(this._ai, this._entity.garrisoned); }, 580 583 581 584 canGarrisonInside: function() { return this._entity.garrisoned.length < this.garrisonMax(); }, 582 585 … … 584 587 585 588 move: function(x, z, queued) { 586 589 queued = queued || false; 587 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });590 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued }); 588 591 return this; 589 592 }, 590 593 591 594 attackMove: function(x, z, queued) { 592 595 queued = queued || false; 593 Engine.PostCommand( {"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });596 Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "queued": queued }); 594 597 return this; 595 598 }, 596 599 597 600 // violent, aggressive, defensive, passive, standground 598 601 setStance: function(stance,queued){ 599 Engine.PostCommand( {"type": "stance", "entities": [this.id()], "name" : stance, "queued": queued });602 Engine.PostCommand(PlayerID,{"type": "stance", "entities": [this.id()], "name" : stance, "queued": queued }); 600 603 return this; 601 604 }, 602 605 603 606 // TODO: replace this with the proper "STOP" command 604 607 stopMoving: function() { 605 608 if (this.position() !== undefined) 606 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": this.position()[0], "z": this.position()[1], "queued": false});609 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": this.position()[0], "z": this.position()[1], "queued": false}); 607 610 }, 608 611 609 612 unload: function(id) { 610 613 if (!this._template.GarrisonHolder) 611 614 return undefined; 612 Engine.PostCommand( {"type": "unload", "garrisonHolder": this.id(), "entities": [id]});615 Engine.PostCommand(PlayerID,{"type": "unload", "garrisonHolder": this.id(), "entities": [id]}); 613 616 return this; 614 617 }, 615 618 … … 617 620 unloadAll: function() { 618 621 if (!this._template.GarrisonHolder) 619 622 return undefined; 620 Engine.PostCommand( {"type": "unload-all-own", "garrisonHolders": [this.id()]});623 Engine.PostCommand(PlayerID,{"type": "unload-all-own", "garrisonHolders": [this.id()]}); 621 624 return this; 622 625 }, 623 626 624 627 garrison: function(target) { 625 Engine.PostCommand( {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});628 Engine.PostCommand(PlayerID,{"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false}); 626 629 return this; 627 630 }, 628 631 629 632 attack: function(unitId) { 630 Engine.PostCommand( {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});633 Engine.PostCommand(PlayerID,{"type": "attack", "entities": [this.id()], "target": unitId, "queued": false}); 631 634 return this; 632 635 }, 633 636 … … 635 638 flee: function(unitToFleeFrom) { 636 639 if (this.position() !== undefined && unitToFleeFrom.position() !== undefined) { 637 640 var FleeDirection = [this.position()[0] - unitToFleeFrom.position()[0],this.position()[1] - unitToFleeFrom.position()[1]]; 638 var dist = VectorDistance(unitToFleeFrom.position(), this.position() );641 var dist = m.VectorDistance(unitToFleeFrom.position(), this.position() ); 639 642 FleeDirection[0] = (FleeDirection[0]/dist) * 8; 640 643 FleeDirection[1] = (FleeDirection[1]/dist) * 8; 641 644 642 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": this.position()[0] + FleeDirection[0]*5, "z": this.position()[1] + FleeDirection[1]*5, "queued": false});645 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": this.position()[0] + FleeDirection[0]*5, "z": this.position()[1] + FleeDirection[1]*5, "queued": false}); 643 646 } 644 647 return this; 645 648 }, 646 649 647 650 gather: function(target, queued) { 648 651 queued = queued || false; 649 Engine.PostCommand( {"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued});652 Engine.PostCommand(PlayerID,{"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued}); 650 653 return this; 651 654 }, 652 655 653 656 repair: function(target, queued) { 654 657 queued = queued || false; 655 Engine.PostCommand( {"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued});658 Engine.PostCommand(PlayerID,{"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued}); 656 659 return this; 657 660 }, 658 661 659 662 returnResources: function(target, queued) { 660 663 queued = queued || false; 661 Engine.PostCommand( {"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued});664 Engine.PostCommand(PlayerID,{"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued}); 662 665 return this; 663 666 }, 664 667 665 668 destroy: function() { 666 Engine.PostCommand( {"type": "delete-entities", "entities": [this.id()] });669 Engine.PostCommand(PlayerID,{"type": "delete-entities", "entities": [this.id()] }); 667 670 return this; 668 671 }, 669 672 670 673 barter: function(buyType, sellType, amount) { 671 Engine.PostCommand( {"type": "barter", "sell" : sellType, "buy" : buyType, "amount" : amount });674 Engine.PostCommand(PlayerID,{"type": "barter", "sell" : sellType, "buy" : buyType, "amount" : amount }); 672 675 return this; 673 676 }, 674 677 … … 686 689 return this; 687 690 } 688 691 689 Engine.PostCommand( {692 Engine.PostCommand(PlayerID,{ 690 693 "type": "train", 691 694 "entities": [this.id()], 692 695 "template": type, … … 699 702 construct: function(template, x, z, angle, metadata) { 700 703 // TODO: verify this unit can construct this, just for internal 701 704 // sanity-checking and error reporting 702 703 Engine.PostCommand({ 705 Engine.PostCommand(PlayerID,{ 704 706 "type": "construct", 705 707 "entities": [this.id()], 706 708 "template": template, … … 716 718 }, 717 719 718 720 research: function(template) { 719 Engine.PostCommand( { "type": "research", "entity": this.id(), "template": template });721 Engine.PostCommand(PlayerID,{ "type": "research", "entity": this.id(), "template": template }); 720 722 return this; 721 723 }, 722 724 723 725 stopProduction: function(id) { 724 Engine.PostCommand( { "type": "stop-production", "entity": this.id(), "id": id });726 Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": id }); 725 727 return this; 726 728 }, 727 729 … … 732 734 for (var i in queue) 733 735 { 734 736 if (queue[i].progress < percentToStopAt) 735 Engine.PostCommand( { "type": "stop-production", "entity": this.id(), "id": queue[i].id });737 Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": queue[i].id }); 736 738 } 737 739 return this; 738 740 } 739 741 }); 740 742 743 return m; 744 745 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/terrain-analysis.js
1 var API3 = function(m) 2 { 3 1 4 /* 2 5 * TerrainAnalysis, inheriting from the Map Component. 3 6 * … … 12 15 * But truly separating optimizes. 13 16 */ 14 17 15 function TerrainAnalysis() {18 m.TerrainAnalysis = function() { 16 19 this.cellSize = 4; 17 20 } 18 21 19 copyPrototype(TerrainAnalysis,Map);22 m.copyPrototype(m.TerrainAnalysis, m.Map); 20 23 21 TerrainAnalysis.prototype.init = function(sharedScript,rawState) {24 m.TerrainAnalysis.prototype.init = function(sharedScript,rawState) { 22 25 var self = this; 23 26 24 27 var passabilityMap = rawState.passabilityMap; … … 108 111 }; 109 112 110 113 // Returns the (approximately) closest point which is passable by searching in a spiral pattern 111 TerrainAnalysis.prototype.findClosestPassablePoint = function(startPoint, onLand, limitDistance, quickscope){114 m.TerrainAnalysis.prototype.findClosestPassablePoint = function(startPoint, onLand, limitDistance, quickscope){ 112 115 var w = this.width; 113 116 var p = startPoint; 114 117 var direction = 1; … … 150 153 151 154 // Returns an estimate of a tile accessibility. It checks neighboring cells over two levels. 152 155 // returns a count. It's not integer. About 2 should be fairly accessible already. 153 TerrainAnalysis.prototype.countConnected = function(startIndex, byLand){156 m.TerrainAnalysis.prototype.countConnected = function(startIndex, byLand){ 154 157 var count = 0.0; 155 158 156 159 var w = this.width; … … 181 184 }; 182 185 183 186 // TODO: for now this resets to 255. 184 TerrainAnalysis.prototype.updateMapWithEvents = function(sharedAI) {187 m.TerrainAnalysis.prototype.updateMapWithEvents = function(sharedAI) { 185 188 var self = this; 186 189 187 190 var events = sharedAI.events; … … 243 246 * so this can use the land regions already. 244 247 245 248 */ 246 function Accessibility() {249 m.Accessibility = function() { 247 250 248 251 } 249 252 250 copyPrototype(Accessibility,TerrainAnalysis);253 m.copyPrototype(m.Accessibility, m.TerrainAnalysis); 251 254 252 Accessibility.prototype.init = function(rawState, terrainAnalyser){255 m.Accessibility.prototype.init = function(rawState, terrainAnalyser){ 253 256 var self = this; 254 257 255 258 this.Map(rawState, terrainAnalyser.map); … … 322 325 //Engine.DumpImage("NavalPassMap.png", this.navalPassMap, this.width, this.height, 255); 323 326 } 324 327 325 Accessibility.prototype.getAccessValue = function(position, onWater) {328 m.Accessibility.prototype.getAccessValue = function(position, onWater) { 326 329 var gamePos = this.gamePosToMapPos(position); 327 330 if (onWater === true) 328 331 return this.navalPassMap[gamePos[0] + this.width*gamePos[1]]; … … 343 346 344 347 // Returns true if a point is deemed currently accessible (is not blocked by surrounding trees...) 345 348 // NB: accessible means that you can reach it from one side, not necessariliy that you can go ON it. 346 Accessibility.prototype.isAccessible = function(gameState, position, onLand){349 m.Accessibility.prototype.isAccessible = function(gameState, position, onLand){ 347 350 var gamePos = this.gamePosToMapPos(position); 348 351 349 352 // quick check … … 356 359 // Return true if you can go from a point to a point without switching means of transport 357 360 // Hardcore means is also checks for isAccessible at the end (it checks for either water or land though, beware). 358 361 // This is a blind check and not a pathfinder: for all it knows there is a huge block of trees in the middle. 359 Accessibility.prototype.pathAvailable = function(gameState, start, end, onWater, hardcore){362 m.Accessibility.prototype.pathAvailable = function(gameState, start, end, onWater, hardcore){ 360 363 var pstart = this.gamePosToMapPos(start); 361 364 var istart = pstart[0] + pstart[1]*this.width; 362 365 var pend = this.gamePosToMapPos(end); … … 382 385 return false; 383 386 }; 384 387 385 Accessibility.prototype.getTrajectTo = function(start, end, noBound) {388 m.Accessibility.prototype.getTrajectTo = function(start, end, noBound) { 386 389 var pstart = this.gamePosToMapPos(start); 387 390 var istart = pstart[0] + pstart[1]*this.width; 388 391 var pend = this.gamePosToMapPos(end); … … 413 416 // assumes a land unit unless start point is over deep water. 414 417 // if the path is more complicated than "land->sea->land" (or "sea->land->sea"), it will run A* to try and figure it out 415 418 // Thus it can handle arbitrarily complicated paths (theoretically). 416 Accessibility.prototype.getTrajectToIndex = function(istart, iend, noBound){419 m.Accessibility.prototype.getTrajectToIndex = function(istart, iend, noBound){ 417 420 var startRegion = istart; 418 421 var currentRegion = istart; 419 422 … … 530 533 return path; 531 534 }; 532 535 533 Accessibility.prototype.getRegionSize = function(position, onWater){536 m.Accessibility.prototype.getRegionSize = function(position, onWater){ 534 537 var pos = this.gamePosToMapPos(position); 535 538 var index = pos[0] + pos[1]*this.width; 536 539 var ID = (onWater === true) ? this.navalPassMap[index] : this.landPassMap[index]; … … 539 542 return this.regionSize[ID]; 540 543 }; 541 544 542 Accessibility.prototype.getRegionSizei = function(index, onWater) {545 m.Accessibility.prototype.getRegionSizei = function(index, onWater) { 543 546 if (this.regionSize[this.landPassMap[index]] === undefined && (!onWater || this.regionSize[this.navalPassMap[index]] === undefined)) 544 547 return 0; 545 548 if (onWater && this.regionSize[this.navalPassMap[index]] > this.regionSize[this.landPassMap[index]]) … … 549 552 550 553 // Implementation of a fast flood fill. Reasonably good performances for JS. 551 554 // TODO: take big zones of impassable trees into account? 552 Accessibility.prototype.floodFill = function(startIndex, value, onWater)555 m.Accessibility.prototype.floodFill = function(startIndex, value, onWater) 553 556 { 554 557 this.s = startIndex; 555 558 if ((!onWater && this.landPassMap[this.s] !== 0) || (onWater && this.navalPassMap[this.s] !== 0) ) { … … 668 671 } 669 672 670 673 // creates a map of resource density 671 SharedScript.prototype.createResourceMaps = function(sharedScript) {674 m.SharedScript.prototype.createResourceMaps = function(sharedScript) { 672 675 673 676 for (var resource in this.decreaseFactor){ 674 677 // if there is no resourceMap create one with an influence for everything with that resource 675 678 if (! this.resourceMaps[resource]){ 676 679 // We're creting them 8-bit. Things could go above 255 if there are really tons of resources 677 680 // But at that point the precision is not really important anyway. And it saves memory. 678 this.resourceMaps[resource] = new Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));681 this.resourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length)); 679 682 this.resourceMaps[resource].setMaxVal(255); 680 this.CCResourceMaps[resource] = new Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));683 this.CCResourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length)); 681 684 this.CCResourceMaps[resource].setMaxVal(255); 682 685 } 683 686 } … … 711 714 // creates and maintains a map of unused resource density 712 715 // this also takes dropsites into account. 713 716 // resources that are "part" of a dropsite are not counted. 714 SharedScript.prototype.updateResourceMaps = function(sharedScript, events) {717 m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events) { 715 718 716 719 for (var resource in this.decreaseFactor){ 717 720 // if there is no resourceMap create one with an influence for everything with that resource 718 721 if (! this.resourceMaps[resource]){ 719 722 // We're creting them 8-bit. Things could go above 255 if there are really tons of resources 720 723 // But at that point the precision is not really important anyway. And it saves memory. 721 this.resourceMaps[resource] = new Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));724 this.resourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length)); 722 725 this.resourceMaps[resource].setMaxVal(255); 723 this.CCResourceMaps[resource] = new Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));726 this.CCResourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length)); 724 727 this.CCResourceMaps[resource].setMaxVal(255); 725 728 } 726 729 } … … 780 783 } 781 784 } 782 785 }; 786 787 return m; 788 789 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/entitycollection.js
1 function EntityCollection(sharedAI, entities, filters)1 var API3 = function(m) 2 2 { 3 4 m.EntityCollection = function(sharedAI, entities, filters) 5 { 3 6 this._ai = sharedAI; 4 7 this._entities = entities || {}; 5 8 this._filters = filters || []; … … 22 25 } 23 26 }); 24 27 this.frozen = false; 25 } 28 }; 26 29 27 30 // If an entitycollection is frozen, it will never automatically add a unit. 28 31 // But can remove one. 29 32 // this makes it easy to create entity collection that will auto-remove dead units 30 33 // but never add new ones. 31 EntityCollection.prototype.freeze = function()34 m.EntityCollection.prototype.freeze = function() 32 35 { 33 36 this.frozen = true; 34 37 }; 35 EntityCollection.prototype.defreeze = function()38 m.EntityCollection.prototype.defreeze = function() 36 39 { 37 40 this.frozen = false; 38 41 }; 39 42 40 EntityCollection.prototype.allowQuickIter = function()43 m.EntityCollection.prototype.allowQuickIter = function() 41 44 { 42 45 this._quickIter = true; 43 46 this._entitiesArray = []; … … 45 48 this._entitiesArray.push(ent); 46 49 }; 47 50 48 EntityCollection.prototype.toIdArray = function()51 m.EntityCollection.prototype.toIdArray = function() 49 52 { 50 53 var ret = []; 51 54 for (var id in this._entities) … … 53 56 return ret; 54 57 }; 55 58 56 EntityCollection.prototype.toEntityArray = function()59 m.EntityCollection.prototype.toEntityArray = function() 57 60 { 58 61 if (this._quickIter === true) 59 62 return this._entitiesArray; … … 63 66 return ret; 64 67 }; 65 68 66 EntityCollection.prototype.toString = function()69 m.EntityCollection.prototype.toString = function() 67 70 { 68 71 return "[EntityCollection " + this.toEntityArray().join(" ") + "]"; 69 72 }; … … 71 74 /** 72 75 * Returns the (at most) n entities nearest to targetPos. 73 76 */ 74 EntityCollection.prototype.filterNearest = function(targetPos, n)77 m.EntityCollection.prototype.filterNearest = function(targetPos, n) 75 78 { 76 79 // Compute the distance of each entity 77 80 var data = []; // [id, ent, distance] … … 82 85 { 83 86 var ent = this._entitiesArray[i]; 84 87 if (ent.position() !== -1) 85 data.push([ent.id(), ent, SquareVectorDistance(targetPos, ent.position())]);88 data.push([ent.id(), ent, m.SquareVectorDistance(targetPos, ent.position())]); 86 89 } 87 90 } else { 88 91 for (var id in this._entities) 89 92 { 90 93 var ent = this._entities[id]; 91 94 if (ent.position() !== -1) 92 data.push([id, ent, SquareVectorDistance(targetPos, ent.position())]);95 data.push([id, ent, m.SquareVectorDistance(targetPos, ent.position())]); 93 96 } 94 97 } 95 98 … … 102 105 for (var i = 0; i < length; ++i) 103 106 ret[data[i][0]] = data[i][1]; 104 107 105 return new EntityCollection(this._ai, ret);108 return new m.EntityCollection(this._ai, ret); 106 109 }; 107 110 108 EntityCollection.prototype.filter = function(filter, thisp)111 m.EntityCollection.prototype.filter = function(filter, thisp) 109 112 { 110 113 if (typeof(filter) == "function") 111 114 filter = {"func": filter, "dynamicProperties": []}; … … 129 132 } 130 133 } 131 134 132 return new EntityCollection(this._ai, ret, this._filters.concat([filter]));135 return new m.EntityCollection(this._ai, ret, this._filters.concat([filter])); 133 136 }; 134 137 135 EntityCollection.prototype.filter_raw = function(callback, thisp)138 m.EntityCollection.prototype.filter_raw = function(callback, thisp) 136 139 { 137 140 var ret = {}; 138 141 for (var id in this._entities) … … 142 145 if (callback.call(thisp, val, id, this)) 143 146 ret[id] = ent; 144 147 } 145 return new EntityCollection(this._ai, ret);148 return new m.EntityCollection(this._ai, ret); 146 149 }; 147 150 148 EntityCollection.prototype.forEach = function(callback)151 m.EntityCollection.prototype.forEach = function(callback) 149 152 { 150 153 if (this._quickIter === true) 151 154 { … … 162 165 return this; 163 166 }; 164 167 165 EntityCollection.prototype.filterNearest = function(targetPos, n)168 m.EntityCollection.prototype.filterNearest = function(targetPos, n) 166 169 { 167 170 // Compute the distance of each entity 168 171 var data = []; // [ [id, ent, distance], ... ] … … 170 173 { 171 174 var ent = this._entities[id]; 172 175 if (ent.position()) 173 data.push([id, ent, SquareVectorDistance(targetPos, ent.position())]);176 data.push([id, ent, m.SquareVectorDistance(targetPos, ent.position())]); 174 177 } 175 178 176 179 // Sort by increasing distance … … 182 185 for each (var val in data.slice(0, n)) 183 186 ret[val[0]] = val[1]; 184 187 185 return new EntityCollection(this._ai, ret);188 return new m.EntityCollection(this._ai, ret); 186 189 }; 187 190 188 EntityCollection.prototype.move = function(x, z, queued)191 m.EntityCollection.prototype.move = function(x, z, queued) 189 192 { 190 193 queued = queued || false; 191 Engine.PostCommand( {"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});194 Engine.PostCommand(PlayerID,{"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued}); 192 195 return this; 193 196 }; 194 EntityCollection.prototype.attackMove = function(x, z, queued)197 m.EntityCollection.prototype.attackMove = function(x, z, queued) 195 198 { 196 199 queued = queued || false; 197 200 Engine.PostCommand({"type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued}); 198 201 return this; 199 202 }; 200 EntityCollection.prototype.moveIndiv = function(x, z, queued)203 m.EntityCollection.prototype.moveIndiv = function(x, z, queued) 201 204 { 202 205 queued = queued || false; 203 206 for (var id in this._entities) … … 206 209 // It disables JIT compiling of this loop. Don't remove it unless you are sure that the underlying issue has been resolved! 207 210 // TODO: Check this again after the SpiderMonkey upgrade. 208 211 try {} finally {} 209 Engine.PostCommand( {"type": "walk", "entities": [this._entities[id].id()], "x": x, "z": z, "queued": queued});212 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this._entities[id].id()], "x": x, "z": z, "queued": queued}); 210 213 } 211 214 return this; 212 215 }; 213 EntityCollection.prototype.destroy = function()216 m.EntityCollection.prototype.destroy = function() 214 217 { 215 Engine.PostCommand( {"type": "delete-entities", "entities": this.toIdArray()});218 Engine.PostCommand(PlayerID,{"type": "delete-entities", "entities": this.toIdArray()}); 216 219 return this; 217 220 }; 218 EntityCollection.prototype.attack = function(unit)221 m.EntityCollection.prototype.attack = function(unit) 219 222 { 220 223 var unitId; 221 224 if (typeof(unit) === "Entity") … … 226 229 { 227 230 unitId = unit; 228 231 } 229 Engine.PostCommand( {"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});232 Engine.PostCommand(PlayerID,{"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false}); 230 233 return this; 231 234 }; 232 235 // violent, aggressive, defensive, passive, standground 233 EntityCollection.prototype.setStance = function(stance)236 m.EntityCollection.prototype.setStance = function(stance) 234 237 { 235 Engine.PostCommand( {"type": "stance", "entities": this.toIdArray(), "name" : stance, "queued": false});238 Engine.PostCommand(PlayerID,{"type": "stance", "entities": this.toIdArray(), "name" : stance, "queued": false}); 236 239 return this; 237 240 }; 238 241 239 242 // Returns the average position of all units 240 EntityCollection.prototype.getCentrePosition = function()243 m.EntityCollection.prototype.getCentrePosition = function() 241 244 { 242 245 var sumPos = [0, 0]; 243 246 var count = 0; … … 263 266 // returns the average position from the sample first units. 264 267 // This might be faster for huge collections, but there's 265 268 // always a risk that it'll be unprecise. 266 EntityCollection.prototype.getApproximatePosition = function(sample)269 m.EntityCollection.prototype.getApproximatePosition = function(sample) 267 270 { 268 271 var sumPos = [0, 0]; 269 272 var i = 0; … … 291 294 292 295 293 296 // Removes an entity from the collection, returns true if the entity was a member, false otherwise 294 EntityCollection.prototype.removeEnt = function(ent)297 m.EntityCollection.prototype.removeEnt = function(ent) 295 298 { 296 299 if (this._entities[ent.id()]) 297 300 { … … 310 313 }; 311 314 312 315 // Adds an entity to the collection, returns true if the entity was not member, false otherwise 313 EntityCollection.prototype.addEnt = function(ent)316 m.EntityCollection.prototype.addEnt = function(ent) 314 317 { 315 318 if (this._entities[ent.id()]) 316 319 { … … 333 336 // Force can add a unit despite a freezing. 334 337 // If an entitycollection is frozen, it will never automatically add a unit. 335 338 // But can remove one. 336 EntityCollection.prototype.updateEnt = function(ent, force)339 m.EntityCollection.prototype.updateEnt = function(ent, force) 337 340 { 338 341 var passesFilters = true; 339 342 for each (var filter in this._filters) … … 353 356 } 354 357 }; 355 358 356 EntityCollection.prototype.registerUpdates = function(noPush)359 m.EntityCollection.prototype.registerUpdates = function(noPush) 357 360 { 358 361 this._ai.registerUpdatingEntityCollection(this,noPush); 359 362 }; 360 363 361 EntityCollection.prototype.unregister = function()364 m.EntityCollection.prototype.unregister = function() 362 365 { 363 366 this._ai.removeUpdatingEntityCollection(this); 364 367 }; 365 368 366 EntityCollection.prototype.dynamicProperties = function()369 m.EntityCollection.prototype.dynamicProperties = function() 367 370 { 368 371 var ret = []; 369 372 for each (var filter in this._filters) … … 374 377 return ret; 375 378 }; 376 379 377 EntityCollection.prototype.setUID = function(id)380 m.EntityCollection.prototype.setUID = function(id) 378 381 { 379 382 this._UID = id; 380 383 }; 381 384 382 EntityCollection.prototype.getUID = function()385 m.EntityCollection.prototype.getUID = function() 383 386 { 384 387 return this._UID; 385 388 }; 389 390 return m; 391 392 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/utils.js
1 function VectorDistance(a, b)1 var API3 = function(m) 2 2 { 3 4 m.VectorDistance = function(a, b) 5 { 3 6 var dx = a[0] - b[0]; 4 7 var dz = a[1] - b[1]; 5 8 return Math.sqrt(dx*dx + dz*dz); 6 9 } 7 10 8 function SquareVectorDistance(a, b)11 m.SquareVectorDistance = function(a, b) 9 12 { 10 13 var dx = a[0] - b[0]; 11 14 var dz = a[1] - b[1]; … … 13 16 } 14 17 // A is the reference, B must be in "range" of A 15 18 // this supposes the range is already squared 16 function inRange(a, b, range)// checks for X distance19 m.inRange = function(a, b, range)// checks for X distance 17 20 { 18 21 // will avoid unnecessary checking for position in some rare cases... I'm lazy 19 22 if (a === undefined || b === undefined || range === undefined) … … 24 27 return ((dx*dx + dz*dz ) < range); 25 28 } 26 29 // slower than SquareVectorDistance, faster than VectorDistance but not exactly accurate. 27 function ManhattanDistance(a, b)30 m.ManhattanDistance = function(a, b) 28 31 { 29 32 var dx = a[0] - b[0]; 30 33 var dz = a[1] - b[1]; 31 34 return Math.abs(dx) + Math.abs(dz); 32 35 } 33 36 34 function AssocArraytoArray(assocArray) {37 m.AssocArraytoArray = function(assocArray) { 35 38 var endArray = []; 36 39 for (var i in assocArray) 37 40 endArray.push(assocArray[i]); 38 41 return endArray; 39 42 }; 40 43 41 function MemoizeInit(obj)44 m.MemoizeInit = function(obj) 42 45 { 43 46 obj._memoizeCache = {}; 44 47 } 45 48 46 function Memoize(funcname, func)49 m.Memoize = function(funcname, func) 47 50 { 48 51 return function() { 49 52 var args = funcname + '|' + Array.prototype.join.call(arguments, '|'); … … 56 59 }; 57 60 } 58 61 59 function ShallowClone(obj)62 m.ShallowClone = function(obj) 60 63 { 61 64 var ret = {}; 62 65 for (var k in obj) … … 65 68 } 66 69 67 70 // Picks a random element from an array 68 function PickRandom(list){71 m.PickRandom = function(list){ 69 72 if (list.length === 0) 70 73 { 71 74 return undefined; … … 75 78 return list[Math.floor(Math.random()*list.length)]; 76 79 } 77 80 } 81 82 return m; 83 84 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/shared.js
1 var API3 = function(m) 2 { 3 1 4 // Shared script handling templates and basic terrain analysis 2 function SharedScript(settings)5 m.SharedScript = function(settings) 3 6 { 4 7 if (!settings) 5 8 return; … … 37 40 //Return a simple object (using no classes etc) that will be serialized 38 41 //into saved games 39 42 //TODO: that 40 SharedScript.prototype.Serialize = function()43 m.SharedScript.prototype.Serialize = function() 41 44 { 42 45 return { "players" : this._players, "templates" : this._templates, "techTp" : this._techTemplates }; 43 46 }; 44 47 45 48 // Called after the constructor when loading a saved game, with 'data' being 46 49 // whatever Serialize() returned 47 SharedScript.prototype.Deserialize = function(data)50 m.SharedScript.prototype.Deserialize = function(data) 48 51 { 49 52 this._players = data.players; 50 53 this._templates = data.templates; … … 56 59 // (This is a bit yucky and fragile since it's the inverse of 57 60 // CCmpTemplateManager::CopyFoundationSubset and only includes components 58 61 // that our EntityTemplate class currently uses.) 59 varg_FoundationForbiddenComponents = {62 m.g_FoundationForbiddenComponents = { 60 63 "ProductionQueue": 1, 61 64 "ResourceSupply": 1, 62 65 "ResourceDropsite": 1, … … 65 68 66 69 // Components that will be disabled in resource entity templates. 67 70 // Roughly the inverse of CCmpTemplateManager::CopyResourceSubset. 68 varg_ResourceForbiddenComponents = {71 m.g_ResourceForbiddenComponents = { 69 72 "Cost": 1, 70 73 "Decay": 1, 71 74 "Health": 1, … … 74 77 "Vision": 1 75 78 }; 76 79 77 SharedScript.prototype.GetTemplate = function(name)80 m.SharedScript.prototype.GetTemplate = function(name) 78 81 { 79 82 if (this._templates[name]) 80 83 return this._templates[name]; … … 89 92 90 93 var foundation = {}; 91 94 for (var key in base) 92 if (! g_FoundationForbiddenComponents[key])95 if (!m.g_FoundationForbiddenComponents[key]) 93 96 foundation[key] = base[key]; 94 97 95 98 this._derivedTemplates[name] = foundation; … … 101 104 102 105 var resource = {}; 103 106 for (var key in base) 104 if (! g_ResourceForbiddenComponents[key])107 if (!m.g_ResourceForbiddenComponents[key]) 105 108 resource[key] = base[key]; 106 109 107 110 this._derivedTemplates[name] = resource; … … 115 118 // Initialize the shared component. 116 119 // We need to now the initial state of the game for this, as we will use it. 117 120 // This is called right at the end of the map generation. 118 SharedScript.prototype.init = function(state) {121 m.SharedScript.prototype.init = function(state) { 119 122 this.passabilityClasses = state.passabilityClasses; 120 123 this.passabilityMap = state.passabilityMap; 121 124 this.players = this._players; … … 128 131 129 132 this._entities = {}; 130 133 for (var id in state.entities) 131 this._entities[id] = new Entity(this, state.entities[id]);134 this._entities[id] = new m.Entity(this, state.entities[id]); 132 135 133 136 // entity collection updated on create/destroy event. 134 this.entities = new EntityCollection(this, this._entities);137 this.entities = new m.EntityCollection(this, this._entities); 135 138 136 139 // create the terrain analyzer 137 this.terrainAnalyzer = new TerrainAnalysis();140 this.terrainAnalyzer = new m.TerrainAnalysis(); 138 141 this.terrainAnalyzer.init(this, state); 139 this.accessibility = new Accessibility();142 this.accessibility = new m.Accessibility(); 140 143 this.accessibility.init(state, this.terrainAnalyzer); 141 144 142 145 // defined in TerrainAnalysis.js … … 145 148 this.gameState = {}; 146 149 for (var i in this._players) 147 150 { 148 this.gameState[this._players[i]] = new GameState();151 this.gameState[this._players[i]] = new m.GameState(); 149 152 this.gameState[this._players[i]].init(this,state,this._players[i]); 150 153 } 151 154 }; 152 155 153 156 // General update of the shared script, before each AI's update 154 157 // applies entity deltas, and each gamestate. 155 SharedScript.prototype.onUpdate = function(state)158 m.SharedScript.prototype.onUpdate = function(state) 156 159 { 157 160 if (this.isDeserialized && this.turn !== 0) 158 161 { … … 188 191 Engine.ProfileStop(); 189 192 }; 190 193 191 SharedScript.prototype.ApplyEntitiesDelta = function(state)194 m.SharedScript.prototype.ApplyEntitiesDelta = function(state) 192 195 { 193 196 Engine.ProfileStart("Shared ApplyEntitiesDelta"); 194 197 … … 202 205 { 203 206 continue; // Sometimes there are things like foundations which get destroyed too fast 204 207 } 205 this._entities[evt.msg.entity] = new Entity(this, state.entities[evt.msg.entity]);208 this._entities[evt.msg.entity] = new m.Entity(this, state.entities[evt.msg.entity]); 206 209 this.entities.addEnt(this._entities[evt.msg.entity]); 207 210 208 211 // Update all the entity collections since the create operation affects static properties as well as dynamic … … 302 305 Engine.ProfileStop(); 303 306 }; 304 307 305 SharedScript.prototype.registerUpdatingEntityCollection = function(entCollection, noPush)308 m.SharedScript.prototype.registerUpdatingEntityCollection = function(entCollection, noPush) 306 309 { 307 310 if (!noPush) { 308 311 this._entityCollections.push(entCollection); … … 316 319 this._entityCollectionsUID++; 317 320 }; 318 321 319 SharedScript.prototype.removeUpdatingEntityCollection = function(entCollection)322 m.SharedScript.prototype.removeUpdatingEntityCollection = function(entCollection) 320 323 { 321 324 for (var i in this._entityCollections) 322 325 { … … 338 341 } 339 342 }; 340 343 341 SharedScript.prototype.updateEntityCollections = function(property, ent)344 m.SharedScript.prototype.updateEntityCollections = function(property, ent) 342 345 { 343 346 if (this._entityCollectionsByDynProp[property] !== undefined) 344 347 { … … 349 352 } 350 353 } 351 354 352 SharedScript.prototype.setMetadata = function(player, ent, key, value)355 m.SharedScript.prototype.setMetadata = function(player, ent, key, value) 353 356 { 354 357 var metadata = this._entityMetadata[player][ent.id()]; 355 358 if (!metadata) … … 359 362 this.updateEntityCollections('metadata', ent); 360 363 this.updateEntityCollections('metadata.' + key, ent); 361 364 }; 362 SharedScript.prototype.getMetadata = function(player, ent, key)365 m.SharedScript.prototype.getMetadata = function(player, ent, key) 363 366 { 364 367 var metadata = this._entityMetadata[player][ent.id()]; 365 368 … … 367 370 return undefined; 368 371 return metadata[key]; 369 372 }; 370 SharedScript.prototype.deleteMetadata = function(player, ent, key)373 m.SharedScript.prototype.deleteMetadata = function(player, ent, key) 371 374 { 372 375 var metadata = this._entityMetadata[player][ent.id()]; 373 376 … … 378 381 return true; 379 382 }; 380 383 381 function copyPrototype(descendant, parent) {384 m.copyPrototype = function(descendant, parent) { 382 385 var sConstructor = parent.toString(); 383 386 var aMatch = sConstructor.match( /\s*function (.*)\(/ ); 384 387 if ( aMatch != null ) { descendant.prototype[aMatch[1]] = parent; } … … 387 390 } 388 391 }; 389 392 393 return m; 394 395 }(API3); 396 -
binaries/data/mods/public/simulation/ai/common-api-v3/terrain-analysis-pathfinder.js
1 var API3 = function(m) 2 { 3 1 4 // An implementation of A* as a pathfinder. 2 5 // It's oversamplable, and has a specific "distance from block" 3 6 // variable to avoid narrow passages if wanted. … … 11 14 12 15 // The initializer creates an expanded influence map for checking. 13 16 // It's not extraordinarily slow, but it might be. 14 function aStarPath(gameState, onWater, disregardEntities, targetTerritory) {17 m.aStarPath = function(gameState, onWater, disregardEntities, targetTerritory) { 15 18 var self = this; 16 19 17 20 // get the terrain analyzer map as a reference. … … 52 55 } 53 56 this.expandInfluences(255,this.widthMap); 54 57 } 55 copyPrototype(aStarPath,Map);58 m.copyPrototype(m.aStarPath, m.Map); 56 59 57 60 // marks some points of the map as impassable. This can be used to create different paths, or to avoid going through some areas. 58 aStarPath.prototype.markImpassableArea = function(cx, cy, Distance) {61 m.aStarPath.prototype.markImpassableArea = function(cx, cy, Distance) { 59 62 [cx,cy] = this.gamePosToMapPos([cx,cy]); 60 63 var x0 = Math.max(0, cx - Distance); 61 64 var y0 = Math.max(0, cy - Distance); … … 78 81 79 82 // sending gamestate creates a map 80 83 // (you run the risk of "jumping" over obstacles or weird behavior. 81 aStarPath.prototype.getPath = function(start, end, Sampling, preferredWidth, iterationLimit, gamestate)84 m.aStarPath.prototype.getPath = function(start, end, Sampling, preferredWidth, iterationLimit, gamestate) 82 85 { 83 86 this.Sampling = Sampling >= 1 ? Sampling : 1; 84 87 this.minWidth = 1; … … 97 100 } 98 101 if (gamestate !== undefined) 99 102 { 100 this.TotorMap = new Map(gamestate);103 this.TotorMap = new m.Map(gamestate); 101 104 this.TotorMap.addInfluence(s[0],s[1],1,200,'constant'); 102 105 this.TotorMap.addInfluence(e[0],e[1],1,200,'constant'); 103 106 } … … 135 138 136 139 this.isOpened[this.s] = true; 137 140 this.openList.push(this.s); 138 this.fCostArray[this.s] = SquareVectorDistance([this.s%w, Math.floor(this.s/w)], [this.e%w, Math.floor(this.e/w)]);141 this.fCostArray[this.s] = m.SquareVectorDistance([this.s%w, Math.floor(this.s/w)], [this.e%w, Math.floor(this.e/w)]); 139 142 this.gCostArray[this.s] = 0; 140 143 this.parentSquare[this.s] = this.s; 141 144 … … 143 146 144 147 } 145 148 // in case it's not over yet, this can carry on the calculation of a path over multiple turn until it's over 146 aStarPath.prototype.continuePath = function(gamestate)149 m.aStarPath.prototype.continuePath = function(gamestate) 147 150 { 148 151 var w = this.width; 149 152 var h = this.height; … … 208 211 { 209 212 this.parentSquare[index] = this.currentSquare; 210 213 211 this.fCostArray[index] = SquareVectorDistance([index%w, Math.floor(index/w)], target);// * cost[i];214 this.fCostArray[index] = m.SquareVectorDistance([index%w, Math.floor(index/w)], target);// * cost[i]; 212 215 this.gCostArray[index] = this.gCostArray[this.currentSquare] + cost[i] * this.Sampling;// - this.map[index]; 213 216 214 217 if (!this.onWater && this.map[index] === 200) { … … 231 234 this.openList.push(index); 232 235 } 233 236 this.isOpened[index] = true; 234 if ( SquareVectorDistance( [index%w, Math.floor(index/w)] , target) <= this.Sampling*this.Sampling-1) {237 if (m.SquareVectorDistance( [index%w, Math.floor(index/w)] , target) <= this.Sampling*this.Sampling-1) { 235 238 if (this.e != index) 236 239 this.parentSquare[this.e] = index; 237 240 found = true; … … 294 297 if (gamestate !== undefined) 295 298 this.TotorMap.addInfluence(this.currentSquare % w, Math.floor(this.currentSquare / w),1,50,'constant'); 296 299 297 if ( SquareVectorDistance([lastPosx,lastPosy],[this.currentSquare % w, Math.floor(this.currentSquare / w)]) > 300 || changes[this.currentSquare])300 if (m.SquareVectorDistance([lastPosx,lastPosy],[this.currentSquare % w, Math.floor(this.currentSquare / w)]) > 300 || changes[this.currentSquare]) 298 301 { 299 302 lastPosx = (this.currentSquare % w); 300 303 lastPosy = Math.floor(this.currentSquare / w); … … 325 328 } 326 329 327 330 } 331 332 return m; 333 334 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/gamestate.js
1 var API3 = function(m) 2 { 3 4 1 5 /** 2 6 * Provides an API for the rest of the AI scripts to query the world state at a 3 7 * higher level than the raw data. … … 2 6 */ 3 varGameState = function() {7 m.GameState = function() { 4 8 this.ai = null; // must be updated by the AIs. … … 10 14 this.turnCache = {}; 11 15 }; 12 16 13 GameState.prototype.init = function(SharedScript, state, player) {17 m.GameState.prototype.init = function(SharedScript, state, player) { 14 18 this.sharedScript = SharedScript; 15 19 this.EntCollecNames = SharedScript._entityCollectionsName; 16 20 this.EntCollec = SharedScript._entityCollections; … … 23 27 this.techModifications = SharedScript._techModifications[this.player]; 24 28 }; 25 29 26 GameState.prototype.update = function(SharedScript, state) {30 m.GameState.prototype.update = function(SharedScript, state) { 27 31 this.sharedScript = SharedScript; 28 32 this.EntCollecNames = SharedScript._entityCollectionsName; 29 33 this.EntCollec = SharedScript._entityCollections; … … 39 43 this.turnCache = {}; 40 44 }; 41 45 42 GameState.prototype.updatingCollection = function(id, filter, collection, allowQuick){46 m.GameState.prototype.updatingCollection = function(id, filter, collection, allowQuick){ 43 47 // automatically add the player ID 44 48 id = this.player + "-" + id; 45 49 if (!this.EntCollecNames[id]){ … … 56 60 57 61 return this.EntCollecNames[id]; 58 62 }; 59 GameState.prototype.destroyCollection = function(id){63 m.GameState.prototype.destroyCollection = function(id){ 60 64 // automatically add the player ID 61 65 id = this.player + "-" + id; 62 66 … … 65 69 delete this.EntCollecNames[id]; 66 70 } 67 71 }; 68 GameState.prototype.getEC = function(id){72 m.GameState.prototype.getEC = function(id){ 69 73 // automatically add the player ID 70 74 id = this.player + "-" + id; 71 75 … … 74 78 return undefined; 75 79 }; 76 80 77 GameState.prototype.updatingGlobalCollection = function(id, filter, collection, allowQuick) {81 m.GameState.prototype.updatingGlobalCollection = function(id, filter, collection, allowQuick) { 78 82 if (!this.EntCollecNames[id]){ 79 83 if (collection !== undefined) 80 84 this.EntCollecNames[id] = collection.filter(filter); … … 88 92 89 93 return this.EntCollecNames[id]; 90 94 }; 91 GameState.prototype.destroyGlobalCollection = function(id)95 m.GameState.prototype.destroyGlobalCollection = function(id) 92 96 { 93 97 if (this.EntCollecNames[id] !== undefined){ 94 98 this.sharedScript.removeUpdatingEntityCollection(this.EntCollecNames[id]); 95 99 delete this.EntCollecNames[id]; 96 100 } 97 101 }; 98 GameState.prototype.getGEC = function(id)102 m.GameState.prototype.getGEC = function(id) 99 103 { 100 104 if (this.EntCollecNames[id] !== undefined) 101 105 return this.EntCollecNames[id]; 102 106 return undefined; 103 107 }; 104 108 105 GameState.prototype.currentPhase = function()109 m.GameState.prototype.currentPhase = function() 106 110 { 107 111 if (this.isResearched("phase_city")) 108 112 return 3; … … 113 117 return 0; 114 118 }; 115 119 116 GameState.prototype.townPhase = function()120 m.GameState.prototype.townPhase = function() 117 121 { 118 122 if (this.playerData.civ == "athen") 119 123 return "phase_town_athen"; 120 124 return "phase_town_generic"; 121 125 }; 122 126 123 GameState.prototype.cityPhase = function()127 m.GameState.prototype.cityPhase = function() 124 128 { 125 129 return "phase_city_generic"; 126 130 }; 127 131 128 GameState.prototype.isResearched = function(template)132 m.GameState.prototype.isResearched = function(template) 129 133 { 130 134 return this.playerData.researchedTechs[template] !== undefined; 131 135 }; 132 136 // true if started or queued 133 GameState.prototype.isResearching = function(template)137 m.GameState.prototype.isResearching = function(template) 134 138 { 135 139 return (this.playerData.researchStarted[template] !== undefined || this.playerData.researchQueued[template] !== undefined); 136 140 }; 137 141 138 142 // this is an absolute check that doesn't check if we have a building to research from. 139 GameState.prototype.canResearch = function(techTemplateName, noRequirementCheck)143 m.GameState.prototype.canResearch = function(techTemplateName, noRequirementCheck) 140 144 { 141 145 var template = this.getTemplate(techTemplateName); 142 146 if (!template) … … 170 174 171 175 // Private function for checking a set of requirements is met 172 176 // basically copies TechnologyManager's 173 GameState.prototype.checkTechRequirements = function (reqs)177 m.GameState.prototype.checkTechRequirements = function (reqs) 174 178 { 175 179 // If there are no requirements then all requirements are met 176 180 if (!reqs) … … 229 233 }; 230 234 231 235 232 GameState.prototype.getTimeElapsed = function()236 m.GameState.prototype.getTimeElapsed = function() 233 237 { 234 238 return this.timeElapsed; 235 239 }; 236 240 237 GameState.prototype.getTemplate = function(type)241 m.GameState.prototype.getTemplate = function(type) 238 242 { 239 243 if (this.techTemplates[type] !== undefined) 240 return new Technology(this.techTemplates, type);244 return new m.Technology(this.techTemplates, type); 241 245 242 246 if (!this.templates[type]) 243 247 return null; 244 248 245 return new EntityTemplate(this.templates[type], this.techModifications);249 return new m.EntityTemplate(this.templates[type], this.techModifications); 246 250 }; 247 251 248 GameState.prototype.applyCiv = function(str) {252 m.GameState.prototype.applyCiv = function(str) { 249 253 return str.replace(/\{civ\}/g, this.playerData.civ); 250 254 }; 251 255 252 GameState.prototype.civ = function() {256 m.GameState.prototype.civ = function() { 253 257 return this.playerData.civ; 254 258 }; 255 259 256 260 /** 257 261 * @returns {Resources} 258 262 */ 259 GameState.prototype.getResources = function() {260 return new Resources(this.playerData.resourceCounts);263 m.GameState.prototype.getResources = function() { 264 return new m.Resources(this.playerData.resourceCounts); 261 265 }; 262 266 263 GameState.prototype.getMap = function() {267 m.GameState.prototype.getMap = function() { 264 268 return this.sharedScript.passabilityMap; 265 269 }; 266 270 267 GameState.prototype.getPopulation = function() {271 m.GameState.prototype.getPopulation = function() { 268 272 return this.playerData.popCount; 269 273 }; 270 274 271 GameState.prototype.getPopulationLimit = function() {275 m.GameState.prototype.getPopulationLimit = function() { 272 276 return this.playerData.popLimit; 273 277 }; 274 278 275 GameState.prototype.getPopulationMax = function() {279 m.GameState.prototype.getPopulationMax = function() { 276 280 return this.playerData.popMax; 277 281 }; 278 282 279 GameState.prototype.getPassabilityClassMask = function(name) {283 m.GameState.prototype.getPassabilityClassMask = function(name) { 280 284 if (!(name in this.sharedScript.passabilityClasses)){ 281 285 error("Tried to use invalid passability class name '" + name + "'"); 282 286 } 283 287 return this.sharedScript.passabilityClasses[name]; 284 288 }; 285 289 286 GameState.prototype.getPlayerID = function() {290 m.GameState.prototype.getPlayerID = function() { 287 291 return this.player; 288 292 }; 289 293 290 GameState.prototype.isPlayerAlly = function(id) {294 m.GameState.prototype.isPlayerAlly = function(id) { 291 295 return this.playerData.isAlly[id]; 292 296 }; 293 297 294 GameState.prototype.isPlayerEnemy = function(id) {298 m.GameState.prototype.isPlayerEnemy = function(id) { 295 299 return this.playerData.isEnemy[id]; 296 300 }; 297 301 298 GameState.prototype.getEnemies = function(){302 m.GameState.prototype.getEnemies = function(){ 299 303 var ret = []; 300 304 for (var i in this.playerData.isEnemy){ 301 305 if (this.playerData.isEnemy[i]){ … … 305 309 return ret; 306 310 }; 307 311 308 GameState.prototype.isEntityAlly = function(ent) {312 m.GameState.prototype.isEntityAlly = function(ent) { 309 313 if (ent && ent.owner && (typeof ent.owner) === "function"){ 310 314 return this.playerData.isAlly[ent.owner()]; 311 315 } else if (ent && ent.owner){ … … 314 318 return false; 315 319 }; 316 320 317 GameState.prototype.isEntityEnemy = function(ent) {321 m.GameState.prototype.isEntityEnemy = function(ent) { 318 322 if (ent && ent.owner && (typeof ent.owner) === "function"){ 319 323 return this.playerData.isEnemy[ent.owner()]; 320 324 } else if (ent && ent.owner){ … … 323 327 return false; 324 328 }; 325 329 326 GameState.prototype.isEntityOwn = function(ent) {330 m.GameState.prototype.isEntityOwn = function(ent) { 327 331 if (ent && ent.owner && (typeof ent.owner) === "function"){ 328 332 return ent.owner() == this.player; 329 333 } else if (ent && ent.owner){ … … 332 336 return false; 333 337 }; 334 338 335 GameState.prototype.getOwnEntities = function() {336 return this.updatingCollection("own-entities", Filters.byOwner(this.player));339 m.GameState.prototype.getOwnEntities = function() { 340 return this.updatingCollection("own-entities", m.Filters.byOwner(this.player)); 337 341 }; 338 342 339 GameState.prototype.getEnemyEntities = function() {343 m.GameState.prototype.getEnemyEntities = function() { 340 344 var diplomacyChange = false; 341 345 var enemies = this.getEnemies(); 342 346 if (this.enemies){ … … 351 355 } 352 356 } 353 357 if (diplomacyChange || !this.enemies){ 354 return this.updatingCollection("enemy-entities", Filters.byOwners(enemies));358 return this.updatingCollection("enemy-entities", m.Filters.byOwners(enemies)); 355 359 this.enemies = enemies; 356 360 } 357 361 return this.getEC("enemy-entities"); 358 362 }; 359 363 360 GameState.prototype.getEntities = function() {364 m.GameState.prototype.getEntities = function() { 361 365 return this.entities; 362 366 }; 363 367 364 GameState.prototype.getEntityById = function(id){368 m.GameState.prototype.getEntityById = function(id){ 365 369 if (this.entities._entities[id]) { 366 370 return this.entities._entities[id]; 367 371 }else{ … … 370 374 return undefined; 371 375 }; 372 376 373 GameState.prototype.getOwnEntitiesByMetadata = function(key, value, maintain){377 m.GameState.prototype.getOwnEntitiesByMetadata = function(key, value, maintain){ 374 378 if (maintain === true) 375 return this.updatingCollection(key + "-" + value, Filters.byMetadata(this.player, key, value),this.getOwnEntities());376 return this.getOwnEntities().filter( Filters.byMetadata(this.player, key, value));379 return this.updatingCollection(key + "-" + value, m.Filters.byMetadata(this.player, key, value),this.getOwnEntities()); 380 return this.getOwnEntities().filter(m.Filters.byMetadata(this.player, key, value)); 377 381 }; 378 382 379 GameState.prototype.getOwnEntitiesByRole = function(role){383 m.GameState.prototype.getOwnEntitiesByRole = function(role){ 380 384 return this.getOwnEntitiesByMetadata("role", role, true); 381 385 }; 382 386 383 GameState.prototype.getOwnTrainingFacilities = function(){384 return this.updatingCollection("own-training-facilities", Filters.byTrainingQueue(), this.getOwnEntities(), true);387 m.GameState.prototype.getOwnTrainingFacilities = function(){ 388 return this.updatingCollection("own-training-facilities", m.Filters.byTrainingQueue(), this.getOwnEntities(), true); 385 389 }; 386 390 387 GameState.prototype.getOwnResearchFacilities = function(){388 return this.updatingCollection("own-research-facilities", Filters.byResearchAvailable(), this.getOwnEntities(), true);391 m.GameState.prototype.getOwnResearchFacilities = function(){ 392 return this.updatingCollection("own-research-facilities", m.Filters.byResearchAvailable(), this.getOwnEntities(), true); 389 393 }; 390 394 391 GameState.prototype.getOwnEntitiesByType = function(type, maintain){392 var filter = Filters.byType(type);395 m.GameState.prototype.getOwnEntitiesByType = function(type, maintain){ 396 var filter = m.Filters.byType(type); 393 397 if (maintain === true) 394 398 return this.updatingCollection("own-by-type-" + type, filter, this.getOwnEntities()); 395 399 return this.getOwnEntities().filter(filter); 396 400 397 401 }; 398 402 399 GameState.prototype.countEntitiesByType = function(type, maintain) {403 m.GameState.prototype.countEntitiesByType = function(type, maintain) { 400 404 return this.getOwnEntitiesByType(type, maintain).length; 401 405 }; 402 406 403 GameState.prototype.countEntitiesAndQueuedByType = function(type) {407 m.GameState.prototype.countEntitiesAndQueuedByType = function(type) { 404 408 var count = this.countEntitiesByType(type, true); 405 409 406 410 // Count building foundations … … 424 428 return count; 425 429 }; 426 430 427 GameState.prototype.countFoundationsWithType = function(type) {431 m.GameState.prototype.countFoundationsWithType = function(type) { 428 432 var foundationType = "foundation|" + type; 429 433 var count = 0; 430 434 this.getOwnEntities().forEach(function(ent) { … … 435 439 return count; 436 440 }; 437 441 438 GameState.prototype.countOwnEntitiesByRole = function(role) {442 m.GameState.prototype.countOwnEntitiesByRole = function(role) { 439 443 return this.getOwnEntitiesByRole(role).length; 440 444 }; 441 445 442 GameState.prototype.countOwnEntitiesAndQueuedWithRole = function(role) {446 m.GameState.prototype.countOwnEntitiesAndQueuedWithRole = function(role) { 443 447 var count = this.countOwnEntitiesByRole(role); 444 448 445 449 // Count entities in building production queues … … 452 456 return count; 453 457 }; 454 458 455 GameState.prototype.countOwnQueuedEntitiesWithMetadata = function(data, value) {459 m.GameState.prototype.countOwnQueuedEntitiesWithMetadata = function(data, value) { 456 460 // Count entities in building production queues 457 461 var count = 0; 458 462 this.getOwnTrainingFacilities().forEach(function(ent) { … … 468 472 * Find buildings that are capable of training the given unit type, and aren't 469 473 * already too busy. 470 474 */ 471 GameState.prototype.findTrainers = function(template) {475 m.GameState.prototype.findTrainers = function(template) { 472 476 var maxQueueLength = 3; // avoid tying up resources in giant training queues 473 477 474 478 return this.getOwnTrainingFacilities().filter(function(ent) { … … 490 494 /** 491 495 * Find units that are capable of constructing the given building type. 492 496 */ 493 GameState.prototype.findBuilders = function(template) {497 m.GameState.prototype.findBuilders = function(template) { 494 498 return this.getOwnEntities().filter(function(ent) { 495 499 496 500 var buildable = ent.buildableEntities(); … … 505 509 * Find buildings that are capable of researching the given tech, and aren't 506 510 * already too busy. 507 511 */ 508 GameState.prototype.findResearchers = function(templateName, noRequirementCheck) {512 m.GameState.prototype.findResearchers = function(templateName, noRequirementCheck) { 509 513 // let's check we can research the tech. 510 514 if (!this.canResearch(templateName, noRequirementCheck)) 511 515 return []; … … 532 536 }); 533 537 }; 534 538 535 GameState.prototype.getOwnFoundations = function() {536 return this.updatingCollection("ownFoundations", Filters.isFoundation(), this.getOwnEntities());539 m.GameState.prototype.getOwnFoundations = function() { 540 return this.updatingCollection("ownFoundations", m.Filters.isFoundation(), this.getOwnEntities()); 537 541 }; 538 542 539 GameState.prototype.getOwnDropsites = function(resource){543 m.GameState.prototype.getOwnDropsites = function(resource){ 540 544 if (resource !== undefined) 541 return this.updatingCollection("dropsite-own-" + resource, Filters.isDropsite(resource), this.getOwnEntities(), true);542 return this.updatingCollection("dropsite-own", Filters.isDropsite(), this.getOwnEntities(), true);545 return this.updatingCollection("dropsite-own-" + resource, m.Filters.isDropsite(resource), this.getOwnEntities(), true); 546 return this.updatingCollection("dropsite-own", m.Filters.isDropsite(), this.getOwnEntities(), true); 543 547 }; 544 548 545 GameState.prototype.getResourceSupplies = function(resource){546 return this.updatingGlobalCollection("resource-" + resource, Filters.byResource(resource), this.getEntities(), true);549 m.GameState.prototype.getResourceSupplies = function(resource){ 550 return this.updatingGlobalCollection("resource-" + resource, m.Filters.byResource(resource), this.getEntities(), true); 547 551 }; 548 552 549 GameState.prototype.getEntityLimits = function() {553 m.GameState.prototype.getEntityLimits = function() { 550 554 return this.playerData.entityLimits; 551 555 }; 552 556 553 GameState.prototype.getEntityCounts = function() {557 m.GameState.prototype.getEntityCounts = function() { 554 558 return this.playerData.entityCounts; 555 559 }; 556 560 557 561 // Checks whether the maximum number of buildings have been cnstructed for a certain catergory 558 GameState.prototype.isEntityLimitReached = function(category) {562 m.GameState.prototype.isEntityLimitReached = function(category) { 559 563 if(this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 560 564 return false; 561 565 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 562 566 }; 563 567 564 GameState.prototype.findTrainableUnits = function(classes){568 m.GameState.prototype.findTrainableUnits = function(classes){ 565 569 var allTrainable = []; 566 570 this.getOwnEntities().forEach(function(ent) { 567 571 var trainable = ent.trainableEntities(); … … 593 597 // Return all techs which can currently be researched 594 598 // Does not factor cost. 595 599 // If there are pairs, both techs are returned. 596 GameState.prototype.findAvailableTech = function() {600 m.GameState.prototype.findAvailableTech = function() { 597 601 598 602 var allResearchable = []; 599 603 this.getOwnEntities().forEach(function(ent) { … … 625 629 }; 626 630 627 631 // defcon utilities 628 GameState.prototype.timeSinceDefconChange = function() {632 m.GameState.prototype.timeSinceDefconChange = function() { 629 633 return this.getTimeElapsed()-this.ai.defconChangeTime; 630 634 }; 631 GameState.prototype.setDefcon = function(level,force) {635 m.GameState.prototype.setDefcon = function(level,force) { 632 636 if (this.ai.defcon >= level || force) { 633 637 this.ai.defcon = level; 634 638 this.ai.defconChangeTime = this.getTimeElapsed(); 635 639 } 636 640 }; 637 GameState.prototype.defcon = function() {641 m.GameState.prototype.defcon = function() { 638 642 return this.ai.defcon; 639 643 }; 640 644 645 return m; 646 647 }(API3); 648 -
binaries/data/mods/public/simulation/ai/common-api-v3/resources.js
1 function Resources(amounts, population) { 1 var API3 = function(m) 2 { 3 4 m.Resources = function(amounts, population) { 2 5 if (amounts === undefined) { 3 6 amounts = { 4 7 food : 0, … … 19 22 } 20 23 } 21 24 22 Resources.prototype.types = [ "food", "wood", "stone", "metal" ];25 m.Resources.prototype.types = [ "food", "wood", "stone", "metal" ]; 23 26 24 Resources.prototype.reset = function() {27 m.Resources.prototype.reset = function() { 25 28 for ( var tKey in this.types) { 26 29 var t = this.types[tKey]; 27 30 this[t] = 0; … … 29 32 this.population = 0; 30 33 }; 31 34 32 Resources.prototype.canAfford = function(that) {35 m.Resources.prototype.canAfford = function(that) { 33 36 for ( var tKey in this.types) { 34 37 var t = this.types[tKey]; 35 38 if (this[t] < that[t]) { … … 39 42 return true; 40 43 }; 41 44 42 Resources.prototype.add = function(that) {45 m.Resources.prototype.add = function(that) { 43 46 for ( var tKey in this.types) { 44 47 var t = this.types[tKey]; 45 48 this[t] += that[t]; … … 47 50 this.population += that.population; 48 51 }; 49 52 50 Resources.prototype.subtract = function(that) {53 m.Resources.prototype.subtract = function(that) { 51 54 for ( var tKey in this.types) { 52 55 var t = this.types[tKey]; 53 56 this[t] -= that[t]; … … 55 58 this.population += that.population; 56 59 }; 57 60 58 Resources.prototype.multiply = function(n) {61 m.Resources.prototype.multiply = function(n) { 59 62 for ( var tKey in this.types) { 60 63 var t = this.types[tKey]; 61 64 this[t] *= n; … … 63 66 this.population *= n; 64 67 }; 65 68 66 Resources.prototype.toInt = function() {69 m.Resources.prototype.toInt = function() { 67 70 var sum = 0; 68 71 for ( var tKey in this.types) { 69 72 var t = this.types[tKey]; … … 72 75 sum += this.population * 50; // based on typical unit costs 73 76 return sum; 74 77 }; 78 79 return m; 80 81 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/technology.js
1 var API3 = function(m) 2 { 3 1 4 // Wrapper around a technology template 2 5 3 function Technology(allTemplates, templateName)6 m.Technology = function(allTemplates, templateName) 4 7 { 5 8 this._templateName = templateName; 6 9 var template = allTemplates[templateName]; … … 20 23 this._techTemplates = allTemplates; 21 24 } 22 25 // returns generic, or specific if civ provided. 23 Technology.prototype.name = function(civ)26 m.Technology.prototype.name = function(civ) 24 27 { 25 28 if (civ === undefined) 26 29 { … … 34 37 } 35 38 }; 36 39 37 Technology.prototype.pairDef = function()40 m.Technology.prototype.pairDef = function() 38 41 { 39 42 return this._definesPair; 40 43 }; 41 44 // in case this defines a pair only, returns the two paired technologies. 42 Technology.prototype.getPairedTechs = function()45 m.Technology.prototype.getPairedTechs = function() 43 46 { 44 47 if (!this._definesPair) 45 48 return undefined; 46 49 47 var techOne = new Technology(this._techTemplates, this._template.top);48 var techTwo = new Technology(this._techTemplates, this._template.bottom);50 var techOne = new m.Technology(this._techTemplates, this._template.top); 51 var techTwo = new m.Technology(this._techTemplates, this._template.bottom); 49 52 50 53 return [techOne,techTwo]; 51 54 }; 52 55 53 Technology.prototype.pair = function()56 m.Technology.prototype.pair = function() 54 57 { 55 58 if (!this._isPair) 56 59 return undefined; 57 60 return this._template.pair; 58 61 }; 59 62 60 Technology.prototype.pairedWith = function()63 m.Technology.prototype.pairedWith = function() 61 64 { 62 65 if (!this._isPair) 63 66 return undefined; 64 67 return this._pairedWith; 65 68 }; 66 69 67 Technology.prototype.cost = function()70 m.Technology.prototype.cost = function() 68 71 { 69 72 if (!this._template.cost) 70 73 return undefined; … … 72 75 }; 73 76 74 77 // seconds 75 Technology.prototype.researchTime = function()78 m.Technology.prototype.researchTime = function() 76 79 { 77 80 if (!this._template.researchTime) 78 81 return undefined; 79 82 return this._template.researchTime; 80 83 }; 81 84 82 Technology.prototype.requirements = function()85 m.Technology.prototype.requirements = function() 83 86 { 84 87 if (!this._template.requirements) 85 88 return undefined; 86 89 return this._template.requirements; 87 90 }; 88 91 89 Technology.prototype.autoResearch = function()92 m.Technology.prototype.autoResearch = function() 90 93 { 91 94 if (!this._template.autoResearch) 92 95 return undefined; 93 96 return this._template.autoResearch; 94 97 }; 95 98 96 Technology.prototype.supersedes = function()99 m.Technology.prototype.supersedes = function() 97 100 { 98 101 if (!this._template.supersedes) 99 102 return undefined; 100 103 return this._template.supersedes; 101 104 }; 102 105 103 Technology.prototype.modifications = function()106 m.Technology.prototype.modifications = function() 104 107 { 105 108 if (!this._template.modifications) 106 109 return undefined; 107 110 return this._template.modifications; 108 111 }; 109 112 110 Technology.prototype.affects = function()113 m.Technology.prototype.affects = function() 111 114 { 112 115 if (!this._template.affects) 113 116 return undefined; 114 117 return this._template.affects; 115 118 }; 116 119 117 Technology.prototype.isAffected = function(classes)120 m.Technology.prototype.isAffected = function(classes) 118 121 { 119 122 if (!this._template.affects) 120 123 return false; … … 136 139 } 137 140 return false; 138 141 }; 142 143 return m; 144 145 }(API3); -
binaries/data/mods/public/simulation/ai/common-api-v3/baseAI.js
1 1 var PlayerID = -1; 2 2 3 function BaseAI(settings) 3 var API3 = (function() { 4 5 var m = {}; 6 7 m.BaseAI = function(settings) 4 8 { 5 9 if (!settings) 6 10 return; 7 11 8 12 this.player = settings.player; 9 PlayerID = this.player;10 13 11 14 // played turn, in case you don't want the AI to play every turn. 12 15 this.turn = 0; 13 } 16 }; 14 17 15 18 //Return a simple object (using no classes etc) that will be serialized into saved games 16 BaseAI.prototype.Serialize = function()19 m.BaseAI.prototype.Serialize = function() 17 20 { 18 21 // TODO: ought to get the AI script subclass to serialize its own state 19 22 // TODO: actually this is part of a larger reflection on wether AIs should or not. … … 22 25 23 26 //Called after the constructor when loading a saved game, with 'data' being 24 27 //whatever Serialize() returned 25 BaseAI.prototype.Deserialize = function(data, sharedScript)28 m.BaseAI.prototype.Deserialize = function(data, sharedScript) 26 29 { 27 30 // TODO: ought to get the AI script subclass to deserialize its own state 28 31 // TODO: actually this is part of a larger reflection on wether AIs should or not. 29 32 this.isDeserialized = true; 30 33 }; 31 34 32 BaseAI.prototype.Init = function(state, sharedAI)35 m.BaseAI.prototype.Init = function(state, playerID, sharedAI) 33 36 { 37 PlayerID = playerID; 34 38 // define some references 35 39 this.entities = sharedAI.entities; 36 40 this.templates = sharedAI.templates; … … 43 47 this.techModifications = sharedAI._techModifications[this.player]; 44 48 this.playerData = sharedAI.playersData[this.player]; 45 49 46 this.gameState = sharedAI.gameState[ PlayerID];50 this.gameState = sharedAI.gameState[this.player]; 47 51 this.gameState.ai = this; 48 52 this.sharedScript = sharedAI; 49 53 … … 52 56 this.CustomInit(this.gameState, this.sharedScript); 53 57 } 54 58 55 BaseAI.prototype.CustomInit = function()59 m.BaseAI.prototype.CustomInit = function() 56 60 { // AIs override this function 57 61 }; 58 62 59 BaseAI.prototype.HandleMessage = function(state, sharedAI)63 m.BaseAI.prototype.HandleMessage = function(state, playerID, sharedAI) 60 64 { 61 65 this.events = sharedAI.events; 66 PlayerID = playerID; 62 67 63 68 if (this.isDeserialized && this.turn !== 0) 64 69 { … … 70 75 this.OnUpdate(sharedAI); 71 76 }; 72 77 73 BaseAI.prototype.OnUpdate = function()78 m.BaseAI.prototype.OnUpdate = function() 74 79 { // AIs override this function 75 80 }; 76 81 77 BaseAI.prototype.chat = function(message)82 m.BaseAI.prototype.chat = function(message) 78 83 { 79 Engine.PostCommand( {"type": "chat", "message": message});84 Engine.PostCommand(PlayerID,{"type": "chat", "message": message}); 80 85 }; 81 BaseAI.prototype.chatTeam = function(message)86 m.BaseAI.prototype.chatTeam = function(message) 82 87 { 83 Engine.PostCommand( {"type": "chat", "message": "/team " +message});88 Engine.PostCommand(PlayerID,{"type": "chat", "message": "/team " +message}); 84 89 }; 85 BaseAI.prototype.chatEnemies = function(message)90 m.BaseAI.prototype.chatEnemies = function(message) 86 91 { 87 Engine.PostCommand( {"type": "chat", "message": "/enemy " +message});92 Engine.PostCommand(PlayerID,{"type": "chat", "message": "/enemy " +message}); 88 93 }; 89 94 95 return m; 96 97 }()); 98 -
binaries/data/mods/public/simulation/ai/aegis/base-manager.js
1 var AEGIS = function(m) 2 { 1 3 /* Base Manager 2 4 * Handles lower level economic stuffs. 3 5 * Some tasks: … … 10 12 -updating whatever needs updating, keeping track of stuffs (rebuilding needs…) 11 13 */ 12 14 13 var BaseManager = function() { 15 m.BaseManager = function(Config) { 16 this.Config = Config; 14 17 this.farmingFields = false; 15 this.ID = uniqueIDBases++;18 this.ID = m.playerGlobals[PlayerID].uniqueIDBases++; 16 19 17 20 // anchor building: seen as the main building of the base. Needs to have territorial influence 18 21 this.anchor = undefined; … … 31 34 this.territoryIndices = []; 32 35 }; 33 36 34 BaseManager.prototype.init = function(gameState, events, unconstructed){37 m.BaseManager.prototype.init = function(gameState, events, unconstructed){ 35 38 this.constructing = unconstructed; 36 39 // entitycollections 37 this.units = gameState.getOwnEntities().filter( Filters.and(Filters.byClass("Unit"),Filters.byMetadata(PlayerID, "base", this.ID)));38 this.buildings = gameState.getOwnEntities().filter( Filters.and(Filters.byClass("Structure"),Filters.byMetadata(PlayerID, "base", this.ID)));40 this.units = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Unit"),API3.Filters.byMetadata(PlayerID, "base", this.ID))); 41 this.buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byMetadata(PlayerID, "base", this.ID))); 39 42 40 this.workers = this.units.filter( Filters.byMetadata(PlayerID,"role","worker"));43 this.workers = this.units.filter(API3.Filters.byMetadata(PlayerID,"role","worker")); 41 44 42 45 this.workers.allowQuickIter(); 43 46 this.buildings.allowQuickIter(); … … 62 65 this.bigRadius = { 'food':70*70,'wood':200*200,'stone':200*200,'metal':200*200 }; 63 66 }; 64 67 65 BaseManager.prototype.assignEntity = function(unit){68 m.BaseManager.prototype.assignEntity = function(unit){ 66 69 unit.setMetadata(PlayerID, "base", this.ID); 67 70 this.units.updateEnt(unit); 68 71 this.workers.updateEnt(unit); … … 73 76 this.territoryBuildings.push(unit.id()); 74 77 }; 75 78 76 BaseManager.prototype.setAnchor = function(anchorEntity) {79 m.BaseManager.prototype.setAnchor = function(anchorEntity) { 77 80 if (!anchorEntity.hasClass("Structure") || !anchorEntity.hasTerritoryInfluence()) 78 81 { 79 82 warn("Error: Aegis' base " + this.ID + " has been assigned an anchor building that has no territorial influence. Please report this on the forum.") … … 90 93 } 91 94 92 95 // affects the HQ map. 93 BaseManager.prototype.initTerritory = function(HQ, gameState) {96 m.BaseManager.prototype.initTerritory = function(HQ, gameState) { 94 97 if (!this.anchor) 95 98 warn ("Error: Aegis tried to initialize the territory of base " + this.ID + " without assigning it an anchor building first"); 96 99 var radius = Math.round((this.anchor.territoryInfluenceRadius() / 4.0) * 1.25); … … 122 125 } 123 126 } 124 127 125 BaseManager.prototype.initGatheringFunctions = function(HQ, gameState, specTypes) {128 m.BaseManager.prototype.initGatheringFunctions = function(HQ, gameState, specTypes) { 126 129 // init our gathering functions. 127 130 var types = ["food","wood","stone","metal"]; 128 131 if (specTypes !== undefined) … … 136 139 var type = types[i]; 137 140 // TODO: set us as "X" gatherer 138 141 139 this.buildings.filter( Filters.isDropsite(type)).forEach(function(ent) { self.initializeDropsite(gameState, ent,type) });142 this.buildings.filter(API3.Filters.isDropsite(type)).forEach(function(ent) { self.initializeDropsite(gameState, ent,type) }); 140 143 141 144 if (this.getResourceLevel(gameState, type, "all") > 1000) 142 145 this.willGather[type] = 1; … … 151 154 if (needFarm) 152 155 this.willGather["food"] = 1; 153 156 } 154 debug ("food" + this.willGather["food"]);155 debug (this.willGather["wood"]);156 debug (this.willGather["stone"]);157 debug (this.willGather["metal"]);157 m.debug ("food" + this.willGather["food"]); 158 m.debug (this.willGather["wood"]); 159 m.debug (this.willGather["stone"]); 160 m.debug (this.willGather["metal"]); 158 161 } 159 162 160 BaseManager.prototype.checkEvents = function (gameState, events, queues) {163 m.BaseManager.prototype.checkEvents = function (gameState, events, queues) { 161 164 for (i in events) 162 165 { 163 166 if (events[i].type == "Destroy") … … 185 188 if (ent.hasClass("CivCentre")) 186 189 { 187 190 // TODO: might want to tell the queue manager to pause other stuffs if we are the only base. 188 queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true }, 0 , -1,ent.position()));191 queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true }, 0 , -1,ent.position())); 189 192 } else { 190 193 // TODO 191 queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true },0,-1,ent.position()));194 queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre", { "base" : this.ID, "baseAnchor" : true },0,-1,ent.position())); 192 195 } 193 196 } 194 197 } … … 238 241 }; 239 242 240 243 // If no specific dropsite, it'll assign to the closest 241 BaseManager.prototype.assignResourceToDP = function (gameState, supply, specificDP) {244 m.BaseManager.prototype.assignResourceToDP = function (gameState, supply, specificDP) { 242 245 var type = supply.resourceSupplyType()["generic"]; 243 246 if (type == "treasure") 244 247 type = supply.resourceSupplyType()["specific"]; … … 249 252 for (i in this.dropsites) 250 253 { 251 254 var dp = gameState.getEntityById(i); 252 var distance = SquareVectorDistance(supply.position(), dp.position());255 var distance = API3.SquareVectorDistance(supply.position(), dp.position()); 253 256 if (distance < dist && distance < this.bigRadius[type]) 254 257 { 255 258 closest = dp.id(); … … 267 270 // TODO: ought to recount immediatly. 268 271 } 269 272 270 BaseManager.prototype.initializeDropsite = function (gameState, ent, type) {273 m.BaseManager.prototype.initializeDropsite = function (gameState, ent, type) { 271 274 var count = 0, farCount = 0; 272 275 var self = this; 273 276 … … 278 281 resources.filter( function (supply) { //}){ 279 282 if (!supply.position() || !ent.position()) 280 283 return; 281 var distance = SquareVectorDistance(supply.position(), ent.position());284 var distance = API3.SquareVectorDistance(supply.position(), ent.position()); 282 285 283 286 if (supply.getMetadata(PlayerID, "linked-dropsite") == undefined || supply.getMetadata(PlayerID, "linked-dropsite-dist") > distance) { 284 287 if (distance < self.bigRadius[type]) { … … 294 297 } 295 298 }); 296 299 // This one is both for the nearby and the linked 297 var filter = Filters.byMetadata(PlayerID, "linked-dropsite", ent.id());300 var filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite", ent.id()); 298 301 var collection = resources.filter(filter); 299 302 collection.registerUpdates(); 300 303 301 filter = Filters.byMetadata(PlayerID, "linked-dropsite-close",true);304 filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite-close",true); 302 305 var collection2 = collection.filter(filter); 303 306 collection2.registerUpdates(); 304 307 305 filter = Filters.byMetadata(PlayerID, "linked-dropsite-nearby",true);308 filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite-nearby",true); 306 309 var collection3 = collection.filter(filter); 307 310 collection3.registerUpdates(); 308 311 309 filter = Filters.byMetadata(PlayerID, "linked-to-dropsite", ent.id());312 filter = API3.Filters.byMetadata(PlayerID, "linked-to-dropsite", ent.id()); 310 313 var WkCollection = this.workers.filter(filter); 311 314 WkCollection.registerUpdates(); 312 315 … … 318 321 // TODO: get workers on those resources and do something with them. 319 322 } 320 323 321 if ( Config.debug)324 if (m.DebugEnabled) 322 325 { 323 326 // Make resources glow wildly 324 327 if (type == "food") { 325 328 self.dropsites[ent.id()][type][2].forEach(function(ent){ 326 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]});329 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]}); 327 330 }); 328 331 self.dropsites[ent.id()][type][1].forEach(function(ent){ 329 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]});332 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]}); 330 333 }); 331 334 self.dropsites[ent.id()][type][0].forEach(function(ent){ 332 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]});335 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); 333 336 }); 334 337 } 335 338 if (type == "wood") { 336 339 self.dropsites[ent.id()][type][2].forEach(function(ent){ 337 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]});340 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]}); 338 341 }); 339 342 self.dropsites[ent.id()][type][1].forEach(function(ent){ 340 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]});343 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]}); 341 344 }); 342 345 self.dropsites[ent.id()][type][0].forEach(function(ent){ 343 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]});346 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); 344 347 }); 345 348 } 346 349 if (type == "stone") { 347 350 self.dropsites[ent.id()][type][2].forEach(function(ent){ 348 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]});351 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]}); 349 352 }); 350 353 self.dropsites[ent.id()][type][1].forEach(function(ent){ 351 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]});354 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]}); 352 355 }); 353 356 self.dropsites[ent.id()][type][0].forEach(function(ent){ 354 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]});357 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]}); 355 358 }); 356 359 } 357 360 if (type == "metal") { 358 361 self.dropsites[ent.id()][type][2].forEach(function(ent){ 359 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]});362 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]}); 360 363 }); 361 364 self.dropsites[ent.id()][type][1].forEach(function(ent){ 362 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]});365 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]}); 363 366 }); 364 367 self.dropsites[ent.id()][type][0].forEach(function(ent){ 365 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]});368 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]}); 366 369 }); 367 370 } 368 371 } … … 371 374 // completely and "safely" remove a dropsite from our list. 372 375 // this also removes any linked resource and so on. 373 376 // TODO: should re-add the resources to another dropsite. 374 BaseManager.prototype.scrapDropsite = function (gameState, ent) {377 m.BaseManager.prototype.scrapDropsite = function (gameState, ent) { 375 378 if (this.dropsites[ent.id()] === undefined) 376 379 return true; 377 380 … … 398 401 }; 399 402 400 403 // Returns the position of the best place to build a new dropsite for the specified resource 401 BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){404 m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource){ 402 405 403 406 var storeHousePlate = gameState.getTemplate(gameState.applyCiv("structures/{civ}_storehouse")); 404 407 … … 407 410 // Then checks for a good spot in the territory. If none, and town/city phase, checks outside 408 411 // The AI will currently not build a CC if it wouldn't connect with an existing CC. 409 412 410 var territory = Map.createTerritoryMap(gameState);413 var territory = m.createTerritoryMap(gameState); 411 414 412 var obstructions = Map.createObstructionMap(gameState,this.accessIndex,storeHousePlate);415 var obstructions = m.createObstructionMap(gameState,this.accessIndex,storeHousePlate); 413 416 obstructions.expandInfluences(); 414 417 415 418 // copy the resource map as initialization. 416 var friendlyTiles = new Map(gameState.sharedScript, gameState.sharedScript.resourceMaps[resource].map, true);419 var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.resourceMaps[resource].map, true); 417 420 418 var DPFoundations = gameState.getOwnFoundations().filter( Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse")));421 var DPFoundations = gameState.getOwnFoundations().filter(API3.Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse"))); 419 422 420 423 // TODO: might be better to check dropsites someplace else. 421 424 // loop over this in this.terrytoryindices. It's usually a little too much, but it's always enough. … … 434 437 { 435 438 var pos = [j%friendlyTiles.width, Math.floor(j/friendlyTiles.width)]; 436 439 var dpPos = gameState.getEntityById(i).position(); 437 if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250)440 if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) 438 441 { 439 442 friendlyTiles.map[j] = 0; 440 443 continue; 441 } else if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450)444 } else if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) 442 445 friendlyTiles.map[j] /= 2; 443 446 } 444 447 for (var i in DPFoundations._entities) 445 448 { 446 449 var pos = [j%friendlyTiles.width, Math.floor(j/friendlyTiles.width)]; 447 450 var dpPos = gameState.getEntityById(i).position(); 448 if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250)451 if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) 449 452 friendlyTiles.map[j] = 0; 450 else if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450)453 else if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) 451 454 friendlyTiles.map[j] /= 2; 452 455 } 453 456 } 454 457 455 if ( Config.debug)458 if (m.DebugEnabled) 456 459 friendlyTiles.dumpIm("DP_" + resource + "_" + gameState.getTimeElapsed() + ".png"); 457 460 458 461 var best = friendlyTiles.findBestTile(2, obstructions); // try to find a spot to place a DP. … … 469 472 }; 470 473 471 474 // update the resource level of a dropsite. 472 BaseManager.prototype.updateDropsite = function (gameState, ent, type) {475 m.BaseManager.prototype.updateDropsite = function (gameState, ent, type) { 473 476 if (this.dropsites[ent.id()] === undefined || this.dropsites[ent.id()][type] === undefined) 474 477 return undefined; // should initialize it first. 475 478 … … 490 493 }; 491 494 492 495 // Updates dropsites. 493 BaseManager.prototype.updateDropsites = function (gameState) {496 m.BaseManager.prototype.updateDropsites = function (gameState) { 494 497 // for each dropsite, recalculate 495 498 for (i in this.dropsites) 496 499 { … … 507 510 // we're assuming Max - 3 for metal/stone mines, and 20 for any dropsite that has wood. 508 511 // TODO: for wood might want to count the trees too. 509 512 // TODO: this returns "future" worker capacity, might want to have a current one. 510 BaseManager.prototype.getWorkerCapacity = function (gameState, type) {513 m.BaseManager.prototype.getWorkerCapacity = function (gameState, type) { 511 514 var count = 0; 512 515 if (type == "food") 513 516 return 1000000; // TODO: perhaps return something sensible here. … … 530 533 531 534 // TODO: ought to be cached or something probably 532 535 // Returns the amount of resource left 533 BaseManager.prototype.getResourceLevel = function (gameState, type, searchType, threshold) {536 m.BaseManager.prototype.getResourceLevel = function (gameState, type, searchType, threshold) { 534 537 var count = 0; 535 538 if (searchType == "all") 536 539 { 537 540 // return all resources in the base area. 538 gameState.getResourceSupplies(type).filter( Filters.byTerritory(gameState.ai.HQ.basesMap, this.ID)).forEach( function (ent) { //}){541 gameState.getResourceSupplies(type).filter(API3.Filters.byTerritory(gameState.ai.HQ.basesMap, this.ID)).forEach( function (ent) { //}){ 539 542 count += ent.resourceSupplyAmount(); 540 543 }); 541 544 return count; … … 574 577 }; 575 578 576 579 // check our resource levels and react accordingly 577 BaseManager.prototype.checkResourceLevels = function (gameState,queues) {580 m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) { 578 581 for (type in this.willGather) 579 582 { 580 583 if (this.willGather[type] === 0) … … 589 592 if (!this.isFarming && count < 1600 && queues.field.length === 0) 590 593 { 591 594 // tell the queue manager we'll be trying to build fields shortly. 592 for (var i = 0; i < Config.Economy.initialFields;++i)595 for (var i = 0; i < this.Config.Economy.initialFields;++i) 593 596 { 594 var plan = new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID });597 var plan = new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }); 595 598 plan.isGo = function() { return false; }; // don't start right away. 596 599 queues.field.addItem(plan); 597 600 } … … 604 607 if (this.isFarming) 605 608 { 606 609 var numFarms = 0; 607 this.buildings.filter( Filters.byClass("Field")).forEach(function (field) {610 this.buildings.filter(API3.Filters.byClass("Field")).forEach(function (field) { 608 611 if (field.resourceSupplyAmount() > 400) 609 612 numFarms++; 610 613 }); … … 615 618 // let's see if we need to push new farms. 616 619 if (numFd < 2) 617 620 if (numFarms < Math.round(this.gatherersByType(gameState, "food").length / 4.6) || numFarms < Math.round(this.workers.length / 15.0)) 618 queues.field.addItem(new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }));621 queues.field.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID })); 619 622 // TODO: refine count to only count my base. 620 623 } 621 624 } else if (queues.dropsites.length() === 0 && gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_storehouse")) === 0) { … … 626 629 var pos = this.findBestDropsiteLocation(gameState, type); 627 630 if (!pos) 628 631 { 629 debug ("Found no right position for a " + type + " dropsite, going into \"noSpot\" mode");632 m.debug ("Found no right position for a " + type + " dropsite, going into \"noSpot\" mode"); 630 633 this.willGather[type] = 2; // won't build 631 634 // TODO: tell the HQ we'll be needing a new base for this resource, or tell it we've ran out of resource Z. 632 635 } else { 633 debug ("planning new dropsite for " + type);634 queues.dropsites.addItem(new ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : this.ID }, 0, -1, pos));636 m.debug ("planning new dropsite for " + type); 637 queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : this.ID }, 0, -1, pos)); 635 638 } 636 639 } 637 640 } … … 640 643 }; 641 644 642 645 // let's return the estimated gather rates. 643 BaseManager.prototype.getGatherRates = function(gameState, currentRates) {646 m.BaseManager.prototype.getGatherRates = function(gameState, currentRates) { 644 647 645 648 }; 646 649 647 BaseManager.prototype.assignRolelessUnits = function(gameState) {650 m.BaseManager.prototype.assignRolelessUnits = function(gameState) { 648 651 // TODO: make this cleverer. 649 var roleless = this.units.filter( Filters.not(Filters.byHasMetadata(PlayerID, "role")));652 var roleless = this.units.filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "role"))); 650 653 var self = this; 651 654 roleless.forEach(function(ent) { 652 655 if (ent.hasClass("Worker") || ent.hasClass("CitizenSoldier")) { … … 660 663 // If the numbers of workers on the resources is unbalanced then set some of workers to idle so 661 664 // they can be reassigned by reassignIdleWorkers. 662 665 // TODO: actually this probably should be in the HQ. 663 BaseManager.prototype.setWorkersIdleByPriority = function(gameState){666 m.BaseManager.prototype.setWorkersIdleByPriority = function(gameState){ 664 667 var self = this; 665 668 if (gameState.currentPhase() < 2 && gameState.getTimeElapsed() < 360000) 666 669 return; // not in the first phase or the first 6 minutes. … … 685 688 this.gatherersByType(gameState,types.types[i]).forEach( function (ent) { //}){ 686 689 if (nb > 0) 687 690 { 688 // debug ("Moving " +ent.id() + " from " + types.types[i]);691 //m.debug ("Moving " +ent.id() + " from " + types.types[i]); 689 692 nb--; 690 693 // TODO: might want to direct assign. 691 694 ent.stopMoving(); … … 693 696 } 694 697 }); 695 698 } 696 // debug (currentRates);699 //m.debug (currentRates); 697 700 }; 698 701 699 702 // TODO: work on this. 700 BaseManager.prototype.reassignIdleWorkers = function(gameState) {703 m.BaseManager.prototype.reassignIdleWorkers = function(gameState) { 701 704 702 705 var self = this; 703 706 704 707 // Search for idle workers, and tell them to gather resources based on demand 705 var filter = Filters.or(Filters.byMetadata(PlayerID,"subrole","idle"), Filters.not(Filters.byHasMetadata(PlayerID,"subrole")));708 var filter = API3.Filters.or(API3.Filters.byMetadata(PlayerID,"subrole","idle"), API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"subrole"))); 706 709 var idleWorkers = gameState.updatingCollection("idle-workers-base-" + this.ID, filter, this.workers); 707 710 708 711 if (idleWorkers.length) { … … 713 716 } 714 717 if (ent.hasClass("Worker")) { 715 718 var types = gameState.ai.HQ.pickMostNeededResources(gameState); 716 // debug ("assigning " +ent.id() + " to " + types[0]);719 //m.debug ("assigning " +ent.id() + " to " + types[0]); 717 720 ent.setMetadata(PlayerID, "subrole", "gatherer"); 718 721 ent.setMetadata(PlayerID, "gather-type", types[0]); 719 722 … … 734 737 } 735 738 }; 736 739 737 BaseManager.prototype.workersBySubrole = function(gameState, subrole) {738 return gameState.updatingCollection("subrole-" + subrole +"-base-" + this.ID, Filters.byMetadata(PlayerID, "subrole", subrole), this.workers, true);740 m.BaseManager.prototype.workersBySubrole = function(gameState, subrole) { 741 return gameState.updatingCollection("subrole-" + subrole +"-base-" + this.ID, API3.Filters.byMetadata(PlayerID, "subrole", subrole), this.workers, true); 739 742 }; 740 743 741 BaseManager.prototype.gatherersByType = function(gameState, type) {742 return gameState.updatingCollection("workers-gathering-" + type +"-base-" + this.ID, Filters.byMetadata(PlayerID, "gather-type", type), this.workersBySubrole(gameState, "gatherer"));744 m.BaseManager.prototype.gatherersByType = function(gameState, type) { 745 return gameState.updatingCollection("workers-gathering-" + type +"-base-" + this.ID, API3.Filters.byMetadata(PlayerID, "gather-type", type), this.workersBySubrole(gameState, "gatherer")); 743 746 }; 744 747 745 748 746 749 // returns an entity collection of workers. 747 750 // They are idled immediatly and their subrole set to idle. 748 BaseManager.prototype.pickBuilders = function(gameState, number) {749 var collec = new EntityCollection(gameState.sharedScript);751 m.BaseManager.prototype.pickBuilders = function(gameState, number) { 752 var collec = new API3.EntityCollection(gameState.sharedScript); 750 753 // TODO: choose better. 751 var workers = this.workers.filter( Filters.not(Filters.byClass("Cavalry"))).toEntityArray();754 var workers = this.workers.filter(API3.Filters.not(API3.Filters.byClass("Cavalry"))).toEntityArray(); 752 755 workers.sort(function (a,b) { 753 756 var vala = 0, valb = 0; 754 757 if (a.getMetadata(PlayerID,"subrole") == "builder") … … 770 773 return collec; 771 774 } 772 775 773 BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { 776 m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { 777 774 778 // If we have some foundations, and we don't have enough builder-workers, 775 779 // try reassigning some other workers who are nearby 776 780 … … 778 782 779 783 var self = this; 780 784 781 var foundations = this.buildings.filter( Filters.and(Filters.isFoundation(),Filters.not(Filters.byClass("Field")))).toEntityArray();785 var foundations = this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(),API3.Filters.not(API3.Filters.byClass("Field")))).toEntityArray(); 782 786 var damagedBuildings = this.buildings.filter(function (ent) { if (ent.needsRepair() && ent.getMetadata(PlayerID, "plan") == undefined) { return true; } return false; }).toEntityArray(); 783 787 784 788 // Check if nothing to build 785 789 if (!foundations.length && !damagedBuildings.length){ 786 790 return; 787 791 } 788 var workers = this.workers.filter( Filters.not(Filters.byClass("Cavalry")));792 var workers = this.workers.filter(API3.Filters.not(API3.Filters.byClass("Cavalry"))); 789 793 var builderWorkers = this.workersBySubrole(gameState, "builder"); 790 var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter( Filters.isIdle());794 var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter(API3.Filters.isIdle()); 791 795 792 796 // if we're constructing and we have the foundations to our base anchor, only try building that. 793 if (this.constructing == true && this.buildings.filter( Filters.and(Filters.isFoundation(),Filters.byMetadata(PlayerID, "baseAnchor", true))).length !== 0)797 if (this.constructing == true && this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(), API3.Filters.byMetadata(PlayerID, "baseAnchor", true))).length !== 0) 794 798 { 795 foundations = this.buildings.filter( Filters.byMetadata(PlayerID, "baseAnchor", true)).toEntityArray();799 foundations = this.buildings.filter(API3.Filters.byMetadata(PlayerID, "baseAnchor", true)).toEntityArray(); 796 800 var tID = foundations[0].id(); 797 801 workers.forEach(function (ent) { //}){ 798 802 var target = ent.getMetadata(PlayerID, "target-foundation"); … … 832 836 833 837 var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length; 834 838 835 var targetNB = Config.Economy.targetNumBuilders; // TODO: dynamic that.839 var targetNB = this.Config.Economy.targetNumBuilders; // TODO: dynamic that. 836 840 if (target.hasClass("CivCentre") || target.buildTime() > 150 || target.hasClass("House")) 837 841 targetNB *= 2; 838 842 if (target.getMetadata(PlayerID, "baseAnchor") == true) … … 844 848 var addedToThis = 0; 845 849 846 850 idleBuilderWorkers.forEach(function(ent) { 847 if (ent.position() && SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB)851 if (ent.position() && API3.SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB) 848 852 { 849 853 addedWorkers++; 850 854 addedToThis++; … … 876 880 } else if (noRepair && !target.hasClass("CivCentre")) 877 881 continue; 878 882 879 var territory = Map.createTerritoryMap(gameState);883 var territory = m.createTerritoryMap(gameState); 880 884 if (territory.getOwner(target.position()) !== PlayerID || territory.getOwner([target.position()[0] + 5, target.position()[1]]) !== PlayerID) 881 885 continue; 882 886 … … 900 904 } 901 905 }; 902 906 903 BaseManager.prototype.update = function(gameState, queues, events) {907 m.BaseManager.prototype.update = function(gameState, queues, events) { 904 908 Engine.ProfileStart("Base update - base " + this.ID); 905 909 var self = this; 906 910 … … 957 961 Engine.ProfileStart("Run Workers"); 958 962 this.workers.forEach(function(ent) { 959 963 if (!ent.getMetadata(PlayerID, "worker-object")) 960 ent.setMetadata(PlayerID, "worker-object", new Worker(ent));964 ent.setMetadata(PlayerID, "worker-object", new m.Worker(ent)); 961 965 ent.getMetadata(PlayerID, "worker-object").update(self, gameState); 962 966 }); 963 967 Engine.ProfileStop(); 964 968 965 969 Engine.ProfileStop(); 966 970 }; 971 972 return m; 973 974 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/utils-extend.js
1 function AssocArraytoArray(assocArray) { 1 var AEGIS = function(m) 2 { 3 4 m.AssocArraytoArray = function(assocArray) { 2 5 var endArray = []; 3 6 for (var i in assocArray) 4 7 endArray.push(assocArray[i]); … … 7 10 8 11 // A is the reference, B must be in "range" of A 9 12 // this supposes the range is already squared 10 function inRange(a, b, range)// checks for X distance13 m.inRange = function(a, b, range)// checks for X distance 11 14 { 12 15 // will avoid unnecessary checking for position in some rare cases... I'm lazy 13 16 if (a === undefined || b === undefined || range === undefined) … … 18 21 return ((dx*dx + dz*dz ) < range); 19 22 } 20 23 // slower than SquareVectorDistance, faster than VectorDistance but not exactly accurate. 21 function ManhattanDistance(a, b)24 m.ManhattanDistance = function(a, b) 22 25 { 23 26 var dx = a[0] - b[0]; 24 27 var dz = a[1] - b[1]; 25 28 return Math.abs(dx) + Math.abs(dz); 26 29 } 30 31 return m; 32 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/defence.js
1 var AEGIS = function(m) 2 { 3 1 4 // directly imported from Marilyn, with slight modifications to work with qBot. 2 5 3 function Defence(){6 m.Defence = function(Config){ 4 7 this.defenceRatio = Config.Defence.defenceRatio;// How many defenders we want per attacker. Need to balance fewer losses vs. lost economy 5 8 // note: the choice should be a no-brainer most of the time: better deflect the attack. 6 9 // This is also sometimes forcebly overcome by the defense manager. … … 48 51 // 1: Huge army in the base, outnumbering us. 49 52 50 53 51 Defence.prototype.update = function(gameState, events, HQ){54 m.Defence.prototype.update = function(gameState, events, HQ){ 52 55 53 56 Engine.ProfileStart("Defence Manager"); 54 57 55 58 // a litlle cache-ing 56 59 if (!this.idleDefs) { 57 var filter = Filters.and(Filters.byMetadata(PlayerID, "role", "defence"),Filters.isIdle());60 var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "role", "defence"), API3.Filters.isIdle()); 58 61 this.idleDefs = gameState.getOwnEntities().filter(filter); 59 62 this.idleDefs.registerUpdates(); 60 63 } 61 64 if (!this.defenders) { 62 var filter = Filters.byMetadata(PlayerID, "role", "defence");65 var filter = API3.Filters.byMetadata(PlayerID, "role", "defence"); 63 66 this.defenders = gameState.getOwnEntities().filter(filter); 64 67 this.defenders.registerUpdates(); 65 68 } 66 69 /*if (!this.listedEnemyCollection) { 67 var filter = Filters.byMetadata(PlayerID, "listed-enemy", true);70 var filter = API3.Filters.byMetadata(PlayerID, "listed-enemy", true); 68 71 this.listedEnemyCollection = gameState.getEnemyEntities().filter(filter); 69 72 this.listedEnemyCollection.registerUpdates(); 70 73 } 71 this.myBuildings = gameState.getOwnEntities().filter( Filters.byClass("Structure")).toEntityArray();72 this.myUnits = gameState.getOwnEntities().filter( Filters.byClass("Unit"));74 this.myBuildings = gameState.getOwnEntities().filter(API3.Filters.byClass("Structure")).toEntityArray(); 75 this.myUnits = gameState.getOwnEntities().filter(API3.Filters.byClass("Unit")); 73 76 */ 74 var filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]),Filters.byOwner(PlayerID));77 var filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(PlayerID)); 75 78 this.myUnits = gameState.updatingGlobalCollection("player-" +PlayerID + "-soldiers", filter); 76 79 77 filter = Filters.and(Filters.byClass("Structure"),Filters.byOwner(PlayerID));80 filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(PlayerID)); 78 81 this.myBuildings = gameState.updatingGlobalCollection("player-" +PlayerID + "-structures", filter); 79 82 80 this.territoryMap = Map.createTerritoryMap(gameState); // used by many func83 this.territoryMap = m.createTerritoryMap(gameState); // used by many func 81 84 82 85 // First step: we deal with enemy armies, those are the highest priority. 83 86 this.defendFromEnemies(gameState, events, HQ); … … 118 121 } 119 122 for (var o in this.myBuildings) { 120 123 // if the armies out of my buildings LOS (with a little more, because we're cheating right now and big armies could go undetected) 121 if ( inRange(pos, this.myBuildings[o].position(),this.myBuildings[o].visionRange()*this.myBuildings[o].visionRange() + 2500)) {124 if (m.inRange(pos, this.myBuildings[o].position(),this.myBuildings[o].visionRange()*this.myBuildings[o].visionRange() + 2500)) { 122 125 stillDangerousArmies[i] = armies[i]; 123 126 break; 124 127 } … … 138 141 }*/ 139 142 // Incorporates an entity in an army. If no army fits, it creates a new one around this one. 140 143 // an army is basically an entity collection. 141 Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) {144 m.Defence.prototype.armify = function(gameState, entity, HQ, minNBForArmy) { 142 145 if (entity.position() === undefined) 143 146 return; 144 147 if (this.enemyArmy[entity.owner()] === undefined) … … 151 154 if (army.getCentrePosition() === undefined) 152 155 { 153 156 } else { 154 if ( SquareVectorDistance(army.getCentrePosition(), entity.position()) < this.armyCompactSize)157 if (API3.SquareVectorDistance(army.getCentrePosition(), entity.position()) < this.armyCompactSize) 155 158 { 156 159 entity.setMetadata(PlayerID, "inArmy", armyIndex); 157 160 army.addEnt(entity); … … 163 166 if (HQ) 164 167 { 165 168 var self = this; 166 var close = HQ.enemyWatchers[entity.owner()].enemySoldiers.filter( Filters.byDistance(entity.position(), self.armyCompactSize));169 var close = HQ.enemyWatchers[entity.owner()].enemySoldiers.filter(API3.Filters.byDistance(entity.position(), self.armyCompactSize)); 167 170 if (!minNBForArmy || close.length >= minNBForArmy) 168 171 { 169 172 // if we're here, we need to create an army for it, and freeze it to make sure no unit will be added automatically 170 var newArmy = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(entity.owner())]);173 var newArmy = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(entity.owner())]); 171 174 newArmy.addEnt(entity); 172 175 newArmy.freeze(); 173 176 newArmy.registerUpdates(); … … 184 187 } 185 188 } else { 186 189 // if we're here, we need to create an army for it, and freeze it to make sure no unit will be added automatically 187 var newArmy = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(entity.owner())]);190 var newArmy = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(entity.owner())]); 188 191 newArmy.addEnt(entity); 189 192 newArmy.freeze(); 190 193 newArmy.registerUpdates(); … … 195 198 return; 196 199 } 197 200 // Returns if a unit should be seen as dangerous or not. 198 Defence.prototype.evaluateRawEntity = function(gameState, entity) {201 m.Defence.prototype.evaluateRawEntity = function(gameState, entity) { 199 202 if (entity.position && +this.territoryMap.point(entity.position) - 64 === +PlayerID && entity._template.Attack !== undefined) 200 203 return true; 201 204 return false; 202 205 } 203 Defence.prototype.evaluateEntity = function(gameState, entity) {206 m.Defence.prototype.evaluateEntity = function(gameState, entity) { 204 207 if (!entity.position()) 205 208 return false; 206 209 if (this.territoryMap.point(entity.position()) - 64 === entity.owner() || entity.attackTypes() === undefined) … … 210 213 { 211 214 if (!this.myBuildings._entities[i].hasClass("ConquestCritical")) 212 215 continue; 213 if ( SquareVectorDistance(this.myBuildings._entities[i].position(), entity.position()) < 6000)216 if (API3.SquareVectorDistance(this.myBuildings._entities[i].position(), entity.position()) < 6000) 214 217 return true; 215 218 } 216 219 return false; 217 220 } 218 221 // returns false if the unit is in its territory 219 Defence.prototype.reevaluateEntity = function(gameState, entity) {222 m.Defence.prototype.reevaluateEntity = function(gameState, entity) { 220 223 if ( (entity.position() && +this.territoryMap.point(entity.position()) - 64 === +entity.owner()) || entity.attackTypes() === undefined) 221 224 return false; 222 225 return true; 223 226 } 224 227 // This deals with incoming enemy armies, setting the defcon if needed. It will take new soldiers, and assign them to attack 225 228 // TODO: still is still pretty dumb, it could use improvements. 226 Defence.prototype.defendFromEnemies = function(gameState, events, HQ) {229 m.Defence.prototype.defendFromEnemies = function(gameState, events, HQ) { 227 230 var self = this; 228 231 229 232 // New, faster system will loop for enemy soldiers, and also females on occasions ( TODO ) … … 313 316 } else { 314 317 army.forEach(function (ent) { //}){ 315 318 // check if the unit is a breakaway 316 if (ent.position() && SquareVectorDistance(position, ent.position()) > self.armyBreakawaySize)319 if (ent.position() && API3.SquareVectorDistance(position, ent.position()) > self.armyBreakawaySize) 317 320 { 318 321 ent.setMetadata(PlayerID, "inArmy", undefined); 319 322 army.removeEnt(ent); … … 322 325 } else { 323 326 // check if we have registered that unit already. 324 327 if (self.listOfEnemies[ent.id()] === undefined) { 325 self.listOfEnemies[ent.id()] = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(ent.owner())]);328 self.listOfEnemies[ent.id()] = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(ent.owner())]); 326 329 self.listOfEnemies[ent.id()].freeze(); 327 330 self.listOfEnemies[ent.id()].addEnt(ent); 328 331 self.listOfEnemies[ent.id()].registerUpdates(); 329 332 330 self.attackerCache[ent.id()] = self.myUnits.filter( Filters.byTargetedEntity(ent.id()));333 self.attackerCache[ent.id()] = self.myUnits.filter(API3.Filters.byTargetedEntity(ent.id())); 331 334 self.attackerCache[ent.id()].registerUpdates(); 332 335 nbOfAttackers++; 333 336 self.nbAttackers++; … … 373 376 374 377 if (this.nbAttackers === 0 && this.nbDefenders === 0) { 375 378 // Release all our units 376 this.myUnits.filter( Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){379 this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ 377 380 defender.stopMoving(); 378 381 if (defender.getMetadata(PlayerID, "formerrole")) 379 382 defender.setMetadata(PlayerID, "role", defender.getMetadata(PlayerID, "formerrole") ); … … 387 390 return; 388 391 } else if (this.nbAttackers === 0 && this.nbDefenders !== 0) { 389 392 // Release all our units 390 this.myUnits.filter( Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){393 this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ 391 394 defender.stopMoving(); 392 395 if (defender.getMetadata(PlayerID, "formerrole")) 393 396 defender.setMetadata(PlayerID, "role", defender.getMetadata(PlayerID, "formerrole") ); … … 404 407 HQ.ungarrisonAll(gameState); 405 408 } 406 409 407 // debug ("total number of attackers:"+ this.nbAttackers);408 // debug ("total number of defenders:"+ this.nbDefenders);410 //m.debug ("total number of attackers:"+ this.nbAttackers); 411 //m.debug ("total number of defenders:"+ this.nbDefenders); 409 412 410 413 // 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). 411 414 // now I'll list my idle defenders, then my idle soldiers that could defend. … … 419 422 } 420 423 421 424 // we're having too many. Release those that attack units already dealt with, or idle ones. 422 if (this.myUnits.filter( Filters.byMetadata(PlayerID, "role","defence")).length > nbOfAttackers*this.defenceRatio*1.2) {423 this.myUnits.filter( Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){425 if (this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).length > nbOfAttackers*this.defenceRatio*1.2) { 426 this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ 424 427 if ( defender.isIdle() || (defender.unitAIOrderData() && defender.unitAIOrderData()["target"])) { 425 428 if ( defender.isIdle() || (self.attackerCache[defender.unitAIOrderData()["target"]] && self.attackerCache[defender.unitAIOrderData()["target"]].length > 3)) { 426 429 // okay release me. … … 437 440 } 438 441 439 442 440 var nonDefenders = this.myUnits.filter( Filters.or(Filters.not(Filters.byMetadata(PlayerID, "role","defence")),Filters.isIdle()));441 nonDefenders = nonDefenders.filter( Filters.not(Filters.byClass("Female")));442 nonDefenders = nonDefenders.filter( Filters.not(Filters.byMetadata(PlayerID, "subrole","attacking")));443 var nonDefenders = this.myUnits.filter(API3.Filters.or(API3.Filters.not(API3.Filters.byMetadata(PlayerID, "role","defence")),API3.Filters.isIdle())); 444 nonDefenders = nonDefenders.filter(API3.Filters.not(API3.Filters.byClass("Female"))); 445 nonDefenders = nonDefenders.filter(API3.Filters.not(API3.Filters.byMetadata(PlayerID, "subrole","attacking"))); 443 446 var defenceRatio = this.defenceRatio; 444 447 445 448 if (newEnemies.length + this.nbAttackers > (this.nbDefenders + nonDefenders.length) * 0.8 && this.nbAttackers > 9) … … 448 451 if (newEnemies.length + this.nbAttackers > (this.nbDefenders + nonDefenders.length) * 1.5 && this.nbAttackers > 5) 449 452 gameState.setDefcon(1); 450 453 451 // debug ("newEnemies.length "+ newEnemies.length);452 // debug ("nonDefenders.length "+ nonDefenders.length);454 //m.debug ("newEnemies.length "+ newEnemies.length); 455 //m.debug ("nonDefenders.length "+ nonDefenders.length); 453 456 454 457 if (gameState.defcon() > 3) 455 458 HQ.unpauseAllPlans(gameState); … … 457 460 if ( (nonDefenders.length + this.nbDefenders > newEnemies.length + this.nbAttackers) 458 461 || this.nbDefenders + nonDefenders.length < 4) 459 462 { 460 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).toEntityArray();463 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); 461 464 buildings.forEach( function (struct) { 462 465 if (struct.garrisoned() && struct.garrisoned().length) 463 466 struct.unloadAll(); … … 513 516 { 514 517 var ent = nonDefenders._entities[id]; 515 518 if (ent.position()) 516 data.push([id, ent, SquareVectorDistance(enemy.position(), ent.position())]);519 data.push([id, ent, API3.SquareVectorDistance(enemy.position(), ent.position())]); 517 520 } 518 521 // refine the defenders we want. Since it's the distance squared, it has the effect 519 522 // of tending to always prefer closer units, though this refinement should change it slighty. … … 547 550 for each (var val in data.slice(0, Math.min(nonDefenders._length, defRatio - assigned))) 548 551 ret[val[0]] = val[1]; 549 552 550 var defs = new EntityCollection(nonDefenders._ai, ret);553 var defs = new API3.EntityCollection(nonDefenders._ai, ret); 551 554 552 555 // successfully sorted 553 556 defs.forEach(function (defender) { //}){ 554 557 if (defender.getMetadata(PlayerID, "plan") != undefined && (gameState.defcon() < 4 || defender.getMetadata(PlayerID,"subrole") == "walking")) 555 558 HQ.pausePlan(gameState, defender.getMetadata(PlayerID, "plan")); 556 // debug ("Against " +enemy.id() + " Assigning " + defender.id());559 //m.debug ("Against " +enemy.id() + " Assigning " + defender.id()); 557 560 if (defender.getMetadata(PlayerID, "role") == "worker" || defender.getMetadata(PlayerID, "role") == "attack") 558 561 defender.setMetadata(PlayerID, "formerrole", defender.getMetadata(PlayerID, "role")); 559 562 defender.setMetadata(PlayerID, "role","defence"); … … 571 574 /*if (gameState.defcon() <= 3) 572 575 { 573 576 // let's try to garrison neighboring females. 574 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).toEntityArray();575 var females = gameState.getOwnEntities().filter( Filters.byClass("Support"));577 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); 578 var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support")); 576 579 577 580 var cache = {}; 578 581 var garrisoned = false; … … 580 583 garrisoned = false; 581 584 if (ent.position()) 582 585 { 583 if ( SquareVectorDistance(ent.position(), enemy.position()) < 3500)586 if (API3.SquareVectorDistance(ent.position(), enemy.position()) < 3500) 584 587 { 585 588 for (var i in buildings) 586 589 { … … 611 614 // this processes the attackmessages 612 615 // So that a unit that gets attacked will not be completely dumb. 613 616 // warning: huge levels of indentation coming. 614 Defence.prototype.MessageProcess = function(gameState,events, HQ) {617 m.Defence.prototype.MessageProcess = function(gameState,events, HQ) { 615 618 var self = this; 616 619 617 620 for (var key in events){ … … 646 649 if (territory === PlayerID) 647 650 { 648 651 // anyway we'll register the animal as dangerous, and attack it (note: only on our territory. Don't care otherwise). 649 this.listOfWantedUnits[attacker.id()] = new EntityCollection(gameState.sharedScript);652 this.listOfWantedUnits[attacker.id()] = new API3.EntityCollection(gameState.sharedScript); 650 653 this.listOfWantedUnits[attacker.id()].addEnt(attacker); 651 654 this.listOfWantedUnits[attacker.id()].freeze(); 652 655 this.listOfWantedUnits[attacker.id()].registerUpdates(); 653 656 654 var filter = Filters.byTargetedEntity(attacker.id());657 var filter = API3.Filters.byTargetedEntity(attacker.id()); 655 658 this.WantedUnitsAttacker[attacker.id()] = this.myUnits.filter(filter); 656 659 this.WantedUnitsAttacker[attacker.id()].registerUpdates(); 657 660 } … … 666 669 667 670 // Right now, to make the AI less gameable, we'll mark any surrounding resource as inaccessible. 668 671 // usual tower range is 80. Be on the safe side. 669 var close = gameState.getResourceSupplies("wood").filter( Filters.byDistance(attacker.position(), 90));672 var close = gameState.getResourceSupplies("wood").filter(API3.Filters.byDistance(attacker.position(), 90)); 670 673 close.forEach(function (supply) { //}){ 671 674 supply.setMetadata(PlayerID, "inaccessible", true); 672 675 }); … … 683 686 if (this.reevaluateEntity(gameState, attacker)) 684 687 { 685 688 var position = attacker.position(); 686 var close = HQ.enemyWatchers[attacker.owner()].enemySoldiers.filter( Filters.byDistance(position, self.armyCompactSize));689 var close = HQ.enemyWatchers[attacker.owner()].enemySoldiers.filter(API3.Filters.byDistance(position, self.armyCompactSize)); 687 690 688 691 if (close.length > 2 || ourUnit.hasClass("Support") || attacker.hasClass("Siege")) 689 692 { … … 692 695 armyID = attacker.getMetadata(PlayerID, "inArmy"); 693 696 694 697 close.forEach(function (ent) { //}){ 695 if ( SquareVectorDistance(position, ent.position()) < self.armyCompactSize)698 if (API3.SquareVectorDistance(position, ent.position()) < self.armyCompactSize) 696 699 { 697 700 ent.setMetadata(PlayerID, "inArmy", armyID); 698 701 self.enemyArmy[ent.owner()][armyID].addEnt(ent); … … 708 711 // let's try to garrison this support unit. 709 712 if (ourUnit.position()) 710 713 { 711 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).filterNearest(ourUnit.position(),4).toEntityArray();714 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).filterNearest(ourUnit.position(),4).toEntityArray(); 712 715 var garrisoned = false; 713 716 for (var i in buildings) 714 717 { … … 742 745 }; // nice sets of closing brackets, isn't it? 743 746 744 747 // At most, this will put defcon to 4 745 Defence.prototype.DealWithWantedUnits = function(gameState, events, HQ) {748 m.Defence.prototype.DealWithWantedUnits = function(gameState, events, HQ) { 746 749 //if (gameState.defcon() < 3) 747 750 // return; 748 751 … … 841 844 } 842 845 return; 843 846 } 847 848 return m; 849 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/worker.js
1 var AEGIS = function(m) 2 { 3 1 4 /** 2 5 * This class makes a worker do as instructed by the economy manager 3 6 */ … … 2 5 3 varWorker = function(ent) {6 m.Worker = function(ent) { 4 7 this.ent = ent; … … 9 12 this.baseID = 0; 10 13 }; 11 14 12 Worker.prototype.update = function(baseManager, gameState) {15 m.Worker.prototype.update = function(baseManager, gameState) { 13 16 this.baseID = baseManager.ID; 14 17 var subrole = this.ent.getMetadata(PlayerID, "subrole"); 15 18 … … 64 67 } 65 68 Engine.ProfileStop(); 66 69 } 67 // debug: show the resource we're gathering from70 // m.debug: show the resource we're gathering from 68 71 //Engine.PostCommand({"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [10,0,0]}); 69 72 } else if (this.ent.unitAIState().split(".")[1] === "GATHER") { 70 73 … … 93 96 && this.ent.unitAIOrderData()[0]["target"]) 94 97 { 95 98 var ent = gameState.getEntityById(this.ent.unitAIOrderData()[0]["target"]); 96 debug ("here " + this.startApproachingResourceAmount + "," + ent.resourceSupplyAmount());99 m.debug ("here " + this.startApproachingResourceAmount + "," + ent.resourceSupplyAmount()); 97 100 if (ent && this.startApproachingResourceAmount == ent.resourceSupplyAmount() && this.startEnt == ent.id()) { 98 debug (ent.toString() + " is inaccessible");101 m.debug (ent.toString() + " is inaccessible"); 99 102 ent.setMetadata(PlayerID, "inaccessible", true); 100 103 this.ent.flee(ent); 101 104 this.ent.setMetadata(PlayerID, "subrole", "idle"); … … 116 119 var ent = gameState.getEntityById(this.gatheringFrom); 117 120 if ((ent && ent.resourceSupplyAmount() == ent.resourceSupplyMax())) { 118 121 // if someone gathers from it, it's only that the pathfinder sucks. 119 debug (ent.toString() + " is inaccessible");122 m.debug (ent.toString() + " is inaccessible"); 120 123 ent.setMetadata(PlayerID, "inaccessible", true); 121 124 this.ent.flee(ent); 122 125 this.ent.setMetadata(PlayerID, "subrole", "idle"); … … 129 132 var ent = gameState.getEntityById(this.ent.unitAIOrderData()[0].target); 130 133 if (ent && !ent.isHurt()) { 131 134 // if someone gathers from it, it's only that the pathfinder sucks. 132 debug (ent.toString() + " is inaccessible from Combat");135 m.debug (ent.toString() + " is inaccessible from Combat"); 133 136 ent.setMetadata(PlayerID, "inaccessible", true); 134 137 this.ent.flee(ent); 135 138 this.ent.setMetadata(PlayerID, "subrole", "idle"); … … 186 189 // this can happen in two ways: 187 190 // -either we were on an unsatisfactory resource last time we started gathering (this.unsatisfactoryResource) 188 191 // -Or we auto-moved to a bad resource thanks to the great UnitAI. 189 Worker.prototype.checkUnsatisfactoryResource = function(gameState) {192 m.Worker.prototype.checkUnsatisfactoryResource = function(gameState) { 190 193 if (this.unsatisfactoryResource) 191 194 return true; 192 195 if (this.ent.unitAIOrderData().length && this.ent.unitAIState().split(".")[1] === "GATHER" && this.ent.unitAIState().split(".")[2] === "GATHERING" && this.ent.unitAIOrderData()[0]["target"]) … … 198 201 return false; 199 202 }; 200 203 201 Worker.prototype.startGathering = function(baseManager, gameState) { 204 m.Worker.prototype.startGathering = function(baseManager, gameState) { 205 202 206 var resource = this.ent.getMetadata(PlayerID, "gather-type"); 203 207 var ent = this.ent; 204 208 var self = this; … … 219 223 // TODO: this is a huge part of multi-base support. Count only those in the same base as the worker. 220 224 var number = 0; 221 225 222 var ourDropsites = EntityCollectionFromIds(gameState,Object.keys(baseManager.dropsites));226 var ourDropsites = m.EntityCollectionFromIds(gameState,Object.keys(baseManager.dropsites)); 223 227 if (ourDropsites.length === 0) 224 228 { 225 debug ("We do not have a dropsite for " + resource + ", aborting");229 m.debug ("We do not have a dropsite for " + resource + ", aborting"); 226 230 return; 227 231 } 228 232 … … 245 249 return; 246 250 if (dropsite.position() && (baseManager.dropsites[dropsite.id()][resource][4] > 1000 || (number === 1 && baseManager.dropsites[dropsite.id()][resource][4] > 200) ) 247 251 && baseManager.dropsites[dropsite.id()][resource][5].length < maxPerDP) { 248 var dist = SquareVectorDistance(ent.position(), dropsite.position());252 var dist = API3.SquareVectorDistance(ent.position(), dropsite.position()); 249 253 if (dist < minDropsiteDist){ 250 254 minDropsiteDist = dist; 251 255 nearestResources = baseManager.dropsites[dropsite.id()][resource][1]; … … 254 258 } 255 259 }); 256 260 } 261 257 262 // we've found no fitting dropsites close enough from us. 258 263 // So'll try with far away. 259 264 if (!nearestResources || nearestResources.length === 0) { … … 262 267 return; 263 268 if (dropsite.position() && baseManager.dropsites[dropsite.id()][resource][4] > 400 264 269 && baseManager.dropsites[dropsite.id()][resource][5].length < maxPerDP) { 265 var dist = SquareVectorDistance(ent.position(), dropsite.position());270 var dist = API3.SquareVectorDistance(ent.position(), dropsite.position()); 266 271 if (dist < minDropsiteDist){ 267 272 minDropsiteDist = dist; 268 273 nearestResources = baseManager.dropsites[dropsite.id()][resource][1]; … … 271 276 } 272 277 }); 273 278 } 274 279 275 280 if (!nearestResources || nearestResources.length === 0){ 276 281 if (resource === "food") 277 282 if (this.buildAnyField(gameState)) … … 283 288 if (gameState.ai.HQ.switchWorkerBase(gameState, this.ent, resource)) 284 289 return; 285 290 286 // debug ("No fitting dropsite for " + resource + " found, iterating the map.");291 //m.debug ("No fitting dropsite for " + resource + " found, iterating the map."); 287 292 nearestResources = gameState.getResourceSupplies(resource); 288 293 this.unsatisfactoryResource = true; 289 294 // TODO: should try setting up dropsites. … … 298 303 return; 299 304 if (gameState.ai.HQ.switchWorkerBase(gameState, this.ent, resource)) 300 305 return; 301 debug("No " + resource + " found! (1)");306 m.debug("No " + resource + " found! (1)"); 302 307 } 303 308 else 304 309 { 305 310 if (gameState.ai.HQ.switchWorkerBase(gameState, this.ent, resource)) 306 311 return; 307 debug("No " + resource + " found! (1)");312 m.debug("No " + resource + " found! (1)"); 308 313 } 309 314 return; 310 315 } 311 // debug("Found " + nearestResources.length + "spots for " + resource);316 //m.debug("Found " + nearestResources.length + "spots for " + resource); 312 317 313 318 /*if (!nearestDropsite) { 314 debug ("No dropsite for " +resource);319 m.debug ("No dropsite for " +resource); 315 320 return; 316 321 }*/ 317 322 … … 324 329 nearestResources.forEach(function(supply) { //}){ 325 330 // sanity check, perhaps sheep could be garrisoned? 326 331 if (!supply.position()) { 327 // debug ("noposition");332 //m.debug ("noposition"); 328 333 return; 329 334 } 330 335 331 336 if (supply.getMetadata(PlayerID, "inaccessible") === true) { 332 // debug ("inaccessible");337 //m.debug ("inaccessible"); 333 338 return; 334 339 } 335 340 … … 341 346 342 347 // Don't gather enemy farms or farms from another base 343 348 if ((!supply.isOwn(PlayerID) && supply.owner() !== 0) || (supply.isOwn(PlayerID) && supply.getMetadata(PlayerID,"base") !== self.baseID)) { 344 // debug ("enemy");349 //m.debug ("enemy"); 345 350 return; 346 351 } 347 352 348 353 // quickscope accessbility check. 349 354 if (!gameState.ai.accessibility.pathAvailable(gameState, ent.position(), supply.position())) { 350 // debug ("nopath");355 //m.debug ("nopath"); 351 356 return; 352 357 } 353 358 // some simple check for chickens: if they're in a square that's inaccessible, we won't gather from them. 354 359 if (supply.footprintRadius() < 1) 355 360 { 356 var fakeMap = new Map(gameState.sharedScript,gameState.getMap().data);361 var fakeMap = new API3.Map(gameState.sharedScript,gameState.getMap().data); 357 362 var id = fakeMap.gamePosToMapPos(supply.position())[0] + fakeMap.width*fakeMap.gamePosToMapPos(supply.position())[1]; 358 363 if ( (gameState.sharedScript.passabilityClasses["pathfinderObstruction"] & gameState.getMap().data[id]) ) 359 364 { … … 363 368 } 364 369 365 370 // measure the distance to the resource (largely irrelevant) 366 var dist = SquareVectorDistance(supply.position(), ent.position());371 var dist = API3.SquareVectorDistance(supply.position(), ent.position()); 367 372 368 373 if (dist > 4900 && supply.hasClass("Animal")) 369 374 return; 370 375 371 376 // Add on a factor for the nearest dropsite if one exists 372 377 if (nearestDropsite !== undefined ){ 373 dist += 4* SquareVectorDistance(supply.position(), nearestDropsite.position());378 dist += 4*API3.SquareVectorDistance(supply.position(), nearestDropsite.position()); 374 379 dist /= 5.0; 375 380 } 376 381 377 var territoryOwner = Map.createTerritoryMap(gameState).getOwner(supply.position());382 var territoryOwner = m.createTerritoryMap(gameState).getOwner(supply.position()); 378 383 if (territoryOwner != PlayerID && territoryOwner != 0) { 379 384 dist *= 5.0; 380 385 //return; … … 395 400 if (!nearestDropsite) { 396 401 ourDropsites.forEach(function (dropsite){ //}){ 397 402 if (dropsite.position()){ 398 var dist = SquareVectorDistance(pos, dropsite.position());403 var dist = API3.SquareVectorDistance(pos, dropsite.position()); 399 404 if (dist < minDropsiteDist){ 400 405 minDropsiteDist = dist; 401 406 nearestDropsite = dropsite; … … 404 409 }); 405 410 if (!nearestDropsite) 406 411 { 407 debug ("No dropsite for " +resource);412 m.debug ("No dropsite for " +resource); 408 413 return; 409 414 } 410 415 } 411 416 412 417 // if the resource is far away, try to build a farm instead. 413 418 var tried = false; 414 if (resource === "food" && SquareVectorDistance(pos,this.ent.position()) > 22500)419 if (resource === "food" && API3.SquareVectorDistance(pos,this.ent.position()) > 22500) 415 420 { 416 421 tried = this.buildAnyField(gameState); 417 if (!tried && SquareVectorDistance(pos,this.ent.position()) > 62500) {422 if (!tried && API3.SquareVectorDistance(pos,this.ent.position()) > 62500) { 418 423 // TODO: ought to change behavior here. 419 424 return; // wait. a farm should appear. 420 425 } … … 429 434 else 430 435 gameState.turnCache["ressGathererNB"][nearestSupply.id()]++; 431 436 432 this.maxApproachTime = Math.max(30000, VectorDistance(pos,this.ent.position()) * 5000);437 this.maxApproachTime = Math.max(30000, API3.VectorDistance(pos,this.ent.position()) * 5000); 433 438 this.startApproachingResourceAmount = ent.resourceSupplyAmount(); 434 439 this.startEnt = ent.id(); 435 440 ent.gather(nearestSupply); … … 443 448 return; 444 449 445 450 if (resource !== "food") 446 debug("No " + resource + " found! (2)");451 m.debug("No " + resource + " found! (2)"); 447 452 // If we had a fitting closest dropsite with a lot of resources, mark it as not good. It means it's probably full. Then retry. 448 453 // it'll be resetted next time it's counted anyway. 449 454 if (nearestDropsite && nearestDropsite.getMetadata(PlayerID, "resource-quantity-" +resource)+nearestDropsite.getMetadata(PlayerID, "resource-quantity-far-" +resource) > 400) … … 456 461 }; 457 462 458 463 // Makes the worker deposit the currently carried resources at the closest dropsite 459 Worker.prototype.returnResources = function(gameState){464 m.Worker.prototype.returnResources = function(gameState){ 460 465 if (!this.ent.resourceCarrying() || this.ent.resourceCarrying().length === 0){ 461 466 return true; // assume we're OK. 462 467 } … … 472 477 var dist = Math.min(); 473 478 gameState.getOwnDropsites(resource).forEach(function(dropsite){ 474 479 if (dropsite.position()){ 475 var d = SquareVectorDistance(self.ent.position(), dropsite.position());480 var d = API3.SquareVectorDistance(self.ent.position(), dropsite.position()); 476 481 if (d < dist){ 477 482 dist = d; 478 483 closestDropsite = dropsite; … … 481 486 }); 482 487 483 488 if (!closestDropsite){ 484 debug("No dropsite found to deposit " + resource);489 m.debug("No dropsite found to deposit " + resource); 485 490 return false; 486 491 } 487 492 … … 489 494 return true; 490 495 }; 491 496 492 Worker.prototype.startHunting = function(gameState, baseManager){497 m.Worker.prototype.startHunting = function(gameState, baseManager){ 493 498 var ent = this.ent; 494 499 495 500 if (!ent.position() || !baseManager.isHunting) … … 500 505 var resources = gameState.getResourceSupplies("food"); 501 506 502 507 if (resources.length === 0){ 503 debug("No food found to hunt!");508 m.debug("No food found to hunt!"); 504 509 return; 505 510 } 506 511 … … 522 527 return; 523 528 524 529 // measure the distance to the resource 525 var dist = SquareVectorDistance(supply.position(), ent.position());530 var dist = API3.SquareVectorDistance(supply.position(), ent.position()); 526 531 527 var territoryOwner = Map.createTerritoryMap(gameState).getOwner(supply.position());532 var territoryOwner = m.createTerritoryMap(gameState).getOwner(supply.position()); 528 533 if (territoryOwner != PlayerID && territoryOwner != 0) { 529 534 dist *= 3.0; 530 535 } … … 547 552 // find a fitting dropsites in case we haven't already. 548 553 gameState.getOwnDropsites("food").forEach(function (dropsite){ //}){ 549 554 if (dropsite.position()){ 550 var dist = SquareVectorDistance(pos, dropsite.position());555 var dist = API3.SquareVectorDistance(pos, dropsite.position()); 551 556 if (dist < minDropsiteDist){ 552 557 minDropsiteDist = dist; 553 558 nearestDropsite = dropsite; … … 558 563 { 559 564 baseManager.isHunting = false; 560 565 ent.setMetadata(PlayerID, "role", undefined); 561 debug ("No dropsite for hunting food");566 m.debug ("No dropsite for hunting food"); 562 567 return; 563 568 } 564 569 if (minDropsiteDist > 35000) { … … 571 576 } else { 572 577 baseManager.isHunting = false; 573 578 ent.setMetadata(PlayerID, "role", undefined); 574 debug("No food found for hunting! (2)");579 m.debug("No food found for hunting! (2)"); 575 580 } 576 581 }; 577 582 578 Worker.prototype.getResourceType = function(type){583 m.Worker.prototype.getResourceType = function(type){ 579 584 if (!type || !type.generic){ 580 585 return undefined; 581 586 } … … 587 592 } 588 593 }; 589 594 590 Worker.prototype.getGatherRate = function(gameState) {595 m.Worker.prototype.getGatherRate = function(gameState) { 591 596 if (this.ent.getMetadata(PlayerID,"subrole") !== "gatherer") 592 597 return 0; 593 598 var rates = this.ent.resourceGatherRates(); … … 601 606 if (type.generic == "treasure") 602 607 return 1000; 603 608 var tstring = type.generic + "." + type.specific; 604 // debug (+rates[tstring] + " for " + tstring + " for " + this.ent._templateName);609 //m.debug (+rates[tstring] + " for " + tstring + " for " + this.ent._templateName); 605 610 if (rates[tstring]) 606 611 return rates[tstring]; 607 612 return 0; … … 609 614 return 0; 610 615 }; 611 616 612 Worker.prototype.buildAnyField = function(gameState){617 m.Worker.prototype.buildAnyField = function(gameState){ 613 618 var self = this; 614 619 var okay = false; 615 var foundations = gameState.getOwnFoundations().filter( Filters.byMetadata(PlayerID,"base",this.baseID));620 var foundations = gameState.getOwnFoundations().filter(API3.Filters.byMetadata(PlayerID,"base",this.baseID)); 616 621 foundations.filterNearest(this.ent.position(), foundations.length); 617 622 foundations.forEach(function (found) { 618 623 if (found._template.BuildRestrictions.Category === "Field" && !okay) { … … 636 641 } 637 642 return okay; 638 643 }; 644 645 return m; 646 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/attack_plan.js
1 var AEGIS = function(m) 2 { 3 1 4 /* This is an attack plan (despite the name, it's a relic of older times). 2 5 * It deals with everything in an attack, from picking a target to picking a path to it 3 6 * To making sure units rae built, and pushing elements to the queue manager otherwise … … 6 9 * There is a basic support for naval expeditions here. 7 10 */ 8 11 9 function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) {12 m.CityAttack = function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy, type , targetFinder) { 10 13 14 this.Config = Config; 11 15 //This is the list of IDs of the units in the plan 12 16 this.idList=[]; 13 17 … … 33 37 return false; 34 38 } 35 39 36 var CCs = gameState.getOwnEntities().filter( Filters.byClass("CivCentre"));40 var CCs = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")); 37 41 if (CCs.length === 0) 38 42 { 39 43 this.failed = true; 40 44 return false; 41 45 } 42 46 43 debug ("Target (" + PlayerID +") = " +this.targetPlayer);47 m.debug ("Target (" + PlayerID +") = " +this.targetPlayer); 44 48 this.targetFinder = targetFinder || this.defaultTargetFinder; 45 49 this.type = type || "normal"; 46 50 this.name = uniqueID; … … 50 54 51 55 this.maxPreparationTime = 210*1000; 52 56 // in this case we want to have the attack ready by the 13th minute. Countdown. Minimum 2 minutes. 53 if (type !== "superSized" && Config.difficulty >= 1)57 if (type !== "superSized" && this.Config.difficulty >= 1) 54 58 this.maxPreparationTime = 780000 - gameState.getTimeElapsed() < 120000 ? 120000 : 780000 - gameState.getTimeElapsed(); 55 59 56 60 this.pausingStart = 0; … … 120 124 return (strength[0] > 15 || strength[1] > 15); 121 125 };*/ 122 126 123 var filter = Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID));127 var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)); 124 128 this.unitCollection = gameState.getOwnEntities().filter(filter); 125 129 this.unitCollection.registerUpdates(); 126 130 this.unitCollection.length; … … 136 140 var cat = unitCat; 137 141 var Unit = this.unitStat[cat]; 138 142 139 filter = Filters.and(Filters.byClassesAnd(Unit["classes"]),Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID)));143 filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID))); 140 144 this.unit[cat] = gameState.getOwnEntities().filter(filter); 141 145 this.unit[cat].registerUpdates(); 142 146 this.unit[cat].length; … … 186 190 this.anyNotMinimal = true; // used for support plans 187 191 188 192 189 var myFortresses = gameState.getOwnTrainingFacilities().filter( Filters.byClass("GarrisonFortress"));193 var myFortresses = gameState.getOwnTrainingFacilities().filter(API3.Filters.byClass("GarrisonFortress")); 190 194 if (myFortresses.length !== 0) 191 195 { 192 196 // make this our rallypoint … … 237 241 238 242 this.assignUnits(gameState); 239 243 240 // debug ("Before");244 //m.debug ("Before"); 241 245 //Engine.DumpHeap(); 242 246 243 247 // get a good path to an estimated target. 244 this.pathFinder = new aStarPath(gameState,false,false, this.targetPlayer);248 this.pathFinder = new API3.aStarPath(gameState,false,false, this.targetPlayer); 245 249 //Engine.DumpImage("widthmap.png", this.pathFinder.widthMap, this.pathFinder.width,this.pathFinder.height,255); 246 250 247 251 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 253 this.onBoat = false; // tells us if our units are loaded on boats. 250 254 this.needsShip = false; 251 255 252 // debug ("after");256 //m.debug ("after"); 253 257 //Engine.DumpHeap(); 254 258 return true; 255 259 }; 256 260 257 CityAttack.prototype.getName = function(){261 m.CityAttack.prototype.getName = function(){ 258 262 return this.name; 259 263 }; 260 CityAttack.prototype.getType = function(){264 m.CityAttack.prototype.getType = function(){ 261 265 return this.type; 262 266 }; 263 267 // Returns true if the attack can be executed at the current time 264 268 // Basically his checks we have enough units. 265 269 // We run a count of our units. 266 CityAttack.prototype.canStart = function(gameState){270 m.CityAttack.prototype.canStart = function(gameState){ 267 271 for (var unitCat in this.unitStat) { 268 272 var Unit = this.unitStat[unitCat]; 269 273 if (this.unit[unitCat].length < Unit["minSize"]) … … 273 277 274 278 // TODO: check if our target is valid and a few other stuffs (good moment to attack?) 275 279 }; 276 CityAttack.prototype.isStarted = function(){280 m.CityAttack.prototype.isStarted = function(){ 277 281 if ((this.state !== "unexecuted")) 278 debug ("Attack plan already started");282 m.debug ("Attack plan already started"); 279 283 return !(this.state == "unexecuted"); 280 284 }; 281 285 282 CityAttack.prototype.isPaused = function(){286 m.CityAttack.prototype.isPaused = function(){ 283 287 return this.paused; 284 288 }; 285 CityAttack.prototype.setPaused = function(gameState, boolValue){289 m.CityAttack.prototype.setPaused = function(gameState, boolValue){ 286 290 if (!this.paused && boolValue === true) { 287 291 this.pausingStart = gameState.getTimeElapsed(); 288 292 this.paused = true; 289 debug ("Pausing attack plan " +this.name);293 m.debug ("Pausing attack plan " +this.name); 290 294 } else if (this.paused && boolValue === false) { 291 295 this.totalPausingTime += gameState.getTimeElapsed() - this.pausingStart; 292 296 this.paused = false; 293 debug ("Unpausing attack plan " +this.name);297 m.debug ("Unpausing attack plan " +this.name); 294 298 } 295 299 }; 296 CityAttack.prototype.mustStart = function(gameState){300 m.CityAttack.prototype.mustStart = function(gameState){ 297 301 if (this.isPaused() || this.path === undefined) 298 302 return false; 299 303 var MaxReachedEverywhere = true; … … 309 313 }; 310 314 311 315 // Adds a build order. If resetQueue is true, this will reset the queue. 312 CityAttack.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue) {316 m.CityAttack.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue) { 313 317 if (!this.isStarted()) 314 318 { 315 debug ("Adding a build order for " + name);319 m.debug ("Adding a build order for " + name); 316 320 // no minsize as we don't want the plan to fail at the last minute though. 317 321 this.unitStat[name] = unitStats; 318 322 var Unit = this.unitStat[name]; 319 var filter = Filters.and(Filters.byClassesAnd(Unit["classes"]),Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID)));323 var filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID))); 320 324 this.unit[name] = gameState.getOwnEntities().filter(filter); 321 325 this.unit[name].registerUpdates(); 322 326 this.buildOrder.push([0, Unit["classes"], this.unit[name], Unit, name]); … … 330 334 331 335 // Three returns possible: 1 is "keep going", 0 is "failed plan", 2 is "start" 332 336 // 3 is a special case: no valid path returned. Right now I stop attacking alltogether. 333 CityAttack.prototype.updatePreparation = function(gameState, HQ,events) {337 m.CityAttack.prototype.updatePreparation = function(gameState, HQ,events) { 334 338 var self = this; 335 339 336 340 if (this.path == undefined || this.target == undefined || this.path === "toBeContinued") { … … 342 346 targets = this.defaultTargetFinder(gameState, HQ); 343 347 344 348 if (targets.length !== 0) { 345 debug ("Aiming for " + targets);349 m.debug ("Aiming for " + targets); 346 350 // picking a target 347 351 var maxDist = -1; 348 352 var index = 0; 349 353 for (var i in targets._entities) 350 354 { 351 355 // we're sure it has a position has TargetFinder already checks that. 352 var dist = SquareVectorDistance(targets._entities[i].position(), this.rallyPoint);356 var dist = API3.SquareVectorDistance(targets._entities[i].position(), this.rallyPoint); 353 357 if (dist < maxDist || maxDist === -1) 354 358 { 355 359 maxDist = dist; … … 385 389 // Basically we'll add it as a new class to train compulsorily, and we'll recompute our path. 386 390 if (!gameState.ai.HQ.waterMap) 387 391 { 388 debug ("This is actually a water map.");392 m.debug ("This is actually a water map."); 389 393 gameState.ai.HQ.waterMap = true; 390 394 return 0; 391 395 } 392 debug ("We need a ship.");396 m.debug ("We need a ship."); 393 397 this.needsShip = true; 394 398 this.pathWidth = 3; 395 399 this.pathSampling = 3; … … 400 404 { 401 405 // my pathfinder returns arrays in arrays in arrays. 402 406 var waypointPos = this.path[i][0]; 403 var territory = Map.createTerritoryMap(gameState);407 var territory = m.createTerritoryMap(gameState); 404 408 if (territory.getOwner(waypointPos) !== PlayerID || this.path[i][1] === true) 405 409 { 406 410 // if we're suddenly out of our territory or this is the point where we change transportation method. … … 426 430 { 427 431 // my pathfinder returns arrays in arrays in arrays. 428 432 var waypointPos = this.path[i][0]; 429 var territory = Map.createTerritoryMap(gameState);433 var territory = m.createTerritoryMap(gameState); 430 434 if (territory.getOwner(waypointPos) !== PlayerID || this.path[i][1] === true) 431 435 { 432 436 // if we're suddenly out of our territory or this is the point where we change transportation method. … … 511 515 512 516 if (this.buildOrder[0][0] < 1 && queue.length() <= 5) { 513 517 var template = HQ.findBestTrainableSoldier(gameState, this.buildOrder[0][1], this.buildOrder[0][3]["interests"] ); 514 // debug ("tried " + uneval(this.buildOrder[0][1]) +", and " + template);518 //m.debug ("tried " + uneval(this.buildOrder[0][1]) +", and " + template); 515 519 // HACK (TODO replace) : if we have no trainable template... Then we'll simply remove the buildOrder, effectively removing the unit from the plan. 516 520 if (template === undefined) { 517 521 // TODO: this is a complete hack. … … 523 527 if (gameState.getTimeElapsed() > 1800000) 524 528 max *= 2; 525 529 if (gameState.getTemplate(template).hasClass("CitizenSoldier")) 526 queue.addItem( new TrainingPlan(gameState,template, { "role" : "worker", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) );530 queue.addItem( new m.TrainingPlan(gameState,template, { "role" : "worker", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) ); 527 531 else 528 queue.addItem( new TrainingPlan(gameState,template, { "role" : "attack", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) );532 queue.addItem( new m.TrainingPlan(gameState,template, { "role" : "attack", "plan" : this.name, "special" : specialData, "base" : 1 }, this.buildOrder[0][3]["batchSize"],max ) ); 529 533 } 530 534 } 531 535 } … … 546 550 this.targetPos = target.position(); 547 551 count++; 548 552 if (count > 1000){ 549 debug("No target with a valid position found");553 m.debug("No target with a valid position found"); 550 554 return false; 551 555 } 552 556 } … … 559 563 if (path !== "toBeContinued") { 560 564 this.startedPathing = false; 561 565 this.path = path; 562 debug("Pathing ended");566 m.debug("Pathing ended"); 563 567 } 564 568 } 565 569 */ … … 567 571 Engine.ProfileStop(); 568 572 // can happen for now 569 573 if (this.buildOrder.length === 0) { 570 debug ("Ending plan: no build orders");574 m.debug ("Ending plan: no build orders"); 571 575 return 0; // will abort the plan, should return something else 572 576 } 573 577 return 1; … … 583 587 return 0; 584 588 return 0; 585 589 }; 586 CityAttack.prototype.assignUnits = function(gameState){590 m.CityAttack.prototype.assignUnits = function(gameState){ 587 591 var self = this; 588 592 589 593 // TODO: assign myself units that fit only, right now I'm getting anything. … … 604 608 605 609 }; 606 610 // this sends a unit by ID back to the "rally point" 607 CityAttack.prototype.ToRallyPoint = function(gameState,id)611 m.CityAttack.prototype.ToRallyPoint = function(gameState,id) 608 612 { 609 613 // Move back to nearest rallypoint 610 614 gameState.getEntityById(id).move(this.rallyPoint[0],this.rallyPoint[1]); 611 615 } 612 616 // this sends all units back to the "rally point" by entity collections. 613 617 // It doesn't disturb ones that could be currently defending, even if the plan is not (yet) paused. 614 CityAttack.prototype.AllToRallyPoint = function(gameState, evenWorkers) {618 m.CityAttack.prototype.AllToRallyPoint = function(gameState, evenWorkers) { 615 619 var self = this; 616 620 if (evenWorkers) { 617 621 for (var unitCat in this.unit) { … … 634 638 } 635 639 636 640 // Default target finder aims for conquest critical targets 637 CityAttack.prototype.defaultTargetFinder = function(gameState, HQ){641 m.CityAttack.prototype.defaultTargetFinder = function(gameState, HQ){ 638 642 var targets = undefined; 639 643 640 644 targets = HQ.enemyWatchers[this.targetPlayer].getEnemyBuildings(gameState, "CivCentre",true); … … 650 654 } 651 655 // no buildings, attack anything conquest critical, even units (it's assuming it won't move). 652 656 if (targets.length == 0) { 653 targets = gameState.getEnemyEntities().filter( Filters.and( Filters.byOwner(this.targetPlayer),Filters.byClass("ConquestCritical")));657 targets = gameState.getEnemyEntities().filter(API3.Filters.and( API3.Filters.byOwner(this.targetPlayer),API3.Filters.byClass("ConquestCritical"))); 654 658 } 655 659 return targets; 656 660 }; 657 661 658 662 // tupdate 659 CityAttack.prototype.raidingTargetFinder = function(gameState, HQ, Target){663 m.CityAttack.prototype.raidingTargetFinder = function(gameState, HQ, Target){ 660 664 var targets = undefined; 661 665 if (Target == "villager") 662 666 { … … 684 688 // Executes the attack plan, after this is executed the update function will be run every turn 685 689 // If we're here, it's because we have in our IDlist enough units. 686 690 // now the IDlist units are treated turn by turn 687 CityAttack.prototype.StartAttack = function(gameState, HQ){691 m.CityAttack.prototype.StartAttack = function(gameState, HQ){ 688 692 689 693 // check we have a target and a path. 690 694 if (this.targetPos && this.path !== undefined) { … … 701 705 702 706 this.unitCollection.move(this.path[0][0][0], this.path[0][0][1]); 703 707 this.unitCollection.setStance("aggressive"); 704 this.unitCollection.filter( Filters.byClass("Siege")).setStance("defensive");708 this.unitCollection.filter(API3.Filters.byClass("Siege")).setStance("defensive"); 705 709 706 710 this.state = "walking"; 707 711 } else { 708 712 gameState.ai.gameFinished = true; 709 debug ("I do not have any target. So I'll just assume I won the game.");713 m.debug ("I do not have any target. So I'll just assume I won the game."); 710 714 return false; 711 715 } 712 716 return true; 713 717 }; 714 718 715 719 // Runs every turn after the attack is executed 716 CityAttack.prototype.update = function(gameState, HQ, events){720 m.CityAttack.prototype.update = function(gameState, HQ, events){ 717 721 var self = this; 718 722 719 723 Engine.ProfileStart("Update Attack"); … … 750 754 751 755 if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0 && attacker.owner() != PlayerID) { 752 756 753 var territoryMap = Map.createTerritoryMap(gameState);757 var territoryMap = m.createTerritoryMap(gameState); 754 758 if ( +territoryMap.point(attacker.position()) - 64 === +this.targetPlayer) 755 759 { 756 760 attackedNB++; … … 769 773 } 770 774 } 771 775 if (attackedNB > 4) { 772 debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination.");776 m.debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); 773 777 // we must assume we've arrived at the end of the trail. 774 778 this.state = "arrived"; 775 779 } … … 799 803 var enemy = enemySoldiers[j]; 800 804 if (enemy.position() === undefined) // likely garrisoned 801 805 continue; 802 if ( inRange(enemy.position(), attacker.position(), 1000) && this.threatList.indexOf(enemy.id()) === -1)806 if (m.inRange(enemy.position(), attacker.position(), 1000) && this.threatList.indexOf(enemy.id()) === -1) 803 807 this.threatList.push(enemy.id()); 804 808 } 805 809 this.threatList.push(e.msg.attacker); … … 844 848 } 845 849 846 850 // basically haven't moved an inch: very likely stuck) 847 if ( SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0) {851 if (API3.SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0) { 848 852 // check for stuck siege units 849 853 850 var sieges = this.unitCollection.filter( Filters.byClass("Siege"));854 var sieges = this.unitCollection.filter(API3.Filters.byClass("Siege")); 851 855 var farthest = 0; 852 856 var farthestEnt = -1; 853 857 sieges.forEach (function (ent) { 854 if ( SquareVectorDistance(ent.position(),self.position) > farthest)858 if (API3.SquareVectorDistance(ent.position(),self.position) > farthest) 855 859 { 856 farthest = SquareVectorDistance(ent.position(),self.position);860 farthest = API3.SquareVectorDistance(ent.position(),self.position); 857 861 farthestEnt = ent; 858 862 } 859 863 }); … … 863 867 if (gameState.ai.playedTurn % 5 === 0) 864 868 this.position5TurnsAgo = this.position; 865 869 866 if (this.lastPosition && SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) {870 if (this.lastPosition && API3.SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) { 867 871 this.unitCollection.moveIndiv(this.path[0][0][0], this.path[0][0][1]); 868 872 // 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. 869 var walls = gameState.getEnemyEntities().filter( Filters.and(Filters.byOwner(this.targetPlayer),Filters.byClass("StoneWall")));873 var walls = gameState.getEnemyEntities().filter(API3.Filters.and(API3.Filters.byOwner(this.targetPlayer), API3.Filters.byClass("StoneWall"))); 870 874 var nexttoWalls = false; 871 875 walls.forEach( function (ent) { 872 if (!nexttoWalls && SquareVectorDistance(self.position, ent.position()) < 800)876 if (!nexttoWalls && API3.SquareVectorDistance(self.position, ent.position()) < 800) 873 877 nexttoWalls = true; 874 878 }); 875 879 // there are walls but we can attack 876 if (nexttoWalls && this.unitCollection.filter( Filters.byCanAttack("StoneWall")).length !== 0)880 if (nexttoWalls && this.unitCollection.filter(API3.Filters.byCanAttack("StoneWall")).length !== 0) 877 881 { 878 debug ("Attack Plan " +this.type +" " +this.name +" has met walls and is not happy.");882 m.debug ("Attack Plan " +this.type +" " +this.name +" has met walls and is not happy."); 879 883 this.state = "arrived"; 880 884 } else if (nexttoWalls) { 881 885 // abort plan. 882 debug ("Attack Plan " +this.type +" " +this.name +" has met walls and gives up.");886 m.debug ("Attack Plan " +this.type +" " +this.name +" has met walls and gives up."); 883 887 Engine.ProfileStop(); 884 888 return 0; 885 889 } 886 890 } 887 891 888 892 // check if our land units are close enough from the next waypoint. 889 if ( SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) < 7500 ||890 SquareVectorDistance(this.unitCollection.getCentrePosition(), this.path[0][0]) < 650) {891 if (this.unitCollection.filter( Filters.byClass("Siege")).length !== 0892 && SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) >= 7500893 && SquareVectorDistance(this.unitCollection.filter(Filters.byClass("Siege")).getCentrePosition(), this.path[0][0]) >= 650)893 if (API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) < 7500 || 894 API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.path[0][0]) < 650) { 895 if (this.unitCollection.filter(API3.Filters.byClass("Siege")).length !== 0 896 && API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) >= 7500 897 && API3.SquareVectorDistance(this.unitCollection.filter(API3.Filters.byClass("Siege")).getCentrePosition(), this.path[0][0]) >= 650) 894 898 { 895 899 } else { 896 900 897 901 for (var i = 0; i < this.path.length; ++i) 898 902 { 899 debug ("path waypoint " + i + "," + this.path[i][1] + " at " + uneval(this.path[i][0]));903 m.debug ("path waypoint " + i + "," + this.path[i][1] + " at " + uneval(this.path[i][0])); 900 904 } 901 debug ("position is " + this.unitCollection.getCentrePosition());905 m.debug ("position is " + this.unitCollection.getCentrePosition()); 902 906 903 907 // okay so here basically two cases. The first one is "we need a boat at this point". 904 908 // the second one is "we need to unload at this point". The third is "normal". … … 908 912 if (this.path.length > 0){ 909 913 this.unitCollection.move(this.path[0][0][0], this.path[0][0][1]); 910 914 } else { 911 debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination.");915 m.debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); 912 916 // we must assume we've arrived at the end of the trail. 913 917 this.state = "arrived"; 914 918 } … … 917 921 // TODO: make this require an escort later on. 918 922 this.path.shift(); 919 923 if (this.path.length === 0) { 920 debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination.");924 m.debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination."); 921 925 // we must assume we've arrived at the end of the trail. 922 926 this.state = "arrived"; 923 927 } else { … … 925 929 var plan = new TransportPlan(gameState, this.unitCollection.toIdArray(), this.path[0][0], false); 926 930 this.tpPlanID = plan.ID; 927 931 HQ.navalManager.transportPlans.push(plan); 928 debug ("Transporting over sea");932 m.debug ("Transporting over sea"); 929 933 this.state = "transporting"; 930 934 */ 931 935 // TODO: fix this above … … 962 966 }); 963 967 var targetList = []; 964 968 enemyCitizens.forEach( function (enemy) { 965 if ( inRange(enemy.position(), units.getCentrePosition(), 2500) && targetList.indexOf(enemy.id()) === -1)969 if (m.inRange(enemy.position(), units.getCentrePosition(), 2500) && targetList.indexOf(enemy.id()) === -1) 966 970 targetList.push(enemy.id()); 967 971 }); 968 972 if (targetList.length > 0) … … 989 993 if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0 && attacker.owner() != PlayerID) { 990 994 if (ourUnit.hasClass("Siege")) 991 995 { 992 var collec = this.unitCollection.filterNearest(ourUnit.position(), 8).filter( Filters.not(Filters.byClass("Siege"))).toEntityArray();996 var collec = this.unitCollection.filterNearest(ourUnit.position(), 8).filter(API3.Filters.not(API3.Filters.byClass("Siege"))).toEntityArray(); 993 997 if (collec.length !== 0) 994 998 { 995 999 collec[0].attack(attacker.id()); … … 1018 1022 this.unitCollUpdateArray = this.unitCollection.toIdArray(); 1019 1023 } else { 1020 1024 // some stuffs for locality and speed 1021 var territoryMap = Map.createTerritoryMap(gameState);1025 var territoryMap = m.createTerritoryMap(gameState); 1022 1026 var timeElapsed = gameState.getTimeElapsed(); 1023 1027 1024 1028 // Let's check a few units each time we update. Currently 10 … … 1057 1061 if (!enemy.position() || (enemy.hasClass("StoneWall") && ent.canAttackClass("StoneWall"))) { 1058 1062 return false; 1059 1063 } 1060 if ( SquareVectorDistance(enemy.position(),ent.position()) > 3000) {1064 if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 3000) { 1061 1065 return false; 1062 1066 } 1063 1067 return true; … … 1070 1074 } 1071 1075 if (!enemy.hasClass("Support")) 1072 1076 return false; 1073 if ( SquareVectorDistance(enemy.position(),ent.position()) > 10000) {1077 if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 10000) { 1074 1078 return false; 1075 1079 } 1076 1080 return true; … … 1081 1085 if (!enemy.position()) { 1082 1086 return false; 1083 1087 } 1084 if ( SquareVectorDistance(enemy.position(),ent.position()) > 10000) {1088 if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 10000) { 1085 1089 return false; 1086 1090 } 1087 1091 return true; … … 1118 1122 { 1119 1123 var rand = Math.floor(Math.random() * mStruct.length*0.1); 1120 1124 ent.attack(mStruct[+rand].id()); 1121 // debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName());1125 //m.debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); 1122 1126 } 1123 } else if ( SquareVectorDistance(self.targetPos, ent.position()) > 900 ){1124 // debug ("Siege units moving to " + uneval(self.targetPos));1127 } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ 1128 //m.debug ("Siege units moving to " + uneval(self.targetPos)); 1125 1129 ent.move(self.targetPos[0],self.targetPos[1]); 1126 1130 } 1127 1131 } else { 1128 1132 if (mUnit.length !== 0) { 1129 1133 var rand = Math.floor(Math.random() * mUnit.length*0.99); 1130 1134 ent.attack(mUnit[(+rand)].id()); 1131 // debug ("Units attacking a unit from " +mUnit[+rand].owner() + " , " +mUnit[+rand].templateName());1132 } else if ( SquareVectorDistance(self.targetPos, ent.position()) > 900 ){1133 // debug ("Units moving to " + uneval(self.targetPos));1135 //m.debug ("Units attacking a unit from " +mUnit[+rand].owner() + " , " +mUnit[+rand].templateName()); 1136 } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ 1137 //m.debug ("Units moving to " + uneval(self.targetPos)); 1134 1138 ent.move(self.targetPos[0],self.targetPos[1]); 1135 1139 } else if (mStruct.length !== 0) { 1136 1140 mStruct.sort(function (structa,structb) { //}){ … … 1156 1160 { 1157 1161 var rand = Math.floor(Math.random() * mStruct.length*0.1); 1158 1162 ent.attack(mStruct[+rand].id()); 1159 // debug ("Units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName());1163 //m.debug ("Units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); 1160 1164 } 1161 1165 } 1162 1166 } … … 1172 1176 targets = this.defaultTargetFinder(gameState, HQ); 1173 1177 } 1174 1178 if (targets.length) { 1175 debug ("Seems like our target has been destroyed. Switching.");1176 debug ("Aiming for " + targets);1179 m.debug ("Seems like our target has been destroyed. Switching."); 1180 m.debug ("Aiming for " + targets); 1177 1181 // picking a target 1178 1182 this.targetPos = undefined; 1179 1183 var count = 0; … … 1183 1187 this.targetPos = this.target.position(); 1184 1188 count++; 1185 1189 if (count > 1000){ 1186 debug("No target with a valid position found");1190 m.debug("No target with a valid position found"); 1187 1191 Engine.ProfileStop(); 1188 1192 return false; 1189 1193 } … … 1215 1219 1216 1220 return this.unitCollection.length; 1217 1221 }; 1218 CityAttack.prototype.totalCountUnits = function(gameState){1222 m.CityAttack.prototype.totalCountUnits = function(gameState){ 1219 1223 var totalcount = 0; 1220 1224 for (var i in this.idList) 1221 1225 { … … 1224 1228 return totalcount; 1225 1229 }; 1226 1230 // reset any units 1227 CityAttack.prototype.Abort = function(gameState){1231 m.CityAttack.prototype.Abort = function(gameState){ 1228 1232 this.unitCollection.forEach(function(ent) { 1229 1233 ent.setMetadata(PlayerID, "role",undefined); 1230 1234 ent.setMetadata(PlayerID, "subrole",undefined); … … 1238 1242 gameState.ai.queueManager.removeQueue("plan_" + this.name); 1239 1243 gameState.ai.queueManager.removeQueue("plan_" + this.name + "_champ"); 1240 1244 }; 1245 1246 return m; 1247 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/plan-transport.js
1 var AEGIS = function(m) 2 { 3 1 4 /* 2 5 Describes a transport plan 3 6 Constructor assign units (units is an ID array, or an ID), a destionation (position, ingame), and a wanted escort size. … … 15 18 // TODO: finish the support of multiple accessibility indexes. 16 19 // TODO: this doesn't check we can actually reach in the init, which we might want? 17 20 18 varTransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) {21 m.TransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) { 19 22 var self = this; 20 23 21 this.ID = uniqueIDTPlans++;24 this.ID = m.playerGlobals[PlayerID].uniqueIDTPlans++; 22 25 23 26 var unitsID = []; 24 27 if (units.length !== undefined) … … 26 29 else 27 30 unitsID = [units]; 28 31 29 this.units = EntityCollectionFromIds(gameState, unitsID);32 this.units = m.EntityCollectionFromIds(gameState, unitsID); 30 33 this.units.forEach(function (ent) { //}){ 31 34 ent.setMetadata(PlayerID, "tpplan", self.ID); 32 35 ent.setMetadata(PlayerID, "formerRole", ent.getMetadata(PlayerID, "role")); … … 36 39 this.units.freeze(); 37 40 this.units.registerUpdates(); 38 41 39 debug ("Starting a new plan with ID " + this.ID + " to " + destination);40 debug ("units are " + uneval (units));42 m.debug ("Starting a new plan with ID " + this.ID + " to " + destination); 43 m.debug ("units are " + uneval (units)); 41 44 42 45 this.destination = destination; 43 46 this.destinationIndex = gameState.ai.accessibility.getAccessValue(destination); … … 70 73 }; 71 74 72 75 // count available slots 73 TransportPlan.prototype.countFreeSlots = function(onlyTrulyFree)76 m.TransportPlan.prototype.countFreeSlots = function(onlyTrulyFree) 74 77 { 75 78 var slots = 0; 76 79 this.transportShips.forEach(function (ent) { //}){ … … 80 83 }); 81 84 } 82 85 83 TransportPlan.prototype.assignShip = function(gameState, ship)86 m.TransportPlan.prototype.assignShip = function(gameState, ship) 84 87 { 85 88 ship.setMetadata(PlayerID,"tpplan", this.ID); 86 89 } 87 90 88 TransportPlan.prototype.releaseAll = function(gameState)91 m.TransportPlan.prototype.releaseAll = function(gameState) 89 92 { 90 93 this.ships.forEach(function (ent) { ent.setMetadata(PlayerID,"tpplan", undefined) }); 91 94 this.units.forEach(function (ent) { … … 96 99 }); 97 100 } 98 101 99 TransportPlan.prototype.releaseAllShips = function(gameState)102 m.TransportPlan.prototype.releaseAllShips = function(gameState) 100 103 { 101 104 this.ships.forEach(function (ent) { ent.setMetadata(PlayerID,"tpplan", undefined) }); 102 105 } 103 106 104 TransportPlan.prototype.needTpShips = function()107 m.TransportPlan.prototype.needTpShips = function() 105 108 { 106 109 if ((this.allAtOnce && this.countFreeSlots() >= this.units.length) || this.transportShips.length > 0) 107 110 return false; 108 111 return true; 109 112 } 110 113 111 TransportPlan.prototype.needEscortShips = function()114 m.TransportPlan.prototype.needEscortShips = function() 112 115 { 113 116 return !((this.onlyIfOK && this.escortShips.length < this.escortSize) || !this.onlyIfOK); 114 117 } 115 118 116 119 // returns the zone for which we are needing our ships 117 TransportPlan.prototype.neededShipsZone = function()120 m.TransportPlan.prototype.neededShipsZone = function() 118 121 { 119 122 if (!this.seaZone) 120 123 return false; … … 134 137 > there is the possibility that we'll be moving units on land, but that's basically a restart too, with more clearing. 135 138 Grouping Path is basically the same with "grouping" and we never unboard (unless there is a need to) 136 139 */ 137 TransportPlan.prototype.carryOn = function(gameState, navalManager)140 m.TransportPlan.prototype.carryOn = function(gameState, navalManager) 138 141 { 139 142 if (this.state === "unstarted") 140 143 { … … 171 174 // let's get our index this turn. 172 175 this.startIndex = unitIndexes[0]; 173 176 174 debug ("plan " + this.ID + " from " + this.startIndex);177 m.debug ("plan " + this.ID + " from " + this.startIndex); 175 178 176 179 return true; 177 180 } … … 190 193 } 191 194 // we have a path, register the first sea zone. 192 195 this.seaZone = this.path[1]; 193 debug ("Plan " + this.ID + " over seazone " + this.seaZone);196 m.debug ("Plan " + this.ID + " over seazone " + this.seaZone); 194 197 } 195 198 // if we currently have no baoarding spot, try and find one. 196 199 if (!this.boardingSpot) … … 206 209 var passabilityMap = gameState.getMap(); 207 210 var territoryMap = gameState.ai.territoryMap; 208 211 var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction") | gameState.getPassabilityClassMask("building-shore"); 209 var obstructions = new Map(gameState.sharedScript);212 var obstructions = new API3.Map(gameState.sharedScript); 210 213 211 214 // wanted map. 212 var friendlyTiles = new Map(gameState.sharedScript);215 var friendlyTiles = new API3.Map(gameState.sharedScript); 213 216 214 217 for (var j = 0; j < friendlyTiles.length; ++j) 215 218 { … … 248 251 249 252 // we have the spot we want to board at. 250 253 this.boardingSpot = [x,z]; 251 debug ("Plan " + this.ID + " new boarding spot is " + this.boardingSpot);254 m.debug ("Plan " + this.ID + " new boarding spot is " + this.boardingSpot); 252 255 } 253 256 254 257 // if all at once we need to be full, else we just need enough escort ships. … … 262 265 263 266 this.garrisonShipID = -1; 264 267 265 debug ("Boarding");268 m.debug ("Boarding"); 266 269 this.state = "boarding"; 267 270 } 268 271 return true; … … 300 303 301 304 // check if we need to move our units and ships closer together 302 305 var stillMoving = false; 303 if ( SquareVectorDistance(this.ships.getCentrePosition(),this.boardingSpot) > 1600)306 if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.boardingSpot) > 1600) 304 307 { 305 308 this.ships.move(this.boardingSpot[0],this.boardingSpot[1]); 306 309 stillMoving = true; // wait till ships are in position 307 310 } 308 if ( SquareVectorDistance(this.units.getCentrePosition(),this.boardingSpot) > 1600)311 if (API3.SquareVectorDistance(this.units.getCentrePosition(),this.boardingSpot) > 1600) 309 312 { 310 313 this.units.move(this.boardingSpot[0],this.boardingSpot[1]); 311 314 stillMoving = true; // wait till units are in position … … 365 368 var passabilityMap = gameState.getMap(); 366 369 var territoryMap = gameState.ai.territoryMap; 367 370 var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction") | gameState.getPassabilityClassMask("building-shore"); 368 var obstructions = new Map(gameState.sharedScript);371 var obstructions = new API3.Map(gameState.sharedScript); 369 372 370 373 // wanted map. 371 var friendlyTiles = new Map(gameState.sharedScript);374 var friendlyTiles = new API3.Map(gameState.sharedScript); 372 375 373 376 var wantedIndex = -1; 374 377 … … 377 380 this.path.splice(0,2); 378 381 wantedIndex = this.path[0]; 379 382 } else { 380 debug ("too short at " +uneval(this.path));383 m.debug ("too short at " +uneval(this.path)); 381 384 return false; // Incomputable 382 385 } 383 386 … … 431 434 return false; 432 435 433 436 // check if we need to move ships 434 if ( SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400)437 if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) 435 438 { 436 439 this.ships.move(this.unboardingSpot[0],this.unboardingSpot[1]); 437 440 } else { … … 447 450 return false; 448 451 449 452 // check if we need to move ships 450 if ( SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400)453 if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) 451 454 { 452 455 this.ships.move(this.unboardingSpot[0],this.unboardingSpot[1]); 453 456 } else { … … 455 458 // TODO: improve on this. 456 459 if (this.path.length > 1) 457 460 { 458 debug ("plan " + this.ID + " going back for more");461 m.debug ("plan " + this.ID + " going back for more"); 459 462 // basically reset. 460 463 delete this.boardingSpot; 461 464 delete this.unboardingSpot; … … 463 466 this.releaseAllShips(); 464 467 return true; 465 468 } 466 debug ("plan " + this.ID + " is finished");469 m.m.debug ("plan " + this.ID + " is finished"); 467 470 return false; 468 471 } 469 472 } 470 473 471 474 return true; 472 475 } 476 477 return m; 478 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/aegis.js
1 2 var AEGIS = (function() { 3 var m = {}; 4 1 5 // "local" global variables for stuffs that will need a unique ID 2 6 // Note that since order of loading is alphabetic, this means this file must go before any other file using them. 3 var uniqueIDBOPlans = 0; // training/building/research plans 4 var uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map 5 var uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. 7 m.playerGlobals = []; 8 m.DebugEnabled = false; 6 9 7 function AegisBot(settings) {8 BaseAI.call(this, settings);10 m.AegisBot = function AegisBot(settings) { 11 API3.BaseAI.call(this, settings); 9 12 10 Config.updateDifficulty(settings.difficulty); 13 this.Config = new m.Config(); 14 15 this.Config.updateDifficulty(settings.difficulty); 11 16 12 17 this.turn = 0; 13 18 14 19 this.playedTurn = 0; 15 16 this.priorities = Config.priorities;20 21 this.priorities = this.Config.priorities; 17 22 18 23 // this.queues can only be modified by the queue manager or things will go awry. 19 24 this.queues = {}; 20 25 for (i in this.priorities) 21 this.queues[i] = new Queue();26 this.queues[i] = new m.Queue(); 22 27 23 this.queueManager = new QueueManager(this.queues, this.priorities);28 this.queueManager = new m.QueueManager(this.Config, this.queues, this.priorities); 24 29 25 this.HQ = new HQ();30 this.HQ = new m.HQ(this.Config); 26 31 27 32 this.firstTime = true; 28 33 … … 30 35 31 36 this.defcon = 5; 32 37 this.defconChangeTime = -10000000; 33 } 38 }; 34 39 35 AegisBot.prototype = newBaseAI();40 m.AegisBot.prototype = new API3.BaseAI(); 36 41 37 AegisBot.prototype.CustomInit = function(gameState, sharedScript) { 38 42 m.AegisBot.prototype.CustomInit = function(gameState, sharedScript) { 43 44 m.playerGlobals[PlayerID] = {}; 45 m.playerGlobals[PlayerID].uniqueIDBOPlans = 0; // training/building/research plans 46 m.playerGlobals[PlayerID].uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map 47 m.playerGlobals[PlayerID].uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. 48 39 49 this.HQ.init(gameState,sharedScript.events,this.queues); 40 debug ("Initialized with the difficulty " +Config.difficulty);50 m.debug ("Initialized with the difficulty " + this.Config.difficulty); 41 51 42 var ents = gameState.getEntities().filter( Filters.byOwner(PlayerID));52 var ents = gameState.getEntities().filter(API3.Filters.byOwner(this.player)); 43 53 var myKeyEntities = ents.filter(function(ent) { 44 54 return ent.hasClass("CivCentre"); 45 55 }); 46 56 47 57 if (myKeyEntities.length == 0){ 48 myKeyEntities = gameState.getEntities().filter( Filters.byOwner(PlayerID));58 myKeyEntities = gameState.getEntities().filter(API3.Filters.byOwner(this.player)); 49 59 } 50 60 51 var filter = Filters.byClass("CivCentre");52 var enemyKeyEntities = gameState.getEntities().filter( Filters.not(Filters.byOwner(PlayerID))).filter(filter);61 var filter = API3.Filters.byClass("CivCentre"); 62 var enemyKeyEntities = gameState.getEntities().filter(API3.Filters.not(API3.Filters.byOwner(this.player))).filter(filter); 53 63 54 64 if (enemyKeyEntities.length == 0){ 55 enemyKeyEntities = gameState.getEntities().filter( Filters.not(Filters.byOwner(PlayerID)));65 enemyKeyEntities = gameState.getEntities().filter(API3.Filters.not(API3.Filters.byOwner(this.player))); 56 66 } 57 67 58 68 this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position()); 59 69 60 this.pathFinder = new aStarPath(gameState, false, true);70 this.pathFinder = new API3.aStarPath(gameState, false, true); 61 71 this.pathsToMe = []; 62 72 this.pathInfo = { "angle" : 0, "needboat" : true, "mkeyPos" : myKeyEntities.toEntityArray()[0].position(), "ekeyPos" : enemyKeyEntities.toEntityArray()[0].position() }; 63 73 … … 65 75 var pos = [this.pathInfo.mkeyPos[0] + 150*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 150*Math.sin(this.pathInfo.angle)]; 66 76 var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 2, 2);// uncomment for debug:*/, 300000, gameState); 67 77 68 //Engine.DumpImage("initialPath" + PlayerID+ ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255);78 //Engine.DumpImage("initialPath" + this.player + ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255); 69 79 70 80 if (path !== undefined && path[1] !== undefined && path[1] == false) { 71 81 // path is viable and doesn't require boating. … … 80 90 this.chooseRandomStrategy(); 81 91 } 82 92 83 AegisBot.prototype.OnUpdate = function(sharedScript) { 93 m.AegisBot.prototype.OnUpdate = function(sharedScript) { 94 84 95 if (this.gameFinished){ 85 96 return; 86 97 } … … 120 131 { 121 132 if (this.pathInfo.needboat) 122 133 { 123 debug ("Assuming this is a water map");134 m.debug ("Assuming this is a water map"); 124 135 this.HQ.waterMap = true; 125 136 } 126 137 delete this.pathFinder; … … 132 143 var cityPhase = this.gameState.cityPhase(); 133 144 // try going up phases. 134 145 // TODO: softcode this. 135 if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > ( Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40146 if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40 136 147 && this.gameState.findResearchers(townPhase,true).length != 0 && this.queues.majorTech.length() === 0 137 && this.gameState.getOwnEntities().filter( Filters.byClass("Village")).length > 5)148 && this.gameState.getOwnEntities().filter(API3.Filters.byClass("Village")).length > 5) 138 149 { 139 150 this.queueManager.pauseQueue("villager", true); 140 151 this.queueManager.pauseQueue("citizenSoldier", true); 141 152 this.queueManager.pauseQueue("house", true); 142 this.queues.majorTech.addItem(new ResearchPlan(this.gameState, townPhase,0,-1,true)); // we rush the town phase.143 debug ("Trying to reach town phase");153 this.queues.majorTech.addItem(new m.ResearchPlan(this.gameState, townPhase,0,-1,true)); // we rush the town phase. 154 m.debug ("Trying to reach town phase"); 144 155 } 145 else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > ( Config.Economy.cityPhase*1000)156 else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.cityPhase*1000) 146 157 && this.gameState.getOwnEntitiesByRole("worker").length > 85 147 158 && this.gameState.findResearchers(cityPhase, true).length != 0 && this.queues.majorTech.length() === 0) { 148 debug ("Trying to reach city phase");149 this.queues.majorTech.addItem(new ResearchPlan(this.gameState, cityPhase));159 m.debug ("Trying to reach city phase"); 160 this.queues.majorTech.addItem(new m.ResearchPlan(this.gameState, cityPhase)); 150 161 } 151 162 // defcon cooldown 152 163 if (this.defcon < 5 && this.gameState.timeSinceDefconChange() > 20000) 153 164 { 154 165 this.defcon++; 155 debug ("updefconing to " +this.defcon);166 m.debug ("updefconing to " +this.defcon); 156 167 if (this.defcon >= 4 && this.HQ.hasGarrisonedFemales) 157 168 this.HQ.ungarrisonAll(this.gameState); 158 169 } … … 210 221 this.turn++; 211 222 }; 212 223 213 AegisBot.prototype.chooseRandomStrategy = function()224 m.AegisBot.prototype.chooseRandomStrategy = function() 214 225 { 215 226 // deactivated for now. 216 227 this.strategy = "normal"; 217 228 // rarely and if we can assume it's not a water map. 218 if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && Config.difficulty == 2)229 if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && this.Config.difficulty == 2) 219 230 { 220 231 this.strategy = "rush"; 221 232 // going to rush. 222 233 this.HQ.targetNumWorkers = 0; 223 Config.Economy.townPhase = 480;224 Config.Economy.cityPhase = 900;225 Config.Economy.farmsteadStartTime = 600;226 Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2.234 this.Config.Economy.townPhase = 480; 235 this.Config.Economy.cityPhase = 900; 236 this.Config.Economy.farmsteadStartTime = 600; 237 this.Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2. 227 238 } 228 239 }; 229 240 230 /* AegisBot.prototype.Deserialize = function(data, sharedScript)241 /*m.AegisBot.prototype.Deserialize = function(data, sharedScript) 231 242 { 232 243 }; 233 244 … … 237 248 return {}; 238 249 };*/ 239 250 240 function debug(output){241 if ( Config.debug){251 m.debug = function(output){ 252 if (m.DebugEnabled){ 242 253 if (typeof output === "string"){ 243 254 warn(output); 244 255 }else{ 245 256 warn(uneval(output)); 246 257 } 247 258 } 248 } 259 }; 249 260 250 function copyPrototype(descendant, parent) {261 m.copyPrototype = function(descendant, parent) { 251 262 var sConstructor = parent.toString(); 252 263 var aMatch = sConstructor.match( /\s*function (.*)\(/ ); 253 264 if ( aMatch != null ) { descendant.prototype[aMatch[1]] = parent; } 254 265 for (var m in parent.prototype) { 255 266 descendant.prototype[m] = parent.prototype[m]; 256 267 } 257 } 268 }; 269 270 return m; 271 }()); -
binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js
1 var ConstructionPlan = function(gameState, type, metadata, startTime, expectedTime, position) { 1 var AEGIS = function(m) 2 { 3 4 m.ConstructionPlan = function(gameState, type, metadata, startTime, expectedTime, position) { 2 5 this.type = gameState.applyCiv(type); 3 6 this.position = position; 4 7 5 8 this.metadata = metadata; 6 9 7 this.ID = uniqueIDBOPlans++;10 this.ID = m.playerGlobals[PlayerID].uniqueIDBOPlans++; 8 11 9 12 this.template = gameState.getTemplate(this.type); 10 13 if (!this.template) { … … 12 15 } 13 16 14 17 this.category = "building"; 15 this.cost = new Resources(this.template.cost());18 this.cost = new API3.Resources(this.template.cost()); 16 19 this.number = 1; // The number of buildings to build 17 20 18 21 if (!startTime) … … 28 31 }; 29 32 30 33 // return true if we willstart amassing resource for this plan 31 ConstructionPlan.prototype.isGo = function(gameState) {34 m.ConstructionPlan.prototype.isGo = function(gameState) { 32 35 return (gameState.getTimeElapsed() > this.startTime); 33 36 }; 34 37 35 38 // checks other than resource ones. 36 39 // TODO: change this. 37 ConstructionPlan.prototype.canStart = function(gameState) {40 m.ConstructionPlan.prototype.canStart = function(gameState) { 38 41 if (gameState.buildingsBuilt > 0) 39 42 return false; 40 43 … … 51 54 return (builders.length != 0); 52 55 }; 53 56 54 ConstructionPlan.prototype.start = function(gameState) {57 m.ConstructionPlan.prototype.start = function(gameState) { 55 58 56 59 var builders = gameState.findBuilders(this.type).toEntityArray(); 57 60 … … 63 66 if (!pos){ 64 67 if (this.template.hasClass("Naval")) 65 68 gameState.ai.HQ.dockFailed = true; 66 debug("No room to place " + this.type);69 m.debug("No room to place " + this.type); 67 70 return; 68 71 } 69 72 if (this.template.hasClass("Naval")) 70 debug (pos);73 m.debug (pos); 71 74 gameState.buildingsBuilt++; 72 75 73 76 if (gameState.getTemplate(this.type).buildCategory() === "Dock") … … 80 83 builders[0].construct(this.type, pos.x, pos.z, pos.angle, this.metadata); 81 84 }; 82 85 83 ConstructionPlan.prototype.getCost = function() {84 var costs = new Resources();86 m.ConstructionPlan.prototype.getCost = function() { 87 var costs = new API3.Resources(); 85 88 costs.add(this.cost); 86 89 return costs; 87 90 }; 88 91 89 ConstructionPlan.prototype.findGoodPosition = function(gameState) {92 m.ConstructionPlan.prototype.findGoodPosition = function(gameState) { 90 93 var template = gameState.getTemplate(this.type); 91 94 92 95 var cellSize = gameState.cellSize; // size of each tile 93 96 94 97 // First, find all tiles that are far enough away from obstructions: 95 98 96 var obstructionMap = Map.createObstructionMap(gameState,0, template);99 var obstructionMap = m.createObstructionMap(gameState,0, template); 97 100 98 101 //obstructionMap.dumpIm(template.buildCategory() + "_obstructions_pre.png"); 99 102 … … 104 107 105 108 // Compute each tile's closeness to friendly structures: 106 109 107 var friendlyTiles = new Map(gameState.sharedScript);110 var friendlyTiles = new API3.Map(gameState.sharedScript); 108 111 109 112 var alreadyHasHouses = false; 110 113 … … 229 232 "angle" : angle 230 233 }; 231 234 }; 235 236 237 return m; 238 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/entity-extend.js
1 var AEGIS = function(m) 2 { 3 1 4 // returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too. 2 function getMaxStrength(ent, againstClass)5 m.getMaxStrength = function(ent, againstClass) 3 6 { 4 7 var strength = 0.0; 5 8 var attackTypes = ent.attackTypes(); … … 61 64 } 62 65 return strength * hp; 63 66 }; 67 68 return m; 69 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/config.js
1 // Baseconfig is the highest difficulty. 2 var baseConfig = { 3 "Military" : { 1 var AEGIS = function(m) 2 { 3 4 m.Config = function() { 5 this.difficulty = 2; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. 6 // overriden by the GUI 7 8 this.Military = { 4 9 "fortressLapseTime" : 540, // Time to wait between building 2 fortresses 5 10 "defenceBuildingTime" : 600, // Time to wait before building towers or fortresses 6 11 "attackPlansStartTime" : 0, // time to wait before attacking. Start as soon as possible (first barracks) … … 8 13 "popForBarracks1" : 15, 9 14 "popForBarracks2" : 95, 10 15 "timeForBlacksmith" : 900, 11 } ,12 "Economy" :{16 }; 17 this.Economy = { 13 18 "townPhase" : 180, // time to start trying to reach town phase (might be a while after. Still need the requirements + ress ) 14 19 "cityPhase" : 840, // time to start trying to reach city phase 15 20 "popForMarket" : 80, … … 19 24 "targetNumBuilders" : 1.5, // Base number of builders per foundation. 20 25 "femaleRatio" : 0.4, // percent of females among the workforce. 21 26 "initialFields" : 2 22 } ,27 }; 23 28 24 29 // Note: attack settings are set directly in attack_plan.js 25 30 26 31 // defence 27 "Defence" : { 32 this.Defence = 33 { 28 34 "defenceRatio" : 5, // see defence.js for more info. 29 35 "armyCompactSize" : 700, // squared. Half-diameter of an army. 30 36 "armyBreakawaySize" : 900 // squared. 31 } ,37 }; 32 38 33 39 // military 34 "buildings" : { 40 this.buildings = 41 { 35 42 "moderate" : { 36 43 "default" : [ "structures/{civ}_barracks" ] 37 44 }, … … 51 58 "default" : [ "structures/{civ}_fortress" ], 52 59 "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ] 53 60 } 54 } ,61 }; 55 62 56 63 // qbot 57 "priorities" : { // Note these are dynamic, you are only setting the initial values 64 this.priorities = 65 { // Note these are dynamic, you are only setting the initial values 58 66 "house" : 350, 59 67 "villager" : 40, 60 68 "citizenSoldier" : 60, … … 67 75 "majorTech" : 700, 68 76 "minorTech" : 50, 69 77 "civilCentre" : 400 70 }, 71 "difficulty" : 2, // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. 72 "debug" : false 78 }; 73 79 }; 74 80 75 var Config = { 76 "debug": false, 77 "difficulty" : 2, // overriden by the GUI 78 updateDifficulty: function(difficulty) 81 //Config.prototype = new BaseConfig(); 82 83 m.Config.prototype.updateDifficulty = function(difficulty) 84 { 85 this.difficulty = difficulty; 86 // changing settings based on difficulty. 87 if (this.difficulty === 1) 79 88 { 80 Config.difficulty = difficulty; 81 // changing settings based on difficulty. 82 if (Config.difficulty === 1) 83 { 84 Config.Military.defenceBuildingTime = 1200; 85 Config.Military.attackPlansStartTime = 960; 86 Config.Military.popForBarracks1 = 35; 87 Config.Military.popForBarracks2 = 150; // shouldn't reach it 88 Config.Military.popForBlacksmith = 150; // shouldn't reach it 89 this.Military.defenceBuildingTime = 1200; 90 this.Military.attackPlansStartTime = 960; 91 this.Military.popForBarracks1 = 35; 92 this.Military.popForBarracks2 = 150; // shouldn't reach it 93 this.Military.popForBlacksmith = 150; // shouldn't reach it 89 94 90 Config.Economy.cityPhase = 1800;91 Config.Economy.popForMarket = 80;92 Config.Economy.techStartTime = 600;93 Config.Economy.femaleRatio = 0.6;94 Config.Economy.initialFields = 1;95 96 97 else if (Config.difficulty === 0)98 99 Config.Military.defenceBuildingTime = 450;100 Config.Military.attackPlansStartTime = 9600000; // never101 Config.Military.popForBarracks1 = 60;102 Config.Military.popForBarracks2 = 150; // shouldn't reach it103 Config.Military.popForBlacksmith = 150; // shouldn't reach it95 this.Economy.cityPhase = 1800; 96 this.Economy.popForMarket = 80; 97 this.Economy.techStartTime = 600; 98 this.Economy.femaleRatio = 0.6; 99 this.Economy.initialFields = 1; 100 // Config.Economy.targetNumWorkers will be set by AI scripts. 101 } 102 else if (this.difficulty === 0) 103 { 104 this.Military.defenceBuildingTime = 450; 105 this.Military.attackPlansStartTime = 9600000; // never 106 this.Military.popForBarracks1 = 60; 107 this.Military.popForBarracks2 = 150; // shouldn't reach it 108 this.Military.popForBlacksmith = 150; // shouldn't reach it 104 109 105 Config.Economy.cityPhase = 240000; 106 Config.Economy.popForMarket = 200; 107 Config.Economy.techStartTime = 1800; 108 Config.Economy.femaleRatio = 0.2; 109 Config.Economy.initialFields = 1; 110 // Config.Economy.targetNumWorkers will be set by AI scripts. 111 } 110 this.Economy.cityPhase = 240000; 111 this.Economy.popForMarket = 200; 112 this.Economy.techStartTime = 1800; 113 this.Economy.femaleRatio = 0.2; 114 this.Economy.initialFields = 1; 115 // Config.Economy.targetNumWorkers will be set by AI scripts. 112 116 } 113 117 }; 114 118 115 Config.__proto__ = baseConfig; 119 return m; 120 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/queueplan-training.js
1 var TrainingPlan = function(gameState, type, metadata, number, startTime, expectedTime, maxMerge) { 1 var AEGIS = function(m) 2 { 3 4 m.TrainingPlan = function(gameState, type, metadata, number, startTime, expectedTime, maxMerge) { 2 5 this.type = gameState.applyCiv(type); 3 6 this.metadata = metadata; 4 7 5 this.ID = uniqueIDBOPlans++;8 this.ID = m.playerGlobals[PlayerID].uniqueIDBOPlans++; 6 9 7 10 this.template = gameState.getTemplate(this.type); 8 11 if (!this.template) 9 12 return false; 10 13 11 14 this.category = "unit"; 12 this.cost = new Resources(this.template.cost(), this.template._template.Cost.Population);15 this.cost = new API3.Resources(this.template.cost(), this.template._template.Cost.Population); 13 16 if (!number) 14 17 this.number = 1; 15 18 else … … 33 36 }; 34 37 35 38 // return true if we willstart amassing resource for this plan 36 TrainingPlan.prototype.isGo = function(gameState) {39 m.TrainingPlan.prototype.isGo = function(gameState) { 37 40 return (gameState.getTimeElapsed() > this.startTime); 38 41 }; 39 42 40 TrainingPlan.prototype.canStart = function(gameState) {43 m.TrainingPlan.prototype.canStart = function(gameState) { 41 44 if (this.invalidTemplate) 42 45 return false; 43 46 … … 48 51 return (trainers.length != 0); 49 52 }; 50 53 51 TrainingPlan.prototype.start = function(gameState) {54 m.TrainingPlan.prototype.start = function(gameState) { 52 55 //warn("Executing TrainingPlan " + uneval(this)); 53 56 var self = this; 54 57 var trainers = gameState.findTrainers(this.type).toEntityArray(); … … 72 75 } 73 76 }; 74 77 75 TrainingPlan.prototype.getCost = function(){76 var multCost = new Resources();78 m.TrainingPlan.prototype.getCost = function(){ 79 var multCost = new API3.Resources(); 77 80 multCost.add(this.cost); 78 81 multCost.multiply(this.number); 79 82 return multCost; 80 83 }; 81 84 82 TrainingPlan.prototype.addItem = function(amount){85 m.TrainingPlan.prototype.addItem = function(amount){ 83 86 if (amount === undefined) 84 87 amount = 1; 85 88 this.number += amount; 86 89 }; 90 91 92 return m; 93 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js
1 var AEGIS = function(m) 2 { 3 1 4 /* 2 5 * A class that keeps track of enemy buildings, units, and pretty much anything I can think of (still a LOT TODO here) 3 6 * Only watches one enemy, you'll need one per enemy. … … 4 7 * Note: pretty much unused in the current version. 5 8 */ 6 9 7 varenemyWatcher = function(gameState, playerToWatch) {10 m.enemyWatcher = function(gameState, playerToWatch) { 8 11 9 12 this.watched = playerToWatch; 10 13 11 14 // using global entity collections, shared by any AI that knows the name of this. 12 15 13 var filter = Filters.and(Filters.byClass("Structure"),Filters.byOwner(this.watched));16 var filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(this.watched)); 14 17 this.enemyBuildings = gameState.updatingGlobalCollection("player-" +this.watched + "-structures", filter); 15 18 16 filter = Filters.and(Filters.byClass("Unit"),Filters.byOwner(this.watched));19 filter = API3.Filters.and(API3.Filters.byClass("Unit"), API3.Filters.byOwner(this.watched)); 17 20 this.enemyUnits = gameState.updatingGlobalCollection("player-" +this.watched + "-units", filter); 18 21 19 filter = Filters.and(Filters.byClass("Worker"),Filters.byOwner(this.watched));22 filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched)); 20 23 this.enemyCivilians = gameState.updatingGlobalCollection("player-" +this.watched + "-civilians", filter); 21 24 22 filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]),Filters.byOwner(this.watched));25 filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched)); 23 26 this.enemySoldiers = gameState.updatingGlobalCollection("player-" +this.watched + "-soldiers", filter); 24 27 25 filter = Filters.and(Filters.byClass("Worker"),Filters.byOwner(this.watched));28 filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched)); 26 29 this.enemyCivilians = gameState.getEnemyEntities().filter(filter); 27 30 this.enemyCivilians.registerUpdates(); 28 31 29 filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]),Filters.byOwner(this.watched));32 filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched)); 30 33 this.enemySoldiers = gameState.getEnemyEntities().filter(filter); 31 34 this.enemySoldiers.registerUpdates(); 32 35 … … 40 43 this.dangerousArmies = []; 41 44 42 45 }; 43 enemyWatcher.prototype.getAllEnemySoldiers = function() {46 m.enemyWatcher.prototype.getAllEnemySoldiers = function() { 44 47 return this.enemySoldiers; 45 48 }; 46 enemyWatcher.prototype.getAllEnemyBuildings = function() {49 m.enemyWatcher.prototype.getAllEnemyBuildings = function() { 47 50 return this.enemyBuildings; 48 51 }; 49 52 50 enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, OneTime) {51 var filter = Filters.byClass(specialClass);53 m.enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, OneTime) { 54 var filter = API3.Filters.byClass(specialClass); 52 55 53 56 if (OneTime && gameState.getGEC("player-" +this.watched + "-structures-" +specialClass)) 54 57 return gameState.getGEC("player-" +this.watched + "-structures-" +specialClass); … … 57 60 58 61 return gameState.updatingGlobalCollection("player-" +this.watched + "-structures-" +specialClass, filter, gameState.getGEC("player-" +this.watched + "-structures")); 59 62 }; 60 enemyWatcher.prototype.getDangerousArmies = function() {63 m.enemyWatcher.prototype.getDangerousArmies = function() { 61 64 var toreturn = {}; 62 65 for (var i in this.dangerousArmies) 63 66 toreturn[this.dangerousArmies[i]] = this.armies[this.dangerousArmies[i]]; 64 67 return toreturn; 65 68 }; 66 enemyWatcher.prototype.getSafeArmies = function() {69 m.enemyWatcher.prototype.getSafeArmies = function() { 67 70 var toreturn = {}; 68 71 for (var i in this.armies) 69 72 if (this.dangerousArmies.indexOf(i) == -1) 70 73 toreturn[i] = this.armies[i]; 71 74 return toreturn; 72 75 }; 73 enemyWatcher.prototype.resetDangerousArmies = function() {76 m.enemyWatcher.prototype.resetDangerousArmies = function() { 74 77 this.dangerousArmies = []; 75 78 }; 76 enemyWatcher.prototype.setAsDangerous = function(armyID) {79 m.enemyWatcher.prototype.setAsDangerous = function(armyID) { 77 80 if (this.dangerousArmies.indexOf(armyID) === -1) 78 81 this.dangerousArmies.push(armyID); 79 82 }; 80 enemyWatcher.prototype.isDangerous = function(armyID) {83 m.enemyWatcher.prototype.isDangerous = function(armyID) { 81 84 if (this.dangerousArmies.indexOf(armyID) === -1) 82 85 return false; 83 86 return true; 84 87 }; 85 88 // returns [id, army] 86 enemyWatcher.prototype.getArmyFromMember = function(memberID) {89 m.enemyWatcher.prototype.getArmyFromMember = function(memberID) { 87 90 for (var i in this.armies) { 88 91 if (this.armies[i].toIdArray().indexOf(memberID) !== -1) 89 92 return [i,this.armies[i]]; 90 93 } 91 94 return undefined; 92 95 }; 93 enemyWatcher.prototype.isPartOfDangerousArmy = function(memberID) {96 m.enemyWatcher.prototype.isPartOfDangerousArmy = function(memberID) { 94 97 var armyID = this.getArmyFromMember(memberID)[0]; 95 98 if (this.isDangerous(armyID)) 96 99 return true; 97 100 return false; 98 101 }; 99 enemyWatcher.prototype.cleanDebug = function() {102 m.enemyWatcher.prototype.cleanDebug = function() { 100 103 for (var armyID in this.armies) { 101 104 var army = this.armies[armyID]; 102 debug ("Army " +armyID);103 debug (army.length +" members, centered around " +army.getCentrePosition());105 m.debug ("Army " +armyID); 106 m.debug (army.length +" members, centered around " +army.getCentrePosition()); 104 107 } 105 108 } 106 109 107 110 // this will monitor any unmonitored soldier. 108 enemyWatcher.prototype.detectArmies = function(gameState){111 m.enemyWatcher.prototype.detectArmies = function(gameState){ 109 112 //this.cleanDebug(); 110 113 111 114 var self = this; … … 121 124 var armyID = gameState.player + "" + self.totalNBofArmies; 122 125 self.totalNBofArmies++, 123 126 enemy.setMetadata(PlayerID, "EnemyWatcherArmy",armyID); 124 var filter = Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID);127 var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID); 125 128 var army = self.enemySoldiers.filter(filter); 126 129 self.armies[armyID] = army; 127 130 self.armies[armyID].registerUpdates(); … … 140 143 }; 141 144 // this will merge any two army who are too close together. The distance for "army" is fairly big. 142 145 // note: this doesn't actually merge two entity collections... It simply changes the unit metadatas, and will clear the empty entity collection 143 enemyWatcher.prototype.mergeArmies = function(){146 m.enemyWatcher.prototype.mergeArmies = function(){ 144 147 for (var army in this.armies) { 145 148 var firstArmy = this.armies[army]; 146 149 if (firstArmy.length !== 0) { … … 149 152 if (otherArmy !== army && this.armies[otherArmy].length !== 0) { 150 153 var secondArmy = this.armies[otherArmy]; 151 154 // we're not self merging, so we check if the two armies are close together 152 if ( inRange(firstAPos,secondArmy.getApproximatePosition(4), 4000 ) ) {155 if (m.inRange(firstAPos,secondArmy.getApproximatePosition(4), 4000 ) ) { 153 156 // okay so we merge the two together 154 157 155 158 // if the other one was dangerous and we weren't, we're now. … … 166 169 } 167 170 this.ScrapEmptyArmies(); 168 171 }; 169 enemyWatcher.prototype.ScrapEmptyArmies = function(){172 m.enemyWatcher.prototype.ScrapEmptyArmies = function(){ 170 173 var removelist = []; 171 174 for (var army in this.armies) { 172 175 if (this.armies[army].length === 0) { … … 181 184 } 182 185 }; 183 186 // splits any unit too far from the centerposition 184 enemyWatcher.prototype.splitArmies = function(gameState){187 m.enemyWatcher.prototype.splitArmies = function(gameState){ 185 188 var self = this; 186 189 187 var map = Map.createTerritoryMap(gameState);190 var map = m.createTerritoryMap(gameState); 188 191 189 192 for (var armyID in this.armies) { 190 193 var army = this.armies[armyID]; … … 197 200 if (enemy.position() === undefined) 198 201 return; 199 202 200 if (! inRange(enemy.position(),centre, 3500) ) {203 if (!m.inRange(enemy.position(),centre, 3500) ) { 201 204 var newArmyID = gameState.player + "" + self.totalNBofArmies; 202 205 if (self.dangerousArmies.indexOf(armyID) !== -1) 203 206 self.dangerousArmies.push(newArmyID); 204 207 205 208 self.totalNBofArmies++, 206 209 enemy.setMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); 207 var filter = Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID);210 var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); 208 211 var newArmy = self.enemySoldiers.filter(filter); 209 212 self.armies[newArmyID] = newArmy; 210 213 self.armies[newArmyID].registerUpdates(); … … 213 216 }); 214 217 } 215 218 }; 219 220 221 return m; 222 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/entitycollection-extend.js
1 function EntityCollectionFromIds(gameState, idList){ 1 var AEGIS = function(m) 2 { 3 4 m.EntityCollectionFromIds = function(gameState, idList){ 2 5 var ents = {}; 3 6 for (var i in idList){ 4 7 var id = idList[i]; … … 6 9 ents[id] = gameState.entities._entities[id]; 7 10 } 8 11 } 9 return new EntityCollection(gameState.sharedScript, ents);12 return new API3.EntityCollection(gameState.sharedScript, ents); 10 13 } 14 15 return m; 16 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/timer.js
1 var AEGIS = function(m) 2 { 3 1 4 //The Timer class // The instance of this class is created in the qBot object under the name 'timer' 2 5 //The methods that are available to call from this instance are: 3 6 //timer.setTimer : Creates a new timer with the given interval (miliseconds). … … 11 14 12 15 13 16 //-EmjeR-// Timer class // 14 varTimer = function() {17 m.Timer = function() { 15 18 ///Private array. 16 19 var alarmList = []; 17 20 … … 94 97 95 98 96 99 //-EmjeR-// Alarm class // 97 function alarm(gameState, id, interval, delay, repeat) {100 m.alarm = function(gameState, id, interval, delay, repeat) { 98 101 this.id = id; 99 102 this.interval = interval; 100 103 this.delay = delay; … … 104 107 this.active = true; 105 108 this.counter = 0; 106 109 }; 110 111 return m; 112 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/template-manager.js
1 var AEGIS = function(m) 2 { 3 1 4 /* 2 5 * Used to know which templates I have, which templates I know I can train, things like that. 3 6 * Mostly unused. … … 3 6 */ 4 7 5 varTemplateManager = function(gameState) {8 m.TemplateManager = function(gameState) { 6 9 var self = this; 7 10 … … 23 26 this.getTemplateCounters(gameState); 24 27 25 28 }; 26 TemplateManager.prototype.AcknowledgeTemplates = function(gameState)29 m.TemplateManager.prototype.AcknowledgeTemplates = function(gameState) 27 30 { 28 31 var self = this; 29 32 var myEntities = gameState.getOwnEntities(); … … 39 42 40 43 }); 41 44 } 42 TemplateManager.prototype.getBuildableSubtemplates = function(gameState)45 m.TemplateManager.prototype.getBuildableSubtemplates = function(gameState) 43 46 { 44 47 for each (var templateName in this.knownTemplatesList) { 45 48 var template = gameState.getTemplate(templateName); … … 59 62 } 60 63 } 61 64 } 62 TemplateManager.prototype.getTrainableSubtemplates = function(gameState)65 m.TemplateManager.prototype.getTrainableSubtemplates = function(gameState) 63 66 { 64 67 for each (var templateName in this.knownTemplatesList) { 65 68 var template = gameState.getTemplate(templateName); … … 79 82 } 80 83 } 81 84 } 82 TemplateManager.prototype.getTemplateCounters = function(gameState)85 m.TemplateManager.prototype.getTemplateCounters = function(gameState) 83 86 { 84 87 for (var i in this.unitTemplates) 85 88 { … … 89 92 } 90 93 } 91 94 // features auto-caching 92 TemplateManager.prototype.getCountersToClasses = function(gameState,classes,templateName)95 m.TemplateManager.prototype.getCountersToClasses = function(gameState,classes,templateName) 93 96 { 94 97 if (templateName !== undefined && this.templateCounteredBy[templateName]) 95 98 return this.templateCounteredBy[templateName]; … … 114 117 return templates; 115 118 } 116 119 120 121 return m; 122 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/queue.js
1 var AEGIS = function(m) 2 { 3 1 4 /* 2 5 * Holds a list of wanted items to train or construct 3 6 */ … … 2 5 3 varQueue = function() {6 m.Queue = function() { 4 7 this.queue = []; 5 8 this.paused = false; 6 9 }; 7 10 8 Queue.prototype.empty = function() {11 m.Queue.prototype.empty = function() { 9 12 this.queue = []; 10 13 }; 11 14 12 Queue.prototype.addItem = function(plan) {15 m.Queue.prototype.addItem = function(plan) { 13 16 for (var i in this.queue) … … 23 26 this.queue.push(plan); 24 27 }; 25 28 26 Queue.prototype.getNext = function() {29 m.Queue.prototype.getNext = function() { 27 30 if (this.queue.length > 0) { 28 31 return this.queue[0]; 29 32 } else { … … 31 34 } 32 35 }; 33 36 34 Queue.prototype.startNext = function(gameState) {37 m.Queue.prototype.startNext = function(gameState) { 35 38 if (this.queue.length > 0) { 36 39 this.queue.shift().start(gameState); 37 40 return true; … … 42 45 43 46 // returns the maximal account we'll accept for this queue. 44 47 // Currently 100% of the cost of the first element and 80% of that of the second 45 Queue.prototype.maxAccountWanted = function(gameState) {46 var cost = new Resources();48 m.Queue.prototype.maxAccountWanted = function(gameState) { 49 var cost = new API3.Resources(); 47 50 if (this.queue.length > 0 && this.queue[0].isGo(gameState)) 48 51 cost.add(this.queue[0].getCost()); 49 52 if (this.queue.length > 1 && this.queue[1].isGo(gameState)) … … 55 58 return cost; 56 59 }; 57 60 58 Queue.prototype.queueCost = function(){59 var cost = new Resources();61 m.Queue.prototype.queueCost = function(){ 62 var cost = new API3.Resources(); 60 63 for (var key in this.queue){ 61 64 cost.add(this.queue[key].getCost()); 62 65 } 63 66 return cost; 64 67 }; 65 68 66 Queue.prototype.length = function() {69 m.Queue.prototype.length = function() { 67 70 return this.queue.length; 68 71 }; 69 72 70 Queue.prototype.countQueuedUnits = function(){73 m.Queue.prototype.countQueuedUnits = function(){ 71 74 var count = 0; 72 75 for (var i in this.queue){ 73 76 count += this.queue[i].number; … … 75 78 return count; 76 79 }; 77 80 78 Queue.prototype.countQueuedUnitsWithClass = function(classe){81 m.Queue.prototype.countQueuedUnitsWithClass = function(classe){ 79 82 var count = 0; 80 83 for (var i in this.queue){ 81 84 if (this.queue[i].template && this.queue[i].template.hasClass(classe)) … … 83 86 } 84 87 return count; 85 88 }; 86 Queue.prototype.countQueuedUnitsWithMetadata = function(data,value){89 m.Queue.prototype.countQueuedUnitsWithMetadata = function(data,value){ 87 90 var count = 0; 88 91 for (var i in this.queue){ 89 92 if (this.queue[i].metadata[data] && this.queue[i].metadata[data] == value) … … 92 95 return count; 93 96 }; 94 97 95 Queue.prototype.countAllByType = function(t){98 m.Queue.prototype.countAllByType = function(t){ 96 99 var count = 0; 97 100 98 101 for (var i = 0; i < this.queue.length; i++){ … … 102 105 } 103 106 return count; 104 107 }; 108 109 return m; 110 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/headquarters.js
1 var AEGIS = function(m) 2 { 1 3 /* Headquarters 2 4 * Deal with high level logic for the AI. Most of the interesting stuff gets done here. 3 5 * Some tasks: … … 12 14 -picking new CC locations. 13 15 */ 14 16 15 var HQ = function() { 16 this.targetNumBuilders = Config.Economy.targetNumBuilders; // number of workers we want building stuff 17 m.HQ = function(Config) { 17 18 18 this. dockStartTime = Config.Economy.dockStartTime * 1000;19 this.t echStartTime = Config.Economy.techStartTime * 1000;19 this.Config = Config; 20 this.targetNumBuilders = this.Config.Economy.targetNumBuilders; // number of workers we want building stuff 20 21 22 this.dockStartTime = this.Config.Economy.dockStartTime * 1000; 23 this.techStartTime = this.Config.Economy.techStartTime * 1000; 24 21 25 this.dockFailed = false; // sanity check 22 26 this.waterMap = false; // set by the aegis.js file. 23 27 … … 27 31 this.baseManagers = {}; 28 32 29 33 // this means we'll have about a big third of women, and thus we can maximize resource gathering rates. 30 this.femaleRatio = Config.Economy.femaleRatio;34 this.femaleRatio = this.Config.Economy.femaleRatio; 31 35 32 36 this.fortressStartTime = 0; 33 this.fortressLapseTime = Config.Military.fortressLapseTime * 1000;34 this.defenceBuildingTime = Config.Military.defenceBuildingTime * 1000;35 this.attackPlansStartTime = Config.Military.attackPlansStartTime * 1000;36 this.defenceManager = new Defence();37 this.fortressLapseTime = this.Config.Military.fortressLapseTime * 1000; 38 this.defenceBuildingTime = this.Config.Military.defenceBuildingTime * 1000; 39 this.attackPlansStartTime = this.Config.Military.attackPlansStartTime * 1000; 40 this.defenceManager = new m.Defence(this.Config); 37 41 38 this.navalManager = new NavalManager();42 this.navalManager = new m.NavalManager(); 39 43 40 44 this.TotalAttackNumber = 0; 41 45 this.upcomingAttacks = { "CityAttack" : [] }; … … 43 47 }; 44 48 45 49 // More initialisation for stuff that needs the gameState 46 HQ.prototype.init = function(gameState, events, queues){50 m.HQ.prototype.init = function(gameState, events, queues){ 47 51 // initialize base map. Each pixel is a base ID, or 0 if none 48 this.basesMap = new Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length));52 this.basesMap = new API3.Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length)); 49 53 this.basesMap.setMaxVal(255); 50 54 51 if ( Config.Economy.targetNumWorkers)52 this.targetNumWorkers = Config.Economy.targetNumWorkers;55 if (this.Config.Economy.targetNumWorkers) 56 this.targetNumWorkers = this.Config.Economy.targetNumWorkers; 53 57 else if (this.targetNumWorkers === undefined) 54 this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+( Config.difficulty)*0.125,0.3))), 1);58 this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+(this.Config.difficulty)*0.125,0.3))), 1); 55 59 56 60 57 61 // Let's get our initial situation here. 58 62 // TODO: improve on this. 59 63 // TODO: aknowledge bases, assign workers already. 60 var ents = gameState.getEntities().filter( Filters.byOwner(PlayerID));64 var ents = gameState.getEntities().filter(API3.Filters.byOwner(PlayerID)); 61 65 62 66 var workersNB = 0; 63 67 var hasScout = false; 64 68 var treasureAmount = { 'food': 0, 'wood': 0, 'stone': 0, 'metal': 0 }; 65 69 var hasCC = false; 66 70 67 if (ents.filter( Filters.byClass("CivCentre")).length > 0)71 if (ents.filter(API3.Filters.byClass("CivCentre")).length > 0) 68 72 hasCC = true; 69 workersNB = ents.filter( Filters.byClass("Worker")).length;70 if (ents.filter( Filters.byClass("Cavalry")).length > 0)73 workersNB = ents.filter(API3.Filters.byClass("Worker")).length; 74 if (ents.filter(API3.Filters.byClass("Cavalry")).length > 0) 71 75 hasScout = true; 72 76 73 77 // tODO: take multiple CCs into account. 74 78 if (hasCC) 75 79 { 76 var CC = ents.filter( Filters.byClass("CivCentre")).toEntityArray()[0];80 var CC = ents.filter(API3.Filters.byClass("CivCentre")).toEntityArray()[0]; 77 81 for (i in treasureAmount) 78 82 gameState.getResourceSupplies(i).forEach( function (ent) { 79 if (ent.resourceSupplyType().generic === "treasure" && SquareVectorDistance(ent.position(), CC.position()) < 5000)83 if (ent.resourceSupplyType().generic === "treasure" && API3.SquareVectorDistance(ent.position(), CC.position()) < 5000) 80 84 treasureAmount[i] += ent.resourceSupplyMax(); 81 85 }); 82 this.baseManagers[1] = new BaseManager();86 this.baseManagers[1] = new m.BaseManager(this.Config); 83 87 this.baseManagers[1].init(gameState, events); 84 88 this.baseManagers[1].setAnchor(CC); 85 89 this.baseManagers[1].initTerritory(this, gameState); 86 90 this.baseManagers[1].initGatheringFunctions(this, gameState); 87 91 88 if ( Config.debug)92 if (m.DebugEnabled) 89 93 this.basesMap.dumpIm("basesMap.png"); 90 94 var self = this; 91 95 … … 105 109 var pos = this.baseManagers[1].findBestDropsiteLocation(gameState, "wood"); 106 110 if (pos) 107 111 { 108 queues.dropsites.addItem(new ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : 1 }, 0, -1, pos));109 queues.minorTech.addItem(new ResearchPlan(gameState, "gather_capacity_wheelbarrow"));112 queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse",{ "base" : 1 }, 0, -1, pos)); 113 queues.minorTech.addItem(new m.ResearchPlan(gameState, "gather_capacity_wheelbarrow")); 110 114 } 111 115 } 112 116 } 113 117 114 var map = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map);115 if ( Config.debug)118 var map = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map); 119 if (m.DebugEnabled) 116 120 map.dumpIm("map_CC_Wood.png"); 117 121 118 122 //this.reassignIdleWorkers(gameState); … … 125 129 126 130 // load units and buildings from the config files 127 131 128 if (civ in Config.buildings.moderate){129 this.bModerate = Config.buildings.moderate[civ];132 if (civ in this.Config.buildings.moderate){ 133 this.bModerate = this.Config.buildings.moderate[civ]; 130 134 }else{ 131 this.bModerate = Config.buildings.moderate['default'];135 this.bModerate = this.Config.buildings.moderate['default']; 132 136 } 133 137 134 if (civ in Config.buildings.advanced){135 this.bAdvanced = Config.buildings.advanced[civ];138 if (civ in this.Config.buildings.advanced){ 139 this.bAdvanced = this.Config.buildings.advanced[civ]; 136 140 }else{ 137 this.bAdvanced = Config.buildings.advanced['default'];141 this.bAdvanced = this.Config.buildings.advanced['default']; 138 142 } 139 143 140 if (civ in Config.buildings.fort){141 this.bFort = Config.buildings.fort[civ];144 if (civ in this.Config.buildings.fort){ 145 this.bFort = this.Config.buildings.fort[civ]; 142 146 }else{ 143 this.bFort = Config.buildings.fort['default'];147 this.bFort = this.Config.buildings.fort['default']; 144 148 } 145 149 146 150 for (var i in this.bAdvanced){ … … 156 160 } 157 161 158 162 var enemies = gameState.getEnemyEntities(); 159 var filter = Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]);163 var filter = API3.Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]); 160 164 this.enemySoldiers = enemies.filter(filter); // TODO: cope with diplomacy changes 161 165 this.enemySoldiers.registerUpdates(); 162 166 … … 167 171 this.ennWatcherIndex = []; 168 172 for (var i = 1; i <= 8; i++) 169 173 if (PlayerID != i && gameState.isPlayerEnemy(i)) { 170 this.enemyWatchers[i] = new enemyWatcher(gameState, i);174 this.enemyWatchers[i] = new m.enemyWatcher(gameState, i); 171 175 this.ennWatcherIndex.push(i); 172 176 this.defenceManager.enemyArmy[i] = []; 173 177 } 174 178 }; 175 179 176 HQ.prototype.checkEvents = function (gameState, events, queues) {180 m.HQ.prototype.checkEvents = function (gameState, events, queues) { 177 181 for (i in events) 178 182 { 179 183 if (events[i].type == "Destroy") … … 193 197 if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1) 194 198 { 195 199 // Okay so let's try to create a new base around this. 196 var bID = uniqueIDBases;197 this.baseManagers[bID] = new BaseManager();200 var bID = m.playerGlobals[PlayerID].uniqueIDBases; 201 this.baseManagers[bID] = new m.BaseManager(this.Config); 198 202 this.baseManagers[bID].init(gameState, events, true); 199 203 this.baseManagers[bID].setAnchor(ent); 200 204 this.baseManagers[bID].initTerritory(this, gameState); … … 243 247 // TODO: This should probably be changed to favor a more mixed approach for better defense. 244 248 // (or even to adapt based on estimated enemy strategy). 245 249 // TODO: this should probably set which base it wants them in. 246 HQ.prototype.trainMoreWorkers = function(gameState, queues) {250 m.HQ.prototype.trainMoreWorkers = function(gameState, queues) { 247 251 // Count the workers in the world and in progress 248 252 var numFemales = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("units/{civ}_support_female_citizen")); 249 253 numFemales += queues.villager.countQueuedUnitsWithClass("Support"); … … 293 297 294 298 // base "0" means "auto" 295 299 if (template === gameState.applyCiv("units/{civ}_support_female_citizen")) 296 queues.villager.addItem(new TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size ));300 queues.villager.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size )); 297 301 else 298 queues.citizenSoldier.addItem(new TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size));302 queues.citizenSoldier.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size)); 299 303 } 300 304 }; 301 305 302 306 // picks the best template based on parameters and classes 303 HQ.prototype.findBestTrainableUnit = function(gameState, classes, parameters) {307 m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, parameters) { 304 308 var units = gameState.findTrainableUnits(classes); 305 309 306 310 if (units.length === 0) … … 317 321 bTopParam = param[1]; 318 322 } 319 323 if (param[0] == "strength") { 320 aTopParam += getMaxStrength(a[1]) * param[1];321 bTopParam += getMaxStrength(b[1]) * param[1];324 aTopParam += m.getMaxStrength(a[1]) * param[1]; 325 bTopParam += m.getMaxStrength(b[1]) * param[1]; 322 326 } 323 327 if (param[0] == "speed") { 324 328 aTopParam += a[1].walkSpeed() * param[1]; … … 343 347 }; 344 348 345 349 // picks the best template based on parameters and classes 346 HQ.prototype.findBestTrainableSoldier = function(gameState, classes, parameters) {350 m.HQ.prototype.findBestTrainableSoldier = function(gameState, classes, parameters) { 347 351 var units = gameState.findTrainableUnits(classes); 348 352 349 353 if (units.length === 0) … … 361 365 bTopParam = param[1]; 362 366 } 363 367 if (param[0] == "strength") { 364 aTopParam += getMaxStrength(a[1]) * param[1];365 bTopParam += getMaxStrength(b[1]) * param[1];368 aTopParam += m.getMaxStrength(a[1]) * param[1]; 369 bTopParam += m.getMaxStrength(b[1]) * param[1]; 366 370 } 367 371 if (param[0] == "siegeStrength") { 368 aTopParam += getMaxStrength(a[1], "Structure") * param[1];369 bTopParam += getMaxStrength(b[1], "Structure") * param[1];372 aTopParam += m.getMaxStrength(a[1], "Structure") * param[1]; 373 bTopParam += m.getMaxStrength(b[1], "Structure") * param[1]; 370 374 } 371 375 if (param[0] == "speed") { 372 376 aTopParam += a[1].walkSpeed() * param[1]; … … 394 398 // Tries to research any available tech 395 399 // Only one at once. Also does military tech (selection is completely random atm) 396 400 // TODO: Lots, lots, lots here. 397 HQ.prototype.tryResearchTechs = function(gameState, queues) {401 m.HQ.prototype.tryResearchTechs = function(gameState, queues) { 398 402 if (queues.minorTech.length() === 0) 399 403 { 400 404 var possibilities = gameState.findAvailableTech(); … … 402 406 return; 403 407 // randomly pick one. No worries about pairs in that case. 404 408 var p = Math.floor((Math.random()*possibilities.length)); 405 queues.minorTech.addItem(new ResearchPlan(gameState, possibilities[p][0]));409 queues.minorTech.addItem(new m.ResearchPlan(gameState, possibilities[p][0])); 406 410 } 407 411 } 408 412 409 413 // We're given a worker and a resource type 410 414 // We'll assign the worker for the best base for that resource type. 411 415 // TODO: improve choice alogrithm 412 HQ.prototype.switchWorkerBase = function(gameState, worker, type) {416 m.HQ.prototype.switchWorkerBase = function(gameState, worker, type) { 413 417 var bestBase = 0; 418 414 419 for (var i in this.baseManagers) 415 420 { 416 421 if (this.baseManagers[i].willGather[type] >= 1) … … 435 440 // returns an entity collection of workers through BaseManager.pickBuilders 436 441 // TODO: better the choice algo. 437 442 // TODO: also can't get over multiple bases right now. 438 HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number) {443 m.HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number) { 439 444 var accessIndex = this.baseManagers[newBaseID].accessIndex; 440 445 if (!accessIndex) 441 446 return false; 442 447 // sorting bases by whether they are on the same accessindex or not. 443 var baseBest = AssocArraytoArray(this.baseManagers).sort(function (a,b) {448 var baseBest = m.AssocArraytoArray(this.baseManagers).sort(function (a,b) { 444 449 if (a.accessIndex === accessIndex && b.accessIndex !== accessIndex) 445 450 return -1; 446 451 else if (b.accessIndex === accessIndex && a.accessIndex !== accessIndex) … … 459 464 460 465 // returns the current gather rate 461 466 // This is not per-se exact, it performs a few adjustments ad-hoc to account for travel distance, stuffs like that. 462 HQ.prototype.GetCurrentGatherRates = function(gameState) {467 m.HQ.prototype.GetCurrentGatherRates = function(gameState) { 463 468 var self = this; 464 469 465 470 var currentRates = {}; … … 474 479 475 480 476 481 // Pick the resource which most needs another worker 477 HQ.prototype.pickMostNeededResources = function(gameState) {482 m.HQ.prototype.pickMostNeededResources = function(gameState) { 478 483 var self = this; 479 484 480 485 this.wantedRates = gameState.ai.queueManager.wantedGatherRates(gameState); … … 517 522 518 523 // If all the CC's are destroyed then build a new one 519 524 // TODO: rehabilitate. 520 HQ.prototype.buildNewCC= function(gameState, queues) {525 m.HQ.prototype.buildNewCC= function(gameState, queues) { 521 526 var numCCs = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_civil_centre")); 522 527 numCCs += queues.civilCentre.length(); 523 528 … … 529 534 this.baseNeed["wood"] = 50; 530 535 this.baseNeed["stone"] = 50; 531 536 this.baseNeed["metal"] = 50; 532 queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre"));537 queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre")); 533 538 } 534 539 return (gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_civil_centre"), true) == 0 && gameState.currentPhase() > 1); 535 540 }; 536 541 537 542 // Returns the best position to build a new Civil Centre 538 543 // Whose primary function would be to reach new resources of type "resource". 539 HQ.prototype.findBestEcoCCLocation = function(gameState, resource){544 m.HQ.prototype.findBestEcoCCLocation = function(gameState, resource){ 540 545 541 546 var CCPlate = gameState.getTemplate("structures/{civ}_civil_centre"); 542 547 … … 545 550 // Then checks for a good spot in the territory. If none, and town/city phase, checks outside 546 551 // The AI will currently not build a CC if it wouldn't connect with an existing CC. 547 552 548 var territory = Map.createTerritoryMap(gameState);553 var territory = m.createTerritoryMap(gameState); 549 554 550 var obstructions = Map.createObstructionMap(gameState, 0);555 var obstructions = m.createObstructionMap(gameState, 0); 551 556 obstructions.expandInfluences(); 552 557 553 558 // copy the resource map as initialization. 554 var friendlyTiles = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true);559 var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true); 555 560 friendlyTiles.setMaxVal(255); 556 var ents = gameState.getOwnEntities().filter( Filters.byClass("CivCentre")).toEntityArray();557 var eEnts = gameState.getEnemyEntities().filter( Filters.byClass("CivCentre")).toEntityArray();561 var ents = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); 562 var eEnts = gameState.getEnemyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); 558 563 559 564 var dps = gameState.getOwnDropsites().toEntityArray(); 560 565 … … 576 581 var entPos = ents[i].position(); 577 582 entPos = [entPos[0]/4.0,entPos[1]/4.0]; 578 583 579 var dist = SquareVectorDistance(entPos, pos);584 var dist = API3.SquareVectorDistance(entPos, pos); 580 585 if (dist < 2120) 581 586 { 582 587 canBuild = false; … … 598 603 var entPos = eEnts[i].position(); 599 604 entPos = [entPos[0]/4.0,entPos[1]/4.0]; 600 605 // 7100 works well as a limit. 601 if ( SquareVectorDistance(entPos, pos) < 2500)606 if (API3.SquareVectorDistance(entPos, pos) < 2500) 602 607 { 603 608 canBuild = false; 604 609 continue; … … 620 625 continue; 621 626 } 622 627 dpPos = [dpPos[0]/4.0,dpPos[1]/4.0]; 623 if ( SquareVectorDistance(dpPos, pos) < 100)628 if (API3.SquareVectorDistance(dpPos, pos) < 100) 624 629 { 625 630 friendlyTiles.map[j] = 0; 626 631 continue; 627 } else if ( SquareVectorDistance(dpPos, pos) < 400)632 } else if (API3.SquareVectorDistance(dpPos, pos) < 400) 628 633 friendlyTiles.map[j] /= 2; 629 634 } 630 635 … … 645 650 var best = friendlyTiles.findBestTile(6, obstructions); 646 651 var bestIdx = best[0]; 647 652 648 if ( Config.debug)653 if (m.DebugEnabled) 649 654 { 650 655 friendlyTiles.map[bestIdx] = 270; 651 656 friendlyTiles.dumpIm("cc_placement_base_" + gameState.getTimeElapsed() + "_" + resource + "_" + best[1] + ".png",301); … … 659 664 var x = ((bestIdx % friendlyTiles.width) + 0.5) * gameState.cellSize; 660 665 var z = (Math.floor(bestIdx / friendlyTiles.width) + 0.5) * gameState.cellSize; 661 666 662 debug ("Best for value " + best[1] + " at " + uneval([x,z]));667 m.debug ("Best for value " + best[1] + " at " + uneval([x,z])); 663 668 664 669 return [x,z]; 665 670 }; 666 671 667 HQ.prototype.buildTemple = function(gameState, queues){672 m.HQ.prototype.buildTemple = function(gameState, queues){ 668 673 if (gameState.currentPhase() >= 2 ) { 669 674 if (queues.economicBuilding.countQueuedUnits() === 0 && 670 675 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_temple")) === 0){ 671 queues.economicBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_temple", { "base" : 1 }));676 queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_temple", { "base" : 1 })); 672 677 } 673 678 } 674 679 }; 675 680 676 HQ.prototype.buildMarket = function(gameState, queues){677 if (gameState.getPopulation() > Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) {681 m.HQ.prototype.buildMarket = function(gameState, queues){ 682 if (gameState.getPopulation() > this.Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) { 678 683 if (queues.economicBuilding.countQueuedUnitsWithClass("BarterMarket") === 0 && 679 684 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market")) === 0){ 680 685 //only ever build one storehouse/CC/market at a time 681 queues.economicBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_market", { "base" : 1 }));686 queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_market", { "base" : 1 })); 682 687 } 683 688 } 684 689 }; 685 690 686 691 // Build a farmstead to go to town phase faster and prepare for research. Only really active on higher diff mode. 687 HQ.prototype.buildFarmstead = function(gameState, queues){688 if (gameState.getPopulation() > Config.Economy.popForFarmstead) {692 m.HQ.prototype.buildFarmstead = function(gameState, queues){ 693 if (gameState.getPopulation() > this.Config.Economy.popForFarmstead) { 689 694 // achtung: "DropsiteFood" does not refer to CCs. 690 695 if (queues.economicBuilding.countQueuedUnitsWithClass("DropsiteFood") === 0 && 691 696 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_farmstead")) === 0){ 692 697 //only ever build one storehouse/CC/market at a time 693 queues.economicBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_farmstead", { "base" : 1 }));698 queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_farmstead", { "base" : 1 })); 694 699 } 695 700 } 696 701 }; 697 702 698 703 // TODO: generic this, probably per-base 699 HQ.prototype.buildDock = function(gameState, queues){704 m.HQ.prototype.buildDock = function(gameState, queues){ 700 705 if (!this.waterMap || this.dockFailed) 701 706 return; 702 707 if (gameState.getTimeElapsed() > this.dockStartTime) { … … 710 715 if (tp !== "") 711 716 { 712 717 var remaining = this.navalManager.getUnconnectedSeas(gameState, this.baseManagers[1].accessIndex); 713 queues.economicBuilding.addItem(new ConstructionPlan(gameState, tp, { "base" : 1, "sea" : remaining[0] }));718 queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, tp, { "base" : 1, "sea" : remaining[0] })); 714 719 } 715 720 } 716 721 } … … 719 724 // if Aegis has resources it doesn't need, it'll try to barter it for resources it needs 720 725 // once per turn because the info doesn't update between a turn and I don't want to fix it. 721 726 // Not sure how efficient it is but it seems to be sane, at least. 722 HQ.prototype.tryBartering = function(gameState){727 m.HQ.prototype.tryBartering = function(gameState){ 723 728 var done = false; 724 729 if (gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_market"), true) >= 1) { 725 730 … … 732 737 if ( (ress[buy] < 400) || needs[buy] > 0) { // if we need that other resource/ have too little of it 733 738 var markets = gameState.getOwnEntitiesByType(gameState.applyCiv("structures/{civ}_market"), true).toEntityArray(); 734 739 markets[0].barter(buy,sell,100); 735 // debug ("bartered " +sell +" for " + buy + ", value 100");740 //m.debug ("bartered " +sell +" for " + buy + ", value 100"); 736 741 done = true; 737 742 } 738 743 } … … 743 748 744 749 // build more houses if needed. 745 750 // kinda ugly, lots of special cases to both build enough houses but not tooo many… 746 HQ.prototype.buildMoreHouses = function(gameState,queues) {751 m.HQ.prototype.buildMoreHouses = function(gameState,queues) { 747 752 748 753 if (gameState.getPopulationLimit() < gameState.getPopulationMax()) { 749 754 … … 751 756 752 757 if (numPlanned < 3 || (numPlanned < 5 && gameState.getPopulation() > 80)) 753 758 { 754 var plan = new ConstructionPlan(gameState, "structures/{civ}_house", { "base" : 1 }); 759 var plan = new m.ConstructionPlan(gameState, "structures/{civ}_house", { "base" : 1 }); 760 // make the difficulty available to the isGo function without having to pass it as argument 761 var difficulty = this.Config.difficulty; 755 762 // change the starting condition to "less than 15 slots left". 756 763 plan.isGo = function (gameState) { 757 764 var HouseNb = gameState.countEntitiesByType(gameState.applyCiv("foundation|structures/{civ}_house"), true); … … 761 768 freeSlots = gameState.getPopulationLimit() + HouseNb*5 - gameState.getPopulation(); 762 769 else 763 770 freeSlots = gameState.getPopulationLimit() + HouseNb*10 - gameState.getPopulation(); 764 if (gameState.getPopulation() > 55 && Config.difficulty > 1)771 if (gameState.getPopulation() > 55 && difficulty > 1) 765 772 return (freeSlots <= 21); 766 else if (gameState.getPopulation() >= 20 && Config.difficulty !== 0)773 else if (gameState.getPopulation() >= 20 && difficulty !== 0) 767 774 return (freeSlots <= 16); 768 775 else 769 776 return (freeSlots <= 10); … … 774 781 }; 775 782 776 783 // checks if we have bases for all resource types (bar food for now) or if we need to expand. 777 HQ.prototype.checkBasesRessLevel = function(gameState,queues) {784 m.HQ.prototype.checkBasesRessLevel = function(gameState,queues) { 778 785 if (gameState.currentPhase() === 1 && !gameState.isResearching(gameState.townPhase())) 779 786 return; 780 787 var count = { "wood" : 0, "stone" : 0, "metal" : 0 } 781 788 var capacity = { "wood" : 0, "stone" : 0, "metal" : 0 } 782 789 var need = { "wood" : true, "stone" : true, "metal" : true }; 783 790 var posss = []; 791 784 792 for (i in this.baseManagers) 785 793 { 786 794 var base = this.baseManagers[i]; 787 795 for (type in count) 788 796 { 789 if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max( Config.difficulty,2))797 if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max(this.Config.difficulty,2)) 790 798 count[type]++; 791 799 capacity[type] += base.getWorkerCapacity(gameState, type); 792 800 if (base.willGather[type] !== 2) … … 796 804 for (type in count) 797 805 { 798 806 if (count[type] === 0 || need[type] 799 || capacity[type] < gameState.getOwnEntities().filter( Filters.and(Filters.byMetadata(PlayerID, "subrole", "gatherer"),Filters.byMetadata(PlayerID, "gather-type", type))).length * 1.05)807 || capacity[type] < gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byMetadata(PlayerID, "subrole", "gatherer"), API3.Filters.byMetadata(PlayerID, "gather-type", type))).length * 1.05) 800 808 { 801 809 // plan a new base. 802 810 if (gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_civil_centre")) === 0 && queues.civilCentre.length() === 0) { … … 809 817 this.outOf[type] = true; 810 818 } else { 811 819 // base "-1" means new base. 812 queues.civilCentre.addItem(new ConstructionPlan(gameState, "structures/{civ}_civil_centre",{ "base" : -1 }, 0, -1, pos));820 queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre",{ "base" : -1 }, 0, -1, pos)); 813 821 } 814 822 } 815 823 } … … 819 827 // Deals with building fortresses and towers. 820 828 // Currently build towers next to every useful dropsites. 821 829 // TODO: Fortresses are placed randomly atm. 822 HQ.prototype.buildDefences = function(gameState, queues){830 m.HQ.prototype.buildDefences = function(gameState, queues){ 823 831 824 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter( Filters.not(Filters.byHasMetadata(PlayerID,"plan"))).length;832 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"plan"))).length; 825 833 826 834 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv('structures/{civ}_defense_tower')) 827 835 + queues.defenceBuilding.length() < gameState.getEntityLimits()["DefenseTower"] && queues.defenceBuilding.length() < 4 && gameState.currentPhase() > 1) { … … 836 844 { 837 845 var position = dpEnt.position(); 838 846 if (position) { 839 queues.defenceBuilding.addItem(new ConstructionPlan(gameState, 'structures/{civ}_defense_tower', { "base" : i }, 0 , -1, position));847 queues.defenceBuilding.addItem(new m.ConstructionPlan(gameState, 'structures/{civ}_defense_tower', { "base" : i }, 0 , -1, position)); 840 848 } 841 849 dpEnt.setMetadata(PlayerID, "defenseTower", true); 842 850 } … … 855 863 { 856 864 if (!this.fortressStartTime) 857 865 this.fortressStartTime = gameState.getTimeElapsed(); 858 queues.defenceBuilding.addItem(new ConstructionPlan(gameState, this.bFort[0], { "base" : 1 }));859 debug ("Building a fortress");866 queues.defenceBuilding.addItem(new m.ConstructionPlan(gameState, this.bFort[0], { "base" : 1 })); 867 m.debug ("Building a fortress"); 860 868 } 861 869 } 862 870 if (gameState.countEntitiesByType(gameState.applyCiv(this.bFort[i]), true) >= 1) { … … 877 885 } 878 886 }; 879 887 880 HQ.prototype.buildBlacksmith = function(gameState, queues){881 if (gameState.getTimeElapsed() > Config.Military.timeForBlacksmith*1000) {888 m.HQ.prototype.buildBlacksmith = function(gameState, queues){ 889 if (gameState.getTimeElapsed() > this.Config.Military.timeForBlacksmith*1000) { 882 890 if (queues.militaryBuilding.length() === 0 && 883 891 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_blacksmith")) === 0) { 884 892 var tp = gameState.getTemplate(gameState.applyCiv("structures/{civ}_blacksmith")); 885 893 if (tp.available(gameState)) 886 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, "structures/{civ}_blacksmith", { "base" : 1 }));894 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_blacksmith", { "base" : 1 })); 887 895 } 888 896 } 889 897 }; … … 892 900 // They are mostly defined by Config.js. This is unreliable since changes could be done easily. 893 901 // TODO: We need to determine these dynamically. Also doesn't build fortresses since the above function does that. 894 902 // TODO: building placement is bad. Choice of buildings is also fairly dumb. 895 HQ.prototype.constructTrainingBuildings = function(gameState, queues) {903 m.HQ.prototype.constructTrainingBuildings = function(gameState, queues) { 896 904 Engine.ProfileStart("Build buildings"); 897 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter( Filters.not(Filters.byHasMetadata(PlayerID, "plan"))).length;905 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "plan"))).length; 898 906 899 if (workersNumber > Config.Military.popForBarracks1) {907 if (workersNumber > this.Config.Military.popForBarracks1) { 900 908 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) + queues.militaryBuilding.length() < 1) { 901 debug ("Trying to build barracks");902 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));909 m.debug ("Trying to build barracks"); 910 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 903 911 } 904 912 } 905 913 906 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > Config.Military.popForBarracks2)914 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > this.Config.Military.popForBarracks2) 907 915 if (queues.militaryBuilding.length() < 1) 908 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));916 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 909 917 910 918 if (gameState.countEntitiesByType(gameState.applyCiv(this.bModerate[0]), true) === 2 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 3 && workersNumber > 125) 911 919 if (queues.militaryBuilding.length() < 1) 912 920 { 913 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));921 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 914 922 if (gameState.civ() == "gaul" || gameState.civ() == "brit" || gameState.civ() == "iber") { 915 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));916 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));923 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 924 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 917 925 } 918 926 } 919 927 //build advanced military buildings 920 if (workersNumber >= Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){928 if (workersNumber >= this.Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){ 921 929 if (queues.militaryBuilding.length() === 0){ 922 930 var inConst = 0; 923 931 for (var i in this.bAdvanced) … … 925 933 if (inConst == 0 && this.bAdvanced && this.bAdvanced.length !== 0) { 926 934 var i = Math.floor(Math.random() * this.bAdvanced.length); 927 935 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i])) < 1){ 928 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 }));936 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); 929 937 } 930 938 } 931 939 } … … 939 947 if (inConst == 1) { 940 948 var i = Math.floor(Math.random() * this.bAdvanced.length); 941 949 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i])) < 1){ 942 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 }));943 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 }));950 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); 951 queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : 1 })); 944 952 } 945 953 } 946 954 } … … 949 957 }; 950 958 951 959 // TODO: use pop(). Currently unused as this is too gameable. 952 HQ.prototype.garrisonAllFemales = function(gameState) {953 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).toEntityArray();954 var females = gameState.getOwnEntities().filter( Filters.byClass("Support"));960 m.HQ.prototype.garrisonAllFemales = function(gameState) { 961 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); 962 var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support")); 955 963 956 964 var cache = {}; 957 965 … … 974 982 }); 975 983 this.hasGarrisonedFemales = true; 976 984 }; 977 HQ.prototype.ungarrisonAll = function(gameState) {985 m.HQ.prototype.ungarrisonAll = function(gameState) { 978 986 this.hasGarrisonedFemales = false; 979 var buildings = gameState.getOwnEntities().filter( Filters.and(Filters.byClass("Structure"),Filters.byCanGarrison())).toEntityArray();987 var buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byCanGarrison())).toEntityArray(); 980 988 buildings.forEach( function (struct) { 981 989 if (struct.garrisoned() && struct.garrisoned().length) 982 990 struct.unloadAll(); 983 991 }); 984 992 }; 985 993 986 HQ.prototype.pausePlan = function(gameState, planName) {994 m.HQ.prototype.pausePlan = function(gameState, planName) { 987 995 for (var attackType in this.upcomingAttacks) { 988 996 for (var i in this.upcomingAttacks[attackType]) { 989 997 var attack = this.upcomingAttacks[attackType][i]; … … 999 1007 } 1000 1008 } 1001 1009 } 1002 HQ.prototype.unpausePlan = function(gameState, planName) {1010 m.HQ.prototype.unpausePlan = function(gameState, planName) { 1003 1011 for (var attackType in this.upcomingAttacks) { 1004 1012 for (var i in this.upcomingAttacks[attackType]) { 1005 1013 var attack = this.upcomingAttacks[attackType][i]; … … 1015 1023 } 1016 1024 } 1017 1025 } 1018 HQ.prototype.pauseAllPlans = function(gameState) {1026 m.HQ.prototype.pauseAllPlans = function(gameState) { 1019 1027 for (var attackType in this.upcomingAttacks) { 1020 1028 for (var i in this.upcomingAttacks[attackType]) { 1021 1029 var attack = this.upcomingAttacks[attackType][i]; … … 1029 1037 } 1030 1038 } 1031 1039 } 1032 HQ.prototype.unpauseAllPlans = function(gameState) {1040 m.HQ.prototype.unpauseAllPlans = function(gameState) { 1033 1041 for (var attackType in this.upcomingAttacks) { 1034 1042 for (var i in this.upcomingAttacks[attackType]) { 1035 1043 var attack = this.upcomingAttacks[attackType][i]; … … 1047 1055 1048 1056 // Some functions are run every turn 1049 1057 // Others once in a while 1050 HQ.prototype.update = function(gameState, queues, events) { 1058 m.HQ.prototype.update = function(gameState, queues, events) { 1051 1059 Engine.ProfileStart("Headquarters update"); 1052 1060 1053 1061 this.checkEvents(gameState,events,queues); … … 1057 1065 this.trainMoreWorkers(gameState, queues); 1058 1066 1059 1067 // sandbox doesn't expand. 1060 if ( Config.difficulty !== 0)1068 if (this.Config.difficulty !== 0) 1061 1069 this.checkBasesRessLevel(gameState, queues); 1062 1070 1063 1071 this.buildMoreHouses(gameState,queues); … … 1065 1073 if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2) 1066 1074 this.tryResearchTechs(gameState,queues); 1067 1075 1068 if ( Config.difficulty > 1)1076 if (this.Config.difficulty > 1) 1069 1077 this.tryBartering(gameState); 1070 1078 1071 1079 this.buildFarmstead(gameState, queues); … … 1087 1095 for (i in this.baseManagers) 1088 1096 { 1089 1097 this.baseManagers[i].checkEvents(gameState, events, queues) 1090 if ( ( (+i + gameState.ai.playedTurn) % ( uniqueIDBases - 1)) === 0)1098 if ( ( (+i + gameState.ai.playedTurn) % (m.playerGlobals[PlayerID].uniqueIDBases - 1)) === 0) 1091 1099 this.baseManagers[i].update(gameState, queues, events); 1092 1100 } 1093 1101 … … 1113 1121 if (updateStep === 1 || attack.isPaused() ) { 1114 1122 // just chillin' 1115 1123 } else if (updateStep === 0 || updateStep === 3) { 1116 debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" aborted.");1124 m.debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" aborted."); 1117 1125 if (updateStep === 3) { 1118 1126 this.attackPlansEncounteredWater = true; 1119 debug("No attack path found. Aborting.");1127 m.debug("No attack path found. Aborting."); 1120 1128 } 1121 1129 attack.Abort(gameState, this); 1122 1130 this.upcomingAttacks[attackType].splice(i--,1); … … 1130 1138 chatText = "I'm starting an attack against " + gameState.sharedScript.playersData[attack.targetPlayer].name + "."; 1131 1139 gameState.ai.chatTeam(chatText); 1132 1140 1133 debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName());1141 m.debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName()); 1134 1142 attack.StartAttack(gameState,this); 1135 1143 this.startedAttacks[attackType].push(attack); 1136 1144 this.upcomingAttacks[attackType].splice(i--,1); … … 1145 1153 chatText = "I'm starting an attack against " + gameState.sharedScript.playersData[attack.targetPlayer].name + "."; 1146 1154 gameState.ai.chatTeam(chatText); 1147 1155 1148 debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName());1156 m.debug ("Military Manager: Starting " +attack.getType() +" plan " +attack.getName()); 1149 1157 this.startedAttacks[attackType].push(attack); 1150 1158 this.upcomingAttacks[attackType].splice(i--,1); 1151 1159 } … … 1160 1168 { 1161 1169 var remaining = attack.update(gameState,this,events); 1162 1170 if (remaining == 0 || remaining == undefined) { 1163 debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" is now finished.");1171 m.debug ("Military Manager: " +attack.getType() +" plan " +attack.getName() +" is now finished."); 1164 1172 attack.Abort(gameState); 1165 1173 this.startedAttacks[attackType].splice(i--,1); 1166 1174 } … … 1174 1182 if (gameState.ai.strategy === "rush" && this.startedAttacks["CityAttack"].length !== 0) { 1175 1183 // and then we revert. 1176 1184 gameState.ai.strategy = "normal"; 1177 Config.Economy.femaleRatio = 0.4;1185 this.Config.Economy.femaleRatio = 0.4; 1178 1186 gameState.ai.modules.economy.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*0.55), 1); 1179 1187 } else if (gameState.ai.strategy === "rush" && this.upcomingAttacks["CityAttack"].length === 0) 1180 1188 { 1181 Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1, "rush")1189 Lalala = new m.CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "rush") 1182 1190 this.TotalAttackNumber++; 1183 1191 this.upcomingAttacks["CityAttack"].push(Lalala); 1184 debug ("Starting a little something");1192 m.debug ("Starting a little something"); 1185 1193 } else if (gameState.ai.strategy !== "rush" && !this.waterMap) 1186 1194 { 1187 1195 // creating plans after updating because an aborted plan might be reused in that case. … … 1193 1201 } else { 1194 1202 // basically only the first plan, really. 1195 1203 if (this.upcomingAttacks["CityAttack"].length == 0 && gameState.getTimeElapsed() < 12*60000) { 1196 var Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1);1204 var Lalala = new m.CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1); 1197 1205 if (Lalala.failed) 1198 1206 { 1199 1207 this.attackPlansEncounteredWater = true; // hack 1200 1208 } else { 1201 debug ("Military Manager: Creating the plan " +this.TotalAttackNumber);1209 m.debug ("Military Manager: Creating the plan " +this.TotalAttackNumber); 1202 1210 this.TotalAttackNumber++; 1203 1211 this.upcomingAttacks["CityAttack"].push(Lalala); 1204 1212 } 1205 } else if (this.upcomingAttacks["CityAttack"].length == 0 && Config.difficulty !== 0) {1206 var Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1, "superSized");1213 } else if (this.upcomingAttacks["CityAttack"].length == 0 && this.Config.difficulty !== 0) { 1214 var Lalala = new m.CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "superSized"); 1207 1215 if (Lalala.failed) 1208 1216 { 1209 1217 this.attackPlansEncounteredWater = true; // hack 1210 1218 } else { 1211 debug ("Military Manager: Creating the super sized plan " +this.TotalAttackNumber);1219 m.debug ("Military Manager: Creating the super sized plan " +this.TotalAttackNumber); 1212 1220 this.TotalAttackNumber++; 1213 1221 this.upcomingAttacks["CityAttack"].push(Lalala); 1214 1222 } … … 1221 1229 // very old relic. This should be reimplemented someday so the code stays here. 1222 1230 1223 1231 if (this.HarassRaiding && this.preparingRaidNumber + this.startedRaidNumber < 1 && gameState.getTimeElapsed() < 780000) { 1224 var Lalala = new CityAttack(gameState, this,this.totalStartedAttackNumber, -1, "harass_raid");1232 var Lalala = new m.CityAttack(gameState, this,this.totalStartedAttackNumber, -1, "harass_raid"); 1225 1233 if (!Lalala.createSupportPlans(gameState, this, )) { 1226 debug ("Military Manager: harrassing plan not a valid option");1234 m.debug ("Military Manager: harrassing plan not a valid option"); 1227 1235 this.HarassRaiding = false; 1228 1236 } else { 1229 debug ("Military Manager: Creating the harass raid plan " +this.totalStartedAttackNumber);1237 m.debug ("Military Manager: Creating the harass raid plan " +this.totalStartedAttackNumber); 1230 1238 1231 1239 this.totalStartedAttackNumber++; 1232 1240 this.preparingRaidNumber++; … … 1243 1251 this.buildDropsites(gameState, queues); 1244 1252 Engine.ProfileStop(); 1245 1253 1246 if ( Config.difficulty !== 0)1254 if (this.Config.difficulty !== 0) 1247 1255 this.tryBartering(gameState); 1248 1256 1249 1257 this.buildFarmstead(gameState, queues); … … 1255 1263 */ 1256 1264 Engine.ProfileStop(); // Heaquarters update 1257 1265 }; 1266 1267 return m; 1268 1269 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/queueplan-research.js
1 var ResearchPlan = function(gameState, type, startTime, expectedTime, rush) { 1 var AEGIS = function(m) 2 { 3 4 m.ResearchPlan = function(gameState, type, startTime, expectedTime, rush) { 2 5 this.type = type; 3 6 4 this.ID = uniqueIDBOPlans++;7 this.ID = m.playerGlobals[PlayerID].uniqueIDBOPlans++; 5 8 6 9 this.template = gameState.getTemplate(this.type); 7 10 if (!this.template || this.template.researchTime === undefined) { 8 11 return false; 9 12 } 10 13 this.category = "technology"; 11 this.cost = new Resources(this.template.cost(),0);14 this.cost = new API3.Resources(this.template.cost(),0); 12 15 this.number = 1; // Obligatory for compatibility 13 16 14 17 if (!startTime) … … 30 33 }; 31 34 32 35 // return true if we willstart amassing resource for this plan 33 ResearchPlan.prototype.isGo = function(gameState) {36 m.ResearchPlan.prototype.isGo = function(gameState) { 34 37 return (gameState.getTimeElapsed() > this.startTime); 35 38 }; 36 39 37 ResearchPlan.prototype.canStart = function(gameState) {40 m.ResearchPlan.prototype.canStart = function(gameState) { 38 41 // also checks canResearch 39 42 return (gameState.findResearchers(this.type).length !== 0); 40 43 }; 41 44 42 ResearchPlan.prototype.start = function(gameState) {45 m.ResearchPlan.prototype.start = function(gameState) { 43 46 var self = this; 44 47 45 48 // TODO: this is special cased for "rush" technologies, ie the town phase 46 49 // which currently is a 100% focus. 47 50 gameState.ai.queueManager.unpauseAll(); 48 51 49 // debug ("Starting the research plan for " + this.type);52 //m.debug ("Starting the research plan for " + this.type); 50 53 var trainers = gameState.findResearchers(this.type).toEntityArray(); 51 54 52 55 //for (var i in trainers) … … 66 69 } 67 70 }; 68 71 69 ResearchPlan.prototype.getCost = function(){70 var costs = new Resources();72 m.ResearchPlan.prototype.getCost = function(){ 73 var costs = new API3.Resources(); 71 74 costs.add(this.cost); 72 75 return costs; 73 76 }; 74 77 78 79 return m; 80 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/queue-manager.js
1 var AEGIS = function(m) 2 { 3 1 4 // This takes the input queues and picks which items to fund with resources until no more resources are left to distribute. 2 5 // 3 6 // Currently this manager keeps accounts for each queue, split between the 4 main resources … … 17 20 // 18 21 // This system should be improved. It's probably not flexible enough. 19 22 20 var QueueManager = function(queues, priorities) { 23 m.QueueManager = function(Config, queues, priorities) { 24 this.Config = Config; 21 25 this.queues = queues; 22 26 this.priorities = priorities; 23 27 this.account = {}; … … 28 32 this.queueArrays = []; 29 33 for (var p in this.queues) { 30 34 this.account[p] = 0; 31 this.accounts[p] = new Resources();35 this.accounts[p] = new API3.Resources(); 32 36 this.queueArrays.push([p,this.queues[p]]); 33 37 } 34 38 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); … … 36 40 this.curItemQueue = []; 37 41 }; 38 42 39 QueueManager.prototype.getAvailableResources = function(gameState, noAccounts) {43 m.QueueManager.prototype.getAvailableResources = function(gameState, noAccounts) { 40 44 var resources = gameState.getResources(); 41 45 if (noAccounts) 42 46 return resources; … … 46 50 return resources; 47 51 }; 48 52 49 QueueManager.prototype.getTotalAccountedResources = function(gameState) {50 var resources = new Resources();53 m.QueueManager.prototype.getTotalAccountedResources = function(gameState) { 54 var resources = new API3.Resources(); 51 55 for (var key in this.queues) { 52 56 resources.add(this.accounts[key]); 53 57 } 54 58 return resources; 55 59 }; 56 60 57 QueueManager.prototype.currentNeeds = function(gameState) {58 var needs = new Resources();61 m.QueueManager.prototype.currentNeeds = function(gameState) { 62 var needs = new API3.Resources(); 59 63 // get out current resources, not removing accounts. 60 64 var current = this.getAvailableResources(gameState, true); 61 65 //queueArrays because it's faster. … … 82 86 }; 83 87 }; 84 88 85 QueueManager.prototype.futureNeeds = function(gameState) {86 var needs = new Resources();89 m.QueueManager.prototype.futureNeeds = function(gameState) { 90 var needs = new API3.Resources(); 87 91 // get out current resources, not removing accounts. 88 92 var current = this.getAvailableResources(gameState, true); 89 93 //queueArrays because it's faster. … … 108 112 }; 109 113 110 114 // calculate the gather rates we'd want to be able to use all elements in our queues 111 QueueManager.prototype.wantedGatherRates = function(gameState) {115 m.QueueManager.prototype.wantedGatherRates = function(gameState) { 112 116 var rates = { "food" : 0, "wood" : 0, "stone" : 0, "metal" : 0 }; 113 117 var qTime = gameState.getTimeElapsed(); 114 118 var qCosts = { "food" : 0, "wood" : 0, "stone" : 0, "metal" : 0 }; … … 143 147 // estimate time based on priority + cost + nb 144 148 // TODO: work on this. 145 149 for (type in qCosts) 150 { 146 151 qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name])); 152 } 147 153 qTime += 30000; 148 154 } else { 149 155 // TODO: work on this. … … 165 171 return rates; 166 172 }; 167 173 168 /* QueueManager.prototype.logNeeds = function(gameState) {174 /*m.QueueManager.prototype.logNeeds = function(gameState) { 169 175 if (!this.totor) 170 176 { 171 177 this.totor = []; … … 255 261 }; 256 262 */ 257 263 258 QueueManager.prototype.printQueues = function(gameState){259 debug("QUEUES");264 m.QueueManager.prototype.printQueues = function(gameState){ 265 m.debug("QUEUES"); 260 266 for (var i in this.queues){ 261 267 var qStr = ""; 262 268 var q = this.queues[i]; 263 269 if (q.queue.length > 0) 264 debug((i + ":"));270 m.debug((i + ":")); 265 271 for (var j in q.queue){ 266 272 qStr = " " + q.queue[j].type + " "; 267 273 if (q.queue[j].number) 268 274 qStr += "x" + q.queue[j].number; 269 debug (qStr);275 m.debug (qStr); 270 276 } 271 277 } 272 debug ("Accounts");278 m.debug ("Accounts"); 273 279 for (var p in this.accounts) 274 280 { 275 debug(p + ": " + uneval(this.accounts[p]));281 m.debug(p + ": " + uneval(this.accounts[p])); 276 282 } 277 debug("Needed Resources:" + uneval(this.futureNeeds(gameState,false)));278 debug ("Wanted Gather Rates:" + uneval(this.wantedGatherRates(gameState)));279 debug ("Current Resources:" + uneval(gameState.getResources()));280 debug ("Available Resources:" + uneval(this.getAvailableResources(gameState)));283 m.debug("Needed Resources:" + uneval(this.futureNeeds(gameState,false))); 284 m.debug ("Wanted Gather Rates:" + uneval(this.wantedGatherRates(gameState))); 285 m.debug ("Current Resources:" + uneval(gameState.getResources())); 286 m.debug ("Available Resources:" + uneval(this.getAvailableResources(gameState))); 281 287 }; 282 288 283 289 // nice readable HTML version. 284 QueueManager.prototype.HTMLprintQueues = function(gameState){285 if (! Config.debug)290 m.QueueManager.prototype.HTMLprintQueues = function(gameState){ 291 if (!m.DebugEnabled) 286 292 return; 287 293 log("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"> <html> <head> <title>Aegis Queue Manager</title> <link rel=\"stylesheet\" href=\"table.css\"> </head> <body> <table> <caption>Aegis Build Order</caption> "); 288 294 for (var i in this.queues){ … … 325 331 log("</body></html>"); 326 332 }; 327 333 328 QueueManager.prototype.clear = function(){334 m.QueueManager.prototype.clear = function(){ 329 335 this.curItemQueue = []; 330 336 for (var i in this.queues) 331 337 this.queues[i].empty(); 332 338 }; 333 339 334 QueueManager.prototype.update = function(gameState) {340 m.QueueManager.prototype.update = function(gameState) { 335 341 var self = this; 336 342 337 343 for (var i in this.priorities){ … … 430 436 this.accounts[queues[under]] -= amnt; 431 437 this.accounts[queues[over]] += amnt; 432 438 --over; 433 debug ("Shifting " + amnt + " from " + queues[under] + " to " +queues[over]);439 m.debug ("Shifting " + amnt + " from " + queues[under] + " to " +queues[over]); 434 440 continue; 435 441 } else { 436 442 ++under; … … 447 453 448 454 Engine.ProfileStart("Pick items from queues"); 449 455 450 // debug ("start");451 // debug (uneval(this.accounts));456 //m.debug ("start"); 457 //m.debug (uneval(this.accounts)); 452 458 // Start the next item in the queue if we can afford it. 453 459 for (var i in this.queueArrays) 454 460 { … … 457 463 if (queue.length() > 0 && !queue.paused) 458 464 { 459 465 var item = queue.getNext(); 460 var total = new Resources();466 var total = new API3.Resources(); 461 467 total.add(this.accounts[name]); 462 468 if (total.canAfford(item.getCost())) 463 469 { … … 471 477 this.accounts[name].reset(); 472 478 } 473 479 } 474 // debug (uneval(this.accounts));480 //m.debug (uneval(this.accounts)); 475 481 476 482 Engine.ProfileStop(); 477 483 … … 481 487 Engine.ProfileStop(); 482 488 }; 483 489 484 QueueManager.prototype.pauseQueue = function(queue, scrapAccounts) {490 m.QueueManager.prototype.pauseQueue = function(queue, scrapAccounts) { 485 491 if (this.queues[queue]) 486 492 { 487 493 this.queues[queue].paused = true; … … 490 496 } 491 497 } 492 498 493 QueueManager.prototype.unpauseQueue = function(queue) {499 m.QueueManager.prototype.unpauseQueue = function(queue) { 494 500 if (this.queues[queue]) 495 501 this.queues[queue].paused = false; 496 502 } 497 503 498 QueueManager.prototype.pauseAll = function(scrapAccounts, but) {504 m.QueueManager.prototype.pauseAll = function(scrapAccounts, but) { 499 505 for (var p in this.queues) 500 506 if (p != but) 501 507 { … … 505 511 } 506 512 } 507 513 508 QueueManager.prototype.unpauseAll = function(but) {514 m.QueueManager.prototype.unpauseAll = function(but) { 509 515 for (var p in this.queues) 510 516 if (p != but) 511 517 this.queues[p].paused = false; 512 518 } 513 519 514 520 515 QueueManager.prototype.addQueue = function(queueName, priority) {521 m.QueueManager.prototype.addQueue = function(queueName, priority) { 516 522 if (this.queues[queueName] == undefined) { 517 this.queues[queueName] = new Queue();523 this.queues[queueName] = new m.Queue(); 518 524 this.priorities[queueName] = priority; 519 525 this.account[queueName] = 0; 520 this.accounts[queueName] = new Resources();526 this.accounts[queueName] = new API3.Resources(); 521 527 522 528 var self = this; 523 529 this.queueArrays = []; 524 530 for (var p in this.queues) 531 { 525 532 this.queueArrays.push([p,this.queues[p]]); 533 } 526 534 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 527 535 } 528 536 } 529 QueueManager.prototype.removeQueue = function(queueName) {537 m.QueueManager.prototype.removeQueue = function(queueName) { 530 538 if (this.queues[queueName] !== undefined) { 531 539 if ( this.curItemQueue.indexOf(queueName) !== -1) { 532 540 this.curItemQueue.splice(this.curItemQueue.indexOf(queueName),1); … … 539 547 var self = this; 540 548 this.queueArrays = []; 541 549 for (var p in this.queues) 550 { 542 551 this.queueArrays.push([p,this.queues[p]]); 552 } 543 553 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 544 554 } 545 555 } 546 QueueManager.prototype.changePriority = function(queueName, newPriority) {556 m.QueueManager.prototype.changePriority = function(queueName, newPriority) { 547 557 var self = this; 548 558 if (this.queues[queueName] !== undefined) 549 559 this.priorities[queueName] = newPriority; 550 560 this.queueArrays = []; 551 for (var p in this.queues) { 561 for (var p in this.queues) 562 { 552 563 this.queueArrays.push([p,this.queues[p]]); 553 564 } 554 565 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 555 566 } 556 567 568 return m; 569 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/map-module.js
1 var AEGIS = function(m) 2 { 3 1 4 // other map functions 5 m.TERRITORY_PLAYER_MASK = 0x3F; 2 6 3 Map.createObstructionMap = function(gameState, accessIndex, template){7 m.createObstructionMap = function(gameState, accessIndex, template){ 4 8 var passabilityMap = gameState.getMap(); 5 9 var territoryMap = gameState.ai.territoryMap; 6 10 … … 31 35 for (var y = 0; y < passabilityMap.height; ++y) 32 36 { 33 37 var i = x + y*passabilityMap.width; 34 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);38 var tilePlayer = (territoryMap.data[i] & m.TERRITORY_PLAYER_MASK); 35 39 36 40 if (gameState.ai.myIndex !== gameState.ai.accessibility.landPassMap[i]) 37 41 { … … 88 92 var obstructionTiles = new Uint8Array(passabilityMap.data.length); 89 93 for (var i = 0; i < passabilityMap.data.length; ++i) 90 94 { 91 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);95 var tilePlayer = (territoryMap.data[i] & m.TERRITORY_PLAYER_MASK); 92 96 var invalidTerritory = ( 93 97 (!buildOwn && tilePlayer == playerID) || 94 98 (!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) || … … 105 109 } 106 110 } 107 111 108 var map = new Map(gameState.sharedScript, obstructionTiles);112 var map = new API3.Map(gameState.sharedScript, obstructionTiles); 109 113 map.setMaxVal(255); 110 114 111 115 if (template && template.buildDistance()){ … … 126 130 }; 127 131 128 132 129 130 Map.createTerritoryMap = function(gameState) { 133 m.createTerritoryMap = function(gameState) { 131 134 var map = gameState.ai.territoryMap; 132 135 133 var ret = new Map(gameState.sharedScript, map.data);136 var ret = new API3.Map(gameState.sharedScript, map.data); 134 137 135 138 ret.getOwner = function(p) { 136 return this.point(p) & TERRITORY_PLAYER_MASK;139 return this.point(p) & m.TERRITORY_PLAYER_MASK; 137 140 } 138 141 ret.getOwnerIndex = function(p) { 139 return this.map[p] & TERRITORY_PLAYER_MASK;142 return this.map[p] & m.TERRITORY_PLAYER_MASK; 140 143 } 141 144 return ret; 142 145 }; 146 147 return m; 148 }(AEGIS); -
binaries/data/mods/public/simulation/ai/aegis/data.json
1 1 { 2 2 "name": "Aegis Bot", 3 3 "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).", 4 "moduleName" : "AEGIS", 4 5 "constructor": "AegisBot", 5 6 "useShared": true 6 7 } -
binaries/data/mods/public/simulation/ai/aegis/naval-manager.js
1 var AEGIS = function(m) 2 { 3 1 4 /* Naval Manager 2 5 Will deal with anything ships. 3 6 -Basically trade over water (with fleets and goals commissioned by the economy manager) … … 9 12 Does not build them though, that's for the base manager to handle. 10 13 */ 11 14 12 varNavalManager = function() {15 m.NavalManager = function() { 13 16 // accessibility zones for which we have a dock. 14 17 // Connexion is described as [landindex] = [seaIndexes]; 15 18 // technically they also exist for sea zones but I don't care. … … 32 35 }; 33 36 34 37 // More initialisation for stuff that needs the gameState 35 NavalManager.prototype.init = function(gameState, events, queues) {38 m.NavalManager.prototype.init = function(gameState, events, queues) { 36 39 // finished docks 37 this.docks = gameState.getOwnEntities().filter( Filters.and(Filters.byClass("Dock"), Filters.not(Filters.isFoundation())));40 this.docks = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Dock"), API3.Filters.not(API3.Filters.isFoundation()))); 38 41 this.docks.allowQuickIter(); 39 42 this.docks.registerUpdates(); 40 43 41 this.ships = gameState.getOwnEntities().filter( Filters.byClass("Ship"));44 this.ships = gameState.getOwnEntities().filter(API3.Filters.byClass("Ship")); 42 45 // note: those two can overlap (some transport ships are warships too and vice-versa). 43 this.tpShips = this.ships.filter( Filters.byCanGarrison());44 this.warships = this.ships.filter( Filters.byClass("Warship"));46 this.tpShips = this.ships.filter(API3.Filters.byCanGarrison()); 47 this.warships = this.ships.filter(API3.Filters.byClass("Warship")); 45 48 46 49 this.ships.registerUpdates(); 47 50 this.tpShips.registerUpdates(); … … 52 55 if (gameState.ai.accessibility.regionType[i] !== "water") 53 56 { 54 57 // push dummies 55 this.seaShips.push(new EntityCollection(gameState.sharedScript));56 this.seaTpShips.push(new EntityCollection(gameState.sharedScript));57 this.seaWarships.push(new EntityCollection(gameState.sharedScript));58 this.seaShips.push(new API3.EntityCollection(gameState.sharedScript)); 59 this.seaTpShips.push(new API3.EntityCollection(gameState.sharedScript)); 60 this.seaWarships.push(new API3.EntityCollection(gameState.sharedScript)); 58 61 this.wantedTpShips.push(0); 59 62 this.wantedWarships.push(0); 60 63 } else { 61 var collec = this.ships.filter( Filters.byStaticMetadata(PlayerID, "sea", i));64 var collec = this.ships.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); 62 65 collec.registerUpdates(); 63 66 this.seaShips.push(collec); 64 collec = this.tpShips.filter( Filters.byStaticMetadata(PlayerID, "sea", i));67 collec = this.tpShips.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); 65 68 collec.registerUpdates(); 66 69 this.seaTpShips.push(collec); 67 var collec = this.warships.filter( Filters.byStaticMetadata(PlayerID, "sea", i));70 var collec = this.warships.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); 68 71 collec.registerUpdates(); 69 72 this.seaWarships.push(collec); 70 73 … … 76 79 } 77 80 }; 78 81 79 NavalManager.prototype.getUnconnectedSeas = function (gameState, region) {82 m.NavalManager.prototype.getUnconnectedSeas = function (gameState, region) { 80 83 var seas = gameState.ai.accessibility.regionLinks[region] 81 84 if (seas.length === 0) 82 85 return []; … … 89 92 }; 90 93 91 94 // returns true if there is a path from A to B and we have docks. 92 NavalManager.prototype.canReach = function (gameState, regionA, regionB) {95 m.NavalManager.prototype.canReach = function (gameState, regionA, regionB) { 93 96 var path = gameState.ai.accessibility.getTrajectToIndex(regionA, regionB); 94 97 if (!path) 95 98 { … … 100 103 if (gameState.ai.accessibility.regionType[path[i]] == "land") 101 104 if (this.accessibleSeas.indexOf(path[i+1]) === -1) 102 105 { 103 debug ("cannot reach because of " + path[i+1]);106 m.debug ("cannot reach because of " + path[i+1]); 104 107 return false; // we wn't be able to board on that sea 105 108 } 106 109 } … … 108 111 }; 109 112 110 113 111 NavalManager.prototype.checkEvents = function (gameState, queues, events) {114 m.NavalManager.prototype.checkEvents = function (gameState, queues, events) { 112 115 for (i in events) 113 116 { 114 117 if (events[i].type == "Destroy") … … 137 140 } 138 141 }; 139 142 140 NavalManager.prototype.addPlan = function(plan) {143 m.NavalManager.prototype.addPlan = function(plan) { 141 144 this.transportPlans.push(plan); 142 145 }; 143 146 144 147 // will create a plan at the end of the turn. 145 148 // many units can call this separately and end up in the same plan 146 149 // which can be useful. 147 NavalManager.prototype.askForTransport = function(entity, startPos, endPos) {150 m.NavalManager.prototype.askForTransport = function(entity, startPos, endPos) { 148 151 this.askedPlans.push([entity, startPos, endPos]); 149 152 }; 150 153 151 154 // creates aforementionned plans 152 NavalManager.prototype.createPlans = function(gameState) {155 m.NavalManager.prototype.createPlans = function(gameState) { 153 156 var startID = {}; 154 157 155 158 for (i in this.askedPlans) … … 178 181 }; 179 182 180 183 // TODO: work on this. 181 NavalManager.prototype.maintainFleet = function(gameState, queues, events) {184 m.NavalManager.prototype.maintainFleet = function(gameState, queues, events) { 182 185 // check if we have enough transport ships. 183 186 // check per region. 184 187 for (var i = 0; i < this.seaShips.length; ++i) … … 188 191 && tpNb + queues.ships.length() === 0 && gameState.getTemplate(gameState.applyCiv("units/{civ}_ship_bireme")).available(gameState)) 189 192 { 190 193 // TODO: check our dock can build the wanted ship types, for Carthage. 191 queues.ships.addItem(new TrainingPlan(gameState, "units/{civ}_ship_bireme", { "sea" : i }, 1, 0, -1, 1 ));194 queues.ships.addItem(new m.TrainingPlan(gameState, "units/{civ}_ship_bireme", { "sea" : i }, 1, 0, -1, 1 )); 192 195 } 193 196 } 194 197 }; 195 198 196 199 // bumps up the number of ships we want if we need more. 197 NavalManager.prototype.checkLevels = function(gameState, queues) {200 m.NavalManager.prototype.checkLevels = function(gameState, queues) { 198 201 if (queues.ships.length() !== 0) 199 202 return; 200 203 for (var i = 0; i < this.transportPlans.length; ++i) … … 214 217 }; 215 218 216 219 // assigns free ships to plans that need some 217 NavalManager.prototype.assignToPlans = function(gameState, queues, events) {220 m.NavalManager.prototype.assignToPlans = function(gameState, queues, events) { 218 221 for (var i = 0; i < this.transportPlans.length; ++i) 219 222 { 220 223 var plan = this.transportPlans[i]; … … 228 231 { 229 232 if (!ship.getMetadata(PlayerID, "tpplan")) 230 233 { 231 debug ("Assigning ship " + ship.id() + " to plan" + plan.ID);234 m.debug ("Assigning ship " + ship.id() + " to plan" + plan.ID); 232 235 plan.assignShip(gameState, ship); 233 236 return true; 234 237 } … … 239 242 return false; 240 243 }; 241 244 242 NavalManager.prototype.checkActivePlan = function(ID) {245 m.NavalManager.prototype.checkActivePlan = function(ID) { 243 246 for (var i = 0; i < this.transportPlans.length; ++i) 244 247 if (this.transportPlans[i].ID === ID) 245 248 return true; … … 249 252 250 253 // Some functions are run every turn 251 254 // Others once in a while 252 NavalManager.prototype.update = function(gameState, queues, events) {255 m.NavalManager.prototype.update = function(gameState, queues, events) { 253 256 Engine.ProfileStart("Naval Manager update"); 254 257 255 258 this.checkEvents(gameState, queues, events); … … 286 289 } 287 290 Engine.ProfileStop(); 288 291 }; 292 293 return m; 294 }(AEGIS); -
source/simulation2/components/CCmpAIManager.cpp
78 78 NONCOPYABLE(CAIPlayer); 79 79 public: 80 80 CAIPlayer(CAIWorker& worker, const std::wstring& aiName, player_id_t player, uint8_t difficulty, 81 const shared_ptr<ScriptRuntime>& runtime, boost::rand48& rng) :82 m_Worker(worker), m_AIName(aiName), m_Player(player), m_Difficulty(difficulty), m_ScriptInterface( "Engine", "AI", runtime)81 shared_ptr<ScriptInterface> scriptInterface) : 82 m_Worker(worker), m_AIName(aiName), m_Player(player), m_Difficulty(difficulty), m_ScriptInterface(scriptInterface) 83 83 { 84 m_ScriptInterface.SetCallbackData(static_cast<void*> (this));85 86 m_ScriptInterface.ReplaceNondeterministicRNG(rng);87 m_ScriptInterface.LoadGlobalScripts();88 89 m_ScriptInterface.RegisterFunction<void, std::wstring, CAIPlayer::IncludeModule>("IncludeModule");90 m_ScriptInterface.RegisterFunction<void, CAIPlayer::DumpHeap>("DumpHeap");91 m_ScriptInterface.RegisterFunction<void, CAIPlayer::ForceGC>("ForceGC");92 m_ScriptInterface.RegisterFunction<void, CScriptValRooted, CAIPlayer::PostCommand>("PostCommand");93 94 m_ScriptInterface.RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIPlayer::DumpImage>("DumpImage");95 96 m_ScriptInterface.RegisterFunction<void, std::wstring, CScriptVal, CAIPlayer::RegisterSerializablePrototype>("RegisterSerializablePrototype");97 84 } 98 85 99 86 ~CAIPlayer() … … 103 90 m_Commands.clear(); 104 91 } 105 92 106 static void IncludeModule(void* cbdata, std::wstring name)107 {108 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);109 110 self->LoadScripts(name);111 }112 static void DumpHeap(void* cbdata)113 {114 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);115 116 //std::cout << JS_GetGCParameter(self->m_ScriptInterface.GetRuntime(), JSGC_BYTES) << std::endl;117 self->m_ScriptInterface.DumpHeap();118 }119 static void ForceGC(void* cbdata)120 {121 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);122 123 JS_GC(self->m_ScriptInterface.GetContext());124 }125 static void PostCommand(void* cbdata, CScriptValRooted cmd)126 {127 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);128 129 self->m_Commands.push_back(self->m_ScriptInterface.WriteStructuredClone(cmd.get()));130 }131 132 /**133 * Debug function for AI scripts to dump 2D array data (e.g. terrain tile weights).134 * TODO: check if this needs to be here too.135 */136 static void DumpImage(void* UNUSED(cbdata), std::wstring name, std::vector<u32> data, u32 w, u32 h, u32 max)137 {138 // TODO: this is totally not threadsafe.139 140 VfsPath filename = L"screenshots/aidump/" + name;141 142 if (data.size() != w*h)143 {144 debug_warn(L"DumpImage: data size doesn't match w*h");145 return;146 }147 148 if (max == 0)149 {150 debug_warn(L"DumpImage: max must not be 0");151 return;152 }153 154 const size_t bpp = 8;155 int flags = TEX_BOTTOM_UP|TEX_GREY;156 157 const size_t img_size = w * h * bpp/8;158 const size_t hdr_size = tex_hdr_size(filename);159 shared_ptr<u8> buf;160 AllocateAligned(buf, hdr_size+img_size, maxSectorSize);161 Tex t;162 if (tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0)163 return;164 165 u8* img = buf.get() + hdr_size;166 for (size_t i = 0; i < data.size(); ++i)167 img[i] = (u8)((data[i] * 255) / max);168 169 tex_write(&t, filename);170 tex_free(&t);171 }172 173 static void RegisterSerializablePrototype(void* cbdata, std::wstring name, CScriptVal proto)174 {175 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);176 // Add our player number to avoid name conflicts with other prototypes177 // TODO: it would be better if serializable prototypes were stored in ScriptInterfaces178 // and then each serializer would access those matching its own context, but that's179 // not possible with AIs sharing data across contexts180 std::wstringstream protoID;181 protoID << self->m_Player << L"." << name.c_str();182 self->m_Worker.RegisterSerializablePrototype(protoID.str(), proto);183 }184 185 bool LoadScripts(const std::wstring& moduleName)186 {187 // Ignore modules that are already loaded188 if (m_LoadedModules.find(moduleName) != m_LoadedModules.end())189 return true;190 191 // Mark this as loaded, to prevent it recursively loading itself192 m_LoadedModules.insert(moduleName);193 194 // Load and execute *.js195 VfsPaths pathnames;196 vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames);197 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)198 {199 if (!m_ScriptInterface.LoadGlobalScriptFile(*it))200 {201 LOGERROR(L"Failed to load script %ls", it->string().c_str());202 return false;203 }204 }205 206 return true;207 }208 209 93 bool Initialise(bool callConstructor) 210 94 { 211 if (!LoadScripts(m_AIName)) 95 // LoadScripts will only load each script once even though we call it for each player 96 if (!m_Worker.LoadScripts(m_AIName)) 212 97 return false; 213 98 214 99 OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; … … 220 105 } 221 106 222 107 // Get the constructor name from the metadata 108 // If the AI doesn't use modules, we look for the constructor in the global object 109 // TODO: All AIs should use modules. Remove the condition if this requirement is met. 110 std::string moduleName; 223 111 std::string constructor; 224 if (!m_ScriptInterface.GetProperty(metadata.get(), "constructor", constructor)) 112 CScriptVal objectWithConstructor; // object that should contain the cosntructor fucntion 113 CScriptVal ctor; 114 if (!m_ScriptInterface->HasProperty(metadata.get(), "moduleName")) 225 115 { 116 objectWithConstructor = m_ScriptInterface->GetGlobalObject(); 117 } 118 else 119 { 120 m_ScriptInterface->GetProperty(metadata.get(), "moduleName", moduleName); 121 if(!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), moduleName.c_str(), objectWithConstructor) || objectWithConstructor.undefined()) 122 { 123 LOGERROR(L"Failed to create AI player: %ls: can't find the module that should contain the constructor: '%hs'", path.string().c_str(), moduleName.c_str()); 124 return false; 125 } 126 } 127 if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor)) 128 { 226 129 LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); 227 130 return false; 228 131 } 229 132 230 133 // Get the constructor function from the loaded scripts 231 CScriptVal ctor; 232 if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor) 134 if (!m_ScriptInterface->GetProperty(objectWithConstructor.get(), constructor.c_str(), ctor) 233 135 || ctor.undefined()) 234 136 { 235 137 LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); 236 138 return false; 237 139 } 238 140 239 m_ScriptInterface .GetProperty(metadata.get(), "useShared", m_UseSharedComponent);141 m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent); 240 142 241 143 CScriptVal obj; 242 144 … … 244 146 { 245 147 // Set up the data to pass as the constructor argument 246 148 CScriptVal settings; 247 m_ScriptInterface .Eval(L"({})", settings);248 m_ScriptInterface .SetProperty(settings.get(), "player", m_Player, false);249 m_ScriptInterface .SetProperty(settings.get(), "difficulty", m_Difficulty, false);149 m_ScriptInterface->Eval(L"({})", settings); 150 m_ScriptInterface->SetProperty(settings.get(), "player", m_Player, false); 151 m_ScriptInterface->SetProperty(settings.get(), "difficulty", m_Difficulty, false); 250 152 ENSURE(m_Worker.m_HasLoadedEntityTemplates); 251 m_ScriptInterface .SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false);153 m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); 252 154 253 obj = m_ScriptInterface .CallConstructor(ctor.get(), settings.get());155 obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get()); 254 156 } 255 157 else 256 158 { 257 159 // For deserialization, we want to create the object with the correct prototype 258 160 // but don't want to actually run the constructor again 259 161 // XXX: actually we don't currently use this path for deserialization - maybe delete it? 260 obj = m_ScriptInterface .NewObjectFromConstructor(ctor.get());162 obj = m_ScriptInterface->NewObjectFromConstructor(ctor.get()); 261 163 } 262 164 263 165 if (obj.undefined()) … … 266 168 return false; 267 169 } 268 170 269 m_Obj = CScriptValRooted(m_ScriptInterface .GetContext(), obj);171 m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj); 270 172 return true; 271 173 } 272 174 273 void Run(CScriptVal state )175 void Run(CScriptVal state, int playerID) 274 176 { 275 177 m_Commands.clear(); 276 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "HandleMessage", state);178 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID); 277 179 } 278 180 // overloaded with a sharedAI part. 279 181 // javascript can handle both natively on the same function. 280 void Run(CScriptVal state, CScriptValRooted SharedAI)182 void Run(CScriptVal state, int playerID, CScriptValRooted SharedAI) 281 183 { 282 184 m_Commands.clear(); 283 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "HandleMessage", state, SharedAI);185 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID, SharedAI); 284 186 } 285 187 void InitAI(CScriptVal state, CScriptValRooted SharedAI) 286 188 { 287 189 m_Commands.clear(); 288 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "Init", state, SharedAI);190 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "Init", state, m_Player, SharedAI); 289 191 } 290 192 291 193 CAIWorker& m_Worker; … … 294 196 uint8_t m_Difficulty; 295 197 bool m_UseSharedComponent; 296 198 297 ScriptInterfacem_ScriptInterface;199 shared_ptr<ScriptInterface> m_ScriptInterface; 298 200 CScriptValRooted m_Obj; 299 201 std::vector<shared_ptr<ScriptInterface::StructuredClone> > m_Commands; 300 std::set<std::wstring> m_LoadedModules;301 202 }; 302 203 303 204 public: … … 313 214 // removed as soon whenever the new pathfinder is committed 314 215 // And the AIs can stop relying on their own little hands. 315 216 m_ScriptRuntime(ScriptInterface::CreateRuntime(33554432)), 316 m_ScriptInterface( "Engine", "AI", m_ScriptRuntime),217 m_ScriptInterface(new ScriptInterface("Engine", "AI", m_ScriptRuntime)), 317 218 m_TurnNum(0), 318 219 m_CommandsComputed(true), 319 220 m_HasLoadedEntityTemplates(false), … … 321 222 { 322 223 323 224 // TODO: ought to seed the RNG (in a network-synchronised way) before we use it 324 m_ScriptInterface .ReplaceNondeterministicRNG(m_RNG);325 m_ScriptInterface .LoadGlobalScripts();225 m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG); 226 m_ScriptInterface->LoadGlobalScripts(); 326 227 327 m_ScriptInterface .SetCallbackData(NULL);228 m_ScriptInterface->SetCallbackData(static_cast<void*> (this)); 328 229 329 m_ScriptInterface.RegisterFunction<void, CScriptValRooted, CAIWorker::PostCommand>("PostCommand"); 330 m_ScriptInterface.RegisterFunction<void, CAIWorker::DumpHeap>("DumpHeap"); 331 m_ScriptInterface.RegisterFunction<void, CAIWorker::ForceGC>("ForceGC"); 230 m_ScriptInterface->RegisterFunction<void, int, CScriptValRooted, CAIWorker::PostCommand>("PostCommand"); 231 m_ScriptInterface->RegisterFunction<void, std::wstring, CAIWorker::IncludeModule>("IncludeModule"); 232 m_ScriptInterface->RegisterFunction<void, CAIWorker::DumpHeap>("DumpHeap"); 233 m_ScriptInterface->RegisterFunction<void, CAIWorker::ForceGC>("ForceGC"); 332 234 333 m_ScriptInterface .RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIWorker::DumpImage>("DumpImage");235 m_ScriptInterface->RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIWorker::DumpImage>("DumpImage"); 334 236 } 335 237 336 238 ~CAIWorker() … … 343 245 m_PassabilityMapVal = CScriptValRooted(); 344 246 m_TerritoryMapVal = CScriptValRooted(); 345 247 } 248 249 bool LoadScripts(const std::wstring& moduleName) 250 { 251 // Ignore modules that are already loaded 252 if (m_LoadedModules.find(moduleName) != m_LoadedModules.end()) 253 return true; 346 254 347 // This is called by AIs if they use the v3 API. 348 // If the AIs originate the call, cbdata is not NULL. 349 // If the shared component does, it is, so it must not be taken into account. 350 static void PostCommand(void* cbdata, CScriptValRooted cmd) 255 // Mark this as loaded, to prevent it recursively loading itself 256 m_LoadedModules.insert(moduleName); 257 258 // Load and execute *.js 259 VfsPaths pathnames; 260 vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames); 261 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it) 262 { 263 if (!m_ScriptInterface->LoadGlobalScriptFile(*it)) 264 { 265 LOGERROR(L"Failed to load script %ls", it->string().c_str()); 266 return false; 267 } 268 } 269 270 return true; 271 } 272 273 static void IncludeModule(void* cbdata, std::wstring name) 351 274 { 352 if (cbdata == NULL) { 353 debug_warn(L"Warning: the shared component has tried to push an engine command. Ignoring."); 354 return; 275 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 276 self->LoadScripts(name); 277 } 278 279 static void PostCommand(void* cbdata, int playerid, CScriptValRooted cmd) 280 { 281 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 282 self->PostCommand(playerid, cmd); 283 } 284 285 void PostCommand(int playerid, CScriptValRooted cmd) 286 { 287 bool playerFound = false; 288 for (size_t i=0; i<m_Players.size(); i++) 289 { 290 if (m_Players[i]->m_Player == playerid) 291 { 292 m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd.get())); 293 playerFound = true; 294 } 355 295 } 356 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata); 357 self->m_Commands.push_back(self->m_ScriptInterface.WriteStructuredClone(cmd.get())); 296 297 if (!playerFound) 298 LOGERROR(L"Invalid playerid in PostCommand!"); 358 299 } 359 300 // The next two ought to be implmeneted someday but for now as it returns "null" it can't 360 301 static void DumpHeap(void* cbdata) … … 364 305 return; 365 306 } 366 307 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 367 self->m_ScriptInterface .DumpHeap();308 self->m_ScriptInterface->DumpHeap(); 368 309 } 369 310 static void ForceGC(void* cbdata) 370 311 { … … 374 315 } 375 316 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 376 317 PROFILE3("AI compute GC"); 377 JS_GC(self->m_ScriptInterface .GetContext());318 JS_GC(self->m_ScriptInterface->GetContext()); 378 319 } 379 320 380 321 /** … … 424 365 425 366 // reset the value so it can be used to determine if we actually initialized it. 426 367 m_HasSharedComponent = false; 427 428 VfsPaths sharedPathnames; 429 // Check for "shared" module. 430 vfs::GetPathnames(g_VFS, L"simulation/ai/common-api-v3/", L"*.js", sharedPathnames); 431 for (VfsPaths::iterator it = sharedPathnames.begin(); it != sharedPathnames.end(); ++it) 432 { 433 if (!m_ScriptInterface.LoadGlobalScriptFile(*it)) 434 { 435 LOGERROR(L"Failed to load shared script %ls", it->string().c_str()); 436 return false; 437 } 368 369 if (LoadScripts(L"common-api-v3")) 438 370 m_HasSharedComponent = true; 439 } 440 if (!m_HasSharedComponent) 371 else 441 372 return false; 442 373 443 374 // mainly here for the error messages 444 375 OsPath path = L"simulation/ai/common-api-v2/"; 445 376 446 // Constructor name is SharedScript 377 // Constructor name is SharedScript, it's in the module API3 378 // TODO: Hardcoding this is bad, we need a smarter way. 379 CScriptVal AIModule; 447 380 CScriptVal ctor; 448 if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), "SharedScript", ctor) 381 if (!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), "API3", AIModule) || AIModule.undefined()) 382 { 383 LOGERROR(L"Failed to create shared AI component: %ls: can't find module '%hs'", path.string().c_str(), "API3"); 384 return false; 385 } 386 387 if (!m_ScriptInterface->GetProperty(AIModule.get(), "SharedScript", ctor) 449 388 || ctor.undefined()) 450 389 { 451 390 LOGERROR(L"Failed to create shared AI component: %ls: can't find constructor '%hs'", path.string().c_str(), "SharedScript"); … … 454 393 455 394 // Set up the data to pass as the constructor argument 456 395 CScriptVal settings; 457 m_ScriptInterface .Eval(L"({})", settings);396 m_ScriptInterface->Eval(L"({})", settings); 458 397 CScriptVal playersID; 459 m_ScriptInterface .Eval(L"({})", playersID);398 m_ScriptInterface->Eval(L"({})", playersID); 460 399 461 400 for (size_t i = 0; i < m_Players.size(); ++i) 462 401 { 463 jsval val = m_ScriptInterface .ToJSVal(m_ScriptInterface.GetContext(), m_Players[i]->m_Player);464 m_ScriptInterface .SetPropertyInt(playersID.get(), i, CScriptVal(val), true);402 jsval val = m_ScriptInterface->ToJSVal(m_ScriptInterface->GetContext(), m_Players[i]->m_Player); 403 m_ScriptInterface->SetPropertyInt(playersID.get(), i, CScriptVal(val), true); 465 404 } 466 405 467 m_ScriptInterface .SetProperty(settings.get(), "players", playersID);406 m_ScriptInterface->SetProperty(settings.get(), "players", playersID); 468 407 ENSURE(m_HasLoadedEntityTemplates); 469 m_ScriptInterface .SetProperty(settings.get(), "templates", m_EntityTemplates, false);408 m_ScriptInterface->SetProperty(settings.get(), "templates", m_EntityTemplates, false); 470 409 471 410 if (hasTechs) 472 411 { 473 m_ScriptInterface .SetProperty(settings.get(), "techTemplates", m_TechTemplates, false);412 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", m_TechTemplates, false); 474 413 } 475 414 else 476 415 { 477 416 // won't get the tech templates directly. 478 417 CScriptVal fakeTech; 479 m_ScriptInterface .Eval("({})", fakeTech);480 m_ScriptInterface .SetProperty(settings.get(), "techTemplates", fakeTech, false);418 m_ScriptInterface->Eval("({})", fakeTech); 419 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", fakeTech, false); 481 420 } 482 m_SharedAIObj = CScriptValRooted(m_ScriptInterface .GetContext(),m_ScriptInterface.CallConstructor(ctor.get(), settings.get()));421 m_SharedAIObj = CScriptValRooted(m_ScriptInterface->GetContext(),m_ScriptInterface->CallConstructor(ctor.get(), settings.get())); 483 422 484 423 485 424 if (m_SharedAIObj.undefined()) … … 493 432 494 433 bool AddPlayer(const std::wstring& aiName, player_id_t player, uint8_t difficulty, bool callConstructor) 495 434 { 496 shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_Script Runtime, m_RNG));435 shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_ScriptInterface)); 497 436 if (!ai->Initialise(callConstructor)) 498 437 return false; 499 438 … … 501 440 if (!m_HasSharedComponent) 502 441 m_HasSharedComponent = ai->m_UseSharedComponent; 503 442 504 m_ScriptInterface .MaybeGC();443 m_ScriptInterface->MaybeGC(); 505 444 506 445 m_Players.push_back(ai); 507 446 … … 513 452 // this will be run last by InitGame.Js, passing the full game representation. 514 453 // For now it will run for the shared Component. 515 454 // This is NOT run during deserialization. 516 CScriptVal state = m_ScriptInterface .ReadStructuredClone(gameState);517 JSContext* cx = m_ScriptInterface .GetContext();455 CScriptVal state = m_ScriptInterface->ReadStructuredClone(gameState); 456 JSContext* cx = m_ScriptInterface->GetContext(); 518 457 519 458 m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, passabilityMap)); 520 459 m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, territoryMap)); 521 460 if (m_HasSharedComponent) 522 461 { 523 m_ScriptInterface .SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);524 m_ScriptInterface .SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);462 m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true); 463 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 525 464 526 m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "init", state);527 m_ScriptInterface .MaybeGC();465 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state); 466 m_ScriptInterface->MaybeGC(); 528 467 529 468 for (size_t i = 0; i < m_Players.size(); ++i) 530 469 { … … 545 484 { 546 485 m_PassabilityMap = passabilityMap; 547 486 548 JSContext* cx = m_ScriptInterface .GetContext();487 JSContext* cx = m_ScriptInterface->GetContext(); 549 488 m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_PassabilityMap)); 550 489 } 551 490 … … 553 492 { 554 493 m_TerritoryMap = territoryMap; 555 494 556 JSContext* cx = m_ScriptInterface .GetContext();495 JSContext* cx = m_ScriptInterface->GetContext(); 557 496 m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_TerritoryMap)); 558 497 } 559 498 … … 583 522 } 584 523 585 524 void RegisterTechTemplates(const shared_ptr<ScriptInterface::StructuredClone>& techTemplates) { 586 JSContext* cx = m_ScriptInterface .GetContext();587 m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface .ReadStructuredClone(techTemplates));525 JSContext* cx = m_ScriptInterface->GetContext(); 526 m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface->ReadStructuredClone(techTemplates)); 588 527 } 589 528 590 529 void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates) 591 530 { 592 531 m_HasLoadedEntityTemplates = true; 593 532 594 m_ScriptInterface .Eval("({})", m_EntityTemplates);533 m_ScriptInterface->Eval("({})", m_EntityTemplates); 595 534 596 535 for (size_t i = 0; i < templates.size(); ++i) 597 536 { 598 jsval val = templates[i].second->ToJSVal(m_ScriptInterface .GetContext(), false);599 m_ScriptInterface .SetProperty(m_EntityTemplates.get(), templates[i].first.c_str(), CScriptVal(val), true);537 jsval val = templates[i].second->ToJSVal(m_ScriptInterface->GetContext(), false); 538 m_ScriptInterface->SetProperty(m_EntityTemplates.get(), templates[i].first.c_str(), CScriptVal(val), true); 600 539 } 601 540 602 541 // Since the template data is shared between AI players, freeze it 603 542 // to stop any of them changing it and confusing the other players 604 m_ScriptInterface .FreezeObject(m_EntityTemplates.get(), true);543 m_ScriptInterface->FreezeObject(m_EntityTemplates.get(), true); 605 544 } 606 545 607 546 void Serialize(std::ostream& stream, bool isDebug) … … 610 549 611 550 if (isDebug) 612 551 { 613 CDebugSerializer serializer( m_ScriptInterface, stream);552 CDebugSerializer serializer(*m_ScriptInterface, stream); 614 553 serializer.Indent(4); 615 554 SerializeState(serializer); 616 555 } 617 556 else 618 557 { 619 CStdSerializer serializer( m_ScriptInterface, stream);558 CStdSerializer serializer(*m_ScriptInterface, stream); 620 559 // TODO: see comment in Deserialize() 621 560 serializer.SetSerializablePrototypes(m_SerializablePrototypes); 622 561 SerializeState(serializer); … … 637 576 if (m_HasSharedComponent) 638 577 { 639 578 CScriptVal sharedData; 640 if (!m_ScriptInterface .CallFunction(m_SharedAIObj.get(), "Serialize", sharedData))579 if (!m_ScriptInterface->CallFunction(m_SharedAIObj.get(), "Serialize", sharedData)) 641 580 LOGERROR(L"AI shared script Serialize call failed"); 642 581 serializer.ScriptVal("sharedData", sharedData); 643 582 } … … 650 589 serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size()); 651 590 for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j) 652 591 { 653 CScriptVal val = m_ScriptInterface .ReadStructuredClone(m_Players[i]->m_Commands[j]);592 CScriptVal val = m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j]); 654 593 serializer.ScriptVal("command", val); 655 594 } 656 595 657 bool hasCustomSerialize = m_ScriptInterface .HasProperty(m_Players[i]->m_Obj.get(), "Serialize");596 bool hasCustomSerialize = m_ScriptInterface->HasProperty(m_Players[i]->m_Obj.get(), "Serialize"); 658 597 if (hasCustomSerialize) 659 598 { 660 599 CScriptVal scriptData; 661 if (!m_ScriptInterface .CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData))600 if (!m_ScriptInterface->CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData)) 662 601 LOGERROR(L"AI script Serialize call failed"); 663 602 serializer.ScriptVal("data", scriptData); 664 603 } … … 673 612 { 674 613 ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad 675 614 676 CStdDeserializer deserializer( m_ScriptInterface, stream);615 CStdDeserializer deserializer(*m_ScriptInterface, stream); 677 616 678 617 m_PlayerMetadata.clear(); 679 618 m_Players.clear(); … … 695 634 { 696 635 CScriptVal sharedData; 697 636 deserializer.ScriptVal("sharedData", sharedData); 698 if (!m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData))637 if (!m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData)) 699 638 LOGERROR(L"AI shared script Deserialize call failed"); 700 639 } 701 640 … … 717 656 { 718 657 CScriptVal val; 719 658 deserializer.ScriptVal("command", val); 720 m_Players.back()->m_Commands.push_back(m_ScriptInterface .WriteStructuredClone(val.get()));659 m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val.get())); 721 660 } 722 661 723 662 // TODO: this is yucky but necessary while the AIs are sharing data between contexts; … … 726 665 // prototypes could be stored in their ScriptInterface 727 666 deserializer.SetSerializablePrototypes(m_DeserializablePrototypes); 728 667 729 bool hasCustomDeserialize = m_ScriptInterface .HasProperty(m_Players.back()->m_Obj.get(), "Deserialize");668 bool hasCustomDeserialize = m_ScriptInterface->HasProperty(m_Players.back()->m_Obj.get(), "Deserialize"); 730 669 if (hasCustomDeserialize) 731 670 { 732 671 CScriptVal scriptData; 733 672 deserializer.ScriptVal("data", scriptData); 734 673 if (m_Players[i]->m_UseSharedComponent) 735 674 { 736 if (!m_ScriptInterface .CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData, m_SharedAIObj))675 if (!m_ScriptInterface->CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData, m_SharedAIObj)) 737 676 LOGERROR(L"AI script Deserialize call failed"); 738 677 } 739 else if (!m_ScriptInterface .CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData))678 else if (!m_ScriptInterface->CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData)) 740 679 { 741 680 LOGERROR(L"AI script deserialize() call failed"); 742 681 } … … 770 709 if (m_PlayerMetadata.find(path) == m_PlayerMetadata.end()) 771 710 { 772 711 // Load and cache the AI player metadata 773 m_PlayerMetadata[path] = m_ScriptInterface .ReadJSONFile(path);712 m_PlayerMetadata[path] = m_ScriptInterface->ReadJSONFile(path); 774 713 } 775 714 776 715 return m_PlayerMetadata[path]; … … 786 725 if (m_TurnNum++ % 50 == 0) 787 726 { 788 727 PROFILE3("AI compute GC"); 789 m_ScriptInterface .MaybeGC();728 m_ScriptInterface->MaybeGC(); 790 729 } 791 730 return; 792 731 } … … 795 734 CScriptVal state; 796 735 { 797 736 PROFILE3("AI compute read state"); 798 state = m_ScriptInterface .ReadStructuredClone(m_GameState);799 m_ScriptInterface .SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);800 m_ScriptInterface .SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);737 state = m_ScriptInterface->ReadStructuredClone(m_GameState); 738 m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true); 739 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 801 740 } 802 741 803 742 // It would be nice to do 804 // m_ScriptInterface .FreezeObject(state.get(), true);743 // m_ScriptInterface->FreezeObject(state.get(), true); 805 744 // to prevent AI scripts accidentally modifying the state and 806 745 // affecting other AI scripts they share it with. But the performance 807 746 // cost is far too high, so we won't do that. … … 810 749 if (m_HasSharedComponent) 811 750 { 812 751 PROFILE3("AI run shared component"); 813 m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state);752 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state); 814 753 } 815 754 816 755 for (size_t i = 0; i < m_Players.size(); ++i) … … 818 757 PROFILE3("AI script"); 819 758 PROFILE2_ATTR("player: %d", m_Players[i]->m_Player); 820 759 PROFILE2_ATTR("script: %ls", m_Players[i]->m_AIName.c_str()); 760 821 761 if (m_HasSharedComponent && m_Players[i]->m_UseSharedComponent) 822 m_Players[i]->Run(state, m_SharedAIObj);762 m_Players[i]->Run(state, m_Players[i]->m_Player, m_SharedAIObj); 823 763 else 824 m_Players[i]->Run(state );764 m_Players[i]->Run(state, m_Players[i]->m_Player); 825 765 } 826 766 827 767 // Run GC if we are about to overflow 828 if (JS_GetGCParameter(m_ScriptInterface .GetRuntime(), JSGC_BYTES) > 33000000)768 if (JS_GetGCParameter(m_ScriptInterface->GetRuntime(), JSGC_BYTES) > 33000000) 829 769 { 830 770 PROFILE3("AI compute GC"); 831 771 832 JS_GC(m_ScriptInterface .GetContext());772 JS_GC(m_ScriptInterface->GetContext()); 833 773 } 834 774 835 775 // Run the GC every so often. … … 838 778 /*if (m_TurnNum++ % 20 == 0) 839 779 { 840 780 PROFILE3("AI compute GC"); 841 m_ScriptInterface .MaybeGC();781 m_ScriptInterface->MaybeGC(); 842 782 }*/ 843 783 } 844 784 845 785 shared_ptr<ScriptRuntime> m_ScriptRuntime; 846 ScriptInterfacem_ScriptInterface;786 shared_ptr<ScriptInterface> m_ScriptInterface; 847 787 boost::rand48 m_RNG; 848 788 u32 m_TurnNum; 849 789 … … 858 798 CScriptValRooted m_SharedAIObj; 859 799 std::vector<SCommandSets> m_Commands; 860 800 801 std::set<std::wstring> m_LoadedModules; 802 861 803 shared_ptr<ScriptInterface::StructuredClone> m_GameState; 862 804 Grid<u16> m_PassabilityMap; 863 805 CScriptValRooted m_PassabilityMapVal;