ObjectDistributor.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * ObjectDistributor.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 "ObjectDistributor.h"
  12. #include "../VCMI_Lib.h"
  13. #include "RmgMap.h"
  14. #include "CMapGenerator.h"
  15. #include "TreasurePlacer.h"
  16. #include "QuestArtifactPlacer.h"
  17. #include "TownPlacer.h"
  18. #include "TerrainPainter.h"
  19. #include "../mapObjects/CObjectClassesHandler.h"
  20. #include "../mapObjects/MapObjects.h"
  21. #include "Functions.h"
  22. #include "RmgObject.h"
  23. VCMI_LIB_NAMESPACE_BEGIN
  24. void ObjectDistributor::process()
  25. {
  26. //Do that only once
  27. auto lockVec = tryLockAll<ObjectDistributor>();
  28. if (!lockVec.empty())
  29. {
  30. for(auto & z : map.getZones())
  31. {
  32. if(auto * m = z.second->getModificator<ObjectDistributor>())
  33. {
  34. if(m->isFinished())
  35. return;
  36. }
  37. }
  38. distributeLimitedObjects();
  39. distributeSeerHuts();
  40. finished = true;
  41. }
  42. }
  43. void ObjectDistributor::init()
  44. {
  45. //All of the terrain types need to be determined
  46. DEPENDENCY_ALL(TerrainPainter);
  47. POSTFUNCTION(TreasurePlacer);
  48. }
  49. void ObjectDistributor::distributeLimitedObjects()
  50. {
  51. //FIXME: Must be called after TerrainPainter::process()
  52. ObjectInfo oi;
  53. auto zones = map.getZones();
  54. for (auto primaryID : VLC->objtypeh->knownObjects())
  55. {
  56. for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID))
  57. {
  58. auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID);
  59. if (!handler->isStaticObject() && handler->getRMGInfo().value)
  60. {
  61. auto rmgInfo = handler->getRMGInfo();
  62. //Skip objects which don't have global per-map limit here
  63. if (rmgInfo.mapLimit)
  64. {
  65. //Count all zones where this object can be placed
  66. std::vector<std::shared_ptr<Zone>> matchingZones;
  67. for (const auto& it : zones)
  68. {
  69. if (!handler->getTemplates(it.second->getTerrainType()).empty() &&
  70. rmgInfo.value <= it.second->getMaxTreasureValue())
  71. {
  72. matchingZones.push_back(it.second);
  73. }
  74. }
  75. size_t numZones = matchingZones.size();
  76. if (!numZones)
  77. continue;
  78. auto rmgInfo = handler->getRMGInfo();
  79. for (auto& zone : matchingZones)
  80. {
  81. //We already know there are some templates
  82. auto templates = handler->getTemplates(zone->getTerrainType());
  83. //FIXME: Templates empty?! Maybe zone changed terrain type over time?
  84. //Assume the template with fewest terrains is the most suitable
  85. auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
  86. {
  87. return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size();
  88. });
  89. oi.generateObject = [temp]() -> CGObjectInstance *
  90. {
  91. return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
  92. };
  93. oi.value = rmgInfo.value;
  94. oi.probability = rmgInfo.rarity;
  95. oi.templ = temp;
  96. //Rounding up will make sure all possible objects are exhausted
  97. uint32_t mapLimit = rmgInfo.mapLimit.value();
  98. uint32_t maxPerZone = std::ceil(float(mapLimit) / numZones);
  99. //But not more than zone limit
  100. oi.maxPerZone = std::min(maxPerZone, rmgInfo.zoneLimit);
  101. numZones--;
  102. rmgInfo.setMapLimit(mapLimit - oi.maxPerZone);
  103. //Don't add objects with 0 count remaining
  104. if (oi.maxPerZone)
  105. {
  106. zone->getModificator<TreasurePlacer>()->addObjectToRandomPool(oi);
  107. }
  108. }
  109. }
  110. }
  111. }
  112. }
  113. }
  114. void ObjectDistributor::distributeSeerHuts()
  115. {
  116. //TODO: Move typedef outside the class?
  117. //Copy by value to random shuffle
  118. const auto & zoneMap = map.getZones();
  119. RmgMap::ZoneVector zones(zoneMap.begin(), zoneMap.end());
  120. RandomGeneratorUtil::randomShuffle(zones, generator.rand);
  121. const auto & possibleQuestArts = generator.getAllPossibleQuestArtifacts();
  122. size_t availableArts = possibleQuestArts.size();
  123. auto artIt = possibleQuestArts.begin();
  124. for (int i = zones.size() - 1; i >= 0 ; i--)
  125. {
  126. size_t localArts = std::ceil((float)availableArts / (i + 1));
  127. availableArts -= localArts;
  128. auto * qap = zones[i].second->getModificator<QuestArtifactPlacer>();
  129. if (qap)
  130. {
  131. for (;localArts > 0 && artIt != possibleQuestArts.end(); artIt++, localArts--)
  132. {
  133. qap->addRandomArtifact(*artIt);
  134. }
  135. }
  136. }
  137. }
  138. void ObjectDistributor::distributePrisons()
  139. {
  140. //Copy by value to random shuffle
  141. const auto & zoneMap = map.getZones();
  142. RmgMap::ZoneVector zones(zoneMap.begin(), zoneMap.end());
  143. RandomGeneratorUtil::randomShuffle(zones, generator.rand);
  144. size_t allowedPrisons = generator.getPrisonsRemaning();
  145. for (int i = zones.size() - 1; i >= 0; i--)
  146. {
  147. auto zone = zones[i].second;
  148. auto * tp = zone->getModificator<TreasurePlacer>();
  149. if (tp)
  150. {
  151. tp->setMaxPrisons(std::ceil(float(allowedPrisons) / (i + 1)));
  152. allowedPrisons -= tp->getMaxPrisons();
  153. }
  154. }
  155. }
  156. VCMI_LIB_NAMESPACE_END