Ticket #969: ai_buildrestrictions-09282011.patch

File ai_buildrestrictions-09282011.patch, 19.5 KB (added by historic_bruno, 13 years ago)
  • binaries/data/mods/public/simulation/ai/jubot/gamestate.js

     
    4343        return new Resources(this.playerData.resourceCounts);
    4444    },
    4545
    46     getMap: function()
     46    getPassabilityMap: function()
    4747    {
    48         return this.ai.map;
     48        return this.ai.passabilityMap;
    4949    },
    5050
    5151    getPassabilityClassMask: function(name)
     
    5555        return this.ai.passabilityClasses[name];
    5656    },
    5757
     58    getTerritoryMap: function()
     59    {
     60        return this.ai.territoryMap;
     61    },
     62
    5863    getOwnEntities: (function()
    5964    {
    6065        return new EntityCollection(this.ai, this.ai._ownEntities);
  • binaries/data/mods/public/simulation/ai/jubot/plan-building.js

     
    146146
    147147        var cellSize = 4; // size of each tile
    148148
    149         // First, find all tiles that are far enough away from obstructions:
     149        var template = gameState.getTemplate(this.type);
    150150
    151         var map = gameState.getMap();
    152 
     151        // Find all tiles in valid territory that are far enough away from obstructions:
     152        var passabilityMap = gameState.getPassabilityMap();
     153        var territoryMap = gameState.getTerritoryMap();
     154        const TERRITORY_PLAYER_MASK = 0x7F;
    153155        var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
    154         // Only accept valid land tiles (we don't handle docks yet)
    155         obstructionMask |= gameState.getPassabilityClassMask("building-land");
    156156
    157         var obstructionTiles = new Uint16Array(map.data.length);
    158         for (var i = 0; i < map.data.length; ++i)
    159             obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
     157        if (passabilityMap.data.length != territoryMap.data.length)
     158            error("passability and territory data are not matched!");
    160159
    161 //      Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
     160        // See BuildRestrictions.js
     161        switch(template.buildPlacementType())
     162        {
     163        case "shore":
     164            obstructionMask |= gameState.getPassabilityClassMask("building-shore");
     165            break;
     166        case "land":
     167        default:
     168            obstructionMask |= gameState.getPassabilityClassMask("building-land");
     169        }
    162170
    163         this.expandInfluences(obstructionTiles, map.width, map.height);
     171        var playerID = gameState.getPlayerID();
     172        var buildOwn = template.hasBuildTerritory("own");
     173        var buildAlly = template.hasBuildTerritory("ally");
     174        var buildNeutral = template.hasBuildTerritory("neutral");
     175        var buildEnemy = template.hasBuildTerritory("enemy");
    164176
     177        var obstructionTiles = new Uint16Array(passabilityMap.data.length);
     178        for (var i = 0; i < passabilityMap.data.length; ++i)
     179        {
     180            var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
     181            var validTerritory = (
     182                (!buildOwn || tilePlayer == playerID) &&
     183                (!buildAlly || gameState.isPlayerAlly(tilePlayer)) &&
     184                (!buildEnemy || gameState.isPlayerEnemy(tilePlayer)) &&
     185                (!buildNeutral || tilePlayer == 0)
     186            );
     187            obstructionTiles[i] = ((passabilityMap.data[i] & obstructionMask) || !validTerritory) ? 0 : 65535;
     188        }
     189
     190//      Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
     191
     192        this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
     193
     194        // TODO: handle distance restrictions for e.g. CivCentres
     195       
    165196        // Compute each tile's closeness to friendly structures:
    166197
    167         var friendlyTiles = new Uint16Array(map.data.length);
     198        var friendlyTiles = new Uint16Array(passabilityMap.data.length);
    168199
    169200        gameState.getOwnEntities().forEach(function(ent) {
    170201            if (ent.hasClass("Structure"))
     
    176207                var pos = ent.position();
    177208                var x = Math.round(pos[0] / cellSize);
    178209                var z = Math.round(pos[1] / cellSize);
    179                 self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
     210                self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
    180211            }
    181212        });
    182213
     
    190221//              var pos = ent.position();
    191222//              var x = Math.round(pos[0] / cellSize);
    192223//              var z = Math.round(pos[1] / cellSize);
    193 //              self.subtractInfluence(friendlyTiles, map.width, map.height, x, z, infl);
     224//              self.subtractInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
    194225//          }
    195226//      });
    196227
    197228       
    198229        // Find target building's approximate obstruction radius,
    199230        // and expand by a bit to make sure we're not too close
    200         var template = gameState.getTemplate(this.type);
    201231        var radius = Math.ceil(template.obstructionRadius() / cellSize) + 1;
    202232
    203233        // Find the best non-obstructed tile
    204234        var bestIdx = 0;
    205235        var bestVal = -1;
    206         for (var i = 0; i < map.data.length; ++i)
     236        for (var i = 0; i < passabilityMap.data.length; ++i)
    207237        {
    208238            if (obstructionTiles[i] > radius)
    209239            {
     
    220250                }
    221251            }
    222252        }
    223         var x = ((bestIdx % map.width) + 0.5) * cellSize;
    224         var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
     253        var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
     254        var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
    225255
    226 //      Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
    227 //      Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
     256//      Engine.DumpImage("tiles1.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
     257//      Engine.DumpImage("tiles2.png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
    228258
     259        // TODO: special dock placement requirements
     260
    229261        // Fixed angle to match fixed starting cam
    230262        var angle = 0.75*Math.PI;
    231263
  • binaries/data/mods/public/simulation/ai/jubot/plan-buildingecon.js

     
    148148
    149149        var cellSize = 4; // size of each tile
    150150
    151         // First, find all tiles that are far enough away from obstructions:
     151        var template = gameState.getTemplate(this.type);
    152152
    153         var map = gameState.getMap();
    154 
     153        // Find all tiles in valid territory that are far enough away from obstructions:
     154        var passabilityMap = gameState.getPassabilityMap();
     155        var territoryMap = gameState.getTerritoryMap();
     156        const TERRITORY_PLAYER_MASK = 0x7F;
    155157        var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
    156         // Only accept valid land tiles (we don't handle docks yet)
    157         obstructionMask |= gameState.getPassabilityClassMask("building-land");
    158158
    159         var obstructionTiles = new Uint16Array(map.data.length);
    160         for (var i = 0; i < map.data.length; ++i)
    161             obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
     159        if (passabilityMap.data.length != territoryMap.data.length)
     160            error("passability and territory data are not matched!");
    162161
    163 //      Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
     162        // See BuildRestrictions.js
     163        switch(template.buildPlacementType())
     164        {
     165        case "shore":
     166            obstructionMask |= gameState.getPassabilityClassMask("building-shore");
     167            break;
     168        case "land":
     169        default:
     170            obstructionMask |= gameState.getPassabilityClassMask("building-land");
     171        }
    164172
    165         this.expandInfluences(obstructionTiles, map.width, map.height);
     173        var playerID = gameState.getPlayerID();
     174        var buildOwn = template.hasBuildTerritory("own");
     175        var buildAlly = template.hasBuildTerritory("ally");
     176        var buildNeutral = template.hasBuildTerritory("neutral");
     177        var buildEnemy = template.hasBuildTerritory("enemy");
    166178
     179        var obstructionTiles = new Uint16Array(passabilityMap.data.length);
     180        for (var i = 0; i < passabilityMap.data.length; ++i)
     181        {
     182            var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
     183            var validTerritory = (
     184                (!buildOwn || tilePlayer == playerID) &&
     185                (!buildAlly || gameState.isPlayerAlly(tilePlayer)) &&
     186                (!buildEnemy || gameState.isPlayerEnemy(tilePlayer)) &&
     187                (!buildNeutral || tilePlayer == 0)
     188            );
     189            obstructionTiles[i] = ((passabilityMap.data[i] & obstructionMask) || !validTerritory) ? 0 : 65535;
     190        }
     191
     192//      Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
     193
     194        this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
     195
     196        // TODO: handle distance restrictions for e.g. CivCentres
     197       
    167198        // Compute each tile's closeness to friendly structures:
    168199
    169         var friendlyTiles = new Uint16Array(map.data.length);
     200        var friendlyTiles = new Uint16Array(passabilityMap.data.length);
    170201        var infl = 100;
    171202        var pos = this.resourceposition;
    172203        var x = Math.round(pos[0] / cellSize);
    173204        var z = Math.round(pos[1] / cellSize);
    174         self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
     205        self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
    175206       
    176207        //Look at making sure we're a long way from enemy civ centres as well.
    177208
     
    184215        // Find the best non-obstructed tile
    185216        var bestIdx = 0;
    186217        var bestVal = -1;
    187         for (var i = 0; i < map.data.length; ++i)
     218        for (var i = 0; i < passabilityMap.data.length; ++i)
    188219        {
    189220            if (obstructionTiles[i] > radius)
    190221            {
     
    201232                }
    202233            }
    203234        }
    204         var x = ((bestIdx % map.width) + 0.5) * cellSize;
    205         var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
     235        var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
     236        var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
    206237
    207 //      Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
    208 //      Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
     238//      Engine.DumpImage("tiles1.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
     239//      Engine.DumpImage("tiles2.png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
    209240
    210241        // Fixed angle to match fixed starting cam
    211242        var angle = 0.75*Math.PI;
     
    225256
    226257        // First, find all tiles that are far enough away from obstructions:
    227258
    228         var map = gameState.getMap();
     259        var passabilityMap = gameState.getPassabilityMap();
    229260
    230261        var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
    231262        // Only accept valid land tiles (we don't handle docks yet)
    232263        obstructionMask |= gameState.getPassabilityClassMask("building-land");
    233264
    234         var obstructionTiles = new Uint16Array(map.data.length);
    235         for (var i = 0; i < map.data.length; ++i)
    236             obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
     265        var obstructionTiles = new Uint16Array(passabilityMap.data.length);
     266        for (var i = 0; i < passabilityMap.data.length; ++i)
     267            obstructionTiles[i] = (passabilityMap.data[i] & obstructionMask) ? 0 : 65535;
    237268
    238 //      Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
     269//      Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
    239270
    240         this.expandInfluences(obstructionTiles, map.width, map.height);
     271        this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
    241272
    242273        // Compute each tile's closeness to friendly structures:
    243274
    244         var friendlyTiles = new Uint16Array(map.data.length);
     275        var friendlyTiles = new Uint16Array(passabilityMap.data.length);
    245276
    246277        gameState.getOwnEntities().forEach(function(ent) {
    247278            if (ent.hasClass("Structure"))
     
    253284                var pos = ent.position();
    254285                var x = Math.round(pos[0] / cellSize);
    255286                var z = Math.round(pos[1] / cellSize);
    256                 self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
     287                self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
    257288            }
    258289        });
    259290       
    260291        //Look at making sure we're a long way from enemy civ centres as well.
    261292   
    262 //      var enemyTiles = new Uint16Array(map.data.length);
     293//      var enemyTiles = new Uint16Array(passabilityMap.data.length);
    263294//     
    264295//          var foetargets = gameState.entities.filter(function(ent) {
    265296//              return (ent.isEnemy());
     
    271302//              var pos = ent.position();
    272303//              var x = Math.round(pos[0] / cellSize);
    273304//              var z = Math.round(pos[1] / cellSize);
    274 //              self.addInfluence(enemyTiles, map.width, map.height, x, z, infl);
     305//              self.addInfluence(enemyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
    275306//          }
    276307//      });
    277308
     
    284315        // Find the best non-obstructed tile
    285316        var bestIdx = 0;
    286317        var bestVal = -1;
    287         for (var i = 0; i < map.data.length; ++i)
     318        for (var i = 0; i < passabilityMap.data.length; ++i)
    288319        {
    289320            if (obstructionTiles[i] > radius)
    290321            {
     
    301332                }
    302333            }
    303334        }
    304         var x = ((bestIdx % map.width) + 0.5) * cellSize;
    305         var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
     335        var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
     336        var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
    306337
    307 //      Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
    308 //      Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
     338//      Engine.DumpImage("tiles1.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
     339//      Engine.DumpImage("tiles2.png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
    309340
    310341        // Randomise the angle a little, to look less artificial
    311342        //var angle = Math.PI + (Math.random()*2-1) * Math.PI/24;
  • binaries/data/mods/public/simulation/ai/testbot/gamestate.js

     
    3838        return new Resources(this.playerData.resourceCounts);
    3939    },
    4040
    41     getMap: function()
     41    getPassabilityMap: function()
    4242    {
    43         return this.ai.map;
     43        return this.ai.passabilityMap;
    4444    },
    4545
    4646    getPassabilityClassMask: function(name)
     
    5050        return this.ai.passabilityClasses[name];
    5151    },
    5252
     53    getTerritoryMap: function()
     54    {
     55        return this.ai.territoryMap;
     56    },
     57
    5358    getOwnEntities: (function()
    5459    {
    5560        return new EntityCollection(this.ai, this.ai._ownEntities);
     
    231236
    232237    isEntityAlly: function(ent)
    233238    {
    234         return ent && ent.owner !== undefined && this.playerData.isAlly[ent.owner];
     239        return (ent && ent.owner !== undefined && this.playerData.isAlly[ent.owner]);
    235240    },
    236241
    237242    isEntityEnemy: function(ent)
    238243    {
    239         return ent && ent.owner !== undefined && this.playerData.isEnemy[ent.owner];
     244        return (ent && ent.owner !== undefined && this.playerData.isEnemy[ent.owner]);
    240245    },
    241246
    242247    isEntityOwn: function(ent)
  • binaries/data/mods/public/simulation/ai/testbot/plan-building.js

     
    124124
    125125        var cellSize = 4; // size of each tile
    126126
    127         // First, find all tiles that are far enough away from obstructions:
     127        var template = gameState.getTemplate(this.type);
    128128
    129         var map = gameState.getMap();
    130 
     129        // Find all tiles in valid territory that are far enough away from obstructions:
     130        var passabilityMap = gameState.getPassabilityMap();
     131        var territoryMap = gameState.getTerritoryMap();
     132        const TERRITORY_PLAYER_MASK = 0x7F;
    131133        var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
    132         // Only accept valid land tiles (we don't handle docks yet)
    133         obstructionMask |= gameState.getPassabilityClassMask("building-land");
    134134
    135         var obstructionTiles = new Uint16Array(map.data.length);
    136         for (var i = 0; i < map.data.length; ++i)
    137             obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
     135        if (passabilityMap.data.length != territoryMap.data.length)
     136            error("passability and territory data are not matched!");
    138137
    139 //      Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
     138        // See BuildRestrictions.js
     139        switch(template.buildPlacementType())
     140        {
     141        case "shore":
     142            obstructionMask |= gameState.getPassabilityClassMask("building-shore");
     143            break;
     144        case "land":
     145        default:
     146            obstructionMask |= gameState.getPassabilityClassMask("building-land");
     147        }
    140148
    141         this.expandInfluences(obstructionTiles, map.width, map.height);
     149        var playerID = gameState.getPlayerID();
     150        var buildOwn = template.hasBuildTerritory("own");
     151        var buildAlly = template.hasBuildTerritory("ally");
     152        var buildNeutral = template.hasBuildTerritory("neutral");
     153        var buildEnemy = template.hasBuildTerritory("enemy");
    142154
     155        var obstructionTiles = new Uint16Array(passabilityMap.data.length);
     156        for (var i = 0; i < passabilityMap.data.length; ++i)
     157        {
     158            var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
     159            var validTerritory = (
     160                (!buildOwn || tilePlayer == playerID) &&
     161                (!buildAlly || gameState.isPlayerAlly(tilePlayer)) &&
     162                (!buildEnemy || gameState.isPlayerEnemy(tilePlayer)) &&
     163                (!buildNeutral || tilePlayer == 0)
     164            );
     165            obstructionTiles[i] = ((passabilityMap.data[i] & obstructionMask) || !validTerritory) ? 0 : 65535;
     166        }
     167
     168//      Engine.DumpImage("obstruction"+playerID+".png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
     169
     170        this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
     171
     172        // TODO: handle distance restrictions for e.g. CivCentres
     173
    143174        // Compute each tile's closeness to friendly structures:
    144175
    145         var friendlyTiles = new Uint16Array(map.data.length);
     176        var friendlyTiles = new Uint16Array(passabilityMap.data.length);
    146177
    147178        gameState.getOwnEntities().forEach(function(ent) {
    148179            if (ent.hasClass("Structure"))
     
    154185                var pos = ent.position();
    155186                var x = Math.round(pos[0] / cellSize);
    156187                var z = Math.round(pos[1] / cellSize);
    157                 self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
     188                self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
    158189            }
    159190        });
    160191
    161192        // Find target building's approximate obstruction radius,
    162193        // and expand by a bit to make sure we're not too close
    163         var template = gameState.getTemplate(this.type);
    164194        var radius = Math.ceil(template.obstructionRadius() / cellSize) + 2;
    165195
    166196        // Find the best non-obstructed tile
    167197        var bestIdx = 0;
    168198        var bestVal = -1;
    169         for (var i = 0; i < map.data.length; ++i)
     199        for (var i = 0; i < passabilityMap.data.length; ++i)
    170200        {
    171201            if (obstructionTiles[i] > radius)
    172202            {
     
    178208                }
    179209            }
    180210        }
    181         var x = ((bestIdx % map.width) + 0.5) * cellSize;
    182         var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
     211        var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
     212        var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
    183213
    184 //      Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
    185 //      Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
     214//      Engine.DumpImage("influences"+playerID+".png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
     215//      Engine.DumpImage("friendly"+playerID+".png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
    186216
     217        // TODO: special dock placement requirements
     218       
    187219        // Fixed angle to match fixed starting cam
    188220        var angle = 0.75*Math.PI;
    189221