Ticket #3811: t3811_buildingDensity_2.diff
File t3811_buildingDensity_2.diff, 28.1 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Templates.js
142 142 }; 143 143 144 144 // optional properties 145 if (template.BuildRestrictions.D istance)145 if (template.BuildRestrictions.Density) 146 146 { 147 147 ret.buildRestrictions.distance = { 148 148 "fromCategory": template.BuildRestrictions.Distance.FromCategory, 149 149 }; 150 if (template.BuildRestrictions.Distance.MinDistance) ret.buildRestrictions.distance.min = +template.BuildRestrictions.Distance.MinDistance; 151 if (template.BuildRestrictions.Distance.MaxDistance) ret.buildRestrictions.distance.max = +template.BuildRestrictions.Distance.MaxDistance; 150 if (template.BuildRestrictions.Density.MinEntity) 151 ret.buildRestrictions.density.min = +template.BuildRestrictions.Density.MinEntity; 152 if (template.BuildRestrictions.Density.MaxEntity) 153 ret.buildRestrictions.density.max = +template.BuildRestrictions.Density.MaxEntity; 152 154 } 153 155 } 154 156 -
binaries/data/mods/public/gui/session/input.js
100 100 { 101 101 if (placementSupport.template && placementSupport.position) 102 102 { 103 varresult = Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {103 let result = Engine.GuiInterfaceCall("SetBuildingPlacementPreview", { 104 104 "template": placementSupport.template, 105 105 "x": placementSupport.position.x, 106 106 "z": placementSupport.position.z, … … 160 160 true // include foundations 161 161 ); 162 162 163 returnEngine.GuiInterfaceCall("SetWallPlacementPreview", {163 let result = Engine.GuiInterfaceCall("SetWallPlacementPreview", { 164 164 "wallSet": placementSupport.wallSet, 165 165 "start": placementSupport.position, 166 166 "end": placementSupport.wallEndPosition, 167 167 "snapEntities": placementSupport.wallSnapEntities, // snapping entities (towers) for starting a wall segment 168 168 }); 169 170 // Show placement info tooltip if invalid position 171 placementSupport.tooltipError = !result.success; 172 placementSupport.tooltipMessage = ""; 173 if (!result.success) 174 { 175 if (result.message && result.parameters) 176 { 177 let message = result.message; 178 if (result.translateMessage) 179 if (result.pluralMessage) 180 message = translatePlural(result.message, result.pluralMessage, result.pluralCount); 181 else 182 message = translate(message); 183 let parameters = result.parameters; 184 if (result.translateParameters) 185 translateObjectKeys(parameters, result.translateParameters); 186 placementSupport.tooltipMessage = sprintf(message, parameters); 187 } 188 } 189 return result; 169 190 } 170 191 } 171 192 -
binaries/data/mods/public/simulation/components/BuildRestrictions.js
32 32 "</oneOrMore>" + 33 33 "</list>" + 34 34 "</element>" + 35 "<element name='Category' a:help='Specifies the category of this building, for satisfying special constraints. Choices include: CivilCentre, House, DefenseTower, Farmstead, Market, Barracks, Dock, Fortress, Field, Temple, Wall, Fence, Storehouse, Stoa, Resource, Special, Wonder, Apadana, Embassy, Monument'>" +35 "<element name='Category' a:help='Specifies the category of this building, for satisfying special constraints. Choices include: Apadana, Barracks, CivilCentre, DefenseTower, Dock, Embassy, Farmstead, Field, Fence, Fortress, House, Market, Monument, Resource, Special, Stoa, Storehouse, Temple, Tower, Wall, WallTower, Wonder'>" + 36 36 "<text/>" + 37 37 "</element>" + 38 38 "<optional>" + 39 "<element name='D istance' a:help='Specifies distance restrictions on this building, relative to buildings from the given category.'>" +39 "<element name='Density' a:help='Specifies distance restrictions on this building, relative to buildings from the given category.'>" + 40 40 "<interleave>" + 41 41 "<element name='FromClass'>" + 42 42 "<text/>" + 43 43 "</element>" + 44 "<optional><element name='MinDistance'><data type='positiveInteger'/></element></optional>" + 45 "<optional><element name='MaxDistance'><data type='positiveInteger'/></element></optional>" + 44 "<element name='Distance'><data type='positiveInteger'/></element>" + 45 "<optional><element name='MinEntity'><data type='nonNegativeInteger'/></element></optional>" + 46 "<optional><element name='MaxEntity'><data type='nonNegativeInteger'/></element></optional>" + 46 47 "</interleave>" + 47 48 "</element>" + 48 49 "</optional>"; … … 50 51 BuildRestrictions.prototype.Init = function() 51 52 { 52 53 this.territories = this.template.Territory.split(/\s+/); 54 if (this.template.Density) 55 { 56 this.minEntity = +(this.template.Density.MinEntity || 0); 57 this.maxEntity = +(this.template.Density.MaxEntity || Infinity); 58 } 53 59 }; 54 60 55 61 /** … … 60 66 * b. On valid terrain, based on passability class 61 67 * 3. Territory type is allowed (see note below) 62 68 * 4. Dock is on shoreline and facing into water 63 * 5. D istanceconstraints satisfied69 * 5. Density constraints satisfied 64 70 * 65 71 * Returns result object: 66 72 * { … … 79 85 */ 80 86 BuildRestrictions.prototype.CheckPlacement = function() 81 87 { 82 varcmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);83 varname = cmpIdentity ? cmpIdentity.GetGenericName() : "Building";88 let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 89 let name = cmpIdentity ? cmpIdentity.GetGenericName() : "Building"; 84 90 85 varresult = {91 let result = { 86 92 "success": false, 87 93 "message": markForTranslation("%(name)s cannot be built due to unknown error"), 88 94 "parameters": { … … 93 99 }; 94 100 95 101 // TODO: AI has no visibility info 96 varcmpPlayer = QueryOwnerInterface(this.entity, IID_Player);102 let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 97 103 if (!cmpPlayer.IsAI()) 98 104 { 99 105 // Check whether it's in a visible or fogged region 100 varcmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);101 varcmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);106 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 107 let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 102 108 if (!cmpRangeManager || !cmpOwnership) 103 109 return result; // Fail 104 110 105 var explored = (cmpRangeManager.GetLosVisibility(this.entity, cmpOwnership.GetOwner()) != "hidden"); 106 if (!explored) 111 if (cmpRangeManager.GetLosVisibility(this.entity, cmpOwnership.GetOwner()) == "hidden") 107 112 { 108 113 result.message = markForTranslation("%(name)s cannot be built in unexplored area"); 109 114 return result; // Fail … … 111 116 } 112 117 113 118 // Check obstructions and terrain passability 114 varpassClassName = "";119 let passClassName = ""; 115 120 switch (this.template.PlacementType) 116 121 { 117 122 case "shore": … … 129 134 passClassName = "building-land"; 130 135 } 131 136 132 varcmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);137 let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 133 138 if (!cmpObstruction) 134 139 return result; // Fail 135 140 136 141 // for walls, only test the center point 137 142 if (this.template.Category == "Wall") 138 {139 // for walls, only test the center point140 143 var ret = cmpObstruction.CheckFoundation(passClassName, true); 141 }142 144 else 143 {144 145 var ret = cmpObstruction.CheckFoundation(passClassName, false); 145 }146 146 147 147 if (ret != "success") 148 148 { … … 152 152 case "fail_no_obstruction": 153 153 error("CheckPlacement: Error returned from CheckFoundation"); 154 154 break; 155 155 156 case "fail_obstructs_foundation": 156 157 result.message = markForTranslation("%(name)s cannot be built on another building or resource"); 157 158 break; 159 158 160 case "fail_terrain_class": 159 161 // TODO: be more specific and/or list valid terrain? 160 162 result.message = markForTranslation("%(name)s cannot be built on invalid terrain"); … … 163 165 } 164 166 165 167 // Check territory restrictions 166 varcmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);167 varcmpPlayer = QueryOwnerInterface(this.entity, IID_Player);168 varcmpPosition = Engine.QueryInterface(this.entity, IID_Position);169 if (! (cmpTerritoryManager && cmpPlayer && cmpPosition && cmpPosition.IsInWorld()))168 let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); 169 let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 170 let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 171 if (!cmpTerritoryManager || !cmpPlayer || !cmpPosition || !cmpPosition.IsInWorld()) 170 172 return result; // Fail 171 173 172 var pos = cmpPosition.GetPosition2D(); 173 var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); 174 var isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y); 175 var isOwn = tileOwner == cmpPlayer.GetPlayerID(); 176 var isMutualAlly = cmpPlayer.IsExclusiveMutualAlly(tileOwner); 177 var isNeutral = tileOwner == 0; 174 let pos = cmpPosition.GetPosition2D(); 175 let tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); 176 let isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y); 178 177 179 varinvalidTerritory = "";180 if ( isOwn)178 let invalidTerritory = ""; 179 if (tileOwner == cmpPlayer.GetPlayerID()) // Own territory 181 180 { 182 181 if (!this.HasTerritory("own")) 183 182 // Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". … … 186 185 // Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". 187 186 invalidTerritory = markForTranslationWithContext("Territory type", "unconnected own"); 188 187 } 189 else if ( isMutualAlly)188 else if (cmpPlayer.IsExclusiveMutualAlly(tileOwner)) 190 189 { 191 190 if (!this.HasTerritory("ally")) 192 191 // Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". … … 195 194 // Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". 196 195 invalidTerritory = markForTranslationWithContext("Territory type", "unconnected allied"); 197 196 } 198 else if ( isNeutral)197 else if (tileOwner == 0) // Neutral territory 199 198 { 200 199 if (!this.HasTerritory("neutral")) 201 200 // Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". … … 227 226 // 1. ships can be spawned "nearby" 228 227 // 2. builders can pass the terrain where the dock is placed (don't worry about paths) 229 228 // so it's correct even if the criteria changes for these units 230 varcmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);229 let cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint); 231 230 if (!cmpFootprint) 232 231 return result; // Fail 233 232 234 233 // Get building's footprint 235 varshape = cmpFootprint.GetShape();236 varhalfSize = 0;234 let shape = cmpFootprint.GetShape(); 235 let halfSize = 0; 237 236 if (shape.type == "square") 238 halfSize = shape.depth /2;237 halfSize = shape.depth / 2; 239 238 else if (shape.type == "circle") 240 239 halfSize = shape.radius; 241 240 242 varcmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);243 varcmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);241 let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 242 let cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); 244 243 if (!cmpTerrain || !cmpWaterManager) 245 244 return result; // Fail 246 245 247 varang = cmpPosition.GetRotation().y;248 varsz = halfSize * Math.sin(ang);249 varcz = halfSize * Math.cos(ang);246 let ang = cmpPosition.GetRotation().y; 247 let sz = halfSize * Math.sin(ang); 248 let cz = halfSize * Math.cos(ang); 250 249 if ((cmpWaterManager.GetWaterLevel(pos.x + sz, pos.y + cz) - cmpTerrain.GetGroundLevel(pos.x + sz, pos.y + cz)) < 1.0 // front 251 250 || (cmpWaterManager.GetWaterLevel(pos.x - sz, pos.y - cz) - cmpTerrain.GetGroundLevel(pos.x - sz, pos.y - cz)) > 2.0) // back 252 251 { … … 256 255 } 257 256 258 257 // Check distance restriction 259 if (this.template.D istance)258 if (this.template.Density) 260 259 { 261 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 262 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 263 var cat = this.template.Distance.FromClass; 260 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 261 let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 262 let cat = this.template.Density.FromClass; 263 let dist = +this.template.Density.Distance 264 264 265 varfilter = function(id)265 let filter = function(id) 266 266 { 267 varcmpIdentity = Engine.QueryInterface(id, IID_Identity);267 let cmpIdentity = Engine.QueryInterface(id, IID_Identity); 268 268 return cmpIdentity.GetClassesList().indexOf(cat) > -1; 269 269 }; 270 270 271 if (this.template.Distance.MinDistance) 271 let nearEnts = cmpRangeManager.ExecuteQuery(this.entity, 0, dist, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).filter(filter); 272 273 if (nearEnts.length > this.maxEntity) 272 274 { 273 var dist = +this.template.Distance.MinDistance; 274 var nearEnts = cmpRangeManager.ExecuteQuery(this.entity, 0, dist, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).filter(filter); 275 if (nearEnts.length) 276 { 277 var result = markForPluralTranslation( 278 "%(name)s too close to a %(category)s, must be at least %(distance)s meter away", 279 "%(name)s too close to a %(category)s, must be at least %(distance)s meters away", 280 +this.template.Distance.MinDistance); 275 let result = markForPluralTranslation( 276 "%(name)s too close to a %(category)s, must be at least %(distance)s meter away", 277 "%(name)s too close to a %(category)s, must be at least %(distance)s meters away", 278 +this.template.Density.Distance); 281 279 282 result.success = false; 283 result.translateMessage = true; 284 result.parameters = { 285 "name": name, 286 "category": cat, 287 "distance": this.template.Distance.MinDistance 288 }; 289 result.translateParameters = ["name", "category"]; 290 return result; // Fail 291 } 280 result.success = false; 281 result.translateMessage = true; 282 result.parameters = { 283 "name": name, 284 "category": cat, 285 "distance": this.template.Density.Distance 286 }; 287 result.translateParameters = ["name", "category"]; 288 return result; // Fail 292 289 } 293 if (this.template.Distance.MaxDistance) 290 291 if (nearEnts.length < this.minEntity) 294 292 { 295 var dist = +this.template.Distance.MaxDistance; 296 var nearEnts = cmpRangeManager.ExecuteQuery(this.entity, 0, dist, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).filter(filter); 297 if (!nearEnts.length) 298 { 299 var result = markForPluralTranslation( 300 "%(name)s too far from a %(category)s, must be within %(distance)s meter", 301 "%(name)s too far from a %(category)s, must be within %(distance)s meters", 302 +this.template.Distance.MinDistance); 293 let result = markForPluralTranslation( 294 "%(name)s too far from a %(category)s, must be within %(distance)s meter", 295 "%(name)s too far from a %(category)s, must be within %(distance)s meters", 296 +this.template.Density.Distance); 303 297 304 result.success = false; 305 result.translateMessage = true; 306 result.parameters = { 307 "name": name, 308 "category": cat, 309 "distance": this.template.Distance.MaxDistance 310 }; 311 result.translateParameters = ["name", "category"]; 312 return result; // Fail 313 } 298 result.success = false; 299 result.translateMessage = true; 300 result.parameters = { 301 "name": name, 302 "category": cat, 303 "distance": this.template.Density.Distance 304 }; 305 result.translateParameters = ["name", "category"]; 306 return result; // Fail 314 307 } 315 308 } 316 309 -
binaries/data/mods/public/simulation/components/GuiInterface.js
988 988 */ 989 989 GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd) 990 990 { 991 992 993 994 995 996 997 991 let result = { 992 "success": false, 993 "message": "", 994 "parameters": {}, 995 "translateMessage": false, 996 "translateParameters": [], 997 }; 998 998 999 999 // See if we're changing template 1000 1000 if (!this.placementEntity || this.placementEntity[0] != cmd.template) … … 1244 1244 // calculate wall placement and position preview entities 1245 1245 1246 1246 let result = { 1247 "success": true, 1247 1248 "pieces": [], 1248 1249 "cost": { "food": 0, "wood": 0, "stone": 0, "metal": 0, "population": 0, "populationBonus": 0, "time": 0 }, 1249 1250 }; … … 1484 1485 continue; 1485 1486 } 1486 1487 1487 // TODO: Handle results of CheckPlacement 1488 validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success); 1488 let placementResult = cmpBuildRestrictions.CheckPlacement() 1489 if (!placementResult.success) 1490 { 1491 result.success = false; 1492 result.message = placementResult.message; 1493 result.parameters = placementResult.parameters; 1494 result.translateMessage = placementResult.translateMessage; 1495 result.translateParameters = placementResult.translateParameters; 1496 } 1489 1497 1498 validPlacement = (cmpBuildRestrictions && placementResult.success); 1499 1490 1500 // If a wall piece has two control groups, it's likely a segment that spans 1491 1501 // between two existing towers. To avoid placing a duplicate wall segment, 1492 1502 // check for collisions with entities that share both control groups. … … 1550 1560 // If any were entities required to build the wall, but none of them could be validly positioned, return failure 1551 1561 // (see method-level documentation). 1552 1562 if (numRequiredPieces > 0 && result.pieces.length == 0) 1553 return false;1563 return result; 1554 1564 1555 1565 if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY) 1556 1566 result.startSnappedEnt = start.snappedEnt; -
binaries/data/mods/public/simulation/helpers/Walls.js
20 20 */ 21 21 function GetWallPlacement(placementData, wallSet, start, end) 22 22 { 23 varresult = [];23 let result = []; 24 24 25 varcandidateSegments = [26 { "template": wallSet.templates.long, "len": placementData[wallSet.templates.long].templateData.wallPiece.length},27 { "template": wallSet.templates.medium, "len": placementData[wallSet.templates.medium].templateData.wallPiece.length},28 { "template": wallSet.templates.short, "len": placementData[wallSet.templates.short].templateData.wallPiece.length},25 let candidateSegments = [ 26 { "template": wallSet.templates.long, "len": placementData[wallSet.templates.long].templateData.wallPiece.length }, 27 { "template": wallSet.templates.medium, "len": placementData[wallSet.templates.medium].templateData.wallPiece.length }, 28 { "template": wallSet.templates.short, "len": placementData[wallSet.templates.short].templateData.wallPiece.length }, 29 29 ]; 30 30 31 vartowerWidth = placementData[wallSet.templates.tower].templateData.wallPiece.length;31 let towerWidth = placementData[wallSet.templates.tower].templateData.wallPiece.length; 32 32 33 var dir = {"x": end.pos.x - start.pos.x, "z": end.pos.z - start.pos.z};34 varlen = Math.sqrt(dir.x * dir.x + dir.z * dir.z);33 let dir = { "x": end.pos.x - start.pos.x, "z": end.pos.z - start.pos.z }; 34 let len = Math.sqrt(dir.x * dir.x + dir.z * dir.z); 35 35 36 36 // we'll need room for at least our starting and ending towers to fit next to eachother 37 37 if (len <= towerWidth) 38 38 return result; 39 39 40 varplacement = GetWallSegmentsRec(len, candidateSegments, wallSet.minTowerOverlap, wallSet.maxTowerOverlap, towerWidth, 0, []);40 let placement = GetWallSegmentsRec(len, candidateSegments, wallSet.minTowerOverlap, wallSet.maxTowerOverlap, towerWidth, 0, []); 41 41 42 42 // TODO: make sure intermediate towers are spaced out far enough for their obstructions to not overlap, implying that 43 43 // tower's wallpiece lengths should be > their obstruction width, which is undesirable because it prevents towers with … … 44 44 // wide bases 45 45 if (placement) 46 46 { 47 varplacedEntities = placement.segments; // list of chosen candidate segments48 varr = placement.r; // remaining distance to target without towers (must be <= (N-1) * towerWidth)49 vars = r / (2 * placedEntities.length); // spacing47 let placedEntities = placement.segments; // list of chosen candidate segments 48 let r = placement.r; // remaining distance to target without towers (must be <= (N-1) * towerWidth) 49 let s = r / (2 * placedEntities.length); // spacing 50 50 51 var dirNormalized = {"x": dir.x / len, "z": dir.z / len};52 varangle = -Math.atan2(dir.z, dir.x); // angle of this wall segment (relative to world-space X/Z axes)51 let dirNormalized = { "x": dir.x / len, "z": dir.z / len }; 52 let angle = -Math.atan2(dir.z, dir.x); // angle of this wall segment (relative to world-space X/Z axes) 53 53 54 varprogress = 0;55 for ( vari = 0; i < placedEntities.length; i++)54 let progress = 0; 55 for (let i = 0; i < placedEntities.length; i++) 56 56 { 57 varplacedEntity = placedEntities[i];58 vartargetX = start.pos.x + (progress + s + placedEntity.len/2) * dirNormalized.x;59 vartargetZ = start.pos.z + (progress + s + placedEntity.len/2) * dirNormalized.z;57 let placedEntity = placedEntities[i]; 58 let targetX = start.pos.x + (progress + s + placedEntity.len/2) * dirNormalized.x; 59 let targetZ = start.pos.z + (progress + s + placedEntity.len/2) * dirNormalized.z; 60 60 61 61 result.push({ 62 62 "template": placedEntity.template, 63 "pos": { "x": targetX, "z": targetZ},63 "pos": { "x": targetX, "z": targetZ }, 64 64 "angle": angle, 65 65 }); 66 66 67 67 if (i < placedEntities.length - 1) 68 68 { 69 vartowerX = start.pos.x + (progress + placedEntity.len + 2*s) * dirNormalized.x;70 vartowerZ = start.pos.z + (progress + placedEntity.len + 2*s) * dirNormalized.z;69 let towerX = start.pos.x + (progress + placedEntity.len + 2*s) * dirNormalized.x; 70 let towerZ = start.pos.z + (progress + placedEntity.len + 2*s) * dirNormalized.z; 71 71 72 result.push({73 "template": wallSet.templates.tower,74 "pos": {"x": towerX, "z": towerZ},75 "angle": angle,76 });72 result.push({ 73 "template": wallSet.templates.tower, 74 "pos": { "x": towerX, "z": towerZ }, 75 "angle": angle, 76 }); 77 77 } 78 78 79 79 progress += placedEntity.len + 2*s; … … 160 160 // backtrack and try a wall segment of the next length instead. Note that we should prefer to use the long segments first since 161 161 // they can be replaced by gates. 162 162 163 for each (var candSegment incandidateSegments)163 for (let candSegment of candidateSegments) 164 164 { 165 165 segments.push(candSegment); 166 166 167 varnewDistSoFar = distSoFar + candSegment.len;168 varr = d - newDistSoFar;167 let newDistSoFar = distSoFar + candSegment.len; 168 let r = d - newDistSoFar; 169 169 170 varrLowerBound = (1 - 2 * maxOverlap) * segments.length * t;171 varrUpperBound = (1 - 2 * minOverlap) * segments.length * t;170 let rLowerBound = (1 - 2 * maxOverlap) * segments.length * t; 171 let rUpperBound = (1 - 2 * minOverlap) * segments.length * t; 172 172 173 173 if (r < rLowerBound) 174 174 { … … 179 179 } 180 180 else if (r > rUpperBound) 181 181 { 182 varrecursiveResult = GetWallSegmentsRec(d, candidateSegments, minOverlap, maxOverlap, t, newDistSoFar, segments);182 let recursiveResult = GetWallSegmentsRec(d, candidateSegments, minOverlap, maxOverlap, t, newDistSoFar, segments); 183 183 if (!recursiveResult) 184 184 { 185 185 // recursive search with this piece yielded no results, pop it and try the next one … … 192 192 else 193 193 { 194 194 // found a placement 195 return { "segments": segments, "r": r};195 return { "segments": segments, "r": r }; 196 196 } 197 197 } 198 198 -
binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
29 29 <BuildRestrictions> 30 30 <Territory>own neutral</Territory> 31 31 <Category>CivilCentre</Category> 32 <D istance>32 <Density> 33 33 <FromClass>CivilCentre</FromClass> 34 <MinDistance>200</MinDistance> 35 </Distance> 34 <Distance>200</Distance> 35 <MaxEntity>0</MaxEntity> 36 </Density> 36 37 </BuildRestrictions> 37 38 <Capturable> 38 39 <CapturePoints>2500</CapturePoints> -
binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
22 22 </BuildingAI> 23 23 <BuildRestrictions> 24 24 <Category>DefenseTower</Category> 25 <D istance>25 <Density> 26 26 <FromClass>DefenseTower</FromClass> 27 <MinDistance>60</MinDistance> 28 </Distance> 27 <Distance>60</Distance> 28 <MaxEntity>0</MaxEntity> 29 </Density> 29 30 </BuildRestrictions> 30 31 <Cost> 31 32 <BuildTime>150</BuildTime> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml
21 21 </BuildingAI> 22 22 <BuildRestrictions> 23 23 <PlacementType>land-shore</PlacementType> 24 <Category>Wall</Category> 24 <Category>WallTower</Category> 25 <Density> 26 <FromClass>WallTower</FromClass> 27 <Distance>40</Distance> 28 <MaxEntity>2</MaxEntity> 29 </Density> 25 30 </BuildRestrictions> 26 31 <Capturable disable=""/> 27 32 <Repairable> … … 52 57 <Identity> 53 58 <GenericName>Wall Turret</GenericName> 54 59 <Tooltip>Shoots arrows. Garrison to defend a city wall against attackers.</Tooltip> 55 <Classes datatype="tokens">-ConquestCritical StoneWall Tower </Classes>60 <Classes datatype="tokens">-ConquestCritical StoneWall Tower WallTower</Classes> 56 61 <Icon>structures/tower.png</Icon> 57 62 <RequiredTechnology>phase_town</RequiredTechnology> 58 63 </Identity> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wooden_tower.xml
16 16 </Attack> 17 17 <BuildRestrictions> 18 18 <Category>DefenseTower</Category> 19 <D istance>19 <Density> 20 20 <FromClass>DefenseTower</FromClass> 21 <MinDistance>40</MinDistance> 22 </Distance> 21 <Distance>40</Distance> 22 <MaxEntity>0</MaxEntity> 23 </Density> 23 24 </BuildRestrictions> 24 25 <Cost> 25 26 <BuildTime>40</BuildTime> -
binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
26 26 </BuildingAI> 27 27 <BuildRestrictions> 28 28 <Category>Fortress</Category> 29 <D istance>29 <Density> 30 30 <FromClass>Fortress</FromClass> 31 <MinDistance>80</MinDistance> 32 </Distance> 31 <Distance>80</Distance> 32 <MaxEntity>0</MaxEntity> 33 </Density> 33 34 </BuildRestrictions> 34 35 <Capturable> 35 36 <CapturePoints>4000</CapturePoints>