- Timestamp:
- 08/06/11 10:11:05 (13 years ago)
- Location:
- ps/trunk
- Files:
-
- 28 edited
-
binaries/data/mods/public/gui/session/input.js (modified) (6 diffs)
-
binaries/data/mods/public/simulation/components/BuildLimits.js (modified) (3 diffs)
-
binaries/data/mods/public/simulation/components/BuildRestrictions.js (modified) (4 diffs)
-
binaries/data/mods/public/simulation/components/GarrisonHolder.js (modified) (1 diff)
-
binaries/data/mods/public/simulation/components/GuiInterface.js (modified) (3 diffs)
-
binaries/data/mods/public/simulation/components/TrainingQueue.js (modified) (1 diff)
-
binaries/data/mods/public/simulation/data/pathfinder.xml (modified) (1 diff)
-
binaries/data/mods/public/simulation/helpers/Commands.js (modified) (6 diffs)
-
binaries/data/mods/public/simulation/helpers/Player.js (modified) (2 diffs)
-
binaries/data/mods/public/simulation/templates/special/player.xml (modified) (1 diff)
-
binaries/data/mods/public/simulation/templates/template_structure.xml (modified) (1 diff)
-
binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml (modified) (1 diff)
-
binaries/data/mods/public/simulation/templates/template_structure_economic_mill.xml (modified) (1 diff)
-
binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml (modified) (1 diff)
-
source/simulation2/components/CCmpFootprint.cpp (modified) (5 diffs)
-
source/simulation2/components/CCmpObstruction.cpp (modified) (4 diffs)
-
source/simulation2/components/CCmpPathfinder.cpp (modified) (7 diffs)
-
source/simulation2/components/CCmpPathfinder_Common.h (modified) (3 diffs)
-
source/simulation2/components/CCmpTemplateManager.cpp (modified) (1 diff)
-
source/simulation2/components/CCmpTerritoryManager.cpp (modified) (2 diffs)
-
source/simulation2/components/CCmpUnitMotion.cpp (modified) (3 diffs)
-
source/simulation2/components/ICmpObstruction.cpp (modified) (1 diff)
-
source/simulation2/components/ICmpObstruction.h (modified) (1 diff)
-
source/simulation2/components/ICmpPathfinder.h (modified) (1 diff)
-
source/simulation2/components/ICmpTerritoryManager.cpp (modified) (1 diff)
-
source/simulation2/components/ICmpTerritoryManager.h (modified) (2 diffs)
-
source/simulation2/components/ICmpUnitMotion.cpp (modified) (1 diff)
-
source/simulation2/components/ICmpUnitMotion.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ps/trunk/binaries/data/mods/public/gui/session/input.js
r9791 r9970 81 81 if (placementEntity && placementPosition) 82 82 { 83 Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {83 return Engine.GuiInterfaceCall("SetBuildingPlacementPreview", { 84 84 "template": placementEntity, 85 85 "x": placementPosition.x, … … 88 88 }); 89 89 } 90 91 return false; 90 92 } 91 93 … … 329 331 330 332 // Use the preview to check it's a valid build location 331 var ok = Engine.GuiInterfaceCall("SetBuildingPlacementPreview", { 332 "template": placementEntity, 333 "x": placementPosition.x, 334 "z": placementPosition.z, 335 "angle": placementAngle 336 }); 337 if (!ok) 333 if (!updateBuildingPlacementPreview()) 338 334 { 339 335 // invalid location - don't build it … … 562 558 } 563 559 564 Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {560 var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", { 565 561 "template": placementEntity, 566 562 "x": placementPosition.x, 567 "z": placementPosition.z, 568 "angle": placementAngle 563 "z": placementPosition.z 569 564 }); 570 565 if (snapData.snapped) 566 placementAngle = snapData.angle; 567 568 updateBuildingPlacementPreview(); 571 569 break; 572 570 … … 822 820 case "mousemotion": 823 821 placementPosition = Engine.GetTerrainAtPoint(ev.x, ev.y); 824 Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {822 var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", { 825 823 "template": placementEntity, 826 824 "x": placementPosition.x, 827 "z": placementPosition.z, 828 "angle": placementAngle 825 "z": placementPosition.z 829 826 }); 827 if (snapData.snapped) 828 placementAngle = snapData.angle; 829 830 updateBuildingPlacementPreview(); 830 831 831 832 return false; // continue processing mouse motion … … 856 857 case "session.rotate.cw": 857 858 placementAngle += rotation_step; 858 Engine.GuiInterfaceCall("SetBuildingPlacementPreview", { 859 "template": placementEntity, 860 "x": placementPosition.x, 861 "z": placementPosition.z, 862 "angle": placementAngle 863 }); 859 updateBuildingPlacementPreview(); 864 860 break; 865 861 case "session.rotate.ccw": 866 862 placementAngle -= rotation_step; 867 Engine.GuiInterfaceCall("SetBuildingPlacementPreview", { 868 "template": placementEntity, 869 "x": placementPosition.x, 870 "z": placementPosition.z, 871 "angle": placementAngle 872 }); 863 updateBuildingPlacementPreview(); 873 864 break; 874 865 } -
ps/trunk/binaries/data/mods/public/simulation/components/BuildLimits.js
r8836 r9970 2 2 3 3 BuildLimits.prototype.Schema = 4 "<a:help></a:help>" + 4 "<a:help>Specifies per category limits on number of buildings that can be constructed for each player.</a:help>" + 5 "<a:example>" + 6 "<Limits>" + 7 "<CivilCentre/>" + 8 "<ScoutTower>20</ScoutTower>" + 9 "<Fortress>5</Fortress>" + 10 "<Special>" + 11 "<LimitPerCivCentre>1</LimitPerCivCentre>" + 12 "</Special>" + 13 "</Limits>" + 14 "</a:example>" + 5 15 "<element name='LimitMultiplier'>" + 6 16 "<ref name='positiveDecimal'/>" + … … 8 18 "<element name='Limits'>" + 9 19 "<zeroOrMore>" + 10 "<element >" +20 "<element a:help='Specifies a category of building on which to apply this limit. See BuildRestrictions for list of categories.'>" + 11 21 "<anyName />" + 12 "<text />" + 22 "<choice>" + 23 "<text />" + 24 "<element name='LimitPerCivCentre' a:help='Specifies that this limit is per number of civil centres.'>" + 25 "<data type='nonNegativeInteger'/>" + 26 "</element>" + 27 "</choice>" + 13 28 "</element>" + 14 29 "</zeroOrMore>" + 15 30 "</element>"; 16 31 32 /* 33 * TODO: Use an inheriting player_{civ}.xml template for civ-specific limits 34 */ 35 17 36 BuildLimits.prototype.Init = function() 18 37 { 19 this.limit s= [];20 this. unitCount = [];38 this.limit = []; 39 this.count = []; 21 40 for (var category in this.template.Limits) 22 41 { 23 this.limit s[category] = this.template.Limits[category];24 this. unitCount[category] = 0;42 this.limit[category] = this.template.Limits[category]; 43 this.count[category] = 0; 25 44 } 26 45 }; … … 28 47 BuildLimits.prototype.IncrementCount = function(category) 29 48 { 30 if (this.unitCount[category] !== undefined) 31 this.unitCount[category]++; 49 if (this.count[category] !== undefined) 50 { 51 this.count[category]++; 52 } 32 53 }; 33 54 34 55 BuildLimits.prototype.DecrementCount = function(category) 35 56 { 36 if (this.unitCount[category] !== undefined) 37 this.unitCount[category]--; 57 if (this.count[category] !== undefined) 58 { 59 this.count[category]--; 60 } 38 61 }; 39 62 40 63 BuildLimits.prototype.AllowedToBuild = function(category) 41 64 { 42 if (this.unitCount[category]) 65 // TODO: The UI should reflect this before the user tries to place the building, 66 // since the limits are independent of placement location 67 68 // Allow unspecified categories and those with no limit 69 if (this.count[category] === undefined || this.limit[category] === undefined) 43 70 { 44 if (this.unitCount[category] >= this.limits[category]) 71 return true; 72 } 73 74 // Rather than complicating the schema unecessarily, just handle special cases here 75 if (this.limit[category].LimitPerCivCentre !== undefined) 76 { 77 if (this.count[category] >= this.count["CivilCentre"] * this.limit[category].LimitPerCivCentre) 45 78 { 46 79 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 47 80 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 48 var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Build limit reached for this building"};81 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" build limit of "+this.limit[category].LimitPerCivCentre+" per civil centre reached"}; 49 82 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 50 83 cmpGUIInterface.PushNotification(notification); 84 51 85 return false; 52 86 } 53 else54 return true;55 87 } 56 else 88 else if (this.count[category] >= this.limit[category]) 57 89 { 58 //Check here for terrain 59 return true; 90 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 91 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 92 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" build limit of "+this.limit[category]+ " reached"}; 93 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 94 cmpGUIInterface.PushNotification(notification); 95 96 return false; 60 97 } 98 99 return true; 61 100 }; 62 101 -
ps/trunk/binaries/data/mods/public/simulation/components/BuildRestrictions.js
r8836 r9970 2 2 3 3 BuildRestrictions.prototype.Schema = 4 "<element name='PlacementType'>" + 4 "<a:help>Specifies building placement restrictions as they relate to terrain, territories, and distance.</a:help>" + 5 "<a:example>" + 6 "<BuildRestrictions>" + 7 "<PlacementType>land</PlacementType>" + 8 "<Territory>own</Territory>" + 9 "<Category>Special</Category>" + 10 "<Distance>" + 11 "<FromCategory>CivilCentre</FromCategory>" + 12 "<MaxDistance>40</MaxDistance>" + 13 "</Distance>" + 14 "</BuildRestrictions>" + 15 "</a:example>" + 16 "<element name='PlacementType' a:help='Specifies the terrain type restriction for this building.'>" + 5 17 "<choice>" + 6 "<value>standard</value>" + 7 "<value>settlement</value>" + 8 "</choice>" + // TODO: add special types for fields, docks, walls 9 "</element>" + 10 "<element name='Territory'>" + 11 "<choice>" + 12 "<value>all</value>" + 13 "<value>allied</value>" + 18 "<value>land</value>" + 19 "<value>shore</value>" + 14 20 "</choice>" + 15 21 "</element>" + 16 "<element name='Category'>" + 22 "<element name='Territory' a:help='Specifies territory type restrictions for this building.'>" + 23 "<list>" + 24 "<oneOrMore>" + 25 "<choice>" + 26 "<value>own</value>" + 27 "<value>ally</value>" + 28 "<value>neutral</value>" + 29 "<value>enemy</value>" + 30 "</choice>" + 31 "</oneOrMore>" + 32 "</list>" + 33 "</element>" + 34 "<element name='Category' a:help='Specifies the category of this building, for satisfying special constraints.'>" + 17 35 "<choice>" + 18 36 "<value>CivilCentre</value>" + … … 33 51 "<value>Special</value>" + 34 52 "</choice>" + 35 "</element>"; 53 "</element>" + 54 "<optional>" + 55 "<element name='Distance' a:help='Specifies distance restrictions on this building, relative to buildings from the given category.'>" + 56 "<interleave>" + 57 "<element name='FromCategory'>" + 58 "<choice>" + 59 "<value>CivilCentre</value>" + 60 "</choice>" + 61 "</element>" + 62 "<optional><element name='MinDistance'><data type='positiveInteger'/></element></optional>" + 63 "<optional><element name='MaxDistance'><data type='positiveInteger'/></element></optional>" + 64 "</interleave>" + 65 "</element>" + 66 "</optional>"; 36 67 // TODO: add phases, prerequisites, etc 37 68 38 /* 39 * TODO: the vague plan for Category is to add some BuildLimitManager which 40 * specifies the limit per category, and which can determine whether you're 41 * allowed to build more (based on the number in total / per territory / per 42 * civ center as appropriate) 43 */ 44 45 /* 46 * TODO: the vague plan for PlacementType is that it may restrict the locations 47 * and orientations of new construction work (e.g. civ centers must be on settlements, 48 * docks must be on shores), which affects the UI and the build permissions 49 */ 69 BuildRestrictions.prototype.Init = function() 70 { 71 this.territories = this.template.Territory.split(/\s+/); 72 }; 50 73 51 74 BuildRestrictions.prototype.OnOwnershipChanged = function(msg) 52 75 { 76 // This automatically updates building counts 53 77 if (this.template.Category) 54 78 { 55 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);56 79 if (msg.from != -1) 57 80 { 58 var fromPlayerBuildLimits = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(msg.from), IID_BuildLimits);81 var fromPlayerBuildLimits = QueryPlayerIDInterface(msg.from, IID_BuildLimits); 59 82 fromPlayerBuildLimits.DecrementCount(this.template.Category); 60 83 } 61 84 if (msg.to != -1) 62 85 { 63 var toPlayerBuildLimits = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(msg.to), IID_BuildLimits);86 var toPlayerBuildLimits = QueryPlayerIDInterface(msg.to, IID_BuildLimits); 64 87 toPlayerBuildLimits.IncrementCount(this.template.Category); 65 88 } … … 67 90 }; 68 91 92 BuildRestrictions.prototype.CheckPlacement = function(player) 93 { 94 // TODO: Return error code for invalid placement, which can be handled by the UI 95 96 // Check obstructions and terrain passability 97 var passClassName = ""; 98 switch (this.template.PlacementType) 99 { 100 case "shore": 101 passClassName = "building-shore"; 102 break; 103 104 case "land": 105 default: 106 passClassName = "building-land"; 107 } 108 109 var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 110 if (!cmpObstruction || !cmpObstruction.CheckFoundation(passClassName)) 111 { 112 return false; // Fail 113 } 114 115 // Check territory restrictions 116 var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); 117 var cmpPlayer = QueryPlayerIDInterface(player, IID_Player); 118 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 119 if (!(cmpTerritoryManager && cmpPlayer && cmpPosition && cmpPosition.IsInWorld())) 120 { 121 return false; // Fail 122 } 123 124 var pos = cmpPosition.GetPosition2D(); 125 var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); 126 var isOwn = (tileOwner == player); 127 var isNeutral = (tileOwner == 0); 128 var isAlly = !isOwn && cmpPlayer.IsAlly(tileOwner); 129 var isEnemy = !isNeutral && cmpPlayer.IsEnemy(tileOwner); 130 131 if ((isAlly && !this.HasTerritory("ally")) 132 || (isOwn && !this.HasTerritory("own")) 133 || (isNeutral && !this.HasTerritory("neutral")) 134 || (isEnemy && !this.HasTerritory("enemy"))) 135 { 136 return false; // Fail 137 } 138 139 // Check special requirements 140 if (this.template.Category == "Dock") 141 { 142 // Dock must be oriented from land facing into water 143 var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint); 144 if (!cmpFootprint) 145 { 146 return false; // Fail 147 } 148 149 // Get building's footprint 150 var shape = cmpFootprint.GetShape(); 151 var halfSize = 0; 152 if (shape.type == "square") 153 { 154 halfSize = shape.depth/2; 155 } 156 else if (shape.type == "circle") 157 { 158 halfSize = shape.radius; 159 } 160 161 var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 162 var cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); 163 if (!cmpTerrain || !cmpWaterManager) 164 { 165 return false; // Fail 166 } 167 168 var ang = cmpPosition.GetRotation().y; 169 var sz = halfSize * Math.sin(ang); 170 var cz = halfSize * Math.cos(ang); 171 if ((cmpTerrain.GetGroundLevel(pos.x + sz, pos.y + cz) > cmpWaterManager.GetWaterLevel(pos.x + sz, pos.y + cz)) || // front 172 (cmpTerrain.GetGroundLevel(pos.x - sz, pos.y - cz) <= cmpWaterManager.GetWaterLevel(pos.x - sz, pos.y - cz))) // back 173 { 174 return false; // Fail 175 } 176 } 177 178 // Check distance restriction 179 if (this.template.Distance) 180 { 181 var minDist = 65535; 182 var maxDist = 0; 183 var ents = Engine.GetEntitiesWithInterface(IID_BuildRestrictions); 184 for each (var ent in ents) 185 { 186 var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); 187 if (cmpBuildRestrictions.GetCategory() == this.template.Distance.FromCategory && IsOwnedByPlayer(player, ent)) 188 { 189 var cmpEntPosition = Engine.QueryInterface(ent, IID_Position); 190 if (cmpEntPosition && cmpEntPosition.IsInWorld()) 191 { 192 var entPos = cmpEntPosition.GetPosition2D(); 193 var dist = Math.sqrt((pos.x-entPos.x)*(pos.x-entPos.x) + (pos.y-entPos.y)*(pos.y-entPos.y)); 194 if (dist < minDist) 195 { 196 minDist = dist; 197 } 198 if (dist > maxDist) 199 { 200 maxDist = dist; 201 } 202 } 203 } 204 } 205 206 if (this.template.Distance.MinDistance !== undefined && minDist < this.template.Distance.MinDistance 207 || this.template.Distance.MaxDistance !== undefined && maxDist > this.template.Distance.MaxDistance) 208 { 209 return false; // Fail 210 } 211 } 212 213 // Success 214 return true; 215 }; 216 69 217 BuildRestrictions.prototype.GetCategory = function() 70 218 { … … 72 220 }; 73 221 222 BuildRestrictions.prototype.GetTerritories = function() 223 { 224 return this.territories; 225 }; 226 227 BuildRestrictions.prototype.HasTerritory = function(territory) 228 { 229 return (this.territories.indexOf(territory) != -1); 230 }; 231 74 232 Engine.RegisterComponentType(IID_BuildRestrictions, "BuildRestrictions", BuildRestrictions); -
ps/trunk/binaries/data/mods/public/simulation/components/GarrisonHolder.js
r9499 r9970 156 156 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 157 157 pos = cmpPosition.GetPosition(); 158 warn("Can't find free space to ungarrison unit"); 158 159 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 160 var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Can't find free space to ungarrison unit"}; 161 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 162 cmpGUIInterface.PushNotification(notification); 159 163 } 160 164 -
ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js
r9791 r9970 469 469 } 470 470 471 // Check whether it's obstructed by other entities472 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);473 var colliding = (cmpObstruction && cmpObstruction.CheckFoundationCollisions());474 475 471 // Check whether it's in a visible region 476 472 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 477 var visible = (cmpRangeManager.GetLosVisibility(ent, player) == "visible"); 478 479 var ok = (!colliding && visible); 480 473 var visible = (cmpRangeManager && cmpRangeManager.GetLosVisibility(ent, player) == "visible"); 474 var validPlacement = false; 475 476 if (visible) 477 { // Check whether it's obstructed by other entities or invalid terrain 478 var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); 479 if (!cmpBuildRestrictions) 480 error("cmpBuildRestrictions not defined"); 481 482 validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement(player)); 483 } 484 485 var ok = (visible && validPlacement); 486 481 487 // Set it to a red shade if this is an invalid location 482 488 var cmpVisual = Engine.QueryInterface(ent, IID_Visual); … … 493 499 494 500 return false; 501 }; 502 503 GuiInterface.prototype.GetFoundationSnapData = function(player, data) 504 { 505 var cmpTemplateMgr = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 506 var template = cmpTemplateMgr.GetTemplate(data.template); 507 508 if (template.BuildRestrictions.Category == "Dock") 509 { 510 var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 511 var cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); 512 513 // Find direction of most open water, algorithm: 514 // 1. Pick points in a circle around dock 515 // 2. If point is in water, add to array 516 // 3. Scan array looking for consective points 517 // 4. Find longest sequence of conseuctive points 518 // 5. Calculate angle using average of sequence 519 const numPoints = 16; 520 const dist = 20.0; 521 var waterPoints = []; 522 for (var i = 0; i < numPoints; ++i) 523 { 524 var angle = (i/numPoints)*2*Math.PI; 525 var nx = data.x - dist*Math.sin(angle); 526 var nz = data.z + dist*Math.cos(angle); 527 528 if (cmpTerrain.GetGroundLevel(nx, nz) < cmpWaterManager.GetWaterLevel(nx, nz)) 529 { 530 waterPoints.push(i); 531 } 532 } 533 var consec = []; 534 var length = waterPoints.length; 535 for (var i = 0; i < length; ++i) 536 { 537 var count = 0; 538 for (var j = 0; j < (length-1); ++j) 539 { 540 if (((waterPoints[(i + j) % length]+1) % numPoints) == waterPoints[(i + j + 1) % length]) 541 { 542 ++count; 543 } 544 else 545 { 546 break; 547 } 548 } 549 consec[i] = count; 550 } 551 var start = 0; 552 var count = 0; 553 for (var c in consec) 554 { 555 if (consec[c] > count) 556 { 557 start = c; 558 count = consec[c]; 559 } 560 } 561 562 return { "snapped": true, "x": data.x, "z": data.z, "angle": -(((waterPoints[start] + consec[start]/2) % numPoints)/numPoints*2*Math.PI) }; 563 } 564 565 return {"snapped": false}; 495 566 }; 496 567 … … 584 655 "DisplayRallyPoint": 1, 585 656 "SetBuildingPlacementPreview": 1, 657 "GetFoundationSnapData": 1, 586 658 "PlaySound": 1, 587 659 "FindIdleUnit": 1, -
ps/trunk/binaries/data/mods/public/simulation/components/TrainingQueue.js
r8899 r9970 218 218 // For now, just move the unit into the middle of the building where it'll probably get stuck 219 219 pos = cmpPosition.GetPosition(); 220 warn("Can't find free space to spawn trained unit"); 220 221 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 222 var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Can't find free space to spawn trained unit"}; 223 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 224 cmpGUIInterface.PushNotification(notification); 221 225 } 222 226 -
ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.xml
r9929 r9970 16 16 <MinWaterDepth>1</MinWaterDepth> 17 17 </ship> 18 <!-- Building construction classes: --> 18 <!-- Building construction classes: 19 * Land is used for most buildings, which must be away 20 from water and not on cliffs or mountains. 21 * Shore is used for docks, which must be near water and 22 land, yet shallow enough for builders to approach. 23 --> 19 24 <building-land> 20 25 <MaxWaterDepth>0</MaxWaterDepth> 26 <MinShoreDistance>2.0</MinShoreDistance> 21 27 <MaxTerrainSlope>1.0</MaxTerrainSlope> 22 28 </building-land> 29 <building-shore> 30 <MaxShoreDistance>3.0</MaxShoreDistance> 31 <MaxTerrainSlope>1.5</MaxTerrainSlope> 32 </building-shore> 23 33 24 34 </PassabilityClasses> -
ps/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
r9776 r9970 75 75 case "returnresource": 76 76 // Check dropsite is owned by player 77 if (IsOwnedByPlayer( cmd.target, player))77 if (IsOwnedByPlayer(player, cmd.target)) 78 78 { 79 79 var entities = FilterEntityList(cmd.entities, player, controlAllUnits); … … 132 132 // Tentatively create the foundation (we might find later that it's a invalid build command) 133 133 var ent = Engine.AddEntity("foundation|" + cmd.template); 134 // TODO: report errors (e.g. invalid template names) 134 if (ent == INVALID_ENTITY) 135 { 136 // Error (e.g. invalid template names) 137 error("Error creating foundation for '" + cmd.template + "'"); 138 break; 139 } 135 140 136 141 // Move the foundation to the right place … … 139 144 cmpPosition.SetYRotation(cmd.angle); 140 145 141 // Check whether it's obstructed by other entities 142 var cmp Obstruction = Engine.QueryInterface(ent, IID_Obstruction);143 if ( cmpObstruction && cmpObstruction.CheckFoundationCollisions())144 { 145 // TODO: report error to player (the building site was obstructed)146 print("Building site was obstructed\n");146 // Check whether it's obstructed by other entities or invalid terrain 147 var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); 148 if (!cmpBuildRestrictions || !cmpBuildRestrictions.CheckPlacement(player)) 149 { 150 var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 151 cmpGuiInterface.PushNotification({ "player": player, "message": "Building site was obstructed" }); 147 152 148 153 // Remove the foundation because the construction was aborted 149 154 Engine.DestroyEntity(ent); 150 155 break; 156 } 157 158 // Check build limits 159 var cmpBuildLimits = QueryPlayerIDInterface(player, IID_BuildLimits); 160 if (!cmpBuildLimits || !cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory())) 161 { 162 // TODO: The UI should tell the user they can't build this (but we still need this check) 163 164 // Remove the foundation because the construction was aborted 165 Engine.DestroyEntity(ent); 151 166 break; 152 167 } … … 168 183 } 169 184 */ 170 171 var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions);172 var cmpBuildLimits = Engine.QueryInterface(playerEnt, IID_BuildLimits);173 if (!cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory()))174 {175 Engine.DestroyEntity(ent);176 break;177 }178 185 179 186 var cmpCost = Engine.QueryInterface(ent, IID_Cost); 180 187 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts())) 181 188 { 182 // TODO: report error to player (they ran out of resources)183 189 Engine.DestroyEntity(ent); 184 190 break; … … 566 572 567 573 /** 568 * Check if entity is owned by player569 */570 function IsOwnedByPlayer(entity, player)571 {572 var cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);573 return (cmpOwnership && cmpOwnership.GetOwner() == player);574 }575 576 /**577 574 * Check if player can control this entity 578 575 * returns: true if the entity is valid and owned by the player if … … 581 578 function CanControlUnit(entity, player, controlAll) 582 579 { 583 return (IsOwnedByPlayer( entity, player) || controlAll);580 return (IsOwnedByPlayer(player, entity) || controlAll); 584 581 } 585 582 -
ps/trunk/binaries/data/mods/public/simulation/helpers/Player.js
r9726 r9970 232 232 233 233 /** 234 * Returns true if the entity 'target' is owned by player 235 */ 236 function IsOwnedByPlayer(player, target) 237 { 238 var cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership); 239 return (cmpOwnershipTarget && player == cmpOwnershipTarget.GetOwner()); 240 } 241 242 /** 234 243 * Returns true if the entity 'target' is owned by an ally of player 235 244 */ … … 279 288 Engine.RegisterGlobal("QueryPlayerIDInterface", QueryPlayerIDInterface); 280 289 Engine.RegisterGlobal("IsOwnedByAllyOfEntity", IsOwnedByAllyOfEntity); 290 Engine.RegisterGlobal("IsOwnedByPlayer", IsOwnedByPlayer); 281 291 Engine.RegisterGlobal("IsOwnedByAllyOfPlayer", IsOwnedByAllyOfPlayer); 282 292 Engine.RegisterGlobal("IsOwnedByEnemyOfPlayer", IsOwnedByEnemyOfPlayer); -
ps/trunk/binaries/data/mods/public/simulation/templates/special/player.xml
r9936 r9970 4 4 <LimitMultiplier>1.0</LimitMultiplier> 5 5 <Limits> 6 <CivilCentre/> 7 <ScoutTower>20</ScoutTower> 8 <Fortress>5</Fortress> 6 9 </Limits> 7 10 </BuildLimits> -
ps/trunk/binaries/data/mods/public/simulation/templates/template_structure.xml
r9936 r9970 11 11 </BuildingAI> 12 12 <BuildRestrictions> 13 <PlacementType> standard</PlacementType>14 <Territory> allied</Territory>13 <PlacementType>land</PlacementType> 14 <Territory>own</Territory> 15 15 </BuildRestrictions> 16 16 <Cost> -
ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
r9963 r9970 7 7 </Armour> 8 8 <BuildRestrictions> 9 <PlacementType>settlement</PlacementType> 10 <Territory>all</Territory> 9 <Territory>own neutral</Territory> 11 10 <Category>CivilCentre</Category> 11 <Distance> 12 <FromCategory>CivilCentre</FromCategory> 13 <MinDistance>150</MinDistance> 14 </Distance> 12 15 </BuildRestrictions> 13 16 <Cost> -
ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_mill.xml
r9956 r9970 8 8 <BuildRestrictions> 9 9 <Category>Mill</Category> 10 <Territory>all</Territory>11 10 </BuildRestrictions> 12 11 <Cost> -
ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
r9956 r9970 7 7 </Armour> 8 8 <BuildRestrictions> 9 <Territory>own ally neutral</Territory> 10 <PlacementType>shore</PlacementType> 9 11 <Category>Dock</Category> 10 12 </BuildRestrictions> -
ps/trunk/source/simulation2/components/CCmpFootprint.cpp
r8899 r9970 1 /* Copyright (C) 201 0Wildfire Games.1 /* Copyright (C) 2011 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * … … 21 21 #include "ICmpFootprint.h" 22 22 23 #include "ICmpObstruction.h" 24 #include "ICmpObstructionManager.h" 25 #include "ICmpPosition.h" 23 #include "simulation2/components/ICmpObstruction.h" 24 #include "simulation2/components/ICmpObstructionManager.h" 25 #include "simulation2/components/ICmpPathfinder.h" 26 #include "simulation2/components/ICmpPosition.h" 27 #include "simulation2/components/ICmpUnitMotion.h" 26 28 #include "simulation2/MessageTypes.h" 29 #include "graphics/Terrain.h" // For CELL_SIZE 27 30 #include "maths/FixedVector2D.h" 28 31 … … 126 129 // shape.) 127 130 128 CFixedVector3D error(fixed::FromInt(-1), fixed::FromInt(-1), fixed::FromInt(-1));131 const CFixedVector3D error(fixed::FromInt(-1), fixed::FromInt(-1), fixed::FromInt(-1)); 129 132 130 133 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); … … 147 150 // else use zero radius 148 151 149 // The spawn point should be far enough from this footprint to fit the unit, plus a little gap 150 entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2); 151 152 // Get passability class from UnitMotion 153 CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), spawned); 154 if (cmpUnitMotion.null()) 155 return error; 156 157 ICmpPathfinder::pass_class_t spawnedPass = cmpUnitMotion->GetPassabilityClass(); 158 CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY); 159 if (cmpPathfinder.null()) 160 return error; 161 152 162 CFixedVector2D initialPos = cmpPosition->GetPosition2D(); 153 163 entity_angle_t initialAngle = cmpPosition->GetRotation().Y; 154 164 165 // Max spawning distance in tiles 166 const size_t maxSpawningDistance = 4; 167 155 168 if (m_Shape == CIRCLE) 156 169 { 157 entity_pos_t radius = m_Size0 + clearance; 158 159 // Try equally-spaced points around the circle, starting from the front and expanding outwards in alternating directions 160 const ssize_t numPoints = 31; 161 for (ssize_t i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2] 170 // Expand outwards from foundation 171 for (size_t dist = 0; dist <= maxSpawningDistance; ++dist) 162 172 { 163 entity_angle_t angle = initialAngle + (entity_angle_t::Pi()*2).Multiply(entity_angle_t::FromInt(i)/(int)numPoints); 164 165 fixed s, c; 166 sincos_approx(angle, s, c); 167 168 CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Y + c.Multiply(radius)); 169 170 SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity 171 if (!cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Z, spawnedRadius, NULL)) 172 return pos; // this position is okay, so return it 173 // The spawn point should be far enough from this footprint to fit the unit, plus a little gap 174 entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2 + CELL_SIZE*dist); 175 entity_pos_t radius = m_Size0 + clearance; 176 177 // Try equally-spaced points around the circle in alternating directions, starting from the front 178 const ssize_t numPoints = 31 + 2*dist; 179 for (ssize_t i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2] 180 { 181 entity_angle_t angle = initialAngle + (entity_angle_t::Pi()*2).Multiply(entity_angle_t::FromInt(i)/(int)numPoints); 182 183 fixed s, c; 184 sincos_approx(angle, s, c); 185 186 CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Y + c.Multiply(radius)); 187 188 SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity 189 if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, spawnedPass)) 190 return pos; // this position is okay, so return it 191 } 173 192 } 174 193 } … … 178 197 sincos_approx(initialAngle, s, c); 179 198 180 for (size_t edge = 0; edge < 4; ++edge) 199 // Expand outwards from foundation 200 for (size_t dist = 0; dist <= maxSpawningDistance; ++dist) 181 201 { 182 // Try equally-spaced points along the edge, starting from the middle and expanding outwards in alternating directions 183 const ssize_t numPoints = 9; 184 185 // Compute the direction and length of the current edge 186 CFixedVector2D dir; 187 fixed sx, sy; 188 switch (edge) 202 // The spawn point should be far enough from this footprint to fit the unit, plus a little gap 203 entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2 + CELL_SIZE*dist); 204 205 for (size_t edge = 0; edge < 4; ++edge) 189 206 { 190 case 0: 191 dir = CFixedVector2D(c, -s); 192 sx = m_Size0; 193 sy = m_Size1; 194 break; 195 case 1: 196 dir = CFixedVector2D(-s, -c); 197 sx = m_Size1; 198 sy = m_Size0; 199 break; 200 case 2: 201 dir = CFixedVector2D(s, c); 202 sx = m_Size1; 203 sy = m_Size0; 204 break; 205 case 3: 206 dir = CFixedVector2D(-c, s); 207 sx = m_Size0; 208 sy = m_Size1; 209 break; 210 } 211 CFixedVector2D center = initialPos - dir.Perpendicular().Multiply(sy/2 + clearance); 212 dir = dir.Multiply((sx + clearance*2) / (int)(numPoints-1)); 213 214 for (ssize_t i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2] 215 { 216 CFixedVector2D pos (center + dir*i); 217 218 SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity 219 if (!cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, spawnedRadius, NULL)) 220 return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it 207 // Try equally-spaced points along the edge in alternating directions, starting from the middle 208 const ssize_t numPoints = 9 + 2*dist; 209 210 // Compute the direction and length of the current edge 211 CFixedVector2D dir; 212 fixed sx, sy; 213 switch (edge) 214 { 215 case 0: 216 dir = CFixedVector2D(c, -s); 217 sx = m_Size0; 218 sy = m_Size1; 219 break; 220 case 1: 221 dir = CFixedVector2D(-s, -c); 222 sx = m_Size1; 223 sy = m_Size0; 224 break; 225 case 2: 226 dir = CFixedVector2D(s, c); 227 sx = m_Size1; 228 sy = m_Size0; 229 break; 230 case 3: 231 dir = CFixedVector2D(-c, s); 232 sx = m_Size0; 233 sy = m_Size1; 234 break; 235 } 236 CFixedVector2D center = initialPos - dir.Perpendicular().Multiply(sy/2 + clearance); 237 dir = dir.Multiply((sx + clearance*2) / (int)(numPoints-1)); 238 239 for (ssize_t i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2] 240 { 241 CFixedVector2D pos (center + dir*i); 242 243 SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity 244 if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass)) 245 return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it 246 } 221 247 } 222 248 } -
ps/trunk/source/simulation2/components/CCmpObstruction.cpp
r9510 r9970 21 21 #include "ICmpObstruction.h" 22 22 23 #include " ICmpObstructionManager.h"24 #include " ICmpPosition.h"23 #include "simulation2/components/ICmpObstructionManager.h" 24 #include "simulation2/components/ICmpPosition.h" 25 25 26 26 #include "simulation2/MessageTypes.h" … … 329 329 } 330 330 331 virtual bool CheckFoundation Collisions()331 virtual bool CheckFoundation(std::string className) 332 332 { 333 333 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); … … 340 340 CFixedVector2D pos = cmpPosition->GetPosition2D(); 341 341 342 CmpPtr<ICmp ObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);343 if (cmp ObstructionManager.null())342 CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY); 343 if (cmpPathfinder.null()) 344 344 return false; // error 345 346 // Get passability class 347 ICmpPathfinder::pass_class_t passClass = cmpPathfinder->GetPassabilityClass(className); 345 348 346 349 // Ignore collisions with self, or with non-foundation-blocking obstructions … … 348 351 349 352 if (m_Type == STATIC) 350 return cmp ObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, NULL);351 else 352 return cmp ObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Size0, NULL);353 return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass); 354 else 355 return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Size0, passClass); 353 356 } 354 357 -
ps/trunk/source/simulation2/components/CCmpPathfinder.cpp
r9666 r9970 30 30 #include "renderer/Scene.h" 31 31 #include "simulation2/MessageTypes.h" 32 #include "simulation2/components/ICmpObstruction.h" 32 33 #include "simulation2/components/ICmpObstructionManager.h" 33 34 #include "simulation2/components/ICmpWaterManager.h" … … 373 374 CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY); 374 375 376 // TOOD: these bits should come from ICmpTerrain 375 377 CTerrain& terrain = GetSimContext().GetTerrain(); 376 378 379 // avoid integer overflow in intermediate calculation 380 const u16 shoreMax = 32767; 381 382 // First pass - find underwater tiles 383 Grid<bool> waterGrid(m_MapSize, m_MapSize); 377 384 for (u16 j = 0; j < m_MapSize; ++j) 378 385 { … … 381 388 fixed x, z; 382 389 TileCenter(i, j, x, z); 390 391 bool underWater = !cmpWaterMan.null() && (cmpWaterMan->GetWaterLevel(x, z) > terrain.GetExactGroundLevelFixed(x, z)); 392 waterGrid.set(i, j, underWater); 393 } 394 } 395 // Second pass - find shore tiles 396 Grid<u16> shoreGrid(m_MapSize, m_MapSize); 397 for (u16 j = 0; j < m_MapSize; ++j) 398 { 399 for (u16 i = 0; i < m_MapSize; ++i) 400 { 401 // Find a land tile 402 if (!waterGrid.get(i, j) && ( 403 (i > 0 && waterGrid.get(i-1, j)) || (i > 0 && j < m_MapSize-1 && waterGrid.get(i-1, j+1)) || (i > 0 && j > 0 && waterGrid.get(i-1, j-1)) || 404 (i < m_MapSize-1 && waterGrid.get(i+1, j)) || (i < m_MapSize-1 && j < m_MapSize-1 && waterGrid.get(i+1, j+1)) || (i < m_MapSize-1 && j > 0 && waterGrid.get(i+1, j-1)) || 405 (j > 0 && waterGrid.get(i, j-1)) || (j < m_MapSize-1 && waterGrid.get(i, j+1)) 406 )) 407 { 408 shoreGrid.set(i, j, 0); 409 } 410 else 411 { 412 shoreGrid.set(i, j, shoreMax); 413 } 414 } 415 } 416 417 // Expand influences to find shore distance 418 for (size_t y = 0; y < m_MapSize; ++y) 419 { 420 u16 min = shoreMax; 421 for (size_t x = 0; x < m_MapSize; ++x) 422 { 423 u16 g = shoreGrid.get(x, y); 424 if (g > min) 425 shoreGrid.set(x, y, min); 426 else if (g < min) 427 min = g; 428 429 ++min; 430 } 431 for (size_t x = m_MapSize; x > 0; --x) 432 { 433 u16 g = shoreGrid.get(x-1, y); 434 if (g > min) 435 shoreGrid.set(x-1, y, min); 436 else if (g < min) 437 min = g; 438 439 ++min; 440 } 441 } 442 for (size_t x = 0; x < m_MapSize; ++x) 443 { 444 u16 min = shoreMax; 445 for (size_t y = 0; y < m_MapSize; ++y) 446 { 447 u16 g = shoreGrid.get(x, y); 448 if (g > min) 449 shoreGrid.set(x, y, min); 450 else if (g < min) 451 min = g; 452 453 ++min; 454 } 455 for (size_t y = m_MapSize; y > 0; --y) 456 { 457 u16 g = shoreGrid.get(x, y-1); 458 if (g > min) 459 shoreGrid.set(x, y-1, min); 460 else if (g < min) 461 min = g; 462 463 ++min; 464 } 465 } 466 467 // Apply passability classes to terrain 468 for (u16 j = 0; j < m_MapSize; ++j) 469 { 470 for (u16 i = 0; i < m_MapSize; ++i) 471 { 472 fixed x, z; 473 TileCenter(i, j, x, z); 383 474 384 475 TerrainTile t = 0; … … 386 477 u8 obstruct = m_ObstructionGrid->get(i, j); 387 478 388 fixed height = terrain.Get VertexGroundLevelFixed(i, j); // TODO: should use tile centre479 fixed height = terrain.GetExactGroundLevelFixed(x, z); 389 480 390 481 fixed water; … … 395 486 396 487 fixed slope = terrain.GetSlopeFixed(i, j); 488 489 fixed shoredist = fixed::FromInt(shoreGrid.get(i, j)); 397 490 398 491 if (obstruct & ICmpObstructionManager::TILE_OBSTRUCTED_PATHFINDING) … … 412 505 for (size_t n = 0; n < m_PassClasses.size(); ++n) 413 506 { 414 if (!m_PassClasses[n].IsPassable(depth, slope ))507 if (!m_PassClasses[n].IsPassable(depth, slope, shoredist)) 415 508 t |= m_PassClasses[n].m_Mask; 416 509 } … … 551 644 } 552 645 646 bool CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter, 647 entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass) 648 { 649 // Check unit obstruction 650 CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); 651 if (cmpObstructionManager.null()) 652 return false; 653 654 if (cmpObstructionManager->TestUnitShape(filter, x, z, r, NULL)) 655 return false; 656 657 // Test against terrain: 658 659 UpdateGrid(); 660 661 u16 i0, j0, i1, j1; 662 NearestTile(x - r, z - r, i0, j0); 663 NearestTile(x + r, z + r, i1, j1); 664 for (u16 j = j0; j <= j1; ++j) 665 { 666 for (u16 i = i0; i <= i1; ++i) 667 { 668 if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) 669 { 670 return false; 671 } 672 } 673 } 674 return true; 675 } 676 677 bool CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter, 678 entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, 679 entity_pos_t h, entity_id_t id, pass_class_t passClass) 680 { 681 // Check unit obstruction 682 CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); 683 if (cmpObstructionManager.null()) 684 return false; 685 686 if (cmpObstructionManager->TestStaticShape(filter, x, z, a, w, h, NULL)) 687 return false; 688 689 // Test against terrain: 690 691 UpdateGrid(); 692 693 CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), id); 694 if (cmpObstruction.null()) 695 return false; 696 697 ICmpObstructionManager::ObstructionSquare square; 698 if (!cmpObstruction->GetObstructionSquare(square)) 699 return false; 700 701 CFixedVector2D halfSize(square.hw, square.hh); 702 halfSize = halfSize * 1.41421f; 703 CFixedVector2D halfBound = Geometry::GetHalfBoundingBox(square.u, square.v, halfSize); 704 705 u16 i0, j0, i1, j1; 706 NearestTile(square.x - halfBound.X, square.z - halfBound.Y, i0, j0); 707 NearestTile(square.x + halfBound.X, square.z + halfBound.Y, i1, j1); 708 for (u16 j = j0; j <= j1; ++j) 709 { 710 for (u16 i = i0; i <= i1; ++i) 711 { 712 entity_pos_t x, z; 713 TileCenter(i, j, x, z); 714 if (Geometry::PointIsInSquare(CFixedVector2D(x - square.x, z - square.z), square.u, square.v, halfSize) 715 && !IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) 716 { 717 return false; 718 } 719 } 720 } 721 722 return true; 723 } -
ps/trunk/source/simulation2/components/CCmpPathfinder_Common.h
r9666 r9970 97 97 else 98 98 m_MaxSlope = std::numeric_limits<fixed>::max(); 99 } 100 101 bool IsPassable(fixed waterdepth, fixed steepness) 102 { 103 return ((m_MinDepth <= waterdepth && waterdepth <= m_MaxDepth) && (steepness < m_MaxSlope)); 99 100 if (node.GetChild("MinShoreDistance").IsOk()) 101 m_MinShore = node.GetChild("MinShoreDistance").ToFixed(); 102 else 103 m_MinShore = std::numeric_limits<fixed>::min(); 104 105 if (node.GetChild("MaxShoreDistance").IsOk()) 106 m_MaxShore = node.GetChild("MaxShoreDistance").ToFixed(); 107 else 108 m_MaxShore = std::numeric_limits<fixed>::max(); 109 110 } 111 112 bool IsPassable(fixed waterdepth, fixed steepness, fixed shoredist) 113 { 114 return ((m_MinDepth <= waterdepth && waterdepth <= m_MaxDepth) && (steepness < m_MaxSlope) && (m_MinShore <= shoredist && shoredist <= m_MaxShore)); 104 115 } 105 116 … … 109 120 fixed m_MaxDepth; 110 121 fixed m_MaxSlope; 122 fixed m_MinShore; 123 fixed m_MaxShore; 111 124 }; 112 125 … … 248 261 virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass); 249 262 263 virtual bool CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass); 264 265 virtual bool CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass); 266 250 267 virtual void FinishAsyncRequests(); 251 268 -
ps/trunk/source/simulation2/components/CCmpTemplateManager.cpp
r9550 r9970 454 454 permittedComponentTypes.insert("Obstruction"); 455 455 permittedComponentTypes.insert("Decay"); 456 permittedComponentTypes.insert("BuildRestrictions"); 456 457 457 458 // Need these for the Actor Viewer: -
ps/trunk/source/simulation2/components/CCmpTerritoryManager.cpp
r9960 r9970 167 167 return *m_Territories; 168 168 } 169 170 virtual int32_t GetOwner(entity_pos_t x, entity_pos_t z); 169 171 170 172 // To support lazy updates of territory render data, … … 684 686 } 685 687 688 int32_t CCmpTerritoryManager::GetOwner(entity_pos_t x, entity_pos_t z) 689 { 690 u16 i, j; 691 CalculateTerritories(); 692 NearestTile(x, z, i, j, m_Territories->m_W, m_Territories->m_H); 693 return m_Territories->get(i, j); 694 } 686 695 687 696 void TerritoryOverlay::StartRender() -
ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp
r9713 r9970 21 21 #include "ICmpUnitMotion.h" 22 22 23 #include "ICmpObstruction.h" 24 #include "ICmpObstructionManager.h" 25 #include "ICmpOwnership.h" 26 #include "ICmpPosition.h" 27 #include "ICmpPathfinder.h" 28 #include "ICmpRangeManager.h" 29 #include "simulation2/MessageTypes.h" 23 #include "simulation2/components/ICmpObstruction.h" 24 #include "simulation2/components/ICmpObstructionManager.h" 25 #include "simulation2/components/ICmpOwnership.h" 26 #include "simulation2/components/ICmpPosition.h" 27 #include "simulation2/components/ICmpPathfinder.h" 28 #include "simulation2/components/ICmpRangeManager.h" 30 29 #include "simulation2/helpers/Geometry.h" 31 30 #include "simulation2/helpers/Render.h" 31 #include "simulation2/MessageTypes.h" 32 32 #include "simulation2/serialization/SerializeTemplates.h" 33 33 … … 123 123 fixed m_WalkSpeed; // in metres per second 124 124 fixed m_RunSpeed; 125 u8m_PassClass;126 u8m_CostClass;125 ICmpPathfinder::pass_class_t m_PassClass; 126 ICmpPathfinder::cost_class_t m_CostClass; 127 127 128 128 // Dynamic state: … … 401 401 } 402 402 403 virtual ICmpPathfinder::pass_class_t GetPassabilityClass() 404 { 405 return m_PassClass; 406 } 407 403 408 virtual void SetSpeed(fixed speed) 404 409 { -
ps/trunk/source/simulation2/components/ICmpObstruction.cpp
r9510 r9970 24 24 BEGIN_INTERFACE_WRAPPER(Obstruction) 25 25 DEFINE_INTERFACE_METHOD_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUnitRadius) 26 DEFINE_INTERFACE_METHOD_ 0("CheckFoundationCollisions", bool, ICmpObstruction, CheckFoundationCollisions)26 DEFINE_INTERFACE_METHOD_1("CheckFoundation", bool, ICmpObstruction, CheckFoundation, std::string) 27 27 DEFINE_INTERFACE_METHOD_0("GetConstructionCollisions", std::vector<entity_id_t>, ICmpObstruction, GetConstructionCollisions) 28 28 DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool) -
ps/trunk/source/simulation2/components/ICmpObstruction.h
r9889 r9970 45 45 * Test whether this entity is colliding with any obstruction that are set to 46 46 * block the creation of foundations. 47 * @return true if there is a collision47 * @return true if foundation is valid (not obstructed) 48 48 */ 49 virtual bool CheckFoundation Collisions() = 0;49 virtual bool CheckFoundation(std::string className) = 0; 50 50 51 51 /** 52 52 * Returns a list of entities that are colliding with this entity, and that 53 53 * are set to block construction. 54 * @return true if there is a collision54 * @return vector of blocking entities 55 55 */ 56 56 virtual std::vector<entity_id_t> GetConstructionCollisions() = 0; -
ps/trunk/source/simulation2/components/ICmpPathfinder.h
r9665 r9970 151 151 152 152 /** 153 * Check whether a unit placed here is valid and doesn't hit any obstructions 154 * or impassable terrain. 155 * Returns true if the placement is okay. 156 */ 157 virtual bool CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass) = 0; 158 159 /** 160 * Check whether a building placed here is valid and doesn't hit any obstructions 161 * or impassable terrain. 162 * Returns true if the placement is okay. 163 */ 164 virtual bool CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass) = 0; 165 166 /** 153 167 * Toggle the storage and rendering of debug info. 154 168 */ -
ps/trunk/source/simulation2/components/ICmpTerritoryManager.cpp
r9889 r9970 23 23 24 24 BEGIN_INTERFACE_WRAPPER(TerritoryManager) 25 DEFINE_INTERFACE_METHOD_2("GetOwner", int32_t, ICmpTerritoryManager, GetOwner, entity_pos_t, entity_pos_t) 25 26 END_INTERFACE_WRAPPER(TerritoryManager) -
ps/trunk/source/simulation2/components/ICmpTerritoryManager.h
r9889 r9970 19 19 #define INCLUDED_ICMPTERRITORYMANAGER 20 20 21 #include "simulation2/helpers/Grid.h" 21 22 #include "simulation2/system/Interface.h" 22 23 #include "simulation2/helpers/Grid.h" 23 #include "simulation2/components/ICmpPosition.h" 24 24 25 25 class ICmpTerritoryManager : public IComponent … … 30 30 virtual const Grid<u8>& GetTerritoryGrid() = 0; 31 31 32 /** 33 * Get owner of territory at given position 34 * 35 * @return player ID of owner; 0 if neutral territory 36 */ 37 virtual int32_t GetOwner(entity_pos_t x, entity_pos_t z) = 0; 38 32 39 DECLARE_INTERFACE_TYPE(TerritoryManager) 33 40 }; -
ps/trunk/source/simulation2/components/ICmpUnitMotion.cpp
r9605 r9970 87 87 } 88 88 89 virtual ICmpPathfinder::pass_class_t GetPassabilityClass() 90 { 91 return m_Script.Call<ICmpPathfinder::pass_class_t>("GetPassabilityClass"); 92 } 93 89 94 virtual void SetUnitRadius(fixed radius) 90 95 { -
ps/trunk/source/simulation2/components/ICmpUnitMotion.h
r9605 r9970 1 /* Copyright (C) 201 0Wildfire Games.1 /* Copyright (C) 2011 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * … … 21 21 #include "simulation2/system/Interface.h" 22 22 23 #include "ICmpPosition.h" // for entity_pos_t 23 #include "simulation2/components/ICmpPathfinder.h" // for pass_class_t 24 #include "simulation2/components/ICmpPosition.h" // for entity_pos_t 24 25 25 26 /** … … 94 95 95 96 /** 97 * Get the unit's passability class. 98 */ 99 virtual ICmpPathfinder::pass_class_t GetPassabilityClass() = 0; 100 101 /** 96 102 * Override the default obstruction radius, used for planning paths and checking for collisions. 97 103 * Bad things may happen if this entity has an active Obstruction component with a larger
Note:
See TracChangeset
for help on using the changeset viewer.
