Line data Source code
1 : /** map functions */ 2 : 3 0 : PETRA.TERRITORY_PLAYER_MASK = 0x1F; 4 0 : PETRA.TERRITORY_BLINKING_MASK = 0x40; 5 : 6 0 : PETRA.createObstructionMap = function(gameState, accessIndex, template) 7 : { 8 0 : let passabilityMap = gameState.getPassabilityMap(); 9 0 : let territoryMap = gameState.ai.territoryMap; 10 0 : let ratio = territoryMap.cellSize / passabilityMap.cellSize; 11 : 12 : // default values 13 0 : let placementType = "land"; 14 0 : let buildOwn = true; 15 0 : let buildAlly = true; 16 0 : let buildNeutral = true; 17 0 : let buildEnemy = false; 18 : // If there is a template then replace the defaults 19 0 : if (template) 20 : { 21 0 : placementType = template.buildPlacementType(); 22 0 : buildOwn = template.hasBuildTerritory("own"); 23 0 : buildAlly = template.hasBuildTerritory("ally"); 24 0 : buildNeutral = template.hasBuildTerritory("neutral"); 25 0 : buildEnemy = template.hasBuildTerritory("enemy"); 26 : } 27 0 : let obstructionTiles = new Uint8Array(passabilityMap.data.length); 28 : 29 : let passMap; 30 : let obstructionMask; 31 0 : if (placementType == "shore") 32 : { 33 0 : passMap = gameState.ai.accessibility.navalPassMap; 34 0 : obstructionMask = gameState.getPassabilityClassMask("building-shore"); 35 : } 36 : else 37 : { 38 0 : passMap = gameState.ai.accessibility.landPassMap; 39 0 : obstructionMask = gameState.getPassabilityClassMask("building-land"); 40 : } 41 : 42 0 : for (let k = 0; k < territoryMap.data.length; ++k) 43 : { 44 0 : let tilePlayer = territoryMap.data[k] & PETRA.TERRITORY_PLAYER_MASK; 45 0 : let isConnected = (territoryMap.data[k] & PETRA.TERRITORY_BLINKING_MASK) == 0; 46 0 : if (tilePlayer === PlayerID) 47 : { 48 0 : if (!buildOwn || !buildNeutral && !isConnected) 49 0 : continue; 50 : } 51 0 : else if (gameState.isPlayerMutualAlly(tilePlayer)) 52 : { 53 0 : if (!buildAlly || !buildNeutral && !isConnected) 54 0 : continue; 55 : } 56 0 : else if (tilePlayer === 0) 57 : { 58 0 : if (!buildNeutral) 59 0 : continue; 60 : } 61 : else 62 : { 63 0 : if (!buildEnemy) 64 0 : continue; 65 : } 66 : 67 0 : let x = ratio * (k % territoryMap.width); 68 0 : let y = ratio * Math.floor(k / territoryMap.width); 69 0 : for (let ix = 0; ix < ratio; ++ix) 70 : { 71 0 : for (let iy = 0; iy < ratio; ++iy) 72 : { 73 0 : let i = x + ix + (y + iy)*passabilityMap.width; 74 0 : if (placementType != "shore" && accessIndex && accessIndex !== passMap[i]) 75 0 : continue; 76 0 : if (!(passabilityMap.data[i] & obstructionMask)) 77 0 : obstructionTiles[i] = 255; 78 : } 79 : } 80 : } 81 : 82 0 : let map = new API3.Map(gameState.sharedScript, "passability", obstructionTiles); 83 0 : map.setMaxVal(255); 84 : 85 0 : if (template && template.buildDistance()) 86 : { 87 0 : let distance = template.buildDistance(); 88 0 : let minDist = distance.MinDistance ? +distance.MinDistance : 0; 89 0 : if (minDist) 90 : { 91 0 : let obstructionRadius = template.obstructionRadius(); 92 0 : if (obstructionRadius) 93 0 : minDist -= obstructionRadius.min; 94 0 : let fromClass = distance.FromClass; 95 0 : let cellSize = passabilityMap.cellSize; 96 0 : let cellDist = 1 + minDist / cellSize; 97 0 : let structures = gameState.getOwnStructures().filter(API3.Filters.byClass(fromClass)); 98 0 : for (let ent of structures.values()) 99 : { 100 0 : if (!ent.position()) 101 0 : continue; 102 0 : let pos = ent.position(); 103 0 : let x = Math.round(pos[0] / cellSize); 104 0 : let z = Math.round(pos[1] / cellSize); 105 0 : map.addInfluence(x, z, cellDist, -255, "constant"); 106 : } 107 : } 108 : } 109 : 110 0 : return map; 111 : }; 112 : 113 : 114 0 : PETRA.createTerritoryMap = function(gameState) 115 : { 116 0 : let map = gameState.ai.territoryMap; 117 : 118 0 : let ret = new API3.Map(gameState.sharedScript, "territory", map.data); 119 0 : ret.getOwner = function(p) { return this.point(p) & PETRA.TERRITORY_PLAYER_MASK; }; 120 0 : ret.getOwnerIndex = function(p) { return this.map[p] & PETRA.TERRITORY_PLAYER_MASK; }; 121 0 : ret.isBlinking = function(p) { return (this.point(p) & PETRA.TERRITORY_BLINKING_MASK) != 0; }; 122 0 : return ret; 123 : }; 124 : 125 : /** 126 : * The borderMap contains some border and frontier information: 127 : * - border of the map filled once: 128 : * - all mini-cells (1x1) from the big cell (8x8) inaccessibles => bit 0 129 : * - inside a given distance to the border => bit 1 130 : * - frontier of our territory (updated regularly in updateFrontierMap) 131 : * - narrow border (inside our territory) => bit 2 132 : * - large border (inside our territory, exclusive of narrow) => bit 3 133 : */ 134 : 135 0 : PETRA.outside_Mask = 1; 136 0 : PETRA.border_Mask = 2; 137 0 : PETRA.fullBorder_Mask = PETRA.outside_Mask | PETRA.border_Mask; 138 0 : PETRA.narrowFrontier_Mask = 4; 139 0 : PETRA.largeFrontier_Mask = 8; 140 0 : PETRA.fullFrontier_Mask = PETRA.narrowFrontier_Mask | PETRA.largeFrontier_Mask; 141 : 142 0 : PETRA.createBorderMap = function(gameState) 143 : { 144 0 : let map = new API3.Map(gameState.sharedScript, "territory"); 145 0 : let width = map.width; 146 0 : let border = Math.round(80 / map.cellSize); 147 0 : let passabilityMap = gameState.getPassabilityMap(); 148 0 : let obstructionMask = gameState.getPassabilityClassMask("unrestricted"); 149 0 : if (gameState.circularMap) 150 : { 151 0 : let ic = (width - 1) / 2; 152 0 : let radcut = (ic - border) * (ic - border); 153 0 : for (let j = 0; j < map.length; ++j) 154 : { 155 0 : let dx = j%width - ic; 156 0 : let dy = Math.floor(j/width) - ic; 157 0 : let radius = dx*dx + dy*dy; 158 0 : if (radius < radcut) 159 0 : continue; 160 0 : map.map[j] = PETRA.outside_Mask; 161 0 : let ind = API3.getMapIndices(j, map, passabilityMap); 162 0 : for (let k of ind) 163 : { 164 0 : if (passabilityMap.data[k] & obstructionMask) 165 0 : continue; 166 0 : map.map[j] = PETRA.border_Mask; 167 0 : break; 168 : } 169 : } 170 : } 171 : else 172 : { 173 0 : let borderCut = width - border; 174 0 : for (let j = 0; j < map.length; ++j) 175 : { 176 0 : let ix = j%width; 177 0 : let iy = Math.floor(j/width); 178 0 : if (ix < border || ix >= borderCut || iy < border || iy >= borderCut) 179 : { 180 0 : map.map[j] = PETRA.outside_Mask; 181 0 : let ind = API3.getMapIndices(j, map, passabilityMap); 182 0 : for (let k of ind) 183 : { 184 0 : if (passabilityMap.data[k] & obstructionMask) 185 0 : continue; 186 0 : map.map[j] = PETRA.border_Mask; 187 0 : break; 188 : } 189 : } 190 : } 191 : } 192 : 193 : // map.dumpIm("border.png", 5); 194 0 : return map; 195 : }; 196 : 197 0 : PETRA.debugMap = function(gameState, map) 198 : { 199 0 : let width = map.width; 200 0 : let cell = map.cellSize; 201 0 : gameState.getEntities().forEach(ent => { 202 0 : let pos = ent.position(); 203 0 : if (!pos) 204 0 : return; 205 0 : let x = Math.round(pos[0] / cell); 206 0 : let z = Math.round(pos[1] / cell); 207 0 : let id = x + width*z; 208 0 : if (map.map[id] == 1) 209 0 : Engine.PostCommand(PlayerID, { "type": "set-shading-color", "entities": [ent.id()], "rgb": [2, 0, 0] }); 210 0 : else if (map.map[id] == 2) 211 0 : Engine.PostCommand(PlayerID, { "type": "set-shading-color", "entities": [ent.id()], "rgb": [0, 2, 0] }); 212 0 : else if (map.map[id] == 3) 213 0 : Engine.PostCommand(PlayerID, { "type": "set-shading-color", "entities": [ent.id()], "rgb": [0, 0, 2] }); 214 : }); 215 : };