Ticket #3174: lighthouse.patch
File lighthouse.patch, 17.6 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/simulation/templates/structures/ptol_lighthouse.xml
17 17 <GenericName>Lighthouse</GenericName> 18 18 <SpecificName>Pharos</SpecificName> 19 19 <Classes datatype="tokens">Lighthouse Town -City</Classes> 20 <Tooltip>Build along the shore to reveal the shorelines over the entire map (Not implemented). Very large vision range: 180 meters.</Tooltip>20 <Tooltip>Build along the shore to reveal the shorelines over the entire map. Very large vision range: 180 meters.</Tooltip> 21 21 <History>The Ptolemaic dynasty in Egypt built the magnificent Lighthouse of Alexandria near the harbor mouth of that Nile Delta city. This structure could be seen for many kilometers out to sea and was one of the Seven Wonders of the World.</History> 22 22 <Icon>structures/lighthouse.png</Icon> 23 23 <RequiredTechnology>phase_town</RequiredTechnology> … … 41 41 </TerritoryInfluence> 42 42 <Vision> 43 43 <Range>180</Range> 44 <RevealShore>true</RevealShore> 44 45 </Vision> 45 46 <VisualActor> 46 47 <Actor>structures/ptolemies/lighthouse.xml</Actor> -
source/ps/TemplateLoader.cpp
512 512 // Foundations should be visible themselves in fog-of-war if their base template is, 513 513 // but shouldn't have any vision range 514 514 if (out.GetChild("Entity").GetChild("Vision").IsOk()) 515 { 515 516 CParamNode::LoadXMLString(out, "<Entity><Vision><Range>0</Range></Vision></Entity>"); 517 // Foundations should not have special vision capabilities either 518 if (out.GetChild("Entity").GetChild("Vision").GetChild("RevealShore").IsOk()) 519 CParamNode::LoadXMLString(out, "<Entity><Vision><RevealShore>false</RevealShore></Vision></Entity>"); 520 } 516 521 } 517 522 518 523 void CTemplateLoader::CopyConstructionSubset(CParamNode& out, const CParamNode& in) -
source/simulation2/components/CCmpPathfinder.cpp
306 306 return *m_Grid; 307 307 } 308 308 309 Grid<u16> CCmpPathfinder::ComputeShoreGrid(bool expandOnWater) 310 { 311 PROFILE3("ComputeShoreGrid"); 312 313 CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity()); 314 315 // TODO: these bits should come from ICmpTerrain 316 CTerrain& terrain = GetSimContext().GetTerrain(); 317 318 // avoid integer overflow in intermediate calculation 319 const u16 shoreMax = 32767; 320 321 // First pass - find underwater tiles 322 Grid<bool> waterGrid(m_MapSize, m_MapSize); 323 for (u16 j = 0; j < m_MapSize; ++j) 324 { 325 for (u16 i = 0; i < m_MapSize; ++i) 326 { 327 fixed x, z; 328 TileCenter(i, j, x, z); 329 330 bool underWater = cmpWaterManager && (cmpWaterManager->GetWaterLevel(x, z) > terrain.GetExactGroundLevelFixed(x, z)); 331 waterGrid.set(i, j, underWater); 332 } 333 } 334 335 // Second pass - find shore tiles 336 Grid<u16> shoreGrid(m_MapSize, m_MapSize); 337 for (u16 j = 0; j < m_MapSize; ++j) 338 { 339 for (u16 i = 0; i < m_MapSize; ++i) 340 { 341 // Find a land tile 342 if (!waterGrid.get(i, j)) 343 { 344 // If it's bordered by water, it's a shore tile 345 if ((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)) 346 || (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)) 347 || (j > 0 && waterGrid.get(i, j-1)) || (j < m_MapSize-1 && waterGrid.get(i, j+1)) 348 ) 349 shoreGrid.set(i, j, 0); 350 else 351 shoreGrid.set(i, j, shoreMax); 352 } 353 // If we want to expand on water, we want water tiles not to be shore tiles 354 else if (expandOnWater) 355 shoreGrid.set(i, j, shoreMax); 356 } 357 } 358 359 // Expand influences to find shore distance 360 for (u16 y = 0; y < m_MapSize; ++y) 361 { 362 u16 min = shoreMax; 363 for (u16 x = 0; x < m_MapSize; ++x) 364 { 365 if (!waterGrid.get(x, y) || expandOnWater) 366 { 367 u16 g = shoreGrid.get(x, y); 368 if (g > min) 369 shoreGrid.set(x, y, min); 370 else if (g < min) 371 min = g; 372 373 ++min; 374 } 375 } 376 for (u16 x = m_MapSize; x > 0; --x) 377 { 378 if (!waterGrid.get(x-1, y) || expandOnWater) 379 { 380 u16 g = shoreGrid.get(x - 1, y); 381 if (g > min) 382 shoreGrid.set(x - 1, y, min); 383 else if (g < min) 384 min = g; 385 386 ++min; 387 } 388 } 389 } 390 for (u16 x = 0; x < m_MapSize; ++x) 391 { 392 u16 min = shoreMax; 393 for (u16 y = 0; y < m_MapSize; ++y) 394 { 395 if (!waterGrid.get(x, y) || expandOnWater) 396 { 397 u16 g = shoreGrid.get(x, y); 398 if (g > min) 399 shoreGrid.set(x, y, min); 400 else if (g < min) 401 min = g; 402 403 ++min; 404 } 405 } 406 for (u16 y = m_MapSize; y > 0; --y) 407 { 408 if (!waterGrid.get(x, y-1) || expandOnWater) 409 { 410 u16 g = shoreGrid.get(x, y - 1); 411 if (g > min) 412 shoreGrid.set(x, y - 1, min); 413 else if (g < min) 414 min = g; 415 416 ++min; 417 } 418 } 419 } 420 421 return shoreGrid; 422 } 423 309 424 void CCmpPathfinder::UpdateGrid() 310 425 { 311 426 CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); … … 369 484 // Obstructions or terrain changed - we need to recompute passability 370 485 // TODO: only bother recomputing the region that has actually changed 371 486 487 Grid<u16> shoreGrid = ComputeShoreGrid(); 488 372 489 CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity()); 373 374 // TOOD: these bits should come from ICmpTerrain375 490 CTerrain& terrain = GetSimContext().GetTerrain(); 376 491 377 // avoid integer overflow in intermediate calculation378 const u16 shoreMax = 32767;379 380 // First pass - find underwater tiles381 Grid<bool> waterGrid(m_MapSize, m_MapSize);382 for (u16 j = 0; j < m_MapSize; ++j)383 {384 for (u16 i = 0; i < m_MapSize; ++i)385 {386 fixed x, z;387 TileCenter(i, j, x, z);388 389 bool underWater = cmpWaterManager && (cmpWaterManager->GetWaterLevel(x, z) > terrain.GetExactGroundLevelFixed(x, z));390 waterGrid.set(i, j, underWater);391 }392 }393 // Second pass - find shore tiles394 Grid<u16> shoreGrid(m_MapSize, m_MapSize);395 for (u16 j = 0; j < m_MapSize; ++j)396 {397 for (u16 i = 0; i < m_MapSize; ++i)398 {399 // Find a land tile400 if (!waterGrid.get(i, j))401 {402 if ((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))403 || (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))404 || (j > 0 && waterGrid.get(i, j-1)) || (j < m_MapSize-1 && waterGrid.get(i, j+1))405 )406 { // If it's bordered by water, it's a shore tile407 shoreGrid.set(i, j, 0);408 }409 else410 {411 shoreGrid.set(i, j, shoreMax);412 }413 }414 }415 }416 417 // Expand influences on land to find shore distance418 for (u16 y = 0; y < m_MapSize; ++y)419 {420 u16 min = shoreMax;421 for (u16 x = 0; x < m_MapSize; ++x)422 {423 if (!waterGrid.get(x, y))424 {425 u16 g = shoreGrid.get(x, y);426 if (g > min)427 shoreGrid.set(x, y, min);428 else if (g < min)429 min = g;430 431 ++min;432 }433 }434 for (u16 x = m_MapSize; x > 0; --x)435 {436 if (!waterGrid.get(x-1, y))437 {438 u16 g = shoreGrid.get(x-1, y);439 if (g > min)440 shoreGrid.set(x-1, y, min);441 else if (g < min)442 min = g;443 444 ++min;445 }446 }447 }448 for (u16 x = 0; x < m_MapSize; ++x)449 {450 u16 min = shoreMax;451 for (u16 y = 0; y < m_MapSize; ++y)452 {453 if (!waterGrid.get(x, y))454 {455 u16 g = shoreGrid.get(x, y);456 if (g > min)457 shoreGrid.set(x, y, min);458 else if (g < min)459 min = g;460 461 ++min;462 }463 }464 for (u16 y = m_MapSize; y > 0; --y)465 {466 if (!waterGrid.get(x, y-1))467 {468 u16 g = shoreGrid.get(x, y-1);469 if (g > min)470 shoreGrid.set(x, y-1, min);471 else if (g < min)472 min = g;473 474 ++min;475 }476 }477 }478 479 492 // Apply passability classes to terrain 480 493 for (u16 j = 0; j < m_MapSize; ++j) 481 494 { -
source/simulation2/components/CCmpPathfinder_Common.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 242 242 243 243 virtual const Grid<u16>& GetPassabilityGrid(); 244 244 245 virtual Grid<u16> ComputeShoreGrid(bool expandOnWater = false); 246 245 247 virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, Path& ret); 246 248 247 249 virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, entity_id_t notify); -
source/simulation2/components/CCmpRangeManager.cpp
1807 1807 } 1808 1808 } 1809 1809 1810 virtual void RevealShore(player_id_t p, bool enable) 1811 { 1812 if (p <= 0 || p > MAX_LOS_PLAYER_ID) 1813 return; 1814 1815 // Maximum distance to the shore 1816 const u16 maxdist = 10; 1817 1818 CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); 1819 const Grid<u16>& shoreGrid = cmpPathfinder->ComputeShoreGrid(true); 1820 ENSURE(shoreGrid.m_W == m_TerrainVerticesPerSide-1 && shoreGrid.m_H == m_TerrainVerticesPerSide-1); 1821 1822 std::vector<u16>& counts = m_LosPlayerCounts.at(p); 1823 ENSURE(!counts.empty()); 1824 u16* countsData = &counts[0]; 1825 1826 for (u16 j = 0; j < shoreGrid.m_H; ++j) 1827 { 1828 for (u16 i = 0; i < shoreGrid.m_W; ++i) 1829 { 1830 u16 shoredist = shoreGrid.get(i, j); 1831 if (shoredist > maxdist) 1832 continue; 1833 1834 // Maybe we could be more clever and don't add dummy strips of one tile 1835 if (enable) 1836 LosAddStripHelper(p, i, i, j, countsData); 1837 else 1838 LosRemoveStripHelper(p, i, i, j, countsData); 1839 } 1840 } 1841 } 1842 1810 1843 /** 1811 1844 * Returns whether the given vertex is outside the normal bounds of the world 1812 1845 * (i.e. outside the range of a circular map) … … 1861 1894 m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1))); 1862 1895 } 1863 1896 1864 // Mark the LoS tiles around the updated vertex 1865 // 1: left-up, 2: right-up, 3: left-down, 4: right-down 1866 int n1 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO; 1867 int n2 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO; 1868 int n3 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO; 1869 int n4 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO; 1870 1871 u16 sharedDirtyVisibilityMask = m_SharedDirtyVisibilityMasks[owner]; 1872 1873 if (j > 0 && i > 0) 1874 m_DirtyVisibility[n1] |= sharedDirtyVisibilityMask; 1875 if (n2 != n1 && j > 0 && i < m_TerrainVerticesPerSide) 1876 m_DirtyVisibility[n2] |= sharedDirtyVisibilityMask; 1877 if (n3 != n1 && j < m_TerrainVerticesPerSide && i > 0) 1878 m_DirtyVisibility[n3] |= sharedDirtyVisibilityMask; 1879 if (n4 != n1 && j < m_TerrainVerticesPerSide && i < m_TerrainVerticesPerSide) 1880 m_DirtyVisibility[n4] |= sharedDirtyVisibilityMask; 1897 MarkVisibilityDirtyAroundTile(owner, i, j); 1881 1898 } 1882 1899 1883 1900 ASSERT(counts[idx] < 65535); … … 1907 1924 m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1))); 1908 1925 1909 1926 i32 i = i0 + idx - idx0; 1927 MarkVisibilityDirtyAroundTile(owner, i, j); 1928 } 1929 } 1930 } 1910 1931 1911 // Mark the LoS tiles around the updated vertex 1912 // 1: left-up, 2: right-up, 3: left-down, 4: right-down 1913 int n1 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO; 1914 int n2 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO; 1915 int n3 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO; 1916 int n4 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO; 1932 inline void MarkVisibilityDirtyAroundTile(u8 owner, i32 i, i32 j) 1933 { 1934 // Mark the LoS tiles around the updated vertex 1935 // 1: left-up, 2: right-up, 3: left-down, 4: right-down 1936 int n1 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO; 1937 int n2 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO; 1938 int n3 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO; 1939 int n4 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO; 1917 1940 1918 1941 u16 sharedDirtyVisibilityMask = m_SharedDirtyVisibilityMasks[owner]; 1919 1942 1920 if (j > 0 && i > 0) 1921 m_DirtyVisibility[n1] |= sharedDirtyVisibilityMask; 1922 if (n2 != n1 && j > 0 && i < m_TerrainVerticesPerSide) 1923 m_DirtyVisibility[n2] |= sharedDirtyVisibilityMask; 1924 if (n3 != n1 && j < m_TerrainVerticesPerSide && i > 0) 1925 m_DirtyVisibility[n3] |= sharedDirtyVisibilityMask; 1926 if (n4 != n1 && j < m_TerrainVerticesPerSide && i < m_TerrainVerticesPerSide) 1927 m_DirtyVisibility[n4] |= sharedDirtyVisibilityMask; 1928 } 1929 } 1943 if (j > 0 && i > 0) 1944 m_DirtyVisibility[n1] |= sharedDirtyVisibilityMask; 1945 if (n2 != n1 && j > 0 && i < m_TerrainVerticesPerSide) 1946 m_DirtyVisibility[n2] |= sharedDirtyVisibilityMask; 1947 if (n3 != n1 && j < m_TerrainVerticesPerSide && i > 0) 1948 m_DirtyVisibility[n3] |= sharedDirtyVisibilityMask; 1949 if (n4 != n1 && j < m_TerrainVerticesPerSide && i < m_TerrainVerticesPerSide) 1950 m_DirtyVisibility[n4] |= sharedDirtyVisibilityMask; 1930 1951 } 1931 1952 1932 1953 /** -
source/simulation2/components/CCmpVision.cpp
21 21 #include "ICmpVision.h" 22 22 23 23 #include "simulation2/MessageTypes.h" 24 #include "simulation2/components/ICmpOwnership.h"25 24 #include "simulation2/components/ICmpPlayerManager.h" 25 #include "simulation2/components/ICmpRangeManager.h" 26 26 #include "simulation2/components/ICmpValueModificationManager.h" 27 27 28 28 class CCmpVision : public ICmpVision … … 30 30 public: 31 31 static void ClassInit(CComponentManager& componentManager) 32 32 { 33 componentManager.SubscribeToMessageType(MT_OwnershipChanged); 33 34 componentManager.SubscribeToMessageType(MT_ValueModification); 34 35 componentManager.SubscribeToMessageType(MT_Deserialized); 35 36 } … … 39 40 // Template state: 40 41 41 42 entity_pos_t m_Range, m_BaseRange; 43 bool m_RevealShore; 42 44 43 45 static std::string GetSchema() 44 46 { … … 45 47 return 46 48 "<element name='Range'>" 47 49 "<data type='nonNegativeInteger'/>" 48 "</element>"; 50 "</element>" 51 "<optional>" 52 "<element name='RevealShore'>" 53 "<data type='boolean'/>" 54 "</element>" 55 "</optional>"; 49 56 } 50 57 51 58 virtual void Init(const CParamNode& paramNode) 52 59 { 53 60 m_BaseRange = m_Range = paramNode.GetChild("Range").ToFixed(); 61 62 if (paramNode.GetChild("RevealShore").IsOk()) 63 m_RevealShore = paramNode.GetChild("RevealShore").ToBool(); 64 else 65 m_RevealShore = false; 54 66 } 55 67 56 68 virtual void Deinit() … … 71 83 { 72 84 switch (msg.GetType()) 73 85 { 86 case MT_OwnershipChanged: 87 { 88 if (!m_RevealShore) 89 break; 90 91 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 92 if (msgData.entity != GetEntityId()) 93 break; 94 95 CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity()); 96 cmpRangeManager->RevealShore(msgData.from, false); 97 cmpRangeManager->RevealShore(msgData.to, true); 98 break; 99 } 74 100 case MT_ValueModification: 75 101 { 76 102 const CMessageValueModification& msgData = static_cast<const CMessageValueModification&> (msg); -
source/simulation2/components/ICmpPathfinder.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 97 97 virtual const Grid<u16>& GetPassabilityGrid() = 0; 98 98 99 99 /** 100 * Get a grid representing the distance to the shore of the terrain tile. 101 */ 102 virtual Grid<u16> ComputeShoreGrid(bool expandOnWater = false) = 0; 103 104 /** 100 105 * Compute a tile-based path from the given point to the goal, and return the set of waypoints. 101 106 * The waypoints correspond to the centers of horizontally/vertically adjacent tiles 102 107 * along the path. -
source/simulation2/components/ICmpRangeManager.h
353 353 virtual void ExploreTerritories() = 0; 354 354 355 355 /** 356 * Reveal the shore for specified player p. 357 * This works like for entities: if RevealShore is called multiple times with enabled, it 358 * will be necessary to call it the same number of times with !enabled to make the shore 359 * fall back into the FoW. 360 */ 361 virtual void RevealShore(player_id_t p, bool enable) = 0; 362 363 /** 356 364 * Set whether the whole map should be made visible to the given player. 357 365 * If player is -1, the map will be made visible to all players. 358 366 */