DwellingInstanceConstructor.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * DwellingInstanceConstructor.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 "DwellingInstanceConstructor.h"
  12. #include "../CCreatureHandler.h"
  13. #include "../texts/CGeneralTextHandler.h"
  14. #include "../json/JsonRandom.h"
  15. #include "../GameLibrary.h"
  16. #include "../mapObjects/CGDwelling.h"
  17. #include "../mapObjects/ObjectTemplate.h"
  18. #include "../modding/IdentifierStorage.h"
  19. #include "../CConfigHandler.h"
  20. VCMI_LIB_NAMESPACE_BEGIN
  21. bool DwellingInstanceConstructor::hasNameTextID() const
  22. {
  23. return true;
  24. }
  25. void DwellingInstanceConstructor::initTypeData(const JsonNode & input)
  26. {
  27. if (input.Struct().count("name") == 0)
  28. logMod->warn("Dwelling %s missing name!", getJsonKey());
  29. LIBRARY->generaltexth->registerString( input.getModScope(), getNameTextID(), input["name"]);
  30. const JsonVector & levels = input["creatures"].Vector();
  31. const auto totalLevels = levels.size();
  32. availableCreatures.resize(totalLevels);
  33. for(int currentLevel = 0; currentLevel < totalLevels; currentLevel++)
  34. {
  35. const JsonVector & creaturesOnLevel = levels[currentLevel].Vector();
  36. const auto creaturesNumber = creaturesOnLevel.size();
  37. availableCreatures[currentLevel].resize(creaturesNumber);
  38. for(int currentCreature = 0; currentCreature < creaturesNumber; currentCreature++)
  39. {
  40. LIBRARY->identifiers()->requestIdentifier("creature", creaturesOnLevel[currentCreature], [this, currentLevel, currentCreature] (si32 index)
  41. {
  42. availableCreatures.at(currentLevel).at(currentCreature) = CreatureID(index).toCreature();
  43. });
  44. }
  45. assert(!availableCreatures[currentLevel].empty());
  46. }
  47. guards = input["guards"];
  48. bannedForRandomDwelling = input["bannedForRandomDwelling"].Bool();
  49. for (const auto & mapTemplate : getTemplates())
  50. onTemplateAdded(mapTemplate);
  51. }
  52. void DwellingInstanceConstructor::onTemplateAdded(const std::shared_ptr<const ObjectTemplate> mapTemplate)
  53. {
  54. if (bannedForRandomDwelling || settings["mods"]["validation"].String() == "off")
  55. return;
  56. bool invalidForRandomDwelling = false;
  57. int3 corner = mapTemplate->getCornerOffset();
  58. for (const auto & tile : mapTemplate->getBlockedOffsets())
  59. invalidForRandomDwelling |= (tile.x != -corner.x && tile.x != -corner.x-1) || (tile.y != -corner.y && tile.y != -corner.y-1);
  60. for (const auto & tile : {mapTemplate->getVisitableOffset()})
  61. invalidForRandomDwelling |= (tile.x != corner.x && tile.x != corner.x+1) || tile.y != corner.y;
  62. invalidForRandomDwelling |= !mapTemplate->isBlockedAt(corner.x+0, corner.y) && !mapTemplate->isVisibleAt(corner.x+0, corner.y);
  63. invalidForRandomDwelling |= !mapTemplate->isBlockedAt(corner.x+1, corner.y) && !mapTemplate->isVisibleAt(corner.x+1, corner.y);
  64. if (invalidForRandomDwelling)
  65. logMod->warn("Dwelling %s has template %s which is not valid for a random dwelling! Dwellings must not block tiles outside 2x2 range and must be visitable in bottom row. Change dwelling mask or mark dwelling as 'bannedForRandomDwelling'", getJsonKey(), mapTemplate->animationFile.getOriginalName());
  66. }
  67. bool DwellingInstanceConstructor::isBannedForRandomDwelling() const
  68. {
  69. return bannedForRandomDwelling;
  70. }
  71. bool DwellingInstanceConstructor::objectFilter(const CGObjectInstance * obj, std::shared_ptr<const ObjectTemplate> tmpl) const
  72. {
  73. return false;
  74. }
  75. void DwellingInstanceConstructor::initializeObject(CGDwelling * obj) const
  76. {
  77. obj->creatures.resize(availableCreatures.size());
  78. for(const auto & entry : availableCreatures)
  79. {
  80. for(const CCreature * cre : entry)
  81. obj->creatures.back().second.push_back(cre->getId());
  82. }
  83. }
  84. void DwellingInstanceConstructor::randomizeObject(CGDwelling * dwelling, IGameRandomizer & gameRandomizer) const
  85. {
  86. JsonRandom randomizer(dwelling->cb, gameRandomizer);
  87. dwelling->creatures.clear();
  88. dwelling->creatures.reserve(availableCreatures.size());
  89. for(const auto & entry : availableCreatures)
  90. {
  91. dwelling->creatures.resize(dwelling->creatures.size() + 1);
  92. for(const CCreature * cre : entry)
  93. dwelling->creatures.back().second.push_back(cre->getId());
  94. }
  95. bool guarded = false;
  96. if(guards.getType() == JsonNode::JsonType::DATA_BOOL)
  97. {
  98. //simple switch
  99. if(guards.Bool())
  100. {
  101. guarded = true;
  102. }
  103. }
  104. else if(guards.getType() == JsonNode::JsonType::DATA_VECTOR)
  105. {
  106. //custom guards (eg. Elemental Conflux)
  107. JsonRandom::Variables emptyVariables;
  108. for(auto & stack : randomizer.loadCreatures(guards, emptyVariables))
  109. {
  110. dwelling->putStack(SlotID(dwelling->stacksCount()), std::make_unique<CStackInstance>(dwelling->cb, stack.getId(), stack.getCount()));
  111. }
  112. }
  113. else if (dwelling->ID == Obj::CREATURE_GENERATOR1 || dwelling->ID == Obj::CREATURE_GENERATOR4)
  114. {
  115. //default condition - this is dwelling with creatures of level 5 or higher
  116. for(auto creatureEntry : availableCreatures)
  117. {
  118. if(creatureEntry.at(0)->getLevel() >= 5)
  119. {
  120. guarded = true;
  121. break;
  122. }
  123. }
  124. }
  125. if(guarded)
  126. {
  127. for(auto creatureEntry : availableCreatures)
  128. {
  129. const CCreature * crea = creatureEntry.at(0);
  130. dwelling->putStack(SlotID(dwelling->stacksCount()), std::make_unique<CStackInstance>(dwelling->cb, crea->getId(), crea->getGrowth() * 3));
  131. }
  132. }
  133. }
  134. bool DwellingInstanceConstructor::producesCreature(const CCreature * crea) const
  135. {
  136. for(const auto & entry : availableCreatures)
  137. {
  138. for(const CCreature * cre : entry)
  139. if(crea == cre)
  140. return true;
  141. }
  142. return false;
  143. }
  144. std::vector<const CCreature *> DwellingInstanceConstructor::getProducedCreatures() const
  145. {
  146. std::vector<const CCreature *> creatures; //no idea why it's 2D, to be honest
  147. for(const auto & entry : availableCreatures)
  148. {
  149. for(const CCreature * cre : entry)
  150. creatures.push_back(cre);
  151. }
  152. return creatures;
  153. }
  154. VCMI_LIB_NAMESPACE_END