Ticket #2322: AI_in_one_global_WIP_v0.3.diff
File AI_in_one_global_WIP_v0.3.diff, 213.7 KB (added by , 10 years ago) |
---|
-
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-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-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/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/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/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/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/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/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/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/aegis/worker.js
199 199 }; 200 200 201 201 Worker.prototype.startGathering = function(baseManager, gameState) { 202 202 203 var resource = this.ent.getMetadata(PlayerID, "gather-type"); 203 204 var ent = this.ent; 204 205 var self = this; … … 245 246 return; 246 247 if (dropsite.position() && (baseManager.dropsites[dropsite.id()][resource][4] > 1000 || (number === 1 && baseManager.dropsites[dropsite.id()][resource][4] > 200) ) 247 248 && baseManager.dropsites[dropsite.id()][resource][5].length < maxPerDP) { 248 var dist = SquareVectorDistance(ent.position(), dropsite.position());249 var dist = API3.SquareVectorDistance(ent.position(), dropsite.position()); 249 250 if (dist < minDropsiteDist){ 250 251 minDropsiteDist = dist; 251 252 nearestResources = baseManager.dropsites[dropsite.id()][resource][1]; … … 254 255 } 255 256 }); 256 257 } 258 257 259 // we've found no fitting dropsites close enough from us. 258 260 // So'll try with far away. 259 261 if (!nearestResources || nearestResources.length === 0) { … … 262 264 return; 263 265 if (dropsite.position() && baseManager.dropsites[dropsite.id()][resource][4] > 400 264 266 && baseManager.dropsites[dropsite.id()][resource][5].length < maxPerDP) { 265 var dist = SquareVectorDistance(ent.position(), dropsite.position());267 var dist = API3.SquareVectorDistance(ent.position(), dropsite.position()); 266 268 if (dist < minDropsiteDist){ 267 269 minDropsiteDist = dist; 268 270 nearestResources = baseManager.dropsites[dropsite.id()][resource][1]; … … 271 273 } 272 274 }); 273 275 } 274 276 275 277 if (!nearestResources || nearestResources.length === 0){ 276 278 if (resource === "food") 277 279 if (this.buildAnyField(gameState)) … … 353 355 // some simple check for chickens: if they're in a square that's inaccessible, we won't gather from them. 354 356 if (supply.footprintRadius() < 1) 355 357 { 356 var fakeMap = new Map(gameState.sharedScript,gameState.getMap().data);358 var fakeMap = new API3.Map(gameState.sharedScript,gameState.getMap().data); 357 359 var id = fakeMap.gamePosToMapPos(supply.position())[0] + fakeMap.width*fakeMap.gamePosToMapPos(supply.position())[1]; 358 360 if ( (gameState.sharedScript.passabilityClasses["pathfinderObstruction"] & gameState.getMap().data[id]) ) 359 361 { … … 363 365 } 364 366 365 367 // measure the distance to the resource (largely irrelevant) 366 var dist = SquareVectorDistance(supply.position(), ent.position());368 var dist = API3.SquareVectorDistance(supply.position(), ent.position()); 367 369 368 370 if (dist > 4900 && supply.hasClass("Animal")) 369 371 return; 370 372 371 373 // Add on a factor for the nearest dropsite if one exists 372 374 if (nearestDropsite !== undefined ){ 373 dist += 4* SquareVectorDistance(supply.position(), nearestDropsite.position());375 dist += 4*API3.SquareVectorDistance(supply.position(), nearestDropsite.position()); 374 376 dist /= 5.0; 375 377 } 376 378 377 var territoryOwner = Map.createTerritoryMap(gameState).getOwner(supply.position());379 var territoryOwner = API3.Map.createTerritoryMap(gameState).getOwner(supply.position()); 378 380 if (territoryOwner != PlayerID && territoryOwner != 0) { 379 381 dist *= 5.0; 380 382 //return; … … 395 397 if (!nearestDropsite) { 396 398 ourDropsites.forEach(function (dropsite){ //}){ 397 399 if (dropsite.position()){ 398 var dist = SquareVectorDistance(pos, dropsite.position());400 var dist = API3.SquareVectorDistance(pos, dropsite.position()); 399 401 if (dist < minDropsiteDist){ 400 402 minDropsiteDist = dist; 401 403 nearestDropsite = dropsite; … … 411 413 412 414 // if the resource is far away, try to build a farm instead. 413 415 var tried = false; 414 if (resource === "food" && SquareVectorDistance(pos,this.ent.position()) > 22500)416 if (resource === "food" && API3.SquareVectorDistance(pos,this.ent.position()) > 22500) 415 417 { 416 418 tried = this.buildAnyField(gameState); 417 if (!tried && SquareVectorDistance(pos,this.ent.position()) > 62500) {419 if (!tried && API3.SquareVectorDistance(pos,this.ent.position()) > 62500) { 418 420 // TODO: ought to change behavior here. 419 421 return; // wait. a farm should appear. 420 422 } … … 429 431 else 430 432 gameState.turnCache["ressGathererNB"][nearestSupply.id()]++; 431 433 432 this.maxApproachTime = Math.max(30000, VectorDistance(pos,this.ent.position()) * 5000);434 this.maxApproachTime = Math.max(30000, API3.VectorDistance(pos,this.ent.position()) * 5000); 433 435 this.startApproachingResourceAmount = ent.resourceSupplyAmount(); 434 436 this.startEnt = ent.id(); 435 437 ent.gather(nearestSupply); … … 472 474 var dist = Math.min(); 473 475 gameState.getOwnDropsites(resource).forEach(function(dropsite){ 474 476 if (dropsite.position()){ 475 var d = SquareVectorDistance(self.ent.position(), dropsite.position());477 var d = API3.SquareVectorDistance(self.ent.position(), dropsite.position()); 476 478 if (d < dist){ 477 479 dist = d; 478 480 closestDropsite = dropsite; … … 522 524 return; 523 525 524 526 // measure the distance to the resource 525 var dist = SquareVectorDistance(supply.position(), ent.position());527 var dist = API3.SquareVectorDistance(supply.position(), ent.position()); 526 528 527 var territoryOwner = Map.createTerritoryMap(gameState).getOwner(supply.position());529 var territoryOwner = API3.Map.createTerritoryMap(gameState).getOwner(supply.position()); 528 530 if (territoryOwner != PlayerID && territoryOwner != 0) { 529 531 dist *= 3.0; 530 532 } … … 547 549 // find a fitting dropsites in case we haven't already. 548 550 gameState.getOwnDropsites("food").forEach(function (dropsite){ //}){ 549 551 if (dropsite.position()){ 550 var dist = SquareVectorDistance(pos, dropsite.position());552 var dist = API3.SquareVectorDistance(pos, dropsite.position()); 551 553 if (dist < minDropsiteDist){ 552 554 minDropsiteDist = dist; 553 555 nearestDropsite = dropsite; … … 612 614 Worker.prototype.buildAnyField = function(gameState){ 613 615 var self = this; 614 616 var okay = false; 615 var foundations = gameState.getOwnFoundations().filter( Filters.byMetadata(PlayerID,"base",this.baseID));617 var foundations = gameState.getOwnFoundations().filter(API3.Filters.byMetadata(PlayerID,"base",this.baseID)); 616 618 foundations.filterNearest(this.ent.position(), foundations.length); 617 619 foundations.forEach(function (found) { 618 620 if (found._template.BuildRestrictions.Category === "Field" && !okay) { -
binaries/data/mods/public/simulation/ai/aegis/attack_plan.js
6 6 * There is a basic support for naval expeditions here. 7 7 */ 8 8 9 function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) {9 function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy, type , targetFinder) { 10 10 11 this.Config = Config; 11 12 //This is the list of IDs of the units in the plan 12 13 this.idList=[]; 13 14 … … 33 34 return false; 34 35 } 35 36 36 var CCs = gameState.getOwnEntities().filter( Filters.byClass("CivCentre"));37 var CCs = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")); 37 38 if (CCs.length === 0) 38 39 { 39 40 this.failed = true; … … 50 51 51 52 this.maxPreparationTime = 210*1000; 52 53 // 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)54 if (type !== "superSized" && this.Config.difficulty >= 1) 54 55 this.maxPreparationTime = 780000 - gameState.getTimeElapsed() < 120000 ? 120000 : 780000 - gameState.getTimeElapsed(); 55 56 56 57 this.pausingStart = 0; … … 120 121 return (strength[0] > 15 || strength[1] > 15); 121 122 };*/ 122 123 123 var filter = Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID));124 var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)); 124 125 this.unitCollection = gameState.getOwnEntities().filter(filter); 125 126 this.unitCollection.registerUpdates(); 126 127 this.unitCollection.length; … … 136 137 var cat = unitCat; 137 138 var Unit = this.unitStat[cat]; 138 139 139 filter = Filters.and(Filters.byClassesAnd(Unit["classes"]),Filters.and(Filters.byMetadata(PlayerID, "plan",this.name),Filters.byOwner(PlayerID)));140 filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID))); 140 141 this.unit[cat] = gameState.getOwnEntities().filter(filter); 141 142 this.unit[cat].registerUpdates(); 142 143 this.unit[cat].length; … … 186 187 this.anyNotMinimal = true; // used for support plans 187 188 188 189 189 var myFortresses = gameState.getOwnTrainingFacilities().filter( Filters.byClass("GarrisonFortress"));190 var myFortresses = gameState.getOwnTrainingFacilities().filter(API3.Filters.byClass("GarrisonFortress")); 190 191 if (myFortresses.length !== 0) 191 192 { 192 193 // make this our rallypoint … … 241 242 //Engine.DumpHeap(); 242 243 243 244 // get a good path to an estimated target. 244 this.pathFinder = new aStarPath(gameState,false,false, this.targetPlayer);245 this.pathFinder = new API3.aStarPath(gameState,false,false, this.targetPlayer); 245 246 //Engine.DumpImage("widthmap.png", this.pathFinder.widthMap, this.pathFinder.width,this.pathFinder.height,255); 246 247 247 248 this.pathWidth = 6; // prefer a path far from entities. This will avoid units getting stuck in trees and also results in less straight paths. … … 316 317 // no minsize as we don't want the plan to fail at the last minute though. 317 318 this.unitStat[name] = unitStats; 318 319 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)));320 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 321 this.unit[name] = gameState.getOwnEntities().filter(filter); 321 322 this.unit[name].registerUpdates(); 322 323 this.buildOrder.push([0, Unit["classes"], this.unit[name], Unit, name]); … … 349 350 for (var i in targets._entities) 350 351 { 351 352 // we're sure it has a position has TargetFinder already checks that. 352 var dist = SquareVectorDistance(targets._entities[i].position(), this.rallyPoint);353 var dist = API3.SquareVectorDistance(targets._entities[i].position(), this.rallyPoint); 353 354 if (dist < maxDist || maxDist === -1) 354 355 { 355 356 maxDist = dist; … … 400 401 { 401 402 // my pathfinder returns arrays in arrays in arrays. 402 403 var waypointPos = this.path[i][0]; 403 var territory = Map.createTerritoryMap(gameState);404 var territory = API3.Map.createTerritoryMap(gameState); 404 405 if (territory.getOwner(waypointPos) !== PlayerID || this.path[i][1] === true) 405 406 { 406 407 // if we're suddenly out of our territory or this is the point where we change transportation method. … … 426 427 { 427 428 // my pathfinder returns arrays in arrays in arrays. 428 429 var waypointPos = this.path[i][0]; 429 var territory = Map.createTerritoryMap(gameState);430 var territory = API3.Map.createTerritoryMap(gameState); 430 431 if (territory.getOwner(waypointPos) !== PlayerID || this.path[i][1] === true) 431 432 { 432 433 // if we're suddenly out of our territory or this is the point where we change transportation method. … … 650 651 } 651 652 // no buildings, attack anything conquest critical, even units (it's assuming it won't move). 652 653 if (targets.length == 0) { 653 targets = gameState.getEnemyEntities().filter( Filters.and( Filters.byOwner(this.targetPlayer),Filters.byClass("ConquestCritical")));654 targets = gameState.getEnemyEntities().filter(API3.Filters.and( API3.Filters.byOwner(this.targetPlayer),API3.Filters.byClass("ConquestCritical"))); 654 655 } 655 656 return targets; 656 657 }; … … 701 702 702 703 this.unitCollection.move(this.path[0][0][0], this.path[0][0][1]); 703 704 this.unitCollection.setStance("aggressive"); 704 this.unitCollection.filter( Filters.byClass("Siege")).setStance("defensive");705 this.unitCollection.filter(API3.Filters.byClass("Siege")).setStance("defensive"); 705 706 706 707 this.state = "walking"; 707 708 } else { … … 750 751 751 752 if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0 && attacker.owner() != PlayerID) { 752 753 753 var territoryMap = Map.createTerritoryMap(gameState);754 var territoryMap = API3.Map.createTerritoryMap(gameState); 754 755 if ( +territoryMap.point(attacker.position()) - 64 === +this.targetPlayer) 755 756 { 756 757 attackedNB++; … … 844 845 } 845 846 846 847 // 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) {848 if (API3.SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0) { 848 849 // check for stuck siege units 849 850 850 var sieges = this.unitCollection.filter( Filters.byClass("Siege"));851 var sieges = this.unitCollection.filter(API3.Filters.byClass("Siege")); 851 852 var farthest = 0; 852 853 var farthestEnt = -1; 853 854 sieges.forEach (function (ent) { 854 if ( SquareVectorDistance(ent.position(),self.position) > farthest)855 if (API3.SquareVectorDistance(ent.position(),self.position) > farthest) 855 856 { 856 farthest = SquareVectorDistance(ent.position(),self.position);857 farthest = API3.SquareVectorDistance(ent.position(),self.position); 857 858 farthestEnt = ent; 858 859 } 859 860 }); … … 863 864 if (gameState.ai.playedTurn % 5 === 0) 864 865 this.position5TurnsAgo = this.position; 865 866 866 if (this.lastPosition && SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) {867 if (this.lastPosition && API3.SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) { 867 868 this.unitCollection.moveIndiv(this.path[0][0][0], this.path[0][0][1]); 868 869 // 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")));870 var walls = gameState.getEnemyEntities().filter(API3.Filters.and(API3.Filters.byOwner(this.targetPlayer), API3.Filters.byClass("StoneWall"))); 870 871 var nexttoWalls = false; 871 872 walls.forEach( function (ent) { 872 if (!nexttoWalls && SquareVectorDistance(self.position, ent.position()) < 800)873 if (!nexttoWalls && API3.SquareVectorDistance(self.position, ent.position()) < 800) 873 874 nexttoWalls = true; 874 875 }); 875 876 // there are walls but we can attack 876 if (nexttoWalls && this.unitCollection.filter( Filters.byCanAttack("StoneWall")).length !== 0)877 if (nexttoWalls && this.unitCollection.filter(API3.Filters.byCanAttack("StoneWall")).length !== 0) 877 878 { 878 879 debug ("Attack Plan " +this.type +" " +this.name +" has met walls and is not happy."); 879 880 this.state = "arrived"; … … 886 887 } 887 888 888 889 // 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)890 if (API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) < 7500 || 891 API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.path[0][0]) < 650) { 892 if (this.unitCollection.filter(API3.Filters.byClass("Siege")).length !== 0 893 && API3.SquareVectorDistance(this.unitCollection.getCentrePosition(), this.targetPos) >= 7500 894 && API3.SquareVectorDistance(this.unitCollection.filter(API3.Filters.byClass("Siege")).getCentrePosition(), this.path[0][0]) >= 650) 894 895 { 895 896 } else { 896 897 … … 989 990 if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0 && attacker.owner() != PlayerID) { 990 991 if (ourUnit.hasClass("Siege")) 991 992 { 992 var collec = this.unitCollection.filterNearest(ourUnit.position(), 8).filter( Filters.not(Filters.byClass("Siege"))).toEntityArray();993 var collec = this.unitCollection.filterNearest(ourUnit.position(), 8).filter(API3.Filters.not(API3.Filters.byClass("Siege"))).toEntityArray(); 993 994 if (collec.length !== 0) 994 995 { 995 996 collec[0].attack(attacker.id()); … … 1018 1019 this.unitCollUpdateArray = this.unitCollection.toIdArray(); 1019 1020 } else { 1020 1021 // some stuffs for locality and speed 1021 var territoryMap = Map.createTerritoryMap(gameState);1022 var territoryMap = API3.Map.createTerritoryMap(gameState); 1022 1023 var timeElapsed = gameState.getTimeElapsed(); 1023 1024 1024 1025 // Let's check a few units each time we update. Currently 10 … … 1057 1058 if (!enemy.position() || (enemy.hasClass("StoneWall") && ent.canAttackClass("StoneWall"))) { 1058 1059 return false; 1059 1060 } 1060 if ( SquareVectorDistance(enemy.position(),ent.position()) > 3000) {1061 if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 3000) { 1061 1062 return false; 1062 1063 } 1063 1064 return true; … … 1070 1071 } 1071 1072 if (!enemy.hasClass("Support")) 1072 1073 return false; 1073 if ( SquareVectorDistance(enemy.position(),ent.position()) > 10000) {1074 if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 10000) { 1074 1075 return false; 1075 1076 } 1076 1077 return true; … … 1081 1082 if (!enemy.position()) { 1082 1083 return false; 1083 1084 } 1084 if ( SquareVectorDistance(enemy.position(),ent.position()) > 10000) {1085 if (API3.SquareVectorDistance(enemy.position(),ent.position()) > 10000) { 1085 1086 return false; 1086 1087 } 1087 1088 return true; … … 1120 1121 ent.attack(mStruct[+rand].id()); 1121 1122 //debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName()); 1122 1123 } 1123 } else if ( SquareVectorDistance(self.targetPos, ent.position()) > 900 ){1124 } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ 1124 1125 //debug ("Siege units moving to " + uneval(self.targetPos)); 1125 1126 ent.move(self.targetPos[0],self.targetPos[1]); 1126 1127 } … … 1129 1130 var rand = Math.floor(Math.random() * mUnit.length*0.99); 1130 1131 ent.attack(mUnit[(+rand)].id()); 1131 1132 //debug ("Units attacking a unit from " +mUnit[+rand].owner() + " , " +mUnit[+rand].templateName()); 1132 } else if ( SquareVectorDistance(self.targetPos, ent.position()) > 900 ){1133 } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 900 ){ 1133 1134 //debug ("Units moving to " + uneval(self.targetPos)); 1134 1135 ent.move(self.targetPos[0],self.targetPos[1]); 1135 1136 } else if (mStruct.length !== 0) { -
binaries/data/mods/public/simulation/ai/aegis/plan-transport.js
18 18 var TransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) { 19 19 var self = this; 20 20 21 this.ID = uniqueIDTPlans++;21 this.ID = playerGlobals[PlayerID].uniqueIDTPlans++; 22 22 23 23 var unitsID = []; 24 24 if (units.length !== undefined) … … 206 206 var passabilityMap = gameState.getMap(); 207 207 var territoryMap = gameState.ai.territoryMap; 208 208 var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction") | gameState.getPassabilityClassMask("building-shore"); 209 var obstructions = new Map(gameState.sharedScript);209 var obstructions = new API3.Map(gameState.sharedScript); 210 210 211 211 // wanted map. 212 var friendlyTiles = new Map(gameState.sharedScript);212 var friendlyTiles = new API3.Map(gameState.sharedScript); 213 213 214 214 for (var j = 0; j < friendlyTiles.length; ++j) 215 215 { … … 300 300 301 301 // check if we need to move our units and ships closer together 302 302 var stillMoving = false; 303 if ( SquareVectorDistance(this.ships.getCentrePosition(),this.boardingSpot) > 1600)303 if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.boardingSpot) > 1600) 304 304 { 305 305 this.ships.move(this.boardingSpot[0],this.boardingSpot[1]); 306 306 stillMoving = true; // wait till ships are in position 307 307 } 308 if ( SquareVectorDistance(this.units.getCentrePosition(),this.boardingSpot) > 1600)308 if (API3.SquareVectorDistance(this.units.getCentrePosition(),this.boardingSpot) > 1600) 309 309 { 310 310 this.units.move(this.boardingSpot[0],this.boardingSpot[1]); 311 311 stillMoving = true; // wait till units are in position … … 365 365 var passabilityMap = gameState.getMap(); 366 366 var territoryMap = gameState.ai.territoryMap; 367 367 var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction") | gameState.getPassabilityClassMask("building-shore"); 368 var obstructions = new Map(gameState.sharedScript);368 var obstructions = new API3.Map(gameState.sharedScript); 369 369 370 370 // wanted map. 371 var friendlyTiles = new Map(gameState.sharedScript);371 var friendlyTiles = new API3.Map(gameState.sharedScript); 372 372 373 373 var wantedIndex = -1; 374 374 … … 431 431 return false; 432 432 433 433 // check if we need to move ships 434 if ( SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400)434 if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) 435 435 { 436 436 this.ships.move(this.unboardingSpot[0],this.unboardingSpot[1]); 437 437 } else { … … 447 447 return false; 448 448 449 449 // check if we need to move ships 450 if ( SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400)450 if (API3.SquareVectorDistance(this.ships.getCentrePosition(),this.unboardingSpot) > 400) 451 451 { 452 452 this.ships.move(this.unboardingSpot[0],this.unboardingSpot[1]); 453 453 } else { -
binaries/data/mods/public/simulation/ai/aegis/aegis.js
1 1 // "local" global variables for stuffs that will need a unique ID 2 2 // 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. 3 var playerGlobals = []; 4 var g_debugEnabled = false; 6 5 7 6 function AegisBot(settings) { 8 BaseAI.call(this, settings);7 API3.BaseAI.call(this, settings); 9 8 10 Config.updateDifficulty(settings.difficulty); 9 this.Config = new Config(); 10 11 this.Config.updateDifficulty(settings.difficulty); 11 12 12 13 this.turn = 0; 13 14 14 15 this.playedTurn = 0; 15 16 this.priorities = Config.priorities;16 17 this.priorities = this.Config.priorities; 17 18 18 19 // this.queues can only be modified by the queue manager or things will go awry. 19 20 this.queues = {}; 20 21 for (i in this.priorities) 21 22 this.queues[i] = new Queue(); 22 23 23 this.queueManager = new QueueManager(this. queues, this.priorities);24 this.queueManager = new QueueManager(this.Config, this.queues, this.priorities); 24 25 25 this.HQ = new HQ( );26 this.HQ = new HQ(this.Config); 26 27 27 28 this.firstTime = true; 28 29 … … 32 33 this.defconChangeTime = -10000000; 33 34 } 34 35 35 AegisBot.prototype = new BaseAI();36 AegisBot.prototype = new API3.BaseAI(); 36 37 37 38 AegisBot.prototype.CustomInit = function(gameState, sharedScript) { 38 39 40 playerGlobals[PlayerID] = {}; 41 playerGlobals[PlayerID].uniqueIDBOPlans = 0; // training/building/research plans 42 playerGlobals[PlayerID].uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map 43 playerGlobals[PlayerID].uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. 44 39 45 this.HQ.init(gameState,sharedScript.events,this.queues); 40 debug ("Initialized with the difficulty " + Config.difficulty);46 debug ("Initialized with the difficulty " + this.Config.difficulty); 41 47 42 var ents = gameState.getEntities().filter( Filters.byOwner(PlayerID));48 var ents = gameState.getEntities().filter(API3.Filters.byOwner(this.player)); 43 49 var myKeyEntities = ents.filter(function(ent) { 44 50 return ent.hasClass("CivCentre"); 45 51 }); 46 52 47 53 if (myKeyEntities.length == 0){ 48 myKeyEntities = gameState.getEntities().filter( Filters.byOwner(PlayerID));54 myKeyEntities = gameState.getEntities().filter(API3.Filters.byOwner(this.player)); 49 55 } 50 56 51 var filter = Filters.byClass("CivCentre");52 var enemyKeyEntities = gameState.getEntities().filter( Filters.not(Filters.byOwner(PlayerID))).filter(filter);57 var filter = API3.Filters.byClass("CivCentre"); 58 var enemyKeyEntities = gameState.getEntities().filter(API3.Filters.not(API3.Filters.byOwner(this.player))).filter(filter); 53 59 54 60 if (enemyKeyEntities.length == 0){ 55 enemyKeyEntities = gameState.getEntities().filter( Filters.not(Filters.byOwner(PlayerID)));61 enemyKeyEntities = gameState.getEntities().filter(API3.Filters.not(API3.Filters.byOwner(this.player))); 56 62 } 57 63 58 64 this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position()); 59 65 60 this.pathFinder = new aStarPath(gameState, false, true);66 this.pathFinder = new API3.aStarPath(gameState, false, true); 61 67 this.pathsToMe = []; 62 68 this.pathInfo = { "angle" : 0, "needboat" : true, "mkeyPos" : myKeyEntities.toEntityArray()[0].position(), "ekeyPos" : enemyKeyEntities.toEntityArray()[0].position() }; 63 69 … … 65 71 var pos = [this.pathInfo.mkeyPos[0] + 150*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 150*Math.sin(this.pathInfo.angle)]; 66 72 var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 2, 2);// uncomment for debug:*/, 300000, gameState); 67 73 68 //Engine.DumpImage("initialPath" + PlayerID+ ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255);74 //Engine.DumpImage("initialPath" + this.player + ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255); 69 75 70 76 if (path !== undefined && path[1] !== undefined && path[1] == false) { 71 77 // path is viable and doesn't require boating. … … 81 87 } 82 88 83 89 AegisBot.prototype.OnUpdate = function(sharedScript) { 90 84 91 if (this.gameFinished){ 85 92 return; 86 93 } … … 132 139 var cityPhase = this.gameState.cityPhase(); 133 140 // try going up phases. 134 141 // TODO: softcode this. 135 if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > ( Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40142 if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40 136 143 && this.gameState.findResearchers(townPhase,true).length != 0 && this.queues.majorTech.length() === 0 137 && this.gameState.getOwnEntities().filter( Filters.byClass("Village")).length > 5)144 && this.gameState.getOwnEntities().filter(API3.Filters.byClass("Village")).length > 5) 138 145 { 139 146 this.queueManager.pauseQueue("villager", true); 140 147 this.queueManager.pauseQueue("citizenSoldier", true); … … 142 149 this.queues.majorTech.addItem(new ResearchPlan(this.gameState, townPhase,0,-1,true)); // we rush the town phase. 143 150 debug ("Trying to reach town phase"); 144 151 } 145 else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > ( Config.Economy.cityPhase*1000)152 else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.cityPhase*1000) 146 153 && this.gameState.getOwnEntitiesByRole("worker").length > 85 147 154 && this.gameState.findResearchers(cityPhase, true).length != 0 && this.queues.majorTech.length() === 0) { 148 155 debug ("Trying to reach city phase"); … … 215 222 // deactivated for now. 216 223 this.strategy = "normal"; 217 224 // 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)225 if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && this.Config.difficulty == 2) 219 226 { 220 227 this.strategy = "rush"; 221 228 // going to rush. 222 229 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.230 this.Config.Economy.townPhase = 480; 231 this.Config.Economy.cityPhase = 900; 232 this.Config.Economy.farmsteadStartTime = 600; 233 this.Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2. 227 234 } 228 235 }; 229 236 … … 238 245 };*/ 239 246 240 247 function debug(output){ 241 if ( Config.debug){248 if (g_debugEnabled){ 242 249 if (typeof output === "string"){ 243 250 warn(output); 244 251 }else{ -
binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js
4 4 5 5 this.metadata = metadata; 6 6 7 this.ID = uniqueIDBOPlans++;7 this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++; 8 8 9 9 this.template = gameState.getTemplate(this.type); 10 10 if (!this.template) { … … 12 12 } 13 13 14 14 this.category = "building"; 15 this.cost = new Resources(this.template.cost());15 this.cost = new API3.Resources(this.template.cost()); 16 16 this.number = 1; // The number of buildings to build 17 17 18 18 if (!startTime) … … 81 81 }; 82 82 83 83 ConstructionPlan.prototype.getCost = function() { 84 var costs = new Resources();84 var costs = new API3.Resources(); 85 85 costs.add(this.cost); 86 86 return costs; 87 87 }; … … 93 93 94 94 // First, find all tiles that are far enough away from obstructions: 95 95 96 var obstructionMap = Map.createObstructionMap(gameState,0, template);96 var obstructionMap = API3.Map.createObstructionMap(gameState,0, template); 97 97 98 98 //obstructionMap.dumpIm(template.buildCategory() + "_obstructions_pre.png"); 99 99 … … 104 104 105 105 // Compute each tile's closeness to friendly structures: 106 106 107 var friendlyTiles = new Map(gameState.sharedScript);107 var friendlyTiles = new API3.Map(gameState.sharedScript); 108 108 109 109 var alreadyHasHouses = false; 110 110 -
binaries/data/mods/public/simulation/ai/aegis/config.js
1 // Baseconfig is the highest difficulty. 2 var baseConfig = { 3 "Military" : { 1 var Config = function() { 2 this.debug = false; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. 3 this.difficulty = 2; // overriden by the GUI 4 5 this.Military = { 4 6 "fortressLapseTime" : 540, // Time to wait between building 2 fortresses 5 7 "defenceBuildingTime" : 600, // Time to wait before building towers or fortresses 6 8 "attackPlansStartTime" : 0, // time to wait before attacking. Start as soon as possible (first barracks) … … 8 10 "popForBarracks1" : 15, 9 11 "popForBarracks2" : 95, 10 12 "timeForBlacksmith" : 900, 11 } ,12 "Economy" :{13 }; 14 this.Economy = { 13 15 "townPhase" : 180, // time to start trying to reach town phase (might be a while after. Still need the requirements + ress ) 14 16 "cityPhase" : 840, // time to start trying to reach city phase 15 17 "popForMarket" : 80, … … 19 21 "targetNumBuilders" : 1.5, // Base number of builders per foundation. 20 22 "femaleRatio" : 0.4, // percent of females among the workforce. 21 23 "initialFields" : 2 22 } ,24 }; 23 25 24 26 // Note: attack settings are set directly in attack_plan.js 25 27 26 28 // defence 27 "Defence" : { 29 this.Defence = 30 { 28 31 "defenceRatio" : 5, // see defence.js for more info. 29 32 "armyCompactSize" : 700, // squared. Half-diameter of an army. 30 33 "armyBreakawaySize" : 900 // squared. 31 } ,34 }; 32 35 33 36 // military 34 "buildings" : { 37 this.buildings = 38 { 35 39 "moderate" : { 36 40 "default" : [ "structures/{civ}_barracks" ] 37 41 }, … … 51 55 "default" : [ "structures/{civ}_fortress" ], 52 56 "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ] 53 57 } 54 } ,58 }; 55 59 56 60 // qbot 57 "priorities" : { // Note these are dynamic, you are only setting the initial values 61 this.priorities = 62 { // Note these are dynamic, you are only setting the initial values 58 63 "house" : 350, 59 64 "villager" : 40, 60 65 "citizenSoldier" : 60, … … 67 72 "majorTech" : 700, 68 73 "minorTech" : 50, 69 74 "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 75 }; 73 76 }; 74 77 75 var Config = { 76 "debug": false, 77 "difficulty" : 2, // overriden by the GUI 78 updateDifficulty: function(difficulty) 78 //Config.prototype = new BaseConfig(); 79 80 Config.prototype.updateDifficulty = function(difficulty) 81 { 82 this.difficulty = difficulty; 83 // changing settings based on difficulty. 84 if (this.difficulty === 1) 79 85 { 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 86 this.Military.defenceBuildingTime = 1200; 87 this.Military.attackPlansStartTime = 960; 88 this.Military.popForBarracks1 = 35; 89 this.Military.popForBarracks2 = 150; // shouldn't reach it 90 this.Military.popForBlacksmith = 150; // shouldn't reach it 89 91 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 it92 this.Economy.cityPhase = 1800; 93 this.Economy.popForMarket = 80; 94 this.Economy.techStartTime = 600; 95 this.Economy.femaleRatio = 0.6; 96 this.Economy.initialFields = 1; 97 // Config.Economy.targetNumWorkers will be set by AI scripts. 98 } 99 else if (this.difficulty === 0) 100 { 101 this.Military.defenceBuildingTime = 450; 102 this.Military.attackPlansStartTime = 9600000; // never 103 this.Military.popForBarracks1 = 60; 104 this.Military.popForBarracks2 = 150; // shouldn't reach it 105 this.Military.popForBlacksmith = 150; // shouldn't reach it 104 106 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 } 107 this.Economy.cityPhase = 240000; 108 this.Economy.popForMarket = 200; 109 this.Economy.techStartTime = 1800; 110 this.Economy.femaleRatio = 0.2; 111 this.Economy.initialFields = 1; 112 // Config.Economy.targetNumWorkers will be set by AI scripts. 112 113 } 113 114 }; 114 115 Config.__proto__ = baseConfig; -
binaries/data/mods/public/simulation/ai/aegis/queueplan-training.js
2 2 this.type = gameState.applyCiv(type); 3 3 this.metadata = metadata; 4 4 5 this.ID = uniqueIDBOPlans++;5 this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++; 6 6 7 7 this.template = gameState.getTemplate(this.type); 8 8 if (!this.template) 9 9 return false; 10 10 11 11 this.category = "unit"; 12 this.cost = new Resources(this.template.cost(), this.template._template.Cost.Population);12 this.cost = new API3.Resources(this.template.cost(), this.template._template.Cost.Population); 13 13 if (!number) 14 14 this.number = 1; 15 15 else … … 73 73 }; 74 74 75 75 TrainingPlan.prototype.getCost = function(){ 76 var multCost = new Resources();76 var multCost = new API3.Resources(); 77 77 multCost.add(this.cost); 78 78 multCost.multiply(this.number); 79 79 return multCost; -
binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js
10 10 11 11 // using global entity collections, shared by any AI that knows the name of this. 12 12 13 var filter = Filters.and(Filters.byClass("Structure"),Filters.byOwner(this.watched));13 var filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(this.watched)); 14 14 this.enemyBuildings = gameState.updatingGlobalCollection("player-" +this.watched + "-structures", filter); 15 15 16 filter = Filters.and(Filters.byClass("Unit"),Filters.byOwner(this.watched));16 filter = API3.Filters.and(API3.Filters.byClass("Unit"), API3.Filters.byOwner(this.watched)); 17 17 this.enemyUnits = gameState.updatingGlobalCollection("player-" +this.watched + "-units", filter); 18 18 19 filter = Filters.and(Filters.byClass("Worker"),Filters.byOwner(this.watched));19 filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched)); 20 20 this.enemyCivilians = gameState.updatingGlobalCollection("player-" +this.watched + "-civilians", filter); 21 21 22 filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]),Filters.byOwner(this.watched));22 filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched)); 23 23 this.enemySoldiers = gameState.updatingGlobalCollection("player-" +this.watched + "-soldiers", filter); 24 24 25 filter = Filters.and(Filters.byClass("Worker"),Filters.byOwner(this.watched));25 filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched)); 26 26 this.enemyCivilians = gameState.getEnemyEntities().filter(filter); 27 27 this.enemyCivilians.registerUpdates(); 28 28 29 filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]),Filters.byOwner(this.watched));29 filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched)); 30 30 this.enemySoldiers = gameState.getEnemyEntities().filter(filter); 31 31 this.enemySoldiers.registerUpdates(); 32 32 … … 48 48 }; 49 49 50 50 enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, OneTime) { 51 var filter = Filters.byClass(specialClass);51 var filter = API3.Filters.byClass(specialClass); 52 52 53 53 if (OneTime && gameState.getGEC("player-" +this.watched + "-structures-" +specialClass)) 54 54 return gameState.getGEC("player-" +this.watched + "-structures-" +specialClass); … … 121 121 var armyID = gameState.player + "" + self.totalNBofArmies; 122 122 self.totalNBofArmies++, 123 123 enemy.setMetadata(PlayerID, "EnemyWatcherArmy",armyID); 124 var filter = Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID);124 var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID); 125 125 var army = self.enemySoldiers.filter(filter); 126 126 self.armies[armyID] = army; 127 127 self.armies[armyID].registerUpdates(); … … 204 204 205 205 self.totalNBofArmies++, 206 206 enemy.setMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); 207 var filter = Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID);207 var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID); 208 208 var newArmy = self.enemySoldiers.filter(filter); 209 209 self.armies[newArmyID] = newArmy; 210 210 self.armies[newArmyID].registerUpdates(); -
binaries/data/mods/public/simulation/ai/aegis/entitycollection-extend.js
6 6 ents[id] = gameState.entities._entities[id]; 7 7 } 8 8 } 9 return new EntityCollection(gameState.sharedScript, ents);9 return new API3.EntityCollection(gameState.sharedScript, ents); 10 10 } -
binaries/data/mods/public/simulation/ai/aegis/queue.js
43 43 // returns the maximal account we'll accept for this queue. 44 44 // Currently 100% of the cost of the first element and 80% of that of the second 45 45 Queue.prototype.maxAccountWanted = function(gameState) { 46 var cost = new Resources();46 var cost = new API3.Resources(); 47 47 if (this.queue.length > 0 && this.queue[0].isGo(gameState)) 48 48 cost.add(this.queue[0].getCost()); 49 49 if (this.queue.length > 1 && this.queue[1].isGo(gameState)) … … 56 56 }; 57 57 58 58 Queue.prototype.queueCost = function(){ 59 var cost = new Resources();59 var cost = new API3.Resources(); 60 60 for (var key in this.queue){ 61 61 cost.add(this.queue[key].getCost()); 62 62 } -
binaries/data/mods/public/simulation/ai/aegis/headquarters.js
12 12 -picking new CC locations. 13 13 */ 14 14 15 var HQ = function() { 16 this.targetNumBuilders = Config.Economy.targetNumBuilders; // number of workers we want building stuff 15 var HQ = function(Config) { 17 16 18 this. dockStartTime = Config.Economy.dockStartTime * 1000;19 this.t echStartTime = Config.Economy.techStartTime * 1000;17 this.Config = Config; 18 this.targetNumBuilders = this.Config.Economy.targetNumBuilders; // number of workers we want building stuff 20 19 20 this.dockStartTime = this.Config.Economy.dockStartTime * 1000; 21 this.techStartTime = this.Config.Economy.techStartTime * 1000; 22 21 23 this.dockFailed = false; // sanity check 22 24 this.waterMap = false; // set by the aegis.js file. 23 25 … … 27 29 this.baseManagers = {}; 28 30 29 31 // 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;32 this.femaleRatio = this.Config.Economy.femaleRatio; 31 33 32 34 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( );35 this.fortressLapseTime = this.Config.Military.fortressLapseTime * 1000; 36 this.defenceBuildingTime = this.Config.Military.defenceBuildingTime * 1000; 37 this.attackPlansStartTime = this.Config.Military.attackPlansStartTime * 1000; 38 this.defenceManager = new Defence(this.Config); 37 39 38 40 this.navalManager = new NavalManager(); 39 41 … … 45 47 // More initialisation for stuff that needs the gameState 46 48 HQ.prototype.init = function(gameState, events, queues){ 47 49 // 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));50 this.basesMap = new API3.Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length)); 49 51 this.basesMap.setMaxVal(255); 50 52 51 if ( Config.Economy.targetNumWorkers)52 this.targetNumWorkers = Config.Economy.targetNumWorkers;53 if (this.Config.Economy.targetNumWorkers) 54 this.targetNumWorkers = this.Config.Economy.targetNumWorkers; 53 55 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);56 this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+(this.Config.difficulty)*0.125,0.3))), 1); 55 57 56 58 57 59 // Let's get our initial situation here. 58 60 // TODO: improve on this. 59 61 // TODO: aknowledge bases, assign workers already. 60 var ents = gameState.getEntities().filter( Filters.byOwner(PlayerID));62 var ents = gameState.getEntities().filter(API3.Filters.byOwner(PlayerID)); 61 63 62 64 var workersNB = 0; 63 65 var hasScout = false; 64 66 var treasureAmount = { 'food': 0, 'wood': 0, 'stone': 0, 'metal': 0 }; 65 67 var hasCC = false; 66 68 67 if (ents.filter( Filters.byClass("CivCentre")).length > 0)69 if (ents.filter(API3.Filters.byClass("CivCentre")).length > 0) 68 70 hasCC = true; 69 workersNB = ents.filter( Filters.byClass("Worker")).length;70 if (ents.filter( Filters.byClass("Cavalry")).length > 0)71 workersNB = ents.filter(API3.Filters.byClass("Worker")).length; 72 if (ents.filter(API3.Filters.byClass("Cavalry")).length > 0) 71 73 hasScout = true; 72 74 73 75 // tODO: take multiple CCs into account. 74 76 if (hasCC) 75 77 { 76 var CC = ents.filter( Filters.byClass("CivCentre")).toEntityArray()[0];78 var CC = ents.filter(API3.Filters.byClass("CivCentre")).toEntityArray()[0]; 77 79 for (i in treasureAmount) 78 80 gameState.getResourceSupplies(i).forEach( function (ent) { 79 if (ent.resourceSupplyType().generic === "treasure" && SquareVectorDistance(ent.position(), CC.position()) < 5000)81 if (ent.resourceSupplyType().generic === "treasure" && API3.SquareVectorDistance(ent.position(), CC.position()) < 5000) 80 82 treasureAmount[i] += ent.resourceSupplyMax(); 81 83 }); 82 this.baseManagers[1] = new BaseManager( );84 this.baseManagers[1] = new BaseManager(this.Config); 83 85 this.baseManagers[1].init(gameState, events); 84 86 this.baseManagers[1].setAnchor(CC); 85 87 this.baseManagers[1].initTerritory(this, gameState); 86 88 this.baseManagers[1].initGatheringFunctions(this, gameState); 87 89 88 if ( Config.debug)90 if (this.Config.debug) 89 91 this.basesMap.dumpIm("basesMap.png"); 90 92 var self = this; 91 93 … … 111 113 } 112 114 } 113 115 114 var map = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map);115 if ( Config.debug)116 var map = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map); 117 if (this.Config.debug) 116 118 map.dumpIm("map_CC_Wood.png"); 117 119 118 120 //this.reassignIdleWorkers(gameState); … … 125 127 126 128 // load units and buildings from the config files 127 129 128 if (civ in Config.buildings.moderate){129 this.bModerate = Config.buildings.moderate[civ];130 if (civ in this.Config.buildings.moderate){ 131 this.bModerate = this.Config.buildings.moderate[civ]; 130 132 }else{ 131 this.bModerate = Config.buildings.moderate['default'];133 this.bModerate = this.Config.buildings.moderate['default']; 132 134 } 133 135 134 if (civ in Config.buildings.advanced){135 this.bAdvanced = Config.buildings.advanced[civ];136 if (civ in this.Config.buildings.advanced){ 137 this.bAdvanced = this.Config.buildings.advanced[civ]; 136 138 }else{ 137 this.bAdvanced = Config.buildings.advanced['default'];139 this.bAdvanced = this.Config.buildings.advanced['default']; 138 140 } 139 141 140 if (civ in Config.buildings.fort){141 this.bFort = Config.buildings.fort[civ];142 if (civ in this.Config.buildings.fort){ 143 this.bFort = this.Config.buildings.fort[civ]; 142 144 }else{ 143 this.bFort = Config.buildings.fort['default'];145 this.bFort = this.Config.buildings.fort['default']; 144 146 } 145 147 146 148 for (var i in this.bAdvanced){ … … 156 158 } 157 159 158 160 var enemies = gameState.getEnemyEntities(); 159 var filter = Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]);161 var filter = API3.Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]); 160 162 this.enemySoldiers = enemies.filter(filter); // TODO: cope with diplomacy changes 161 163 this.enemySoldiers.registerUpdates(); 162 164 … … 193 195 if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1) 194 196 { 195 197 // Okay so let's try to create a new base around this. 196 var bID = uniqueIDBases;197 this.baseManagers[bID] = new BaseManager( );198 var bID = playerGlobals[PlayerID].uniqueIDBases; 199 this.baseManagers[bID] = new BaseManager(this.Config); 198 200 this.baseManagers[bID].init(gameState, events, true); 199 201 this.baseManagers[bID].setAnchor(ent); 200 202 this.baseManagers[bID].initTerritory(this, gameState); … … 411 413 // TODO: improve choice alogrithm 412 414 HQ.prototype.switchWorkerBase = function(gameState, worker, type) { 413 415 var bestBase = 0; 416 414 417 for (var i in this.baseManagers) 415 418 { 416 419 if (this.baseManagers[i].willGather[type] >= 1) … … 545 548 // Then checks for a good spot in the territory. If none, and town/city phase, checks outside 546 549 // The AI will currently not build a CC if it wouldn't connect with an existing CC. 547 550 548 var territory = Map.createTerritoryMap(gameState);551 var territory = API3.Map.createTerritoryMap(gameState); 549 552 550 var obstructions = Map.createObstructionMap(gameState, 0);553 var obstructions = API3.Map.createObstructionMap(gameState, 0); 551 554 obstructions.expandInfluences(); 552 555 553 556 // copy the resource map as initialization. 554 var friendlyTiles = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true);557 var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true); 555 558 friendlyTiles.setMaxVal(255); 556 var ents = gameState.getOwnEntities().filter( Filters.byClass("CivCentre")).toEntityArray();557 var eEnts = gameState.getEnemyEntities().filter( Filters.byClass("CivCentre")).toEntityArray();559 var ents = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); 560 var eEnts = gameState.getEnemyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); 558 561 559 562 var dps = gameState.getOwnDropsites().toEntityArray(); 560 563 … … 576 579 var entPos = ents[i].position(); 577 580 entPos = [entPos[0]/4.0,entPos[1]/4.0]; 578 581 579 var dist = SquareVectorDistance(entPos, pos);582 var dist = API3.SquareVectorDistance(entPos, pos); 580 583 if (dist < 2120) 581 584 { 582 585 canBuild = false; … … 598 601 var entPos = eEnts[i].position(); 599 602 entPos = [entPos[0]/4.0,entPos[1]/4.0]; 600 603 // 7100 works well as a limit. 601 if ( SquareVectorDistance(entPos, pos) < 2500)604 if (API3.SquareVectorDistance(entPos, pos) < 2500) 602 605 { 603 606 canBuild = false; 604 607 continue; … … 620 623 continue; 621 624 } 622 625 dpPos = [dpPos[0]/4.0,dpPos[1]/4.0]; 623 if ( SquareVectorDistance(dpPos, pos) < 100)626 if (API3.SquareVectorDistance(dpPos, pos) < 100) 624 627 { 625 628 friendlyTiles.map[j] = 0; 626 629 continue; 627 } else if ( SquareVectorDistance(dpPos, pos) < 400)630 } else if (API3.SquareVectorDistance(dpPos, pos) < 400) 628 631 friendlyTiles.map[j] /= 2; 629 632 } 630 633 … … 645 648 var best = friendlyTiles.findBestTile(6, obstructions); 646 649 var bestIdx = best[0]; 647 650 648 if ( Config.debug)651 if (this.Config.debug) 649 652 { 650 653 friendlyTiles.map[bestIdx] = 270; 651 654 friendlyTiles.dumpIm("cc_placement_base_" + gameState.getTimeElapsed() + "_" + resource + "_" + best[1] + ".png",301); … … 674 677 }; 675 678 676 679 HQ.prototype.buildMarket = function(gameState, queues){ 677 if (gameState.getPopulation() > Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) {680 if (gameState.getPopulation() > this.Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) { 678 681 if (queues.economicBuilding.countQueuedUnitsWithClass("BarterMarket") === 0 && 679 682 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market")) === 0){ 680 683 //only ever build one storehouse/CC/market at a time … … 685 688 686 689 // Build a farmstead to go to town phase faster and prepare for research. Only really active on higher diff mode. 687 690 HQ.prototype.buildFarmstead = function(gameState, queues){ 688 if (gameState.getPopulation() > Config.Economy.popForFarmstead) {691 if (gameState.getPopulation() > this.Config.Economy.popForFarmstead) { 689 692 // achtung: "DropsiteFood" does not refer to CCs. 690 693 if (queues.economicBuilding.countQueuedUnitsWithClass("DropsiteFood") === 0 && 691 694 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_farmstead")) === 0){ … … 752 755 if (numPlanned < 3 || (numPlanned < 5 && gameState.getPopulation() > 80)) 753 756 { 754 757 var plan = new ConstructionPlan(gameState, "structures/{civ}_house", { "base" : 1 }); 758 // make the difficulty available to the isGo function without having to pass it as argument 759 var difficulty = this.Config.difficulty; 755 760 // change the starting condition to "less than 15 slots left". 756 761 plan.isGo = function (gameState) { 757 762 var HouseNb = gameState.countEntitiesByType(gameState.applyCiv("foundation|structures/{civ}_house"), true); … … 761 766 freeSlots = gameState.getPopulationLimit() + HouseNb*5 - gameState.getPopulation(); 762 767 else 763 768 freeSlots = gameState.getPopulationLimit() + HouseNb*10 - gameState.getPopulation(); 764 if (gameState.getPopulation() > 55 && Config.difficulty > 1)769 if (gameState.getPopulation() > 55 && difficulty > 1) 765 770 return (freeSlots <= 21); 766 else if (gameState.getPopulation() >= 20 && Config.difficulty !== 0)771 else if (gameState.getPopulation() >= 20 && difficulty !== 0) 767 772 return (freeSlots <= 16); 768 773 else 769 774 return (freeSlots <= 10); … … 781 786 var capacity = { "wood" : 0, "stone" : 0, "metal" : 0 } 782 787 var need = { "wood" : true, "stone" : true, "metal" : true }; 783 788 var posss = []; 789 784 790 for (i in this.baseManagers) 785 791 { 786 792 var base = this.baseManagers[i]; 787 793 for (type in count) 788 794 { 789 if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max( Config.difficulty,2))795 if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max(this.Config.difficulty,2)) 790 796 count[type]++; 791 797 capacity[type] += base.getWorkerCapacity(gameState, type); 792 798 if (base.willGather[type] !== 2) … … 796 802 for (type in count) 797 803 { 798 804 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)805 || 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 806 { 801 807 // plan a new base. 802 808 if (gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_civil_centre")) === 0 && queues.civilCentre.length() === 0) { … … 821 827 // TODO: Fortresses are placed randomly atm. 822 828 HQ.prototype.buildDefences = function(gameState, queues){ 823 829 824 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter( Filters.not(Filters.byHasMetadata(PlayerID,"plan"))).length;830 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"plan"))).length; 825 831 826 832 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv('structures/{civ}_defense_tower')) 827 833 + queues.defenceBuilding.length() < gameState.getEntityLimits()["DefenseTower"] && queues.defenceBuilding.length() < 4 && gameState.currentPhase() > 1) { … … 878 884 }; 879 885 880 886 HQ.prototype.buildBlacksmith = function(gameState, queues){ 881 if (gameState.getTimeElapsed() > Config.Military.timeForBlacksmith*1000) {887 if (gameState.getTimeElapsed() > this.Config.Military.timeForBlacksmith*1000) { 882 888 if (queues.militaryBuilding.length() === 0 && 883 889 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_blacksmith")) === 0) { 884 890 var tp = gameState.getTemplate(gameState.applyCiv("structures/{civ}_blacksmith")); … … 894 900 // TODO: building placement is bad. Choice of buildings is also fairly dumb. 895 901 HQ.prototype.constructTrainingBuildings = function(gameState, queues) { 896 902 Engine.ProfileStart("Build buildings"); 897 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter( Filters.not(Filters.byHasMetadata(PlayerID, "plan"))).length;903 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "plan"))).length; 898 904 899 if (workersNumber > Config.Military.popForBarracks1) {905 if (workersNumber > this.Config.Military.popForBarracks1) { 900 906 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) + queues.militaryBuilding.length() < 1) { 901 907 debug ("Trying to build barracks"); 902 908 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 903 909 } 904 910 } 905 911 906 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > Config.Military.popForBarracks2)912 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > this.Config.Military.popForBarracks2) 907 913 if (queues.militaryBuilding.length() < 1) 908 914 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 909 915 … … 917 923 } 918 924 } 919 925 //build advanced military buildings 920 if (workersNumber >= Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){926 if (workersNumber >= this.Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){ 921 927 if (queues.militaryBuilding.length() === 0){ 922 928 var inConst = 0; 923 929 for (var i in this.bAdvanced) … … 950 956 951 957 // TODO: use pop(). Currently unused as this is too gameable. 952 958 HQ.prototype.garrisonAllFemales = function(gameState) { 953 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).toEntityArray();954 var females = gameState.getOwnEntities().filter( Filters.byClass("Support"));959 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); 960 var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support")); 955 961 956 962 var cache = {}; 957 963 … … 976 982 }; 977 983 HQ.prototype.ungarrisonAll = function(gameState) { 978 984 this.hasGarrisonedFemales = false; 979 var buildings = gameState.getOwnEntities().filter( Filters.and(Filters.byClass("Structure"),Filters.byCanGarrison())).toEntityArray();985 var buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byCanGarrison())).toEntityArray(); 980 986 buildings.forEach( function (struct) { 981 987 if (struct.garrisoned() && struct.garrisoned().length) 982 988 struct.unloadAll(); … … 1047 1053 1048 1054 // Some functions are run every turn 1049 1055 // Others once in a while 1050 HQ.prototype.update = function(gameState, queues, events) { 1056 HQ.prototype.update = function(gameState, queues, events) { 1051 1057 Engine.ProfileStart("Headquarters update"); 1052 1058 1053 1059 this.checkEvents(gameState,events,queues); … … 1057 1063 this.trainMoreWorkers(gameState, queues); 1058 1064 1059 1065 // sandbox doesn't expand. 1060 if ( Config.difficulty !== 0)1066 if (this.Config.difficulty !== 0) 1061 1067 this.checkBasesRessLevel(gameState, queues); 1062 1068 1063 1069 this.buildMoreHouses(gameState,queues); … … 1065 1071 if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2) 1066 1072 this.tryResearchTechs(gameState,queues); 1067 1073 1068 if ( Config.difficulty > 1)1074 if (this.Config.difficulty > 1) 1069 1075 this.tryBartering(gameState); 1070 1076 1071 1077 this.buildFarmstead(gameState, queues); … … 1087 1093 for (i in this.baseManagers) 1088 1094 { 1089 1095 this.baseManagers[i].checkEvents(gameState, events, queues) 1090 if ( ( (+i + gameState.ai.playedTurn) % ( uniqueIDBases - 1)) === 0)1096 if ( ( (+i + gameState.ai.playedTurn) % (playerGlobals[PlayerID].uniqueIDBases - 1)) === 0) 1091 1097 this.baseManagers[i].update(gameState, queues, events); 1092 1098 } 1093 1099 … … 1174 1180 if (gameState.ai.strategy === "rush" && this.startedAttacks["CityAttack"].length !== 0) { 1175 1181 // and then we revert. 1176 1182 gameState.ai.strategy = "normal"; 1177 Config.Economy.femaleRatio = 0.4;1183 this.Config.Economy.femaleRatio = 0.4; 1178 1184 gameState.ai.modules.economy.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*0.55), 1); 1179 1185 } else if (gameState.ai.strategy === "rush" && this.upcomingAttacks["CityAttack"].length === 0) 1180 1186 { 1181 Lalala = new CityAttack(gameState, this, this.TotalAttackNumber, -1, "rush")1187 Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "rush") 1182 1188 this.TotalAttackNumber++; 1183 1189 this.upcomingAttacks["CityAttack"].push(Lalala); 1184 1190 debug ("Starting a little something"); … … 1193 1199 } else { 1194 1200 // basically only the first plan, really. 1195 1201 if (this.upcomingAttacks["CityAttack"].length == 0 && gameState.getTimeElapsed() < 12*60000) { 1196 var Lalala = new CityAttack(gameState, this, this.TotalAttackNumber, -1);1202 var Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1); 1197 1203 if (Lalala.failed) 1198 1204 { 1199 1205 this.attackPlansEncounteredWater = true; // hack … … 1202 1208 this.TotalAttackNumber++; 1203 1209 this.upcomingAttacks["CityAttack"].push(Lalala); 1204 1210 } 1205 } else if (this.upcomingAttacks["CityAttack"].length == 0 && Config.difficulty !== 0) {1206 var Lalala = new CityAttack(gameState, this, this.TotalAttackNumber, -1, "superSized");1211 } else if (this.upcomingAttacks["CityAttack"].length == 0 && this.Config.difficulty !== 0) { 1212 var Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "superSized"); 1207 1213 if (Lalala.failed) 1208 1214 { 1209 1215 this.attackPlansEncounteredWater = true; // hack … … 1243 1249 this.buildDropsites(gameState, queues); 1244 1250 Engine.ProfileStop(); 1245 1251 1246 if ( Config.difficulty !== 0)1252 if (this.Config.difficulty !== 0) 1247 1253 this.tryBartering(gameState); 1248 1254 1249 1255 this.buildFarmstead(gameState, queues); -
binaries/data/mods/public/simulation/ai/aegis/queueplan-research.js
1 1 var ResearchPlan = function(gameState, type, startTime, expectedTime, rush) { 2 2 this.type = type; 3 3 4 this.ID = uniqueIDBOPlans++;4 this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++; 5 5 6 6 this.template = gameState.getTemplate(this.type); 7 7 if (!this.template || this.template.researchTime === undefined) { 8 8 return false; 9 9 } 10 10 this.category = "technology"; 11 this.cost = new Resources(this.template.cost(),0);11 this.cost = new API3.Resources(this.template.cost(),0); 12 12 this.number = 1; // Obligatory for compatibility 13 13 14 14 if (!startTime) … … 67 67 }; 68 68 69 69 ResearchPlan.prototype.getCost = function(){ 70 var costs = new Resources();70 var costs = new API3.Resources(); 71 71 costs.add(this.cost); 72 72 return costs; 73 73 }; -
binaries/data/mods/public/simulation/ai/aegis/queue-manager.js
17 17 // 18 18 // This system should be improved. It's probably not flexible enough. 19 19 20 var QueueManager = function(queues, priorities) { 20 var QueueManager = function(Config, queues, priorities) { 21 this.Config = Config; 21 22 this.queues = queues; 22 23 this.priorities = priorities; 23 24 this.account = {}; … … 28 29 this.queueArrays = []; 29 30 for (var p in this.queues) { 30 31 this.account[p] = 0; 31 this.accounts[p] = new Resources();32 this.accounts[p] = new API3.Resources(); 32 33 this.queueArrays.push([p,this.queues[p]]); 33 34 } 34 35 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); … … 47 48 }; 48 49 49 50 QueueManager.prototype.getTotalAccountedResources = function(gameState) { 50 var resources = new Resources();51 var resources = new API3.Resources(); 51 52 for (var key in this.queues) { 52 53 resources.add(this.accounts[key]); 53 54 } … … 55 56 }; 56 57 57 58 QueueManager.prototype.currentNeeds = function(gameState) { 58 var needs = new Resources();59 var needs = new API3.Resources(); 59 60 // get out current resources, not removing accounts. 60 61 var current = this.getAvailableResources(gameState, true); 61 62 //queueArrays because it's faster. … … 83 84 }; 84 85 85 86 QueueManager.prototype.futureNeeds = function(gameState) { 86 var needs = new Resources();87 var needs = new API3.Resources(); 87 88 // get out current resources, not removing accounts. 88 89 var current = this.getAvailableResources(gameState, true); 89 90 //queueArrays because it's faster. … … 143 144 // estimate time based on priority + cost + nb 144 145 // TODO: work on this. 145 146 for (type in qCosts) 147 { 146 148 qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name])); 149 } 147 150 qTime += 30000; 148 151 } else { 149 152 // TODO: work on this. … … 282 285 283 286 // nice readable HTML version. 284 287 QueueManager.prototype.HTMLprintQueues = function(gameState){ 285 if (! Config.debug)288 if (!this.Config.debug) 286 289 return; 287 290 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 291 for (var i in this.queues){ … … 457 460 if (queue.length() > 0 && !queue.paused) 458 461 { 459 462 var item = queue.getNext(); 460 var total = new Resources();463 var total = new API3.Resources(); 461 464 total.add(this.accounts[name]); 462 465 if (total.canAfford(item.getCost())) 463 466 { … … 517 520 this.queues[queueName] = new Queue(); 518 521 this.priorities[queueName] = priority; 519 522 this.account[queueName] = 0; 520 this.accounts[queueName] = new Resources();523 this.accounts[queueName] = new API3.Resources(); 521 524 522 525 var self = this; 523 526 this.queueArrays = []; 524 527 for (var p in this.queues) 528 { 525 529 this.queueArrays.push([p,this.queues[p]]); 530 } 526 531 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 527 532 } 528 533 } … … 539 544 var self = this; 540 545 this.queueArrays = []; 541 546 for (var p in this.queues) 547 { 542 548 this.queueArrays.push([p,this.queues[p]]); 549 } 543 550 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 544 551 } 545 552 } … … 548 555 if (this.queues[queueName] !== undefined) 549 556 this.priorities[queueName] = newPriority; 550 557 this.queueArrays = []; 551 for (var p in this.queues) { 558 for (var p in this.queues) 559 { 552 560 this.queueArrays.push([p,this.queues[p]]); 553 561 } 554 562 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); -
binaries/data/mods/public/simulation/ai/aegis/map-module.js
1 1 // other map functions 2 2 3 Map.createObstructionMap = function(gameState, accessIndex, template){3 API3.Map.createObstructionMap = function(gameState, accessIndex, template){ 4 4 var passabilityMap = gameState.getMap(); 5 5 var territoryMap = gameState.ai.territoryMap; 6 6 … … 31 31 for (var y = 0; y < passabilityMap.height; ++y) 32 32 { 33 33 var i = x + y*passabilityMap.width; 34 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);34 var tilePlayer = (territoryMap.data[i] & 0x3F); 35 35 36 36 if (gameState.ai.myIndex !== gameState.ai.accessibility.landPassMap[i]) 37 37 { … … 88 88 var obstructionTiles = new Uint8Array(passabilityMap.data.length); 89 89 for (var i = 0; i < passabilityMap.data.length; ++i) 90 90 { 91 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);91 var tilePlayer = (territoryMap.data[i] & 0x3F); 92 92 var invalidTerritory = ( 93 93 (!buildOwn && tilePlayer == playerID) || 94 94 (!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) || … … 105 105 } 106 106 } 107 107 108 var map = new Map(gameState.sharedScript, obstructionTiles);108 var map = new API3.Map(gameState.sharedScript, obstructionTiles); 109 109 map.setMaxVal(255); 110 110 111 111 if (template && template.buildDistance()){ … … 127 127 128 128 129 129 130 Map.createTerritoryMap = function(gameState) {130 API3.Map.createTerritoryMap = function(gameState) { 131 131 var map = gameState.ai.territoryMap; 132 132 133 var ret = new Map(gameState.sharedScript, map.data);133 var ret = new API3.Map(gameState.sharedScript, map.data); 134 134 135 135 ret.getOwner = function(p) { 136 return this.point(p) & TERRITORY_PLAYER_MASK;136 return this.point(p) & 0x3F; 137 137 } 138 138 ret.getOwnerIndex = function(p) { 139 return this.map[p] & TERRITORY_PLAYER_MASK;139 return this.map[p] & 0x3F; 140 140 } 141 141 return ret; 142 142 }; -
binaries/data/mods/public/simulation/ai/aegis/naval-manager.js
34 34 // More initialisation for stuff that needs the gameState 35 35 NavalManager.prototype.init = function(gameState, events, queues) { 36 36 // finished docks 37 this.docks = gameState.getOwnEntities().filter( Filters.and(Filters.byClass("Dock"), Filters.not(Filters.isFoundation())));37 this.docks = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Dock"), API3.Filters.not(API3.Filters.isFoundation()))); 38 38 this.docks.allowQuickIter(); 39 39 this.docks.registerUpdates(); 40 40 41 this.ships = gameState.getOwnEntities().filter( Filters.byClass("Ship"));41 this.ships = gameState.getOwnEntities().filter(API3.Filters.byClass("Ship")); 42 42 // 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"));43 this.tpShips = this.ships.filter(API3.Filters.byCanGarrison()); 44 this.warships = this.ships.filter(API3.Filters.byClass("Warship")); 45 45 46 46 this.ships.registerUpdates(); 47 47 this.tpShips.registerUpdates(); … … 52 52 if (gameState.ai.accessibility.regionType[i] !== "water") 53 53 { 54 54 // 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));55 this.seaShips.push(new API3.EntityCollection(gameState.sharedScript)); 56 this.seaTpShips.push(new API3.EntityCollection(gameState.sharedScript)); 57 this.seaWarships.push(new API3.EntityCollection(gameState.sharedScript)); 58 58 this.wantedTpShips.push(0); 59 59 this.wantedWarships.push(0); 60 60 } else { 61 var collec = this.ships.filter( Filters.byStaticMetadata(PlayerID, "sea", i));61 var collec = this.ships.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); 62 62 collec.registerUpdates(); 63 63 this.seaShips.push(collec); 64 collec = this.tpShips.filter( Filters.byStaticMetadata(PlayerID, "sea", i));64 collec = this.tpShips.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); 65 65 collec.registerUpdates(); 66 66 this.seaTpShips.push(collec); 67 var collec = this.warships.filter( Filters.byStaticMetadata(PlayerID, "sea", i));67 var collec = this.warships.filter(API3.Filters.byStaticMetadata(PlayerID, "sea", i)); 68 68 collec.registerUpdates(); 69 69 this.seaWarships.push(collec); 70 70 -
binaries/data/mods/public/simulation/ai/aegis/base-manager.js
10 10 -updating whatever needs updating, keeping track of stuffs (rebuilding needs…) 11 11 */ 12 12 13 var BaseManager = function() { 13 var BaseManager = function(Config) { 14 this.Config = Config; 14 15 this.farmingFields = false; 15 this.ID = uniqueIDBases++;16 this.ID = playerGlobals[PlayerID].uniqueIDBases++; 16 17 17 18 // anchor building: seen as the main building of the base. Needs to have territorial influence 18 19 this.anchor = undefined; … … 34 35 BaseManager.prototype.init = function(gameState, events, unconstructed){ 35 36 this.constructing = unconstructed; 36 37 // 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)));38 this.units = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Unit"),API3.Filters.byMetadata(PlayerID, "base", this.ID))); 39 this.buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byMetadata(PlayerID, "base", this.ID))); 39 40 40 this.workers = this.units.filter( Filters.byMetadata(PlayerID,"role","worker"));41 this.workers = this.units.filter(API3.Filters.byMetadata(PlayerID,"role","worker")); 41 42 42 43 this.workers.allowQuickIter(); 43 44 this.buildings.allowQuickIter(); … … 136 137 var type = types[i]; 137 138 // TODO: set us as "X" gatherer 138 139 139 this.buildings.filter( Filters.isDropsite(type)).forEach(function(ent) { self.initializeDropsite(gameState, ent,type) });140 this.buildings.filter(API3.Filters.isDropsite(type)).forEach(function(ent) { self.initializeDropsite(gameState, ent,type) }); 140 141 141 142 if (this.getResourceLevel(gameState, type, "all") > 1000) 142 143 this.willGather[type] = 1; … … 249 250 for (i in this.dropsites) 250 251 { 251 252 var dp = gameState.getEntityById(i); 252 var distance = SquareVectorDistance(supply.position(), dp.position());253 var distance = API3.SquareVectorDistance(supply.position(), dp.position()); 253 254 if (distance < dist && distance < this.bigRadius[type]) 254 255 { 255 256 closest = dp.id(); … … 278 279 resources.filter( function (supply) { //}){ 279 280 if (!supply.position() || !ent.position()) 280 281 return; 281 var distance = SquareVectorDistance(supply.position(), ent.position());282 var distance = API3.SquareVectorDistance(supply.position(), ent.position()); 282 283 283 284 if (supply.getMetadata(PlayerID, "linked-dropsite") == undefined || supply.getMetadata(PlayerID, "linked-dropsite-dist") > distance) { 284 285 if (distance < self.bigRadius[type]) { … … 294 295 } 295 296 }); 296 297 // This one is both for the nearby and the linked 297 var filter = Filters.byMetadata(PlayerID, "linked-dropsite", ent.id());298 var filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite", ent.id()); 298 299 var collection = resources.filter(filter); 299 300 collection.registerUpdates(); 300 301 301 filter = Filters.byMetadata(PlayerID, "linked-dropsite-close",true);302 filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite-close",true); 302 303 var collection2 = collection.filter(filter); 303 304 collection2.registerUpdates(); 304 305 305 filter = Filters.byMetadata(PlayerID, "linked-dropsite-nearby",true);306 filter = API3.Filters.byMetadata(PlayerID, "linked-dropsite-nearby",true); 306 307 var collection3 = collection.filter(filter); 307 308 collection3.registerUpdates(); 308 309 309 filter = Filters.byMetadata(PlayerID, "linked-to-dropsite", ent.id());310 filter = API3.Filters.byMetadata(PlayerID, "linked-to-dropsite", ent.id()); 310 311 var WkCollection = this.workers.filter(filter); 311 312 WkCollection.registerUpdates(); 312 313 … … 318 319 // TODO: get workers on those resources and do something with them. 319 320 } 320 321 321 if ( Config.debug)322 if (this.Config.debug) 322 323 { 323 324 // Make resources glow wildly 324 325 if (type == "food") { 325 326 self.dropsites[ent.id()][type][2].forEach(function(ent){ 326 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]});327 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]}); 327 328 }); 328 329 self.dropsites[ent.id()][type][1].forEach(function(ent){ 329 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]});330 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]}); 330 331 }); 331 332 self.dropsites[ent.id()][type][0].forEach(function(ent){ 332 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]});333 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); 333 334 }); 334 335 } 335 336 if (type == "wood") { 336 337 self.dropsites[ent.id()][type][2].forEach(function(ent){ 337 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]});338 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]}); 338 339 }); 339 340 self.dropsites[ent.id()][type][1].forEach(function(ent){ 340 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]});341 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]}); 341 342 }); 342 343 self.dropsites[ent.id()][type][0].forEach(function(ent){ 343 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]});344 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); 344 345 }); 345 346 } 346 347 if (type == "stone") { 347 348 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]});349 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]}); 349 350 }); 350 351 self.dropsites[ent.id()][type][1].forEach(function(ent){ 351 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]});352 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]}); 352 353 }); 353 354 self.dropsites[ent.id()][type][0].forEach(function(ent){ 354 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]});355 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]}); 355 356 }); 356 357 } 357 358 if (type == "metal") { 358 359 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]});360 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]}); 360 361 }); 361 362 self.dropsites[ent.id()][type][1].forEach(function(ent){ 362 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]});363 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]}); 363 364 }); 364 365 self.dropsites[ent.id()][type][0].forEach(function(ent){ 365 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]});366 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]}); 366 367 }); 367 368 } 368 369 } … … 407 408 // Then checks for a good spot in the territory. If none, and town/city phase, checks outside 408 409 // The AI will currently not build a CC if it wouldn't connect with an existing CC. 409 410 410 var territory = Map.createTerritoryMap(gameState);411 var territory = API3.Map.createTerritoryMap(gameState); 411 412 412 var obstructions = Map.createObstructionMap(gameState,this.accessIndex,storeHousePlate);413 var obstructions = API3.Map.createObstructionMap(gameState,this.accessIndex,storeHousePlate); 413 414 obstructions.expandInfluences(); 414 415 415 416 // copy the resource map as initialization. 416 var friendlyTiles = new Map(gameState.sharedScript, gameState.sharedScript.resourceMaps[resource].map, true);417 var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.resourceMaps[resource].map, true); 417 418 418 var DPFoundations = gameState.getOwnFoundations().filter( Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse")));419 var DPFoundations = gameState.getOwnFoundations().filter(API3.Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse"))); 419 420 420 421 // TODO: might be better to check dropsites someplace else. 421 422 // loop over this in this.terrytoryindices. It's usually a little too much, but it's always enough. … … 434 435 { 435 436 var pos = [j%friendlyTiles.width, Math.floor(j/friendlyTiles.width)]; 436 437 var dpPos = gameState.getEntityById(i).position(); 437 if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250)438 if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) 438 439 { 439 440 friendlyTiles.map[j] = 0; 440 441 continue; 441 } else if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450)442 } else if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) 442 443 friendlyTiles.map[j] /= 2; 443 444 } 444 445 for (var i in DPFoundations._entities) 445 446 { 446 447 var pos = [j%friendlyTiles.width, Math.floor(j/friendlyTiles.width)]; 447 448 var dpPos = gameState.getEntityById(i).position(); 448 if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250)449 if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 250) 449 450 friendlyTiles.map[j] = 0; 450 else if (dpPos && SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450)451 else if (dpPos && API3.SquareVectorDistance(friendlyTiles.gamePosToMapPos(dpPos), pos) < 450) 451 452 friendlyTiles.map[j] /= 2; 452 453 } 453 454 } 454 455 455 if ( Config.debug)456 if (this.Config.debug) 456 457 friendlyTiles.dumpIm("DP_" + resource + "_" + gameState.getTimeElapsed() + ".png"); 457 458 458 459 var best = friendlyTiles.findBestTile(2, obstructions); // try to find a spot to place a DP. … … 535 536 if (searchType == "all") 536 537 { 537 538 // return all resources in the base area. 538 gameState.getResourceSupplies(type).filter( Filters.byTerritory(gameState.ai.HQ.basesMap, this.ID)).forEach( function (ent) { //}){539 gameState.getResourceSupplies(type).filter(API3.Filters.byTerritory(gameState.ai.HQ.basesMap, this.ID)).forEach( function (ent) { //}){ 539 540 count += ent.resourceSupplyAmount(); 540 541 }); 541 542 return count; … … 589 590 if (!this.isFarming && count < 1600 && queues.field.length === 0) 590 591 { 591 592 // tell the queue manager we'll be trying to build fields shortly. 592 for (var i = 0; i < Config.Economy.initialFields;++i)593 for (var i = 0; i < this.Config.Economy.initialFields;++i) 593 594 { 594 595 var plan = new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }); 595 596 plan.isGo = function() { return false; }; // don't start right away. … … 604 605 if (this.isFarming) 605 606 { 606 607 var numFarms = 0; 607 this.buildings.filter( Filters.byClass("Field")).forEach(function (field) {608 this.buildings.filter(API3.Filters.byClass("Field")).forEach(function (field) { 608 609 if (field.resourceSupplyAmount() > 400) 609 610 numFarms++; 610 611 }); … … 646 647 647 648 BaseManager.prototype.assignRolelessUnits = function(gameState) { 648 649 // TODO: make this cleverer. 649 var roleless = this.units.filter( Filters.not(Filters.byHasMetadata(PlayerID, "role")));650 var roleless = this.units.filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "role"))); 650 651 var self = this; 651 652 roleless.forEach(function(ent) { 652 653 if (ent.hasClass("Worker") || ent.hasClass("CitizenSoldier")) { … … 702 703 var self = this; 703 704 704 705 // 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")));706 var filter = API3.Filters.or(API3.Filters.byMetadata(PlayerID,"subrole","idle"), API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"subrole"))); 706 707 var idleWorkers = gameState.updatingCollection("idle-workers-base-" + this.ID, filter, this.workers); 707 708 708 709 if (idleWorkers.length) { … … 735 736 }; 736 737 737 738 BaseManager.prototype.workersBySubrole = function(gameState, subrole) { 738 return gameState.updatingCollection("subrole-" + subrole +"-base-" + this.ID, Filters.byMetadata(PlayerID, "subrole", subrole), this.workers, true);739 return gameState.updatingCollection("subrole-" + subrole +"-base-" + this.ID, API3.Filters.byMetadata(PlayerID, "subrole", subrole), this.workers, true); 739 740 }; 740 741 741 742 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"));743 return gameState.updatingCollection("workers-gathering-" + type +"-base-" + this.ID, API3.Filters.byMetadata(PlayerID, "gather-type", type), this.workersBySubrole(gameState, "gatherer")); 743 744 }; 744 745 745 746 746 747 // returns an entity collection of workers. 747 748 // They are idled immediatly and their subrole set to idle. 748 749 BaseManager.prototype.pickBuilders = function(gameState, number) { 749 var collec = new EntityCollection(gameState.sharedScript);750 var collec = new API3.EntityCollection(gameState.sharedScript); 750 751 // TODO: choose better. 751 var workers = this.workers.filter( Filters.not(Filters.byClass("Cavalry"))).toEntityArray();752 var workers = this.workers.filter(API3.Filters.not(API3.Filters.byClass("Cavalry"))).toEntityArray(); 752 753 workers.sort(function (a,b) { 753 754 var vala = 0, valb = 0; 754 755 if (a.getMetadata(PlayerID,"subrole") == "builder") … … 771 772 } 772 773 773 774 BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { 775 774 776 // If we have some foundations, and we don't have enough builder-workers, 775 777 // try reassigning some other workers who are nearby 776 778 … … 778 780 779 781 var self = this; 780 782 781 var foundations = this.buildings.filter( Filters.and(Filters.isFoundation(),Filters.not(Filters.byClass("Field")))).toEntityArray();783 var foundations = this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(),API3.Filters.not(API3.Filters.byClass("Field")))).toEntityArray(); 782 784 var damagedBuildings = this.buildings.filter(function (ent) { if (ent.needsRepair() && ent.getMetadata(PlayerID, "plan") == undefined) { return true; } return false; }).toEntityArray(); 783 785 784 786 // Check if nothing to build 785 787 if (!foundations.length && !damagedBuildings.length){ 786 788 return; 787 789 } 788 var workers = this.workers.filter( Filters.not(Filters.byClass("Cavalry")));790 var workers = this.workers.filter(API3.Filters.not(API3.Filters.byClass("Cavalry"))); 789 791 var builderWorkers = this.workersBySubrole(gameState, "builder"); 790 var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter( Filters.isIdle());792 var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter(API3.Filters.isIdle()); 791 793 792 794 // 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)795 if (this.constructing == true && this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(), API3.Filters.byMetadata(PlayerID, "baseAnchor", true))).length !== 0) 794 796 { 795 foundations = this.buildings.filter( Filters.byMetadata(PlayerID, "baseAnchor", true)).toEntityArray();797 foundations = this.buildings.filter(API3.Filters.byMetadata(PlayerID, "baseAnchor", true)).toEntityArray(); 796 798 var tID = foundations[0].id(); 797 799 workers.forEach(function (ent) { //}){ 798 800 var target = ent.getMetadata(PlayerID, "target-foundation"); … … 832 834 833 835 var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length; 834 836 835 var targetNB = Config.Economy.targetNumBuilders; // TODO: dynamic that.837 var targetNB = this.Config.Economy.targetNumBuilders; // TODO: dynamic that. 836 838 if (target.hasClass("CivCentre") || target.buildTime() > 150 || target.hasClass("House")) 837 839 targetNB *= 2; 838 840 if (target.getMetadata(PlayerID, "baseAnchor") == true) … … 844 846 var addedToThis = 0; 845 847 846 848 idleBuilderWorkers.forEach(function(ent) { 847 if (ent.position() && SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB)849 if (ent.position() && API3.SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB) 848 850 { 849 851 addedWorkers++; 850 852 addedToThis++; … … 876 878 } else if (noRepair && !target.hasClass("CivCentre")) 877 879 continue; 878 880 879 var territory = Map.createTerritoryMap(gameState);881 var territory = API3.Map.createTerritoryMap(gameState); 880 882 if (territory.getOwner(target.position()) !== PlayerID || territory.getOwner([target.position()[0] + 5, target.position()[1]]) !== PlayerID) 881 883 continue; 882 884 -
binaries/data/mods/public/simulation/ai/aegis/defence.js
1 1 // directly imported from Marilyn, with slight modifications to work with qBot. 2 2 3 function Defence( ){3 function Defence(Config){ 4 4 this.defenceRatio = Config.Defence.defenceRatio;// How many defenders we want per attacker. Need to balance fewer losses vs. lost economy 5 5 // note: the choice should be a no-brainer most of the time: better deflect the attack. 6 6 // This is also sometimes forcebly overcome by the defense manager. … … 54 54 55 55 // a litlle cache-ing 56 56 if (!this.idleDefs) { 57 var filter = Filters.and(Filters.byMetadata(PlayerID, "role", "defence"),Filters.isIdle());57 var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "role", "defence"), API3.Filters.isIdle()); 58 58 this.idleDefs = gameState.getOwnEntities().filter(filter); 59 59 this.idleDefs.registerUpdates(); 60 60 } 61 61 if (!this.defenders) { 62 var filter = Filters.byMetadata(PlayerID, "role", "defence");62 var filter = API3.Filters.byMetadata(PlayerID, "role", "defence"); 63 63 this.defenders = gameState.getOwnEntities().filter(filter); 64 64 this.defenders.registerUpdates(); 65 65 } 66 66 /*if (!this.listedEnemyCollection) { 67 var filter = Filters.byMetadata(PlayerID, "listed-enemy", true);67 var filter = API3.Filters.byMetadata(PlayerID, "listed-enemy", true); 68 68 this.listedEnemyCollection = gameState.getEnemyEntities().filter(filter); 69 69 this.listedEnemyCollection.registerUpdates(); 70 70 } 71 this.myBuildings = gameState.getOwnEntities().filter( Filters.byClass("Structure")).toEntityArray();72 this.myUnits = gameState.getOwnEntities().filter( Filters.byClass("Unit"));71 this.myBuildings = gameState.getOwnEntities().filter(API3.Filters.byClass("Structure")).toEntityArray(); 72 this.myUnits = gameState.getOwnEntities().filter(API3.Filters.byClass("Unit")); 73 73 */ 74 var filter = Filters.and(Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]),Filters.byOwner(PlayerID));74 var filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(PlayerID)); 75 75 this.myUnits = gameState.updatingGlobalCollection("player-" +PlayerID + "-soldiers", filter); 76 76 77 filter = Filters.and(Filters.byClass("Structure"),Filters.byOwner(PlayerID));77 filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(PlayerID)); 78 78 this.myBuildings = gameState.updatingGlobalCollection("player-" +PlayerID + "-structures", filter); 79 79 80 this.territoryMap = Map.createTerritoryMap(gameState); // used by many func80 this.territoryMap = API3.Map.createTerritoryMap(gameState); // used by many func 81 81 82 82 // First step: we deal with enemy armies, those are the highest priority. 83 83 this.defendFromEnemies(gameState, events, HQ); … … 151 151 if (army.getCentrePosition() === undefined) 152 152 { 153 153 } else { 154 if ( SquareVectorDistance(army.getCentrePosition(), entity.position()) < this.armyCompactSize)154 if (API3.SquareVectorDistance(army.getCentrePosition(), entity.position()) < this.armyCompactSize) 155 155 { 156 156 entity.setMetadata(PlayerID, "inArmy", armyIndex); 157 157 army.addEnt(entity); … … 163 163 if (HQ) 164 164 { 165 165 var self = this; 166 var close = HQ.enemyWatchers[entity.owner()].enemySoldiers.filter( Filters.byDistance(entity.position(), self.armyCompactSize));166 var close = HQ.enemyWatchers[entity.owner()].enemySoldiers.filter(API3.Filters.byDistance(entity.position(), self.armyCompactSize)); 167 167 if (!minNBForArmy || close.length >= minNBForArmy) 168 168 { 169 169 // 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())]);170 var newArmy = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(entity.owner())]); 171 171 newArmy.addEnt(entity); 172 172 newArmy.freeze(); 173 173 newArmy.registerUpdates(); … … 184 184 } 185 185 } else { 186 186 // 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())]);187 var newArmy = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(entity.owner())]); 188 188 newArmy.addEnt(entity); 189 189 newArmy.freeze(); 190 190 newArmy.registerUpdates(); … … 210 210 { 211 211 if (!this.myBuildings._entities[i].hasClass("ConquestCritical")) 212 212 continue; 213 if ( SquareVectorDistance(this.myBuildings._entities[i].position(), entity.position()) < 6000)213 if (API3.SquareVectorDistance(this.myBuildings._entities[i].position(), entity.position()) < 6000) 214 214 return true; 215 215 } 216 216 return false; … … 313 313 } else { 314 314 army.forEach(function (ent) { //}){ 315 315 // check if the unit is a breakaway 316 if (ent.position() && SquareVectorDistance(position, ent.position()) > self.armyBreakawaySize)316 if (ent.position() && API3.SquareVectorDistance(position, ent.position()) > self.armyBreakawaySize) 317 317 { 318 318 ent.setMetadata(PlayerID, "inArmy", undefined); 319 319 army.removeEnt(ent); … … 322 322 } else { 323 323 // check if we have registered that unit already. 324 324 if (self.listOfEnemies[ent.id()] === undefined) { 325 self.listOfEnemies[ent.id()] = new EntityCollection(gameState.sharedScript, {}, [Filters.byOwner(ent.owner())]);325 self.listOfEnemies[ent.id()] = new API3.EntityCollection(gameState.sharedScript, {}, [API3.Filters.byOwner(ent.owner())]); 326 326 self.listOfEnemies[ent.id()].freeze(); 327 327 self.listOfEnemies[ent.id()].addEnt(ent); 328 328 self.listOfEnemies[ent.id()].registerUpdates(); 329 329 330 self.attackerCache[ent.id()] = self.myUnits.filter( Filters.byTargetedEntity(ent.id()));330 self.attackerCache[ent.id()] = self.myUnits.filter(API3.Filters.byTargetedEntity(ent.id())); 331 331 self.attackerCache[ent.id()].registerUpdates(); 332 332 nbOfAttackers++; 333 333 self.nbAttackers++; … … 373 373 374 374 if (this.nbAttackers === 0 && this.nbDefenders === 0) { 375 375 // Release all our units 376 this.myUnits.filter( Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){376 this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ 377 377 defender.stopMoving(); 378 378 if (defender.getMetadata(PlayerID, "formerrole")) 379 379 defender.setMetadata(PlayerID, "role", defender.getMetadata(PlayerID, "formerrole") ); … … 387 387 return; 388 388 } else if (this.nbAttackers === 0 && this.nbDefenders !== 0) { 389 389 // Release all our units 390 this.myUnits.filter( Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){390 this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ 391 391 defender.stopMoving(); 392 392 if (defender.getMetadata(PlayerID, "formerrole")) 393 393 defender.setMetadata(PlayerID, "role", defender.getMetadata(PlayerID, "formerrole") ); … … 419 419 } 420 420 421 421 // 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) { //}){422 if (this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).length > nbOfAttackers*this.defenceRatio*1.2) { 423 this.myUnits.filter(API3.Filters.byMetadata(PlayerID, "role","defence")).forEach(function (defender) { //}){ 424 424 if ( defender.isIdle() || (defender.unitAIOrderData() && defender.unitAIOrderData()["target"])) { 425 425 if ( defender.isIdle() || (self.attackerCache[defender.unitAIOrderData()["target"]] && self.attackerCache[defender.unitAIOrderData()["target"]].length > 3)) { 426 426 // okay release me. … … 437 437 } 438 438 439 439 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")));440 var nonDefenders = this.myUnits.filter(API3.Filters.or(API3.Filters.not(API3.Filters.byMetadata(PlayerID, "role","defence")),API3.Filters.isIdle())); 441 nonDefenders = nonDefenders.filter(API3.Filters.not(API3.Filters.byClass("Female"))); 442 nonDefenders = nonDefenders.filter(API3.Filters.not(API3.Filters.byMetadata(PlayerID, "subrole","attacking"))); 443 443 var defenceRatio = this.defenceRatio; 444 444 445 445 if (newEnemies.length + this.nbAttackers > (this.nbDefenders + nonDefenders.length) * 0.8 && this.nbAttackers > 9) … … 457 457 if ( (nonDefenders.length + this.nbDefenders > newEnemies.length + this.nbAttackers) 458 458 || this.nbDefenders + nonDefenders.length < 4) 459 459 { 460 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).toEntityArray();460 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); 461 461 buildings.forEach( function (struct) { 462 462 if (struct.garrisoned() && struct.garrisoned().length) 463 463 struct.unloadAll(); … … 513 513 { 514 514 var ent = nonDefenders._entities[id]; 515 515 if (ent.position()) 516 data.push([id, ent, SquareVectorDistance(enemy.position(), ent.position())]);516 data.push([id, ent, API3.SquareVectorDistance(enemy.position(), ent.position())]); 517 517 } 518 518 // refine the defenders we want. Since it's the distance squared, it has the effect 519 519 // of tending to always prefer closer units, though this refinement should change it slighty. … … 547 547 for each (var val in data.slice(0, Math.min(nonDefenders._length, defRatio - assigned))) 548 548 ret[val[0]] = val[1]; 549 549 550 var defs = new EntityCollection(nonDefenders._ai, ret);550 var defs = new API3.EntityCollection(nonDefenders._ai, ret); 551 551 552 552 // successfully sorted 553 553 defs.forEach(function (defender) { //}){ … … 571 571 /*if (gameState.defcon() <= 3) 572 572 { 573 573 // 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"));574 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray(); 575 var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support")); 576 576 577 577 var cache = {}; 578 578 var garrisoned = false; … … 580 580 garrisoned = false; 581 581 if (ent.position()) 582 582 { 583 if ( SquareVectorDistance(ent.position(), enemy.position()) < 3500)583 if (API3.SquareVectorDistance(ent.position(), enemy.position()) < 3500) 584 584 { 585 585 for (var i in buildings) 586 586 { … … 646 646 if (territory === PlayerID) 647 647 { 648 648 // 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);649 this.listOfWantedUnits[attacker.id()] = new API3.EntityCollection(gameState.sharedScript); 650 650 this.listOfWantedUnits[attacker.id()].addEnt(attacker); 651 651 this.listOfWantedUnits[attacker.id()].freeze(); 652 652 this.listOfWantedUnits[attacker.id()].registerUpdates(); 653 653 654 var filter = Filters.byTargetedEntity(attacker.id());654 var filter = API3.Filters.byTargetedEntity(attacker.id()); 655 655 this.WantedUnitsAttacker[attacker.id()] = this.myUnits.filter(filter); 656 656 this.WantedUnitsAttacker[attacker.id()].registerUpdates(); 657 657 } … … 666 666 667 667 // Right now, to make the AI less gameable, we'll mark any surrounding resource as inaccessible. 668 668 // usual tower range is 80. Be on the safe side. 669 var close = gameState.getResourceSupplies("wood").filter( Filters.byDistance(attacker.position(), 90));669 var close = gameState.getResourceSupplies("wood").filter(API3.Filters.byDistance(attacker.position(), 90)); 670 670 close.forEach(function (supply) { //}){ 671 671 supply.setMetadata(PlayerID, "inaccessible", true); 672 672 }); … … 683 683 if (this.reevaluateEntity(gameState, attacker)) 684 684 { 685 685 var position = attacker.position(); 686 var close = HQ.enemyWatchers[attacker.owner()].enemySoldiers.filter( Filters.byDistance(position, self.armyCompactSize));686 var close = HQ.enemyWatchers[attacker.owner()].enemySoldiers.filter(API3.Filters.byDistance(position, self.armyCompactSize)); 687 687 688 688 if (close.length > 2 || ourUnit.hasClass("Support") || attacker.hasClass("Siege")) 689 689 { … … 692 692 armyID = attacker.getMetadata(PlayerID, "inArmy"); 693 693 694 694 close.forEach(function (ent) { //}){ 695 if ( SquareVectorDistance(position, ent.position()) < self.armyCompactSize)695 if (API3.SquareVectorDistance(position, ent.position()) < self.armyCompactSize) 696 696 { 697 697 ent.setMetadata(PlayerID, "inArmy", armyID); 698 698 self.enemyArmy[ent.owner()][armyID].addEnt(ent); … … 708 708 // let's try to garrison this support unit. 709 709 if (ourUnit.position()) 710 710 { 711 var buildings = gameState.getOwnEntities().filter( Filters.byCanGarrison()).filterNearest(ourUnit.position(),4).toEntityArray();711 var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).filterNearest(ourUnit.position(),4).toEntityArray(); 712 712 var garrisoned = false; 713 713 for (var i in buildings) 714 714 { -
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/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 }; -
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"; … … 221 106 222 107 // Get the constructor name from the metadata 223 108 std::string constructor; 224 if (!m_ScriptInterface .GetProperty(metadata.get(), "constructor", constructor))109 if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor)) 225 110 { 226 111 LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); 227 112 return false; … … 229 114 230 115 // Get the constructor function from the loaded scripts 231 116 CScriptVal ctor; 232 if (!m_ScriptInterface .GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor)117 if (!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), constructor.c_str(), ctor) 233 118 || ctor.undefined()) 234 119 { 235 120 LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); 236 121 return false; 237 122 } 238 123 239 m_ScriptInterface .GetProperty(metadata.get(), "useShared", m_UseSharedComponent);124 m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent); 240 125 241 126 CScriptVal obj; 242 127 … … 244 129 { 245 130 // Set up the data to pass as the constructor argument 246 131 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);132 m_ScriptInterface->Eval(L"({})", settings); 133 m_ScriptInterface->SetProperty(settings.get(), "player", m_Player, false); 134 m_ScriptInterface->SetProperty(settings.get(), "difficulty", m_Difficulty, false); 250 135 ENSURE(m_Worker.m_HasLoadedEntityTemplates); 251 m_ScriptInterface .SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false);136 m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); 252 137 253 obj = m_ScriptInterface .CallConstructor(ctor.get(), settings.get());138 obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get()); 254 139 } 255 140 else 256 141 { 257 142 // For deserialization, we want to create the object with the correct prototype 258 143 // but don't want to actually run the constructor again 259 144 // XXX: actually we don't currently use this path for deserialization - maybe delete it? 260 obj = m_ScriptInterface .NewObjectFromConstructor(ctor.get());145 obj = m_ScriptInterface->NewObjectFromConstructor(ctor.get()); 261 146 } 262 147 263 148 if (obj.undefined()) … … 266 151 return false; 267 152 } 268 153 269 m_Obj = CScriptValRooted(m_ScriptInterface .GetContext(), obj);154 m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj); 270 155 return true; 271 156 } 272 157 273 void Run(CScriptVal state )158 void Run(CScriptVal state, int playerID) 274 159 { 275 160 m_Commands.clear(); 276 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "HandleMessage", state);161 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID); 277 162 } 278 163 // overloaded with a sharedAI part. 279 164 // javascript can handle both natively on the same function. 280 void Run(CScriptVal state, CScriptValRooted SharedAI)165 void Run(CScriptVal state, int playerID, CScriptValRooted SharedAI) 281 166 { 282 167 m_Commands.clear(); 283 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "HandleMessage", state, SharedAI);168 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID, SharedAI); 284 169 } 285 170 void InitAI(CScriptVal state, CScriptValRooted SharedAI) 286 171 { 287 172 m_Commands.clear(); 288 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "Init", state, SharedAI);173 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "Init", state, m_Player, SharedAI); 289 174 } 290 175 291 176 CAIWorker& m_Worker; … … 294 179 uint8_t m_Difficulty; 295 180 bool m_UseSharedComponent; 296 181 297 ScriptInterfacem_ScriptInterface;182 shared_ptr<ScriptInterface> m_ScriptInterface; 298 183 CScriptValRooted m_Obj; 299 184 std::vector<shared_ptr<ScriptInterface::StructuredClone> > m_Commands; 300 std::set<std::wstring> m_LoadedModules;301 185 }; 302 186 303 187 public: … … 313 197 // removed as soon whenever the new pathfinder is committed 314 198 // And the AIs can stop relying on their own little hands. 315 199 m_ScriptRuntime(ScriptInterface::CreateRuntime(33554432)), 316 m_ScriptInterface( "Engine", "AI", m_ScriptRuntime),200 m_ScriptInterface(new ScriptInterface("Engine", "AI", m_ScriptRuntime)), 317 201 m_TurnNum(0), 318 202 m_CommandsComputed(true), 319 203 m_HasLoadedEntityTemplates(false), … … 321 205 { 322 206 323 207 // 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();208 m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG); 209 m_ScriptInterface->LoadGlobalScripts(); 326 210 327 m_ScriptInterface .SetCallbackData(NULL);211 m_ScriptInterface->SetCallbackData(static_cast<void*> (this)); 328 212 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"); 213 m_ScriptInterface->RegisterFunction<void, int, CScriptValRooted, CAIWorker::PostCommand>("PostCommand"); 214 m_ScriptInterface->RegisterFunction<void, std::wstring, CAIWorker::IncludeModule>("IncludeModule"); 215 m_ScriptInterface->RegisterFunction<void, CAIWorker::DumpHeap>("DumpHeap"); 216 m_ScriptInterface->RegisterFunction<void, CAIWorker::ForceGC>("ForceGC"); 332 217 333 m_ScriptInterface .RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIWorker::DumpImage>("DumpImage");218 m_ScriptInterface->RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIWorker::DumpImage>("DumpImage"); 334 219 } 335 220 336 221 ~CAIWorker() … … 343 228 m_PassabilityMapVal = CScriptValRooted(); 344 229 m_TerritoryMapVal = CScriptValRooted(); 345 230 } 231 232 bool LoadScripts(const std::wstring& moduleName) 233 { 234 // Ignore modules that are already loaded 235 if (m_LoadedModules.find(moduleName) != m_LoadedModules.end()) 236 return true; 346 237 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) 238 // Mark this as loaded, to prevent it recursively loading itself 239 m_LoadedModules.insert(moduleName); 240 241 // Load and execute *.js 242 VfsPaths pathnames; 243 vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames); 244 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it) 245 { 246 if (!m_ScriptInterface->LoadGlobalScriptFile(*it)) 247 { 248 LOGERROR(L"Failed to load script %ls", it->string().c_str()); 249 return false; 250 } 251 } 252 253 return true; 254 } 255 256 static void IncludeModule(void* cbdata, std::wstring name) 351 257 { 352 if (cbdata == NULL) { 353 debug_warn(L"Warning: the shared component has tried to push an engine command. Ignoring."); 354 return; 258 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 259 self->LoadScripts(name); 260 } 261 262 static void PostCommand(void* cbdata, int playerid, CScriptValRooted cmd) 263 { 264 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 265 self->PostCommand(playerid, cmd); 266 } 267 268 void PostCommand(int playerid, CScriptValRooted cmd) 269 { 270 bool playerFound = false; 271 for (int i=0; i<m_Players.size(); i++) 272 { 273 if (m_Players[i]->m_Player == playerid) 274 { 275 m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd.get())); 276 playerFound = true; 277 } 355 278 } 356 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata); 357 self->m_Commands.push_back(self->m_ScriptInterface.WriteStructuredClone(cmd.get())); 279 280 if (!playerFound) 281 LOGERROR(L"Invalid playerid in PostCommand!"); 358 282 } 359 283 // The next two ought to be implmeneted someday but for now as it returns "null" it can't 360 284 static void DumpHeap(void* cbdata) … … 364 288 return; 365 289 } 366 290 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 367 self->m_ScriptInterface .DumpHeap();291 self->m_ScriptInterface->DumpHeap(); 368 292 } 369 293 static void ForceGC(void* cbdata) 370 294 { … … 374 298 } 375 299 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 376 300 PROFILE3("AI compute GC"); 377 JS_GC(self->m_ScriptInterface .GetContext());301 JS_GC(self->m_ScriptInterface->GetContext()); 378 302 } 379 303 380 304 /** … … 424 348 425 349 // reset the value so it can be used to determine if we actually initialized it. 426 350 m_HasSharedComponent = false; 427 351 352 if (LoadScripts(L"common-api-v3")) 353 m_HasSharedComponent = true; 354 else 355 return false; 356 /* 428 357 VfsPaths sharedPathnames; 429 358 // Check for "shared" module. 430 359 vfs::GetPathnames(g_VFS, L"simulation/ai/common-api-v3/", L"*.js", sharedPathnames); 431 360 for (VfsPaths::iterator it = sharedPathnames.begin(); it != sharedPathnames.end(); ++it) 432 361 { 433 if (!m_ScriptInterface .LoadGlobalScriptFile(*it))362 if (!m_ScriptInterface->LoadGlobalScriptFile(*it)) 434 363 { 435 364 LOGERROR(L"Failed to load shared script %ls", it->string().c_str()); 436 365 return false; … … 439 368 } 440 369 if (!m_HasSharedComponent) 441 370 return false; 442 371 */ 443 372 // mainly here for the error messages 444 373 OsPath path = L"simulation/ai/common-api-v2/"; 445 374 446 // Constructor name is SharedScript 375 // Constructor name is SharedScript, it's in the module API3 376 // TODO: Hardcoding this bad, we need a smarter way. 377 CScriptVal AIModule; 447 378 CScriptVal ctor; 448 if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), "SharedScript", ctor) 379 if (!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), "API3", AIModule) || AIModule.undefined()) 380 { 381 LOGERROR(L"Failed to create shared AI component: %ls: can't find module '%hs'", path.string().c_str(), "API3"); 382 return false; 383 } 384 385 if (!m_ScriptInterface->GetProperty(AIModule.get(), "SharedScript", ctor) 449 386 || ctor.undefined()) 450 387 { 451 388 LOGERROR(L"Failed to create shared AI component: %ls: can't find constructor '%hs'", path.string().c_str(), "SharedScript"); … … 454 391 455 392 // Set up the data to pass as the constructor argument 456 393 CScriptVal settings; 457 m_ScriptInterface .Eval(L"({})", settings);394 m_ScriptInterface->Eval(L"({})", settings); 458 395 CScriptVal playersID; 459 m_ScriptInterface .Eval(L"({})", playersID);396 m_ScriptInterface->Eval(L"({})", playersID); 460 397 461 398 for (size_t i = 0; i < m_Players.size(); ++i) 462 399 { 463 jsval val = m_ScriptInterface .ToJSVal(m_ScriptInterface.GetContext(), m_Players[i]->m_Player);464 m_ScriptInterface .SetPropertyInt(playersID.get(), i, CScriptVal(val), true);400 jsval val = m_ScriptInterface->ToJSVal(m_ScriptInterface->GetContext(), m_Players[i]->m_Player); 401 m_ScriptInterface->SetPropertyInt(playersID.get(), i, CScriptVal(val), true); 465 402 } 466 403 467 m_ScriptInterface .SetProperty(settings.get(), "players", playersID);404 m_ScriptInterface->SetProperty(settings.get(), "players", playersID); 468 405 ENSURE(m_HasLoadedEntityTemplates); 469 m_ScriptInterface .SetProperty(settings.get(), "templates", m_EntityTemplates, false);406 m_ScriptInterface->SetProperty(settings.get(), "templates", m_EntityTemplates, false); 470 407 471 408 if (hasTechs) 472 409 { 473 m_ScriptInterface .SetProperty(settings.get(), "techTemplates", m_TechTemplates, false);410 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", m_TechTemplates, false); 474 411 } 475 412 else 476 413 { 477 414 // won't get the tech templates directly. 478 415 CScriptVal fakeTech; 479 m_ScriptInterface .Eval("({})", fakeTech);480 m_ScriptInterface .SetProperty(settings.get(), "techTemplates", fakeTech, false);416 m_ScriptInterface->Eval("({})", fakeTech); 417 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", fakeTech, false); 481 418 } 482 m_SharedAIObj = CScriptValRooted(m_ScriptInterface .GetContext(),m_ScriptInterface.CallConstructor(ctor.get(), settings.get()));419 m_SharedAIObj = CScriptValRooted(m_ScriptInterface->GetContext(),m_ScriptInterface->CallConstructor(ctor.get(), settings.get())); 483 420 484 421 485 422 if (m_SharedAIObj.undefined()) … … 493 430 494 431 bool AddPlayer(const std::wstring& aiName, player_id_t player, uint8_t difficulty, bool callConstructor) 495 432 { 496 shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_Script Runtime, m_RNG));433 shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_ScriptInterface)); 497 434 if (!ai->Initialise(callConstructor)) 498 435 return false; 499 436 … … 501 438 if (!m_HasSharedComponent) 502 439 m_HasSharedComponent = ai->m_UseSharedComponent; 503 440 504 m_ScriptInterface .MaybeGC();441 m_ScriptInterface->MaybeGC(); 505 442 506 443 m_Players.push_back(ai); 507 444 … … 513 450 // this will be run last by InitGame.Js, passing the full game representation. 514 451 // For now it will run for the shared Component. 515 452 // This is NOT run during deserialization. 516 CScriptVal state = m_ScriptInterface .ReadStructuredClone(gameState);517 JSContext* cx = m_ScriptInterface .GetContext();453 CScriptVal state = m_ScriptInterface->ReadStructuredClone(gameState); 454 JSContext* cx = m_ScriptInterface->GetContext(); 518 455 519 456 m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, passabilityMap)); 520 457 m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, territoryMap)); 521 458 if (m_HasSharedComponent) 522 459 { 523 m_ScriptInterface .SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);524 m_ScriptInterface .SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);460 m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true); 461 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 525 462 526 m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "init", state);527 m_ScriptInterface .MaybeGC();463 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state); 464 m_ScriptInterface->MaybeGC(); 528 465 529 466 for (size_t i = 0; i < m_Players.size(); ++i) 530 467 { … … 545 482 { 546 483 m_PassabilityMap = passabilityMap; 547 484 548 JSContext* cx = m_ScriptInterface .GetContext();485 JSContext* cx = m_ScriptInterface->GetContext(); 549 486 m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_PassabilityMap)); 550 487 } 551 488 … … 553 490 { 554 491 m_TerritoryMap = territoryMap; 555 492 556 JSContext* cx = m_ScriptInterface .GetContext();493 JSContext* cx = m_ScriptInterface->GetContext(); 557 494 m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_TerritoryMap)); 558 495 } 559 496 … … 583 520 } 584 521 585 522 void RegisterTechTemplates(const shared_ptr<ScriptInterface::StructuredClone>& techTemplates) { 586 JSContext* cx = m_ScriptInterface .GetContext();587 m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface .ReadStructuredClone(techTemplates));523 JSContext* cx = m_ScriptInterface->GetContext(); 524 m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface->ReadStructuredClone(techTemplates)); 588 525 } 589 526 590 527 void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates) 591 528 { 592 529 m_HasLoadedEntityTemplates = true; 593 530 594 m_ScriptInterface .Eval("({})", m_EntityTemplates);531 m_ScriptInterface->Eval("({})", m_EntityTemplates); 595 532 596 533 for (size_t i = 0; i < templates.size(); ++i) 597 534 { 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);535 jsval val = templates[i].second->ToJSVal(m_ScriptInterface->GetContext(), false); 536 m_ScriptInterface->SetProperty(m_EntityTemplates.get(), templates[i].first.c_str(), CScriptVal(val), true); 600 537 } 601 538 602 539 // Since the template data is shared between AI players, freeze it 603 540 // to stop any of them changing it and confusing the other players 604 m_ScriptInterface .FreezeObject(m_EntityTemplates.get(), true);541 m_ScriptInterface->FreezeObject(m_EntityTemplates.get(), true); 605 542 } 606 543 607 544 void Serialize(std::ostream& stream, bool isDebug) … … 610 547 611 548 if (isDebug) 612 549 { 613 CDebugSerializer serializer( m_ScriptInterface, stream);550 CDebugSerializer serializer(*m_ScriptInterface, stream); 614 551 serializer.Indent(4); 615 552 SerializeState(serializer); 616 553 } 617 554 else 618 555 { 619 CStdSerializer serializer( m_ScriptInterface, stream);556 CStdSerializer serializer(*m_ScriptInterface, stream); 620 557 // TODO: see comment in Deserialize() 621 558 serializer.SetSerializablePrototypes(m_SerializablePrototypes); 622 559 SerializeState(serializer); … … 637 574 if (m_HasSharedComponent) 638 575 { 639 576 CScriptVal sharedData; 640 if (!m_ScriptInterface .CallFunction(m_SharedAIObj.get(), "Serialize", sharedData))577 if (!m_ScriptInterface->CallFunction(m_SharedAIObj.get(), "Serialize", sharedData)) 641 578 LOGERROR(L"AI shared script Serialize call failed"); 642 579 serializer.ScriptVal("sharedData", sharedData); 643 580 } … … 650 587 serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size()); 651 588 for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j) 652 589 { 653 CScriptVal val = m_ScriptInterface .ReadStructuredClone(m_Players[i]->m_Commands[j]);590 CScriptVal val = m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j]); 654 591 serializer.ScriptVal("command", val); 655 592 } 656 593 657 bool hasCustomSerialize = m_ScriptInterface .HasProperty(m_Players[i]->m_Obj.get(), "Serialize");594 bool hasCustomSerialize = m_ScriptInterface->HasProperty(m_Players[i]->m_Obj.get(), "Serialize"); 658 595 if (hasCustomSerialize) 659 596 { 660 597 CScriptVal scriptData; 661 if (!m_ScriptInterface .CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData))598 if (!m_ScriptInterface->CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData)) 662 599 LOGERROR(L"AI script Serialize call failed"); 663 600 serializer.ScriptVal("data", scriptData); 664 601 } … … 673 610 { 674 611 ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad 675 612 676 CStdDeserializer deserializer( m_ScriptInterface, stream);613 CStdDeserializer deserializer(*m_ScriptInterface, stream); 677 614 678 615 m_PlayerMetadata.clear(); 679 616 m_Players.clear(); … … 695 632 { 696 633 CScriptVal sharedData; 697 634 deserializer.ScriptVal("sharedData", sharedData); 698 if (!m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData))635 if (!m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData)) 699 636 LOGERROR(L"AI shared script Deserialize call failed"); 700 637 } 701 638 … … 717 654 { 718 655 CScriptVal val; 719 656 deserializer.ScriptVal("command", val); 720 m_Players.back()->m_Commands.push_back(m_ScriptInterface .WriteStructuredClone(val.get()));657 m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val.get())); 721 658 } 722 659 723 660 // TODO: this is yucky but necessary while the AIs are sharing data between contexts; … … 726 663 // prototypes could be stored in their ScriptInterface 727 664 deserializer.SetSerializablePrototypes(m_DeserializablePrototypes); 728 665 729 bool hasCustomDeserialize = m_ScriptInterface .HasProperty(m_Players.back()->m_Obj.get(), "Deserialize");666 bool hasCustomDeserialize = m_ScriptInterface->HasProperty(m_Players.back()->m_Obj.get(), "Deserialize"); 730 667 if (hasCustomDeserialize) 731 668 { 732 669 CScriptVal scriptData; 733 670 deserializer.ScriptVal("data", scriptData); 734 671 if (m_Players[i]->m_UseSharedComponent) 735 672 { 736 if (!m_ScriptInterface .CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData, m_SharedAIObj))673 if (!m_ScriptInterface->CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData, m_SharedAIObj)) 737 674 LOGERROR(L"AI script Deserialize call failed"); 738 675 } 739 else if (!m_ScriptInterface .CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData))676 else if (!m_ScriptInterface->CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData)) 740 677 { 741 678 LOGERROR(L"AI script deserialize() call failed"); 742 679 } … … 770 707 if (m_PlayerMetadata.find(path) == m_PlayerMetadata.end()) 771 708 { 772 709 // Load and cache the AI player metadata 773 m_PlayerMetadata[path] = m_ScriptInterface .ReadJSONFile(path);710 m_PlayerMetadata[path] = m_ScriptInterface->ReadJSONFile(path); 774 711 } 775 712 776 713 return m_PlayerMetadata[path]; … … 786 723 if (m_TurnNum++ % 50 == 0) 787 724 { 788 725 PROFILE3("AI compute GC"); 789 m_ScriptInterface .MaybeGC();726 m_ScriptInterface->MaybeGC(); 790 727 } 791 728 return; 792 729 } … … 795 732 CScriptVal state; 796 733 { 797 734 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);735 state = m_ScriptInterface->ReadStructuredClone(m_GameState); 736 m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true); 737 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 801 738 } 802 739 803 740 // It would be nice to do 804 // m_ScriptInterface .FreezeObject(state.get(), true);741 // m_ScriptInterface->FreezeObject(state.get(), true); 805 742 // to prevent AI scripts accidentally modifying the state and 806 743 // affecting other AI scripts they share it with. But the performance 807 744 // cost is far too high, so we won't do that. … … 810 747 if (m_HasSharedComponent) 811 748 { 812 749 PROFILE3("AI run shared component"); 813 m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state);750 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state); 814 751 } 815 752 816 753 for (size_t i = 0; i < m_Players.size(); ++i) … … 818 755 PROFILE3("AI script"); 819 756 PROFILE2_ATTR("player: %d", m_Players[i]->m_Player); 820 757 PROFILE2_ATTR("script: %ls", m_Players[i]->m_AIName.c_str()); 758 821 759 if (m_HasSharedComponent && m_Players[i]->m_UseSharedComponent) 822 m_Players[i]->Run(state, m_SharedAIObj);760 m_Players[i]->Run(state, m_Players[i]->m_Player, m_SharedAIObj); 823 761 else 824 m_Players[i]->Run(state );762 m_Players[i]->Run(state, m_Players[i]->m_Player); 825 763 } 826 764 827 765 // Run GC if we are about to overflow 828 if (JS_GetGCParameter(m_ScriptInterface .GetRuntime(), JSGC_BYTES) > 33000000)766 if (JS_GetGCParameter(m_ScriptInterface->GetRuntime(), JSGC_BYTES) > 33000000) 829 767 { 830 768 PROFILE3("AI compute GC"); 831 769 832 JS_GC(m_ScriptInterface .GetContext());770 JS_GC(m_ScriptInterface->GetContext()); 833 771 } 834 772 835 773 // Run the GC every so often. … … 838 776 /*if (m_TurnNum++ % 20 == 0) 839 777 { 840 778 PROFILE3("AI compute GC"); 841 m_ScriptInterface .MaybeGC();779 m_ScriptInterface->MaybeGC(); 842 780 }*/ 843 781 } 844 782 845 783 shared_ptr<ScriptRuntime> m_ScriptRuntime; 846 ScriptInterfacem_ScriptInterface;784 shared_ptr<ScriptInterface> m_ScriptInterface; 847 785 boost::rand48 m_RNG; 848 786 u32 m_TurnNum; 849 787 … … 858 796 CScriptValRooted m_SharedAIObj; 859 797 std::vector<SCommandSets> m_Commands; 860 798 799 std::set<std::wstring> m_LoadedModules; 800 861 801 shared_ptr<ScriptInterface::StructuredClone> m_GameState; 862 802 Grid<u16> m_PassabilityMap; 863 803 CScriptValRooted m_PassabilityMapVal;