Ticket #2322: AI_in_one_global_WIP_v0.1.diff

File AI_in_one_global_WIP_v0.1.diff, 76.9 KB (added by Yves, 10 years ago)

WIP patch showing how multiple Aegis bots can share one global object

  • binaries/data/mods/public/simulation/ai/aegis/attack_plan.js

     
    66 * There is a basic support for naval expeditions here.
    77 */
    88
    9 function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) {
     9function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy, type , targetFinder) {
    1010   
     11    this.Config = Config;
    1112    //This is the list of IDs of the units in the plan
    1213    this.idList=[];
    1314   
     
    5051   
    5152    this.maxPreparationTime = 210*1000;
    5253    // 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)
    5455        this.maxPreparationTime = 780000 - gameState.getTimeElapsed() < 120000 ? 120000 : 780000 - gameState.getTimeElapsed();
    5556   
    5657    this.pausingStart = 0;
  • binaries/data/mods/public/simulation/ai/aegis/queueplan-research.js

     
    11var ResearchPlan = function(gameState, type, startTime, expectedTime, rush) {
    22    this.type = type;
    33
    4     this.ID = uniqueIDBOPlans++;
     4    this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++;
    55
    66    this.template = gameState.getTemplate(this.type);
    77    if (!this.template || this.template.researchTime === undefined) {
  • binaries/data/mods/public/simulation/ai/aegis/map-module.js

     
    3131            for (var y = 0; y < passabilityMap.height; ++y)
    3232            {
    3333                var i = x + y*passabilityMap.width;
    34                 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
     34                var tilePlayer = (territoryMap.data[i] & 0x3F);
    3535               
    3636                if (gameState.ai.myIndex !== gameState.ai.accessibility.landPassMap[i])
    3737                {
     
    8888        var obstructionTiles = new Uint8Array(passabilityMap.data.length);
    8989        for (var i = 0; i < passabilityMap.data.length; ++i)
    9090        {
    91             var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
     91            var tilePlayer = (territoryMap.data[i] & 0x3F);
    9292            var invalidTerritory = (
    9393                                    (!buildOwn && tilePlayer == playerID) ||
    9494                                    (!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) ||
     
    133133    var ret = new Map(gameState.sharedScript, map.data);
    134134   
    135135    ret.getOwner = function(p) {
    136         return this.point(p) & TERRITORY_PLAYER_MASK;
     136        return this.point(p) & 0x3F;
    137137    }
    138138    ret.getOwnerIndex = function(p) {
    139         return this.map[p] & TERRITORY_PLAYER_MASK;
     139        return this.map[p] & 0x3F;
    140140    }
    141141    return ret;
    142142};
  • binaries/data/mods/public/simulation/ai/aegis/headquarters.js

     
    1212    -picking new CC locations.
    1313 */
    1414
    15 var HQ = function() {
    16     this.targetNumBuilders = Config.Economy.targetNumBuilders; // number of workers we want building stuff
     15var HQ = function(Config) {
    1716   
    18     this.dockStartTime =  Config.Economy.dockStartTime * 1000;
    19     this.techStartTime = Config.Economy.techStartTime * 1000;
     17    this.Config = Config;
     18    this.targetNumBuilders = this.Config.Economy.targetNumBuilders; // number of workers we want building stuff
    2019   
     20    this.dockStartTime =  this.Config.Economy.dockStartTime * 1000;
     21    this.techStartTime = this.Config.Economy.techStartTime * 1000;
     22   
    2123    this.dockFailed = false;    // sanity check
    2224    this.waterMap = false;  // set by the aegis.js file.
    2325   
     
    2729    this.baseManagers = {};
    2830   
    2931    // 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;
    3133   
    3234    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);
    3739   
    3840    this.navalManager = new NavalManager();
    3941   
     
    4850    this.basesMap = new Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length));
    4951    this.basesMap.setMaxVal(255);
    5052
    51     if (Config.Economy.targetNumWorkers)
    52         this.targetNumWorkers = Config.Economy.targetNumWorkers;
     53    if (this.Config.Economy.targetNumWorkers)
     54        this.targetNumWorkers = this.Config.Economy.targetNumWorkers;
    5355    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);
    5557
    5658
    5759    // Let's get our initial situation here.
     
    7981                if (ent.resourceSupplyType().generic === "treasure" && SquareVectorDistance(ent.position(), CC.position()) < 5000)
    8082                    treasureAmount[i] += ent.resourceSupplyMax();
    8183            });
    82         this.baseManagers[1] = new BaseManager();
     84        this.baseManagers[1] = new BaseManager(this.Config);
    8385        this.baseManagers[1].init(gameState, events);
    8486        this.baseManagers[1].setAnchor(CC);
    8587        this.baseManagers[1].initTerritory(this, gameState);
    8688        this.baseManagers[1].initGatheringFunctions(this, gameState);
    8789       
    88         if (Config.debug)
     90        if (this.Config.debug)
    8991            this.basesMap.dumpIm("basesMap.png");
    9092        var self = this;
    9193
     
    112114    }
    113115   
    114116    var map = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map);
    115     if (Config.debug)
     117    if (this.Config.debug)
    116118        map.dumpIm("map_CC_Wood.png");
    117119   
    118120    //this.reassignIdleWorkers(gameState);
     
    125127   
    126128    // load units and buildings from the config files
    127129   
    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];
    130132    }else{
    131         this.bModerate = Config.buildings.moderate['default'];
     133        this.bModerate = this.Config.buildings.moderate['default'];
    132134    }
    133135   
    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];
    136138    }else{
    137         this.bAdvanced = Config.buildings.advanced['default'];
     139        this.bAdvanced = this.Config.buildings.advanced['default'];
    138140    }
    139141   
    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];
    142144    }else{
    143         this.bFort = Config.buildings.fort['default'];
     145        this.bFort = this.Config.buildings.fort['default'];
    144146    }
    145147   
    146148    for (var i in this.bAdvanced){
     
    193195                if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1)
    194196                {
    195197                    // 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);
    198200                    this.baseManagers[bID].init(gameState, events, true);
    199201                    this.baseManagers[bID].setAnchor(ent);
    200202                    this.baseManagers[bID].initTerritory(this, gameState);
     
    411413// TODO: improve choice alogrithm
    412414HQ.prototype.switchWorkerBase = function(gameState, worker, type) {
    413415    var bestBase = 0;
     416
    414417    for (var i in this.baseManagers)
    415418    {
    416419        if (this.baseManagers[i].willGather[type] >= 1)
     
    645648    var best = friendlyTiles.findBestTile(6, obstructions);
    646649    var bestIdx = best[0];
    647650
    648     if (Config.debug)
     651    if (this.Config.debug)
    649652    {
    650653        friendlyTiles.map[bestIdx] = 270;
    651654        friendlyTiles.dumpIm("cc_placement_base_" + gameState.getTimeElapsed() + "_" + resource + "_" + best[1] + ".png",301);
     
    674677};
    675678
    676679HQ.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 ) {
    678681        if (queues.economicBuilding.countQueuedUnitsWithClass("BarterMarket") === 0 &&
    679682            gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market")) === 0){
    680683            //only ever build one storehouse/CC/market at a time
     
    685688
    686689// Build a farmstead to go to town phase faster and prepare for research. Only really active on higher diff mode.
    687690HQ.prototype.buildFarmstead = function(gameState, queues){
    688     if (gameState.getPopulation() > Config.Economy.popForFarmstead) {
     691    if (gameState.getPopulation() > this.Config.Economy.popForFarmstead) {
    689692        // achtung: "DropsiteFood" does not refer to CCs.
    690693        if (queues.economicBuilding.countQueuedUnitsWithClass("DropsiteFood") === 0 &&
    691694            gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_farmstead")) === 0){
     
    752755        if (numPlanned < 3 || (numPlanned < 5 && gameState.getPopulation() > 80))
    753756        {
    754757            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;
    755760            // change the starting condition to "less than 15 slots left".
    756761            plan.isGo = function (gameState) {
    757762                var HouseNb = gameState.countEntitiesByType(gameState.applyCiv("foundation|structures/{civ}_house"), true);
     
    761766                    freeSlots = gameState.getPopulationLimit() + HouseNb*5 - gameState.getPopulation();
    762767                else
    763768                    freeSlots = gameState.getPopulationLimit() + HouseNb*10 - gameState.getPopulation();
    764                 if (gameState.getPopulation() > 55 && Config.difficulty > 1)
     769                if (gameState.getPopulation() > 55 && difficulty > 1)
    765770                    return (freeSlots <= 21);
    766                 else if (gameState.getPopulation() >= 20 && Config.difficulty !== 0)
     771                else if (gameState.getPopulation() >= 20 && difficulty !== 0)
    767772                    return (freeSlots <= 16);
    768773                else
    769774                    return (freeSlots <= 10);
     
    781786    var capacity = { "wood" : 0, "stone" : 0, "metal" : 0 }
    782787    var need = { "wood" : true, "stone" : true, "metal" : true };
    783788    var posss = [];
     789
    784790    for (i in this.baseManagers)
    785791    {
    786792        var base = this.baseManagers[i];
    787793        for (type in count)
    788794        {
    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))
    790796                count[type]++;
    791797            capacity[type] += base.getWorkerCapacity(gameState, type);
    792798            if (base.willGather[type] !== 2)
     
    878884};
    879885
    880886HQ.prototype.buildBlacksmith = function(gameState, queues){
    881     if (gameState.getTimeElapsed() > Config.Military.timeForBlacksmith*1000) {
     887    if (gameState.getTimeElapsed() > this.Config.Military.timeForBlacksmith*1000) {
    882888        if (queues.militaryBuilding.length() === 0 &&
    883889            gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_blacksmith")) === 0) {
    884890            var tp = gameState.getTemplate(gameState.applyCiv("structures/{civ}_blacksmith"));
     
    896902    Engine.ProfileStart("Build buildings");
    897903    var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(Filters.not(Filters.byHasMetadata(PlayerID, "plan"))).length;
    898904
    899     if (workersNumber > Config.Military.popForBarracks1) {
     905    if (workersNumber > this.Config.Military.popForBarracks1) {
    900906        if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) + queues.militaryBuilding.length() < 1) {
    901907            debug ("Trying to build barracks");
    902908            queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));
    903909        }
    904910    }
    905911   
    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)
    907913        if (queues.militaryBuilding.length() < 1)
    908914            queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 }));
    909915   
     
    917923            }
    918924        }
    919925    //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){
    921927        if (queues.militaryBuilding.length() === 0){
    922928            var inConst = 0;
    923929            for (var i in this.bAdvanced)
     
    10471053
    10481054// Some functions are run every turn
    10491055// Others once in a while
    1050 HQ.prototype.update = function(gameState, queues, events) {
     1056HQ.prototype.update = function(gameState, queues, events) { 
    10511057    Engine.ProfileStart("Headquarters update");
    10521058   
    10531059    this.checkEvents(gameState,events,queues);
     
    10571063    this.trainMoreWorkers(gameState, queues);
    10581064   
    10591065    // sandbox doesn't expand.
    1060     if (Config.difficulty !== 0)
     1066    if (this.Config.difficulty !== 0)
    10611067        this.checkBasesRessLevel(gameState, queues);
    10621068
    10631069    this.buildMoreHouses(gameState,queues);
     
    10651071    if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2)
    10661072        this.tryResearchTechs(gameState,queues);
    10671073   
    1068     if (Config.difficulty > 1)
     1074    if (this.Config.difficulty > 1)
    10691075        this.tryBartering(gameState);
    10701076   
    10711077    this.buildFarmstead(gameState, queues);
     
    10871093    for (i in this.baseManagers)
    10881094    {
    10891095        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)
    10911097            this.baseManagers[i].update(gameState, queues, events);
    10921098    }
    10931099
     
    11741180    if (gameState.ai.strategy === "rush" && this.startedAttacks["CityAttack"].length !== 0) {
    11751181        // and then we revert.
    11761182        gameState.ai.strategy = "normal";
    1177         Config.Economy.femaleRatio = 0.4;
     1183        this.Config.Economy.femaleRatio = 0.4;
    11781184        gameState.ai.modules.economy.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*0.55), 1);
    11791185    } else if (gameState.ai.strategy === "rush" && this.upcomingAttacks["CityAttack"].length === 0)
    11801186    {
    1181         Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1, "rush")
     1187        Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "rush")
    11821188        this.TotalAttackNumber++;
    11831189        this.upcomingAttacks["CityAttack"].push(Lalala);
    11841190        debug ("Starting a little something");
     
    11931199            } else {
    11941200                // basically only the first plan, really.
    11951201                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);
    11971203                    if (Lalala.failed)
    11981204                    {
    11991205                        this.attackPlansEncounteredWater = true; // hack
     
    12021208                        this.TotalAttackNumber++;
    12031209                        this.upcomingAttacks["CityAttack"].push(Lalala);
    12041210                    }
    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");
    12071213                    if (Lalala.failed)
    12081214                    {
    12091215                        this.attackPlansEncounteredWater = true; // hack
     
    12431249    this.buildDropsites(gameState, queues);
    12441250    Engine.ProfileStop();
    12451251
    1246     if (Config.difficulty !== 0)
     1252    if (this.Config.difficulty !== 0)
    12471253        this.tryBartering(gameState);
    12481254       
    12491255    this.buildFarmstead(gameState, queues);
  • binaries/data/mods/public/simulation/ai/aegis/aegis.js

     
    11// "local" global variables for stuffs that will need a unique ID
    22// 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.
     3var playerGlobals = [];
     4var g_debugEnabled = false;
    65
    76function AegisBot(settings) {
    87    BaseAI.call(this, settings);
    98
    10     Config.updateDifficulty(settings.difficulty);
     9    this.Config = new Config();
     10
     11    this.Config.updateDifficulty(settings.difficulty);
    1112   
    1213    this.turn = 0;
    1314
    1415    this.playedTurn = 0;
    15        
    16     this.priorities = Config.priorities;
     16   
     17    this.priorities = this.Config.priorities;
    1718
    1819    // this.queues can only be modified by the queue manager or things will go awry.
    1920    this.queues = {};
    2021    for (i in this.priorities)
    2122        this.queues[i] = new Queue();
    2223
    23     this.queueManager = new QueueManager(this.queues, this.priorities);
     24    this.queueManager = new QueueManager(this.Config, this.queues, this.priorities);
    2425
    25     this.HQ = new HQ();
     26    this.HQ = new HQ(this.Config);
    2627
    2728    this.firstTime = true;
    2829
     
    3536AegisBot.prototype = new BaseAI();
    3637
    3738AegisBot.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
    3945    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);
    4147
    42     var ents = gameState.getEntities().filter(Filters.byOwner(PlayerID));
     48    var ents = gameState.getEntities().filter(Filters.byOwner(this.player));
    4349    var myKeyEntities = ents.filter(function(ent) {
    4450            return ent.hasClass("CivCentre");
    4551    });
    4652
    4753    if (myKeyEntities.length == 0){
    48         myKeyEntities = gameState.getEntities().filter(Filters.byOwner(PlayerID));
     54        myKeyEntities = gameState.getEntities().filter(Filters.byOwner(this.player));
    4955    }
    5056   
    5157    var filter = Filters.byClass("CivCentre");
    52     var enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(PlayerID))).filter(filter);
     58    var enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(this.player))).filter(filter);
    5359   
    5460    if (enemyKeyEntities.length == 0){
    55         enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(PlayerID)));
     61        enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(this.player)));
    5662    }
    5763
    5864    this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position());
     
    6571    var pos = [this.pathInfo.mkeyPos[0] + 150*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 150*Math.sin(this.pathInfo.angle)];
    6672    var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 2, 2);// uncomment for debug:*/, 300000, gameState);
    6773
    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);
    6975   
    7076    if (path !== undefined && path[1] !== undefined && path[1] == false) {
    7177        // path is viable and doesn't require boating.
     
    8187}
    8288
    8389AegisBot.prototype.OnUpdate = function(sharedScript) {
     90
    8491    if (this.gameFinished){
    8592        return;
    8693    }
     
    132139        var cityPhase = this.gameState.cityPhase();
    133140        // try going up phases.
    134141        // TODO: softcode this.
    135         if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40
     142        if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40
    136143            && this.gameState.findResearchers(townPhase,true).length != 0 && this.queues.majorTech.length() === 0
    137144            && this.gameState.getOwnEntities().filter(Filters.byClass("Village")).length > 5)
    138145        {
     
    142149            this.queues.majorTech.addItem(new ResearchPlan(this.gameState, townPhase,0,-1,true));   // we rush the town phase.
    143150            debug ("Trying to reach town phase");
    144151        }
    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)
    146153                && this.gameState.getOwnEntitiesByRole("worker").length > 85
    147154                && this.gameState.findResearchers(cityPhase, true).length != 0 && this.queues.majorTech.length() === 0) {
    148155            debug ("Trying to reach city phase");
     
    215222    // deactivated for now.
    216223    this.strategy = "normal";
    217224    // 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)
    219226    {
    220227        this.strategy = "rush";
    221228        // going to rush.
    222229        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.
    227234    }
    228235};
    229236
     
    238245};*/
    239246
    240247function debug(output){
    241     if (Config.debug){
     248    if (g_debugEnabled){
    242249        if (typeof output === "string"){
    243250            warn(output);
    244251        }else{
  • binaries/data/mods/public/simulation/ai/aegis/defence.js

     
    11// directly imported from Marilyn, with slight modifications to work with qBot.
    22
    3 function Defence(){
     3function Defence(Config){
    44    this.defenceRatio = Config.Defence.defenceRatio;// How many defenders we want per attacker.  Need to balance fewer losses vs. lost economy
    55                            // note: the choice should be a no-brainer most of the time: better deflect the attack.
    66                            // This is also sometimes forcebly overcome by the defense manager.
  • binaries/data/mods/public/simulation/ai/aegis/worker.js

     
    199199};
    200200
    201201Worker.prototype.startGathering = function(baseManager, gameState) {
     202
    202203    var resource = this.ent.getMetadata(PlayerID, "gather-type");
    203204    var ent = this.ent;
    204205    var self = this;
     
    254255            }
    255256        });
    256257    }
     258   
    257259    // we've found no fitting dropsites close enough from us.
    258260    // So'll try with far away.
    259261    if (!nearestResources || nearestResources.length === 0) {
     
    271273            }
    272274        });
    273275    }
    274 
     276   
    275277    if (!nearestResources || nearestResources.length === 0){
    276278        if (resource === "food")
    277279            if (this.buildAnyField(gameState))
  • binaries/data/mods/public/simulation/ai/aegis/base-manager.js

     
    1010    -updating whatever needs updating, keeping track of stuffs (rebuilding needs…)
    1111 */
    1212
    13 var BaseManager = function() {
     13var BaseManager = function(Config) {
     14    this.Config = Config;
    1415    this.farmingFields = false;
    15     this.ID = uniqueIDBases++;
     16    this.ID = playerGlobals[PlayerID].uniqueIDBases++;
    1617   
    1718    // anchor building: seen as the main building of the base. Needs to have territorial influence
    1819    this.anchor = undefined;
     
    318319        // TODO: get workers on those resources and do something with them.
    319320    }
    320321   
    321     if (Config.debug)
     322    if (this.Config.debug)
    322323    {
    323324        // Make resources glow wildly
    324325        if (type == "food") {
    325326            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]});
    327328            });
    328329            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]});
    330331            });
    331332            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]});
    333334            });
    334335        }
    335336        if (type == "wood") {
    336337            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]});
    338339            });
    339340            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]});
    341342            });
    342343            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]});
    344345            });
    345346        }
    346347        if (type == "stone") {
    347348            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]});
    349350            });
    350351            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]});
    352353            });
    353354            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]});
    355356            });
    356357        }
    357358        if (type == "metal") {
    358359            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]});
    360361            });
    361362            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]});
    363364            });
    364365            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]});
    366367            });
    367368        }
    368369    }
     
    452453        }
    453454    }
    454455   
    455     if (Config.debug)
     456    if (this.Config.debug)
    456457        friendlyTiles.dumpIm("DP_" + resource + "_" + gameState.getTimeElapsed() + ".png");
    457458   
    458459    var best = friendlyTiles.findBestTile(2, obstructions); // try to find a spot to place a DP.
     
    589590            if (!this.isFarming && count < 1600 && queues.field.length === 0)
    590591            {
    591592                // 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)
    593594                {
    594595                    var plan = new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID });
    595596                    plan.isGo = function() { return false; };   // don't start right away.
     
    771772}
    772773
    773774BaseManager.prototype.assignToFoundations = function(gameState, noRepair) {
     775
    774776    // If we have some foundations, and we don't have enough builder-workers,
    775777    // try reassigning some other workers who are nearby
    776778   
     
    832834       
    833835        var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length;
    834836
    835         var targetNB = Config.Economy.targetNumBuilders;    // TODO: dynamic that.
     837        var targetNB = this.Config.Economy.targetNumBuilders;   // TODO: dynamic that.
    836838        if (target.hasClass("CivCentre") || target.buildTime() > 150 || target.hasClass("House"))
    837839            targetNB *= 2;
    838840        if (target.getMetadata(PlayerID, "baseAnchor") == true)
  • binaries/data/mods/public/simulation/ai/aegis/plan-transport.js

     
    1818var TransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) {
    1919    var self = this;
    2020
    21     this.ID = uniqueIDTPlans++;
     21    this.ID = playerGlobals[PlayerID].uniqueIDTPlans++;
    2222   
    2323    var unitsID = [];
    2424    if (units.length !== undefined)
  • binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js

     
    44
    55    this.metadata = metadata;
    66
    7     this.ID = uniqueIDBOPlans++;
     7    this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++;
    88
    99    this.template = gameState.getTemplate(this.type);
    1010    if (!this.template) {
  • binaries/data/mods/public/simulation/ai/aegis/queue-manager.js

     
    1717//
    1818// This system should be improved. It's probably not flexible enough.
    1919
    20 var QueueManager = function(queues, priorities) {
     20var QueueManager = function(Config, queues, priorities) {
     21    this.Config = Config;
    2122    this.queues = queues;
    2223    this.priorities = priorities;
    2324    this.account = {};
     
    143144                // estimate time based on priority + cost + nb
    144145                // TODO: work on this.
    145146                for (type in qCosts)
     147                {
    146148                    qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name]));
     149                }
    147150                qTime += 30000;
    148151            } else {
    149152                // TODO: work on this.
     
    282285
    283286// nice readable HTML version.
    284287QueueManager.prototype.HTMLprintQueues = function(gameState){
    285     if (!Config.debug)
     288    if (!this.Config.debug)
    286289        return;
    287290    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> ");
    288291    for (var i in this.queues){
     
    522525        var self = this;
    523526        this.queueArrays = [];
    524527        for (var p in this.queues)
     528        {
    525529            this.queueArrays.push([p,this.queues[p]]);
     530        }
    526531        this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) });
    527532    }
    528533}
     
    539544        var self = this;
    540545        this.queueArrays = [];
    541546        for (var p in this.queues)
     547        {
    542548            this.queueArrays.push([p,this.queues[p]]);
     549        }
    543550        this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) });
    544551    }
    545552}
     
    548555    if (this.queues[queueName] !== undefined)
    549556        this.priorities[queueName] = newPriority;
    550557    this.queueArrays = [];
    551     for (var p in this.queues) {
     558    for (var p in this.queues)
     559    {
    552560        this.queueArrays.push([p,this.queues[p]]);
    553561    }
    554562    this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) });
  • binaries/data/mods/public/simulation/ai/aegis/config.js

     
    1 // Baseconfig is the highest difficulty.
    2 var baseConfig = {
    3     "Military" : {
     1var 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 = {
    46        "fortressLapseTime" : 540, // Time to wait between building 2 fortresses
    57        "defenceBuildingTime" : 600, // Time to wait before building towers or fortresses
    68        "attackPlansStartTime" : 0, // time to wait before attacking. Start as soon as possible (first barracks)
     
    810        "popForBarracks1" : 15,
    911        "popForBarracks2" : 95,
    1012        "timeForBlacksmith" : 900,
    11     },
    12     "Economy" : {
     13    };
     14    this.Economy = {
    1315        "townPhase" : 180,  // time to start trying to reach town phase (might be a while after. Still need the requirements + ress )
    1416        "cityPhase" : 840,  // time to start trying to reach city phase
    1517        "popForMarket" : 80,
     
    1921        "targetNumBuilders" : 1.5, // Base number of builders per foundation.
    2022        "femaleRatio" : 0.4, // percent of females among the workforce.
    2123        "initialFields" : 2
    22     },
     24    };
    2325   
    2426    // Note: attack settings are set directly in attack_plan.js
    2527   
    2628    // defence
    27     "Defence" : {
     29    this.Defence =
     30    {
    2831        "defenceRatio" : 5, // see defence.js for more info.
    2932        "armyCompactSize" : 700,    // squared. Half-diameter of an army.
    3033        "armyBreakawaySize" : 900  // squared.
    31     },
     34    };
    3235   
    3336    // military
    34     "buildings" : {
     37    this.buildings =
     38    {
    3539        "moderate" : {
    3640            "default" : [ "structures/{civ}_barracks" ]
    3741        },
     
    5155            "default" : [ "structures/{civ}_fortress" ],
    5256            "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ]
    5357        }
    54     },
     58    };
    5559
    5660    // 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
    5863        "house" : 350,
    5964        "villager" : 40,
    6065        "citizenSoldier" : 60,
     
    6772        "majorTech" : 700,
    6873        "minorTech" : 50,
    6974        "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    };
    7376};
    7477
    75 var Config = {
    76     "debug": false,
    77     "difficulty" : 2,   // overriden by the GUI
    78     updateDifficulty: function(difficulty)
     78//Config.prototype = new BaseConfig();
     79
     80Config.prototype.updateDifficulty = function(difficulty)
     81{
     82    this.difficulty = difficulty;
     83    // changing settings based on difficulty.
     84    if (this.difficulty === 1)
    7985    {
    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
    8991
    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             // Config.Economy.targetNumWorkers will be set by AI scripts.
    96         }
    97         else if (Config.difficulty === 0)
    98         {
    99             Config.Military.defenceBuildingTime = 450;
    100             Config.Military.attackPlansStartTime = 9600000; // never
    101             Config.Military.popForBarracks1 = 60;
    102             Config.Military.popForBarracks2 = 150;  // shouldn't reach it
    103             Config.Military.popForBlacksmith = 150; // shouldn't reach it
     92        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
    104106
    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.
    112113    }
    113114};
    114 
    115 Config.__proto__ = baseConfig;
  • binaries/data/mods/public/simulation/ai/aegis/queueplan-training.js

     
    22    this.type = gameState.applyCiv(type);
    33    this.metadata = metadata;
    44
    5     this.ID = uniqueIDBOPlans++;
     5    this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++;
    66   
    77    this.template = gameState.getTemplate(this.type);
    88    if (!this.template)
  • binaries/data/mods/public/simulation/ai/common-api-v3/entitycollection.js

     
    188188EntityCollection.prototype.move = function(x, z, queued)
    189189{
    190190    queued = queued || false;
    191     Engine.PostCommand({"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});
     191    Engine.PostCommand(PlayerID,{"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});
    192192    return this;
    193193};
    194194EntityCollection.prototype.attackMove = function(x, z, queued)
    195195{
    196196    queued = queued || false;
    197     Engine.PostCommand({"type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});
     197    Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});
    198198    return this;
    199199};
    200200EntityCollection.prototype.moveIndiv = function(x, z, queued)
     
    206206        // It disables JIT compiling of this loop. Don't remove it unless you are sure that the underlying issue has been resolved!
    207207        // TODO: Check this again after the SpiderMonkey upgrade.
    208208        try {} finally {}
    209         Engine.PostCommand({"type": "walk", "entities": [this._entities[id].id()], "x": x, "z": z, "queued": queued});
     209        Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this._entities[id].id()], "x": x, "z": z, "queued": queued});
    210210    }
    211211    return this;
    212212};
    213213EntityCollection.prototype.destroy = function()
    214214{
    215     Engine.PostCommand({"type": "delete-entities", "entities": this.toIdArray()});
     215    Engine.PostCommand(PlayerID,{"type": "delete-entities", "entities": this.toIdArray()});
    216216    return this;
    217217};
    218218EntityCollection.prototype.attack = function(unit)
     
    226226    {
    227227        unitId = unit;
    228228    }   
    229     Engine.PostCommand({"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});
     229    Engine.PostCommand(PlayerID,{"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});
    230230    return this;
    231231};
    232232// violent, aggressive, defensive, passive, standground
    233233EntityCollection.prototype.setStance = function(stance)
    234234{
    235     Engine.PostCommand({"type": "stance", "entities": this.toIdArray(), "name" : stance, "queued": false});
     235    Engine.PostCommand(PlayerID,{"type": "stance", "entities": this.toIdArray(), "name" : stance, "queued": false});
    236236    return this;
    237237};
    238238
  • binaries/data/mods/public/simulation/ai/common-api-v3/baseAI.js

     
    66        return;
    77
    88    this.player = settings.player;
    9     PlayerID = this.player;
    109
    1110    // played turn, in case you don't want the AI to play every turn.
    1211    this.turn = 0;
     
    2928    this.isDeserialized = true;
    3029};
    3130
    32 BaseAI.prototype.Init = function(state, sharedAI)
     31BaseAI.prototype.Init = function(state, playerID, sharedAI)
    3332{
     33    PlayerID = playerID;
    3434    // define some references
    3535    this.entities = sharedAI.entities;
    3636    this.templates = sharedAI.templates;
     
    4343    this.techModifications = sharedAI._techModifications[this.player];
    4444    this.playerData = sharedAI.playersData[this.player];
    4545   
    46     this.gameState = sharedAI.gameState[PlayerID];
     46    this.gameState = sharedAI.gameState[this.player];
    4747    this.gameState.ai = this;
    4848    this.sharedScript = sharedAI;
    4949   
     
    5656{   // AIs override this function
    5757};
    5858
    59 BaseAI.prototype.HandleMessage = function(state, sharedAI)
     59BaseAI.prototype.HandleMessage = function(state, playerID, sharedAI)
    6060{
    6161    this.events = sharedAI.events;
     62    PlayerID = playerID;
    6263   
    6364    if (this.isDeserialized && this.turn !== 0)
    6465    {
     
    7677
    7778BaseAI.prototype.chat = function(message)
    7879{
    79     Engine.PostCommand({"type": "chat", "message": message});
     80    Engine.PostCommand(PlayerID,{"type": "chat", "message": message});
    8081};
    8182BaseAI.prototype.chatTeam = function(message)
    8283{
    83     Engine.PostCommand({"type": "chat", "message": "/team " +message});
     84    Engine.PostCommand(PlayerID,{"type": "chat", "message": "/team " +message});
    8485};
    8586BaseAI.prototype.chatEnemies = function(message)
    8687{
    87     Engine.PostCommand({"type": "chat", "message": "/enemy " +message});
     88    Engine.PostCommand(PlayerID,{"type": "chat", "message": "/enemy " +message});
    8889};
    8990
  • binaries/data/mods/public/simulation/ai/common-api-v3/map-module.js

     
    22 * Copied with changes from QuantumState's original for qBot, it's a component for storing 8 bit values.
    33 */
    44
    5 const TERRITORY_PLAYER_MASK = 0x3F;
    6 
    75function Map(sharedScript, originalMap, actualCopy){
    86    // get the map to find out the correct dimensions
    97    var gameMap = sharedScript.passabilityMap;
  • binaries/data/mods/public/simulation/ai/common-api-v3/entity.js

     
    584584
    585585    move: function(x, z, queued) {
    586586        queued = queued || false;
    587         Engine.PostCommand({"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });
     587        Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });
    588588        return this;
    589589    },
    590590   
    591591    attackMove: function(x, z, queued) {
    592592        queued = queued || false;
    593         Engine.PostCommand({"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });
     593        Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });
    594594        return this;
    595595    },
    596596
    597597    // violent, aggressive, defensive, passive, standground
    598598    setStance: function(stance,queued){
    599         Engine.PostCommand({"type": "stance", "entities": [this.id()], "name" : stance, "queued": queued });
     599        Engine.PostCommand(PlayerID,{"type": "stance", "entities": [this.id()], "name" : stance, "queued": queued });
    600600        return this;
    601601    },
    602602
    603603    // TODO: replace this with the proper "STOP" command
    604604    stopMoving: function() {
    605605        if (this.position() !== undefined)
    606             Engine.PostCommand({"type": "walk", "entities": [this.id()], "x": this.position()[0], "z": this.position()[1], "queued": false});
     606            Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": this.position()[0], "z": this.position()[1], "queued": false});
    607607    },
    608608
    609609    unload: function(id) {
    610610        if (!this._template.GarrisonHolder)
    611611            return undefined;
    612         Engine.PostCommand({"type": "unload", "garrisonHolder": this.id(), "entities": [id]});
     612        Engine.PostCommand(PlayerID,{"type": "unload", "garrisonHolder": this.id(), "entities": [id]});
    613613        return this;
    614614    },
    615615
     
    617617    unloadAll: function() {
    618618        if (!this._template.GarrisonHolder)
    619619            return undefined;
    620         Engine.PostCommand({"type": "unload-all-own", "garrisonHolders": [this.id()]});
     620        Engine.PostCommand(PlayerID,{"type": "unload-all-own", "garrisonHolders": [this.id()]});
    621621        return this;
    622622    },
    623623
    624624    garrison: function(target) {
    625         Engine.PostCommand({"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});
     625        Engine.PostCommand(PlayerID,{"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});
    626626        return this;
    627627    },
    628628
    629629    attack: function(unitId) {
    630         Engine.PostCommand({"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});
     630        Engine.PostCommand(PlayerID,{"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});
    631631        return this;
    632632    },
    633633   
     
    639639            FleeDirection[0] = (FleeDirection[0]/dist) * 8;
    640640            FleeDirection[1] = (FleeDirection[1]/dist) * 8;
    641641           
    642             Engine.PostCommand({"type": "walk", "entities": [this.id()], "x": this.position()[0] + FleeDirection[0]*5, "z": this.position()[1] + FleeDirection[1]*5, "queued": false});
     642            Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": this.position()[0] + FleeDirection[0]*5, "z": this.position()[1] + FleeDirection[1]*5, "queued": false});
    643643        }
    644644        return this;
    645645    },
    646646
    647647    gather: function(target, queued) {
    648648        queued = queued || false;
    649         Engine.PostCommand({"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued});
     649        Engine.PostCommand(PlayerID,{"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued});
    650650        return this;
    651651    },
    652652
    653653    repair: function(target, queued) {
    654654        queued = queued || false;
    655         Engine.PostCommand({"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued});
     655        Engine.PostCommand(PlayerID,{"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued});
    656656        return this;
    657657    },
    658658   
    659659    returnResources: function(target, queued) {
    660660        queued = queued || false;
    661         Engine.PostCommand({"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued});
     661        Engine.PostCommand(PlayerID,{"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued});
    662662        return this;
    663663    },
    664664
    665665    destroy: function() {
    666         Engine.PostCommand({"type": "delete-entities", "entities": [this.id()] });
     666        Engine.PostCommand(PlayerID,{"type": "delete-entities", "entities": [this.id()] });
    667667        return this;
    668668    },
    669669   
    670670    barter: function(buyType, sellType, amount) {
    671         Engine.PostCommand({"type": "barter", "sell" : sellType, "buy" : buyType, "amount" : amount });
     671        Engine.PostCommand(PlayerID,{"type": "barter", "sell" : sellType, "buy" : buyType, "amount" : amount });
    672672        return this;
    673673    },
    674674   
     
    686686            return this;
    687687        }
    688688
    689         Engine.PostCommand({
     689        Engine.PostCommand(PlayerID,{
    690690            "type": "train",
    691691            "entities": [this.id()],
    692692            "template": type,
     
    699699    construct: function(template, x, z, angle, metadata) {
    700700        // TODO: verify this unit can construct this, just for internal
    701701        // sanity-checking and error reporting
    702 
    703         Engine.PostCommand({
     702        Engine.PostCommand(PlayerID,{
    704703            "type": "construct",
    705704            "entities": [this.id()],
    706705            "template": template,
     
    716715    },
    717716                   
    718717     research: function(template) {
    719         Engine.PostCommand({ "type": "research", "entity": this.id(), "template": template });
     718        Engine.PostCommand(PlayerID,{ "type": "research", "entity": this.id(), "template": template });
    720719        return this;
    721720    },
    722721
    723722    stopProduction: function(id) {
    724         Engine.PostCommand({ "type": "stop-production", "entity": this.id(), "id": id });
     723        Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": id });
    725724        return this;
    726725    },
    727726   
     
    732731        for (var i in queue)
    733732        {
    734733            if (queue[i].progress < percentToStopAt)
    735                 Engine.PostCommand({ "type": "stop-production", "entity": this.id(), "id": queue[i].id });
     734                Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": queue[i].id });
    736735        }
    737736        return this;
    738737    }
  • source/simulation2/components/CCmpAIManager.cpp

     
    7878        NONCOPYABLE(CAIPlayer);
    7979    public:
    8080        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)
    8383        {
    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");
    9784        }
    9885
    9986        ~CAIPlayer()
     
    10390            m_Commands.clear();
    10491        }
    10592
    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 prototypes
    177             // TODO: it would be better if serializable prototypes were stored in ScriptInterfaces
    178             //  and then each serializer would access those matching its own context, but that's
    179             //  not possible with AIs sharing data across contexts
    180             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 loaded
    188             if (m_LoadedModules.find(moduleName) != m_LoadedModules.end())
    189                 return true;
    190 
    191             // Mark this as loaded, to prevent it recursively loading itself
    192             m_LoadedModules.insert(moduleName);
    193 
    194             // Load and execute *.js
    195             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 
    20993        bool Initialise(bool callConstructor)
    21094        {
    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))
    21297                return false;
    21398
    21499            OsPath path = L"simulation/ai/" + m_AIName + L"/data.json";
     
    221106
    222107            // Get the constructor name from the metadata
    223108            std::string constructor;
    224             if (!m_ScriptInterface.GetProperty(metadata.get(), "constructor", constructor))
     109            if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor))
    225110            {
    226111                LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str());
    227112                return false;
     
    229114
    230115            // Get the constructor function from the loaded scripts
    231116            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)
    233118                || ctor.undefined())
    234119            {
    235120                LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str());
    236121                return false;
    237122            }
    238123
    239             m_ScriptInterface.GetProperty(metadata.get(), "useShared", m_UseSharedComponent);
     124            m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent);
    240125           
    241126            CScriptVal obj;
    242127
     
    244129            {
    245130                // Set up the data to pass as the constructor argument
    246131                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);
    250135                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);
    252137
    253                 obj = m_ScriptInterface.CallConstructor(ctor.get(), settings.get());
     138                obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get());
    254139            }
    255140            else
    256141            {
    257142                // For deserialization, we want to create the object with the correct prototype
    258143                // but don't want to actually run the constructor again
    259144                // 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());
    261146            }
    262147
    263148            if (obj.undefined())
     
    266151                return false;
    267152            }
    268153
    269             m_Obj = CScriptValRooted(m_ScriptInterface.GetContext(), obj);
     154            m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj);
    270155            return true;
    271156        }
    272157
    273         void Run(CScriptVal state)
     158        void Run(CScriptVal state, int playerID)
    274159        {
    275160            m_Commands.clear();
    276             m_ScriptInterface.CallFunctionVoid(m_Obj.get(), "HandleMessage", state);
     161            m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID);
    277162        }
    278163        // overloaded with a sharedAI part.
    279164        // 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)
    281166        {
    282167            m_Commands.clear();
    283             m_ScriptInterface.CallFunctionVoid(m_Obj.get(), "HandleMessage", state, SharedAI);
     168            m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID, SharedAI);
    284169        }
    285170        void InitAI(CScriptVal state, CScriptValRooted SharedAI)
    286171        {
    287172            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);
    289174        }
    290175
    291176        CAIWorker& m_Worker;
     
    294179        uint8_t m_Difficulty;
    295180        bool m_UseSharedComponent;
    296181       
    297         ScriptInterface m_ScriptInterface;
     182        shared_ptr<ScriptInterface> m_ScriptInterface;
    298183        CScriptValRooted m_Obj;
    299184        std::vector<shared_ptr<ScriptInterface::StructuredClone> > m_Commands;
    300         std::set<std::wstring> m_LoadedModules;
    301185    };
    302186
    303187public:
     
    313197        // removed as soon whenever the new pathfinder is committed
    314198        // And the AIs can stop relying on their own little hands.
    315199        m_ScriptRuntime(ScriptInterface::CreateRuntime(33554432)),
    316         m_ScriptInterface("Engine", "AI", m_ScriptRuntime),
     200        m_ScriptInterface(new ScriptInterface("Engine", "AI", m_ScriptRuntime)),
    317201        m_TurnNum(0),
    318202        m_CommandsComputed(true),
    319203        m_HasLoadedEntityTemplates(false),
     
    321205    {
    322206
    323207        // 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();
    326210
    327         m_ScriptInterface.SetCallbackData(NULL);
     211        m_ScriptInterface->SetCallbackData(static_cast<void*> (this));
    328212
    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");
    332217       
    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");
    334219    }
    335220
    336221    ~CAIWorker()
     
    343228        m_PassabilityMapVal = CScriptValRooted();
    344229        m_TerritoryMapVal = CScriptValRooted();
    345230    }
     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;
    346237
    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)
    351257    {
    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            }
    355278        }
    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!"); 
    358282    }
    359283    // The next two ought to be implmeneted someday but for now as it returns "null" it can't
    360284    static void DumpHeap(void* cbdata)
     
    364288            return;
    365289        }
    366290        CAIWorker* self = static_cast<CAIWorker*> (cbdata);
    367         self->m_ScriptInterface.DumpHeap();
     291        self->m_ScriptInterface->DumpHeap();
    368292    }
    369293    static void ForceGC(void* cbdata)
    370294    {
     
    374298        }
    375299        CAIWorker* self = static_cast<CAIWorker*> (cbdata);
    376300        PROFILE3("AI compute GC");
    377         JS_GC(self->m_ScriptInterface.GetContext());
     301        JS_GC(self->m_ScriptInterface->GetContext());
    378302    }
    379303   
    380304    /**
     
    424348       
    425349        // reset the value so it can be used to determine if we actually initialized it.
    426350        m_HasSharedComponent = false;
    427                
     351       
     352        if (LoadScripts(L"common-api-v3"))
     353            m_HasSharedComponent = true;
     354        else
     355            return false;
     356        /*     
    428357        VfsPaths sharedPathnames;
    429358        // Check for "shared" module.
    430359        vfs::GetPathnames(g_VFS, L"simulation/ai/common-api-v3/", L"*.js", sharedPathnames);
    431360        for (VfsPaths::iterator it = sharedPathnames.begin(); it != sharedPathnames.end(); ++it)
    432361        {
    433             if (!m_ScriptInterface.LoadGlobalScriptFile(*it))
     362            if (!m_ScriptInterface->LoadGlobalScriptFile(*it))
    434363            {
    435364                LOGERROR(L"Failed to load shared script %ls", it->string().c_str());
    436365                return false;
     
    439368        }
    440369        if (!m_HasSharedComponent)
    441370            return false;
    442        
     371        */
    443372        // mainly here for the error messages
    444373        OsPath path = L"simulation/ai/common-api-v2/";
    445374       
    446375        // Constructor name is SharedScript
    447376        CScriptVal ctor;
    448         if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), "SharedScript", ctor)
     377        if (!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), "SharedScript", ctor)
    449378            || ctor.undefined())
    450379        {
    451380            LOGERROR(L"Failed to create shared AI component: %ls: can't find constructor '%hs'", path.string().c_str(), "SharedScript");
     
    454383       
    455384        // Set up the data to pass as the constructor argument
    456385        CScriptVal settings;
    457         m_ScriptInterface.Eval(L"({})", settings);
     386        m_ScriptInterface->Eval(L"({})", settings);
    458387        CScriptVal playersID;
    459         m_ScriptInterface.Eval(L"({})", playersID);
     388        m_ScriptInterface->Eval(L"({})", playersID);
    460389       
    461390        for (size_t i = 0; i < m_Players.size(); ++i)
    462391        {
    463             jsval val = m_ScriptInterface.ToJSVal(m_ScriptInterface.GetContext(), m_Players[i]->m_Player);
    464             m_ScriptInterface.SetPropertyInt(playersID.get(), i, CScriptVal(val), true);
     392            jsval val = m_ScriptInterface->ToJSVal(m_ScriptInterface->GetContext(), m_Players[i]->m_Player);
     393            m_ScriptInterface->SetPropertyInt(playersID.get(), i, CScriptVal(val), true);
    465394        }
    466395       
    467         m_ScriptInterface.SetProperty(settings.get(), "players", playersID);
     396        m_ScriptInterface->SetProperty(settings.get(), "players", playersID);
    468397        ENSURE(m_HasLoadedEntityTemplates);
    469         m_ScriptInterface.SetProperty(settings.get(), "templates", m_EntityTemplates, false);
     398        m_ScriptInterface->SetProperty(settings.get(), "templates", m_EntityTemplates, false);
    470399       
    471400        if (hasTechs)
    472401        {
    473             m_ScriptInterface.SetProperty(settings.get(), "techTemplates", m_TechTemplates, false);
     402            m_ScriptInterface->SetProperty(settings.get(), "techTemplates", m_TechTemplates, false);
    474403        }
    475404        else
    476405        {
    477406            // won't get the tech templates directly.
    478407            CScriptVal fakeTech;
    479             m_ScriptInterface.Eval("({})", fakeTech);
    480             m_ScriptInterface.SetProperty(settings.get(), "techTemplates", fakeTech, false);
     408            m_ScriptInterface->Eval("({})", fakeTech);
     409            m_ScriptInterface->SetProperty(settings.get(), "techTemplates", fakeTech, false);
    481410        }
    482         m_SharedAIObj = CScriptValRooted(m_ScriptInterface.GetContext(),m_ScriptInterface.CallConstructor(ctor.get(), settings.get()));
     411        m_SharedAIObj = CScriptValRooted(m_ScriptInterface->GetContext(),m_ScriptInterface->CallConstructor(ctor.get(), settings.get()));
    483412   
    484413       
    485414        if (m_SharedAIObj.undefined())
     
    493422
    494423    bool AddPlayer(const std::wstring& aiName, player_id_t player, uint8_t difficulty, bool callConstructor)
    495424    {
    496         shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_ScriptRuntime, m_RNG));
     425        shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_ScriptInterface));
    497426        if (!ai->Initialise(callConstructor))
    498427            return false;
    499428       
     
    501430        if (!m_HasSharedComponent)
    502431            m_HasSharedComponent = ai->m_UseSharedComponent;
    503432
    504         m_ScriptInterface.MaybeGC();
     433        m_ScriptInterface->MaybeGC();
    505434
    506435        m_Players.push_back(ai);
    507436
     
    513442        // this will be run last by InitGame.Js, passing the full game representation.
    514443        // For now it will run for the shared Component.
    515444        // This is NOT run during deserialization.
    516         CScriptVal state = m_ScriptInterface.ReadStructuredClone(gameState);
    517         JSContext* cx = m_ScriptInterface.GetContext();
     445        CScriptVal state = m_ScriptInterface->ReadStructuredClone(gameState);
     446        JSContext* cx = m_ScriptInterface->GetContext();
    518447
    519448        m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, passabilityMap));
    520449        m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, territoryMap));
    521450        if (m_HasSharedComponent)
    522451        {
    523             m_ScriptInterface.SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);
    524             m_ScriptInterface.SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);
     452            m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);
     453            m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);
    525454
    526             m_ScriptInterface.CallFunctionVoid(m_SharedAIObj.get(), "init", state);
    527             m_ScriptInterface.MaybeGC();
     455            m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state);
     456            m_ScriptInterface->MaybeGC();
    528457           
    529458            for (size_t i = 0; i < m_Players.size(); ++i)
    530459            {
     
    545474        {
    546475            m_PassabilityMap = passabilityMap;
    547476
    548             JSContext* cx = m_ScriptInterface.GetContext();
     477            JSContext* cx = m_ScriptInterface->GetContext();
    549478            m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_PassabilityMap));
    550479        }
    551480
     
    553482        {
    554483            m_TerritoryMap = territoryMap;
    555484
    556             JSContext* cx = m_ScriptInterface.GetContext();
     485            JSContext* cx = m_ScriptInterface->GetContext();
    557486            m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_TerritoryMap));
    558487        }
    559488
     
    583512    }
    584513
    585514    void RegisterTechTemplates(const shared_ptr<ScriptInterface::StructuredClone>& techTemplates) {
    586         JSContext* cx = m_ScriptInterface.GetContext();
    587         m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface.ReadStructuredClone(techTemplates));
     515        JSContext* cx = m_ScriptInterface->GetContext();
     516        m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface->ReadStructuredClone(techTemplates));
    588517    }
    589518   
    590519    void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates)
    591520    {
    592521        m_HasLoadedEntityTemplates = true;
    593522
    594         m_ScriptInterface.Eval("({})", m_EntityTemplates);
     523        m_ScriptInterface->Eval("({})", m_EntityTemplates);
    595524
    596525        for (size_t i = 0; i < templates.size(); ++i)
    597526        {
    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);
     527            jsval val = templates[i].second->ToJSVal(m_ScriptInterface->GetContext(), false);
     528            m_ScriptInterface->SetProperty(m_EntityTemplates.get(), templates[i].first.c_str(), CScriptVal(val), true);
    600529        }
    601530
    602531        // Since the template data is shared between AI players, freeze it
    603532        // to stop any of them changing it and confusing the other players
    604         m_ScriptInterface.FreezeObject(m_EntityTemplates.get(), true);
     533        m_ScriptInterface->FreezeObject(m_EntityTemplates.get(), true);
    605534    }
    606535
    607536    void Serialize(std::ostream& stream, bool isDebug)
     
    610539
    611540        if (isDebug)
    612541        {
    613             CDebugSerializer serializer(m_ScriptInterface, stream);
     542            CDebugSerializer serializer(*m_ScriptInterface, stream);
    614543            serializer.Indent(4);
    615544            SerializeState(serializer);
    616545        }
    617546        else
    618547        {
    619             CStdSerializer serializer(m_ScriptInterface, stream);
     548            CStdSerializer serializer(*m_ScriptInterface, stream);
    620549            // TODO: see comment in Deserialize()
    621550            serializer.SetSerializablePrototypes(m_SerializablePrototypes);
    622551            SerializeState(serializer);
     
    637566        if (m_HasSharedComponent)
    638567        {
    639568            CScriptVal sharedData;
    640             if (!m_ScriptInterface.CallFunction(m_SharedAIObj.get(), "Serialize", sharedData))
     569            if (!m_ScriptInterface->CallFunction(m_SharedAIObj.get(), "Serialize", sharedData))
    641570                LOGERROR(L"AI shared script Serialize call failed");
    642571            serializer.ScriptVal("sharedData", sharedData);
    643572        }
     
    650579            serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size());
    651580            for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j)
    652581            {
    653                 CScriptVal val = m_ScriptInterface.ReadStructuredClone(m_Players[i]->m_Commands[j]);
     582                CScriptVal val = m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j]);
    654583                serializer.ScriptVal("command", val);
    655584            }
    656585
    657             bool hasCustomSerialize = m_ScriptInterface.HasProperty(m_Players[i]->m_Obj.get(), "Serialize");
     586            bool hasCustomSerialize = m_ScriptInterface->HasProperty(m_Players[i]->m_Obj.get(), "Serialize");
    658587            if (hasCustomSerialize)
    659588            {
    660589                CScriptVal scriptData;
    661                 if (!m_ScriptInterface.CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData))
     590                if (!m_ScriptInterface->CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData))
    662591                    LOGERROR(L"AI script Serialize call fa
    663592    {
    664593        friendlyTiles.map[bestIdx] = 270;iled");