ObstaclePlacer.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * ObstaclePlacer.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "../mapObjects/CObjectClassesHandler.h"
  12. #include "ObstaclePlacer.h"
  13. #include "ObjectManager.h"
  14. #include "TreasurePlacer.h"
  15. #include "RockPlacer.h"
  16. #include "WaterRoutes.h"
  17. #include "WaterProxy.h"
  18. #include "RoadPlacer.h"
  19. #include "RiverPlacer.h"
  20. #include "RmgMap.h"
  21. #include "CMapGenerator.h"
  22. #include "../CRandomGenerator.h"
  23. #include "Functions.h"
  24. void ObstaclePlacer::process()
  25. {
  26. auto * manager = zone.getModificator<ObjectManager>();
  27. if(!manager)
  28. return;
  29. auto * riverManager = zone.getModificator<RiverPlacer>();
  30. typedef std::vector<ObjectTemplate> ObstacleVector;
  31. //obstacleVector possibleObstacles;
  32. std::map<int, ObstacleVector> obstaclesBySize;
  33. typedef std::pair<int, ObstacleVector> ObstaclePair;
  34. std::vector<ObstaclePair> possibleObstacles;
  35. //get all possible obstacles for this terrain
  36. for(auto primaryID : VLC->objtypeh->knownObjects())
  37. {
  38. for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID))
  39. {
  40. auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID);
  41. if(handler->isStaticObject())
  42. {
  43. for(auto temp : handler->getTemplates())
  44. {
  45. if(temp.canBePlacedAt(zone.getTerrainType()) && temp.getBlockMapOffset().valid())
  46. obstaclesBySize[temp.getBlockedOffsets().size()].push_back(temp);
  47. }
  48. }
  49. }
  50. }
  51. for(auto o : obstaclesBySize)
  52. {
  53. possibleObstacles.push_back(o);
  54. }
  55. boost::sort(possibleObstacles, [](const ObstaclePair &p1, const ObstaclePair &p2) -> bool
  56. {
  57. return p1.first > p2.first; //bigger obstacles first
  58. });
  59. auto blockedArea = zone.area().getSubarea([this](const int3 & t)
  60. {
  61. return map.shouldBeBlocked(t);
  62. });
  63. blockedArea.subtract(zone.areaUsed());
  64. zone.areaPossible().subtract(blockedArea);
  65. auto prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
  66. //reverse order, since obstacles begin in bottom-right corner, while the map coordinates begin in top-left
  67. auto blockedTiles = blockedArea.getTilesVector();
  68. int tilePos = 0;
  69. while(!blockedArea.empty() && tilePos < blockedArea.getTilesVector().size())
  70. {
  71. auto tile = blockedArea.getTilesVector()[tilePos];
  72. std::list<rmg::Object> allObjects;
  73. std::vector<std::pair<rmg::Object*, int3>> weightedObjects; //obj + position
  74. int maxWeight = std::numeric_limits<int>::min();
  75. for(int i = 0; i < possibleObstacles.size(); ++i)
  76. {
  77. if(!possibleObstacles[i].first)
  78. continue;
  79. for(auto & temp : possibleObstacles[i].second)
  80. {
  81. auto handler = VLC->objtypeh->getHandlerFor(temp.id, temp.subid);
  82. auto obj = handler->create(temp);
  83. allObjects.emplace_back(*obj);
  84. rmg::Object * rmgObject = &allObjects.back();
  85. for(auto & offset : obj->getBlockedOffsets())
  86. {
  87. rmgObject->setPosition(tile - offset);
  88. if(!map.isOnMap(rmgObject->getPosition()))
  89. continue;
  90. if(!rmgObject->getArea().getSubarea([this](const int3 & t)
  91. {
  92. return !map.isOnMap(t);
  93. }).empty())
  94. continue;
  95. if(prohibitedArea.overlap(rmgObject->getArea()))
  96. continue;
  97. if(!zone.area().contains(rmgObject->getArea()))
  98. continue;
  99. int coverageBlocked = 0;
  100. int coveragePossible = 0;
  101. //do not use area intersection in optimization purposes
  102. for(auto & t : rmgObject->getArea().getTilesVector())
  103. {
  104. if(map.shouldBeBlocked(t))
  105. ++coverageBlocked;
  106. if(zone.areaPossible().contains(t))
  107. ++coveragePossible;
  108. }
  109. int coverageOverlap = possibleObstacles[i].first - coverageBlocked - coveragePossible;
  110. int weight = possibleObstacles[i].first + coverageBlocked - coverageOverlap * possibleObstacles[i].first;
  111. assert(coverageOverlap >= 0);
  112. if(weight > maxWeight)
  113. {
  114. weightedObjects.clear();
  115. maxWeight = weight;
  116. weightedObjects.emplace_back(rmgObject, rmgObject->getPosition());
  117. if(weight > 0)
  118. break;
  119. }
  120. else if(weight == maxWeight)
  121. weightedObjects.emplace_back(rmgObject, rmgObject->getPosition());
  122. }
  123. }
  124. if(maxWeight > 0)
  125. break;
  126. }
  127. if(weightedObjects.empty())
  128. {
  129. tilePos += 1;
  130. continue;
  131. }
  132. auto objIter = RandomGeneratorUtil::nextItem(weightedObjects, generator.rand);
  133. objIter->first->setPosition(objIter->second);
  134. manager->placeObject(*objIter->first, false, false);
  135. blockedArea.subtract(objIter->first->getArea());
  136. tilePos = 0;
  137. //river processing
  138. if(riverManager)
  139. {
  140. if(objIter->first->instances().front()->object().typeName == "mountain")
  141. riverManager->riverSource().unite(objIter->first->getArea());
  142. if(objIter->first->instances().front()->object().typeName == "lake")
  143. riverManager->riverSink().unite(objIter->first->getArea());
  144. }
  145. if(maxWeight < 0)
  146. logGlobal->warn("Placed obstacle with negative weight at %s", objIter->second.toString());
  147. for(auto & o : allObjects)
  148. {
  149. if(&o != objIter->first)
  150. o.clear();
  151. }
  152. }
  153. }
  154. void ObstaclePlacer::init()
  155. {
  156. DEPENDENCY(ObjectManager);
  157. DEPENDENCY(TreasurePlacer);
  158. DEPENDENCY(WaterRoutes);
  159. DEPENDENCY(WaterProxy);
  160. DEPENDENCY(RoadPlacer);
  161. DEPENDENCY_ALL(RockPlacer);
  162. }