QuestArtifactPlacer.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * QuestArtifact.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 "QuestArtifactPlacer.h"
  12. #include "../CMapGenerator.h"
  13. #include "../RmgMap.h"
  14. #include "TreasurePlacer.h"
  15. #include "../CZonePlacer.h"
  16. #include "../../GameLibrary.h"
  17. #include "../../entities/artifact/CArtHandler.h"
  18. #include "../../mapObjectConstructors/AObjectTypeHandler.h"
  19. #include "../../mapObjectConstructors/CObjectClassesHandler.h"
  20. #include "../../mapObjects/MapObjects.h"
  21. #include <vstd/RNG.h>
  22. VCMI_LIB_NAMESPACE_BEGIN
  23. void QuestArtifactPlacer::process()
  24. {
  25. findZonesForQuestArts();
  26. placeQuestArtifacts(zone.getRand());
  27. }
  28. void QuestArtifactPlacer::init()
  29. {
  30. DEPENDENCY_ALL(TreasurePlacer);
  31. }
  32. void QuestArtifactPlacer::addQuestArtZone(std::shared_ptr<Zone> otherZone)
  33. {
  34. RecursiveLock lock(externalAccessMutex);
  35. questArtZones.push_back(otherZone);
  36. }
  37. void QuestArtifactPlacer::addQuestArtifact(const ArtifactID& id, ui32 desiredValue)
  38. {
  39. logGlobal->trace("Need to place quest artifact %s (desired value %u)",
  40. LIBRARY->artifacts()->getById(id)->getNameTranslated(),
  41. desiredValue);
  42. RecursiveLock lock(externalAccessMutex);
  43. questArtifactsToPlace.push_back({id, desiredValue});
  44. }
  45. void QuestArtifactPlacer::removeQuestArtifact(const ArtifactID& id)
  46. {
  47. logGlobal->trace("Will not try to place quest artifact %s", LIBRARY->artifacts()->getById(id)->getNameTranslated());
  48. RecursiveLock lock(externalAccessMutex);
  49. vstd::erase_if(questArtifactsToPlace, [&id](const QuestArtifactRequest& request)
  50. {
  51. return request.id == id;
  52. });
  53. }
  54. void QuestArtifactPlacer::rememberPotentialArtifactToReplace(CGObjectInstance* obj, ui32 value)
  55. {
  56. RecursiveLock lock(externalAccessMutex);
  57. artifactsToReplace.push_back({obj, value});
  58. }
  59. std::vector<CGObjectInstance*> QuestArtifactPlacer::getPossibleArtifactsToReplace() const
  60. {
  61. RecursiveLock lock(externalAccessMutex);
  62. std::vector<CGObjectInstance*> result;
  63. result.reserve(artifactsToReplace.size());
  64. for (const auto& candidate : artifactsToReplace)
  65. {
  66. result.push_back(candidate.object);
  67. }
  68. return result;
  69. }
  70. CGObjectInstance * QuestArtifactPlacer::drawObjectToReplace(ui32 desiredValue)
  71. {
  72. RecursiveLock lock(externalAccessMutex);
  73. if (artifactsToReplace.empty())
  74. {
  75. return nullptr;
  76. }
  77. auto bestIt = artifactsToReplace.end();
  78. ui32 bestDiff = std::numeric_limits<ui32>::max();
  79. for (auto it = artifactsToReplace.begin(); it != artifactsToReplace.end(); ++it)
  80. {
  81. const ui32 value = it->value;
  82. auto diff = std::abs(static_cast<int>(value) - static_cast<int>(desiredValue));
  83. if (diff < bestDiff)
  84. {
  85. bestDiff = diff;
  86. bestIt = it;
  87. if (diff == 0)
  88. break;
  89. }
  90. }
  91. if (bestIt == artifactsToReplace.end())
  92. {
  93. return nullptr;
  94. }
  95. auto* ret = bestIt->object;
  96. artifactsToReplace.erase(bestIt);
  97. return ret;
  98. }
  99. void QuestArtifactPlacer::findZonesForQuestArts()
  100. {
  101. const auto& distances = generator.getZonePlacer()->getDistanceMap().at(zone.getId());
  102. for (auto const& connectedZone : distances)
  103. {
  104. // Choose zones that are 1 or 2 connections away
  105. if (vstd::iswithin(connectedZone.second, 1, 2))
  106. {
  107. addQuestArtZone(map.getZones().at(connectedZone.first));
  108. }
  109. }
  110. logGlobal->trace("Number of nearby zones suitable for quest artifacts: %d", questArtZones.size());
  111. }
  112. void QuestArtifactPlacer::placeQuestArtifacts(vstd::RNG & rand)
  113. {
  114. for (const auto & questRequest : questArtifactsToPlace)
  115. {
  116. RandomGeneratorUtil::randomShuffle(questArtZones, rand);
  117. for (auto zone : questArtZones)
  118. {
  119. auto* qap = zone->getModificator<QuestArtifactPlacer>();
  120. auto objectToReplace = qap->drawObjectToReplace(questRequest.desiredValue);
  121. if (!objectToReplace)
  122. continue;
  123. logGlobal->trace("Replacing %s at %s with the quest artifact %s (desired value %u)",
  124. objectToReplace->getObjectName(),
  125. objectToReplace->anchorPos().toString(),
  126. LIBRARY->artifacts()->getById(questRequest.id)->getNameTranslated(),
  127. questRequest.desiredValue);
  128. //Update appearance. Terrain is irrelevant.
  129. auto handler = LIBRARY->objtypeh->getHandlerFor(Obj::ARTIFACT, questRequest.id);
  130. auto newObj = handler->create(map.mapInstance->cb, nullptr);
  131. auto templates = handler->getTemplates();
  132. newObj->appearance = templates.front();
  133. newObj->setAnchorPos(objectToReplace->anchorPos());
  134. mapProxy->insertObject(newObj);
  135. mapProxy->removeObject(objectToReplace);
  136. break;
  137. }
  138. }
  139. }
  140. // TODO: Unused?
  141. void QuestArtifactPlacer::dropReplacedArtifact(const CGObjectInstance* obj)
  142. {
  143. RecursiveLock lock(externalAccessMutex);
  144. vstd::erase_if(artifactsToReplace, [obj](const ReplacementCandidate& candidate)
  145. {
  146. return candidate.object == obj;
  147. });
  148. }
  149. size_t QuestArtifactPlacer::getMaxQuestArtifactCount() const
  150. {
  151. RecursiveLock lock(externalAccessMutex);
  152. return questArtifacts.size();
  153. }
  154. ArtifactID QuestArtifactPlacer::drawRandomArtifact()
  155. {
  156. RecursiveLock lock(externalAccessMutex);
  157. if (!questArtifacts.empty())
  158. {
  159. RandomGeneratorUtil::randomShuffle(questArtifacts, zone.getRand());
  160. ArtifactID ret = questArtifacts.back();
  161. questArtifacts.pop_back();
  162. generator.banQuestArt(ret);
  163. return ret;
  164. }
  165. else
  166. {
  167. throw rmgException("No quest artifacts left for this zone!");
  168. }
  169. }
  170. void QuestArtifactPlacer::addRandomArtifact(const ArtifactID & artid)
  171. {
  172. RecursiveLock lock(externalAccessMutex);
  173. questArtifacts.push_back(artid);
  174. generator.unbanQuestArt(artid);
  175. }
  176. VCMI_LIB_NAMESPACE_END