Ticket #804: dockbuildifx-07232011.patch
File dockbuildifx-07232011.patch, 31.1 KB (added by , 13 years ago) |
---|
-
binaries/data/mods/public/gui/session/input.js
80 80 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, 86 86 "z": placementPosition.z, 87 87 "angle": placementAngle 88 88 }); 89 89 } 90 91 return false; 90 92 } 91 93 92 94 function resetPlacementEntity() … … 328 330 var selection = g_Selection.toList(); 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 340 336 // TODO: play a sound? … … 561 557 placementAngle = defaultPlacementAngle; 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 573 571 case "mousebuttonup": … … 821 819 { 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 832 833 … … 855 856 { 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 } 875 866 -
binaries/data/mods/public/simulation/components/BuildRestrictions.js
5 5 "<choice>" + 6 6 "<value>standard</value>" + 7 7 "<value>settlement</value>" + 8 "</choice>" + // TODO: add special types for fields, docks, walls 8 "<value>shore</value>" + 9 "</choice>" + // TODO: add special types for fields, walls 9 10 "</element>" + 10 11 "<element name='Territory'>" + 11 12 "<choice>" + … … 48 49 * docks must be on shores), which affects the UI and the build permissions 49 50 */ 50 51 52 BuildRestrictions.prototype.Init = function() 53 { 54 }; 55 51 56 BuildRestrictions.prototype.OnOwnershipChanged = function(msg) 52 57 { 53 58 if (this.template.Category) … … 66 71 } 67 72 }; 68 73 74 BuildRestrictions.prototype.CheckPlacement = function() 75 { 76 // First check obstructions and terrain passability 77 var passClassName = ""; 78 switch(this.template.PlacementType) 79 { 80 case "shore": 81 passClassName = "building-shore" 82 break; 83 84 case "standard": 85 case "settlement": 86 passClassName = "building-land" 87 break; 88 89 default: 90 error("Unknown placement type: "+this.template.PlacementType); 91 } 92 93 var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 94 if (!cmpObstruction || !cmpObstruction.IsValidFoundation(passClassName)) 95 { 96 return false; // Fail 97 } 98 99 // Check special requirements 100 if (this.template.Category == "Dock") 101 { 102 // Dock must be oriented from land facing into water 103 var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint); 104 if (!cmpFootprint) 105 return false; // Fail 106 107 var shape = cmpFootprint.GetShape(); 108 109 // Get building's footprint 110 var halfX = 0; 111 var halfZ = 0; 112 if (shape.type == "square") 113 { 114 halfX = shape.width/2; 115 halfZ = shape.depth/2; 116 } 117 else if (shape.type == "circle") 118 { // Approximate as square? 119 halfX = shape.radius; 120 halfZ = shape.radius; 121 } 122 123 var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 124 var cmpWaterMgr = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); 125 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 126 127 if (!cmpTerrain || !cmpPosition || !cmpWaterMgr) 128 return false; // Fail 129 130 var pos = cmpPosition.GetPosition(); 131 var ang = cmpPosition.GetRotation().y; 132 var s = Math.sin(ang); 133 var c = Math.cos(ang); 134 if ((cmpTerrain.GetGroundLevel(pos.x + s*halfX, pos.z + c*halfZ) 135 > cmpWaterMgr.GetWaterLevel(pos.x + s*halfX, pos.z + c*halfZ)) || // front 136 (cmpTerrain.GetGroundLevel(pos.x - s*halfX, pos.z - c*halfZ) 137 <= cmpWaterMgr.GetWaterLevel(pos.x - s*halfX, pos.z - c*halfZ)) // back 138 ) 139 return false; // Fail 140 } 141 142 // Success 143 return true; 144 }; 145 69 146 BuildRestrictions.prototype.GetCategory = function() 70 147 { 71 148 return this.template.Category; -
binaries/data/mods/public/simulation/components/GarrisonHolder.js
155 155 // For now, just move the unit into the middle of the building where it'll probably get stuck 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 161 165 var cmpNewPosition = Engine.QueryInterface(entity, IID_Position); -
binaries/data/mods/public/simulation/components/GuiInterface.js
468 468 pos.SetYRotation(cmd.angle); 469 469 } 470 470 471 // Check whether it's obstructed by other entities 472 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction); 473 var colliding = (cmpObstruction && cmpObstruction.CheckFoundationCollisions()); 471 // Check whether it's obstructed by other entities or invalid terrain 472 var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); 473 if (!cmpBuildRestrictions) 474 error("cmpBuildRestrictions null"); 475 var placementValid = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement()); 474 476 475 477 // Check whether it's in a visible region 476 478 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 477 var visible = (cmpRangeManager .GetLosVisibility(ent, player) == "visible");479 var visible = (cmpRangeManager && cmpRangeManager.GetLosVisibility(ent, player) == "visible"); 478 480 479 var ok = ( !colliding&& visible);481 var ok = (placementValid && visible); 480 482 481 483 // Set it to a red shade if this is an invalid location 482 484 var cmpVisual = Engine.QueryInterface(ent, IID_Visual); … … 494 496 return false; 495 497 }; 496 498 499 GuiInterface.prototype.GetFoundationSnapData = function(player, data) 500 { 501 var cmpTemplateMgr = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 502 var template = cmpTemplateMgr.GetTemplate(data.template); 503 504 if (template.BuildRestrictions.Category == "Dock") 505 { 506 // Autorotate to shore 507 var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 508 var norm = cmpTerrain.CalcNormal(data.x, data.z); 509 510 if (norm.y != 1.0) 511 { 512 return { "snapped": true, "x": data.x, "z": data.z, "angle": Math.atan2(norm.x, norm.z) }; 513 } 514 } 515 516 return {"snapped": false}; 517 }; 518 497 519 GuiInterface.prototype.PlaySound = function(player, data) 498 520 { 499 521 // Ignore if no entity was passed … … 583 605 "SetStatusBars": 1, 584 606 "DisplayRallyPoint": 1, 585 607 "SetBuildingPlacementPreview": 1, 608 "GetFoundationSnapData": 1, 586 609 "PlaySound": 1, 587 610 "FindIdleUnit": 1, 588 611 -
binaries/data/mods/public/simulation/components/TrainingQueue.js
217 217 // What should we do here? 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 223 227 var cmpNewPosition = Engine.QueryInterface(ent, IID_Position); -
binaries/data/mods/public/simulation/data/pathfinder.xml
14 14 <ship> 15 15 <MinWaterDepth>1</MinWaterDepth> 16 16 </ship> 17 <!-- Building construction classes: --> 17 <!-- Building construction classes: 18 * Land is used for most buildings, which must be away 19 from water and not on cliffs or mountains. 20 * Shore is used for docks, which must be near water and 21 land, yet shallow enough for builders to approach. 22 --> 18 23 <building-land> 19 24 <MaxWaterDepth>0</MaxWaterDepth> 25 <MinShoreDistance>2.0</MinShoreDistance> 20 26 <MaxTerrainSlope>1.0</MaxTerrainSlope> 21 27 </building-land> 28 <building-shore> 29 <MaxShoreDistance>4.0</MaxShoreDistance> 30 <MaxTerrainSlope>1.0</MaxTerrainSlope> 31 </building-shore> 22 32 23 33 </PassabilityClasses> 24 34 -
binaries/data/mods/public/simulation/helpers/Commands.js
131 131 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 137 142 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 138 143 cmpPosition.JumpTo(cmd.x, cmd.z); 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())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()) 144 149 { 145 // TODO: report error to player (the building site was obstructed)146 print("Building site was obstructed\n");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); -
binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
7 7 <Icon>structures/dock.png</Icon> 8 8 </Identity> 9 9 <BuildRestrictions> 10 <PlacementType>shore</PlacementType> 10 11 <Category>Dock</Category> 11 12 </BuildRestrictions> 12 13 <Cost> -
source/simulation2/components/CCmpFootprint.cpp
22 22 23 23 #include "ICmpObstruction.h" 24 24 #include "ICmpObstructionManager.h" 25 #include "ICmpPathfinder.h" 25 26 #include "ICmpPosition.h" 27 #include "ICmpUnitMotion.h" 26 28 #include "simulation2/MessageTypes.h" 27 29 #include "maths/FixedVector2D.h" 28 30 … … 146 148 } 147 149 // else use zero radius 148 150 151 // Get passability class from UnitMotion 152 CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), spawned); 153 if (cmpUnitMotion.null()) 154 return error; 155 156 u16 spawnedPass = cmpUnitMotion->GetPassabilityClass(); 157 CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY); 158 if (cmpPathfinder.null()) 159 return error; 160 149 161 // The spawn point should be far enough from this footprint to fit the unit, plus a little gap 150 162 entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2); 151 163 … … 168 180 CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Y + c.Multiply(radius)); 169 181 170 182 SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity 171 if ( !cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Z, spawnedRadius, NULL))183 if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, spawnedPass)) 172 184 return pos; // this position is okay, so return it 173 185 } 174 186 } … … 177 189 fixed s, c; 178 190 sincos_approx(initialAngle, s, c); 179 191 180 for (size_t edge = 0; edge < 4; ++edge) 192 // Expand outwards to a max of 4 tiles from foundation 193 for (size_t dist = 0; dist <= 4; ++dist) 181 194 { 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) 195 for (size_t edge = 0; edge < 4; ++edge) 189 196 { 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)); 197 // Try equally-spaced points along the edge in alternating directions, starting from the middle 198 const ssize_t numPoints = 9 + 2*dist; 213 199 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); 200 // Compute the direction and length of the current edge 201 CFixedVector2D dir; 202 fixed sx, sy; 203 switch (edge) 204 { 205 case 0: 206 dir = CFixedVector2D(c, -s); 207 sx = m_Size0; 208 sy = m_Size1; 209 break; 210 case 1: 211 dir = CFixedVector2D(-s, -c); 212 sx = m_Size1; 213 sy = m_Size0; 214 break; 215 case 2: 216 dir = CFixedVector2D(s, c); 217 sx = m_Size1; 218 sy = m_Size0; 219 break; 220 case 3: 221 dir = CFixedVector2D(-c, s); 222 sx = m_Size0; 223 sy = m_Size1; 224 break; 225 } 226 dir.Normalize(fixed::FromFloat(1.0f + 0.25f*(float)dist)); 227 CFixedVector2D center = initialPos - dir.Perpendicular().Multiply(sy/2 + clearance); 228 dir = dir.Multiply((sx + clearance*2) / (int)(numPoints-1)); 217 229 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 230 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] 231 { 232 CFixedVector2D pos (center + dir*i); 233 234 SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity 235 if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass)) 236 return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it 237 } 221 238 } 222 239 } 223 240 } -
source/simulation2/components/CCmpObstruction.cpp
328 328 return entity_pos_t::Zero(); 329 329 } 330 330 331 virtual bool CheckFoundationCollisions()331 virtual bool IsValidFoundation(std::string className) 332 332 { 333 333 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); 334 334 if (cmpPosition.null()) … … 339 339 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 345 346 // Get passability class 347 u16 passClass = cmpPathfinder->GetPassabilityClass(className); 348 346 349 // Ignore collisions with self, or with non-foundation-blocking obstructions 347 350 SkipTagFlagsObstructionFilter filter(m_Tag, ICmpObstructionManager::FLAG_BLOCK_FOUNDATION); 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);353 return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, passClass); 351 354 else 352 return cmp ObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Size0, NULL);355 return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Size0, passClass); 353 356 } 354 357 355 358 virtual std::vector<entity_id_t> GetConstructionCollisions() -
source/simulation2/components/CCmpPathfinder.cpp
374 374 375 375 CTerrain& terrain = GetSimContext().GetTerrain(); 376 376 377 // Compute influence map for shore distance 378 Grid<u16> shoreGrid(m_MapSize, m_MapSize); 377 379 for (u16 j = 0; j < m_MapSize; ++j) 378 380 { 379 381 for (u16 i = 0; i < m_MapSize; ++i) 380 382 { 381 383 fixed x, z; 382 384 TileCenter(i, j, x, z); 385 386 fixed height = terrain.GetExactGroundLevelFixed(x, z); 387 fixed water; 388 if (!cmpWaterMan.null()) 389 water = cmpWaterMan->GetWaterLevel(x, z); 390 fixed depth = water - height; 383 391 392 if (depth > fixed::Zero() && depth < fixed::FromFloat(1.f)) 393 { // Shore (allowing for precision error) 394 shoreGrid.set(i, j, 0); 395 } 396 else 397 { 398 shoreGrid.set(i, j, 32767); 399 } 400 } 401 } 402 403 // Expand influences 404 for (size_t y = 0; y < m_MapSize; ++y) 405 { 406 u16 min = 32767; 407 for (size_t x = 0; x < m_MapSize; ++x) 408 { 409 u16 g = shoreGrid.get(x, y); 410 if (g > min) 411 shoreGrid.set(x, y, min); 412 else if (g < min) 413 min = g; 414 415 ++min; 416 } 417 for (size_t x = m_MapSize; x > 0; --x) 418 { 419 u16 g = shoreGrid.get(x-1, y); 420 if (g > min) 421 shoreGrid.set(x-1, y, min); 422 else if (g < min) 423 min = g; 424 425 ++min; 426 } 427 } 428 for (size_t x = 0; x < m_MapSize; ++x) 429 { 430 u16 min = 32767; 431 for (size_t y = 0; y < m_MapSize; ++y) 432 { 433 u16 g = shoreGrid.get(x, y); 434 if (g > min) 435 shoreGrid.set(x, y, min); 436 else if (g < min) 437 min = g; 438 439 ++min; 440 } 441 for (size_t y = m_MapSize; y > 0; --y) 442 { 443 u16 g = shoreGrid.get(x, y-1); 444 if (g > min) 445 shoreGrid.set(x, y-1, min); 446 else if (g < min) 447 min = g; 448 449 ++min; 450 } 451 } 452 453 for (u16 j = 0; j < m_MapSize; ++j) 454 { 455 for (u16 i = 0; i < m_MapSize; ++i) 456 { 457 fixed x, z; 458 TileCenter(i, j, x, z); 459 384 460 TerrainTile t = 0; 385 461 386 462 u8 obstruct = m_ObstructionGrid->get(i, j); 387 463 388 fixed height = terrain.Get VertexGroundLevelFixed(i, j); // TODO: should use tile centre464 fixed height = terrain.GetExactGroundLevelFixed(x, z); 389 465 390 466 fixed water; 391 467 if (!cmpWaterMan.null()) … … 395 471 396 472 fixed slope = terrain.GetSlopeFixed(i, j); 397 473 474 fixed shoredist = fixed::FromInt(shoreGrid.get(i, j)); 475 398 476 if (obstruct & ICmpObstructionManager::TILE_OBSTRUCTED_PATHFINDING) 399 477 t |= 1; 400 478 … … 411 489 { 412 490 for (size_t n = 0; n < m_PassClasses.size(); ++n) 413 491 { 414 if (!m_PassClasses[n].IsPassable(depth, slope ))492 if (!m_PassClasses[n].IsPassable(depth, slope, shoredist)) 415 493 t |= m_PassClasses[n].m_Mask; 416 494 } 417 495 } -
source/simulation2/components/CCmpPathfinder_Common.h
96 96 m_MaxSlope = node.GetChild("MaxTerrainSlope").ToFixed(); 97 97 else 98 98 m_MaxSlope = std::numeric_limits<fixed>::max(); 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 99 110 } 100 111 101 bool IsPassable(fixed waterdepth, fixed steepness )112 bool IsPassable(fixed waterdepth, fixed steepness, fixed shoredist) 102 113 { 103 return ((m_MinDepth <= waterdepth && waterdepth <= m_MaxDepth) && (steepness < m_MaxSlope) );114 return ((m_MinDepth <= waterdepth && waterdepth <= m_MaxDepth) && (steepness < m_MaxSlope) && (m_MinShore <= shoredist && shoredist <= m_MaxShore)); 104 115 } 105 116 106 117 ICmpPathfinder::pass_class_t m_Mask; … … 108 119 fixed m_MinDepth; 109 120 fixed m_MaxDepth; 110 121 fixed m_MaxSlope; 122 fixed m_MinShore; 123 fixed m_MaxShore; 111 124 }; 112 125 113 126 typedef u16 TerrainTile; … … 247 260 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, pass_class_t passClass); 266 250 267 virtual void FinishAsyncRequests(); 251 268 252 269 void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests); -
source/simulation2/components/CCmpPathfinder_Vertex.cpp
892 892 893 893 return visible; 894 894 } 895 896 bool CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter, 897 entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass) 898 { 899 // Check unit obstruction 900 CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); 901 if (cmpObstructionManager.null()) 902 return false; 903 904 if (cmpObstructionManager->TestUnitShape(filter, x, z, r, NULL)) 905 return false; 906 907 // Test against terrain: 908 909 UpdateGrid(); 910 911 // TODO: Probably a better way to test this 912 u16 i0, j0, i1, j1; 913 NearestTile(x - r, z - r, i0, j0); 914 NearestTile(x + r, z + r, i1, j1); 915 for (u16 i = i0; i <= i1; ++i) 916 { 917 for (u16 j = j0; j <= j1; ++j) 918 { 919 if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) 920 { 921 return false; 922 } 923 } 924 } 925 return true; 926 } 927 928 bool CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter, 929 entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, 930 entity_pos_t h, pass_class_t passClass) 931 { 932 // Check unit obstruction 933 CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); 934 if (cmpObstructionManager.null()) 935 return false; 936 937 if (cmpObstructionManager->TestStaticShape(filter, x, z, a, w, h, NULL)) 938 return false; 939 940 // Test against terrain: 941 942 UpdateGrid(); 943 944 // TODO: Probably a better way to test this 945 u16 i0, j0, i1, j1; 946 NearestTile(x - w/2, z - h/2, i0, j0); 947 NearestTile(x + w/2, z + h/2, i1, j1); 948 for (u16 i = i0; i <= i1; ++i) 949 { 950 for (u16 j = j0; j <= j1; ++j) 951 { 952 if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) 953 { 954 return false; 955 } 956 } 957 } 958 return true; 959 } -
source/simulation2/components/CCmpTemplateManager.cpp
453 453 permittedComponentTypes.insert("Footprint"); 454 454 permittedComponentTypes.insert("Obstruction"); 455 455 permittedComponentTypes.insert("Decay"); 456 permittedComponentTypes.insert("BuildRestrictions"); 456 457 457 458 // Need these for the Actor Viewer: 458 459 permittedComponentTypes.insert("Attack"); -
source/simulation2/components/CCmpUnitMotion.cpp
400 400 return m_RunSpeed; 401 401 } 402 402 403 virtual u16 GetPassabilityClass() 404 { 405 return m_PassClass; 406 } 407 403 408 virtual void SetSpeed(fixed speed) 404 409 { 405 410 m_Speed = speed; -
source/simulation2/components/ICmpObstruction.cpp
23 23 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("IsValidFoundation", bool, ICmpObstruction, IsValidFoundation, 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) 29 29 DEFINE_INTERFACE_METHOD_1("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, bool) -
source/simulation2/components/ICmpObstruction.h
44 44 /** 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 CheckFoundationCollisions() = 0;49 virtual bool IsValidFoundation(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; 57 57 -
source/simulation2/components/ICmpPathfinder.h
150 150 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) = 0; 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, pass_class_t passClass) = 0; 165 166 /** 153 167 * Toggle the storage and rendering of debug info. 154 168 */ 155 169 virtual void SetDebugOverlay(bool enabled) = 0; -
source/simulation2/components/ICmpUnitMotion.cpp
86 86 return m_Script.Call<fixed>("GetRunSpeed"); 87 87 } 88 88 89 virtual u16 GetPassabilityClass() 90 { 91 return m_Script.Call<u16>("GetPassabilityClass"); 92 } 93 89 94 virtual void SetUnitRadius(fixed radius) 90 95 { 91 96 m_Script.CallVoid("SetUnitRadius", radius); -
source/simulation2/components/ICmpUnitMotion.h
93 93 virtual fixed GetRunSpeed() = 0; 94 94 95 95 /** 96 * Get the unit's passability class. 97 */ 98 virtual u16 GetPassabilityClass() = 0; 99 100 /** 96 101 * Override the default obstruction radius, used for planning paths and checking for collisions. 97 102 * Bad things may happen if this entity has an active Obstruction component with a larger 98 103 * radius. (This is intended primarily for formation controllers.)