CommonConstructors.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * CommonConstructors.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 "CommonConstructors.h"
  12. #include "../texts/CGeneralTextHandler.h"
  13. #include "../IGameCallback.h"
  14. #include "../json/JsonRandom.h"
  15. #include "../constants/StringConstants.h"
  16. #include "../TerrainHandler.h"
  17. #include "../VCMI_Lib.h"
  18. #include "../entities/faction/CTownHandler.h"
  19. #include "../entities/hero/CHeroClass.h"
  20. #include "../mapObjects/CGHeroInstance.h"
  21. #include "../mapObjects/CGMarket.h"
  22. #include "../mapObjects/CGTownInstance.h"
  23. #include "../mapObjects/MiscObjects.h"
  24. #include "../mapObjects/ObjectTemplate.h"
  25. #include "../modding/IdentifierStorage.h"
  26. #include "../mapping/CMapDefines.h"
  27. VCMI_LIB_NAMESPACE_BEGIN
  28. bool CObstacleConstructor::isStaticObject()
  29. {
  30. return true;
  31. }
  32. bool CreatureInstanceConstructor::hasNameTextID() const
  33. {
  34. return true;
  35. }
  36. std::string CreatureInstanceConstructor::getNameTextID() const
  37. {
  38. return VLC->creatures()->getByIndex(getSubIndex())->getNamePluralTextID();
  39. }
  40. bool ResourceInstanceConstructor::hasNameTextID() const
  41. {
  42. return true;
  43. }
  44. std::string ResourceInstanceConstructor::getNameTextID() const
  45. {
  46. return TextIdentifier("core", "restypes", getSubIndex()).get();
  47. }
  48. void CTownInstanceConstructor::initTypeData(const JsonNode & input)
  49. {
  50. VLC->identifiers()->requestIdentifier("faction", input["faction"], [&](si32 index)
  51. {
  52. faction = (*VLC->townh)[index];
  53. });
  54. filtersJson = input["filters"];
  55. // change scope of "filters" to scope of object that is being loaded
  56. // since this filters require to resolve building ID's
  57. filtersJson.setModScope(input["faction"].getModScope());
  58. }
  59. void CTownInstanceConstructor::afterLoadFinalization()
  60. {
  61. assert(faction);
  62. for(const auto & entry : filtersJson.Struct())
  63. {
  64. filters[entry.first] = LogicalExpression<BuildingID>(entry.second, [this](const JsonNode & node)
  65. {
  66. return BuildingID(VLC->identifiers()->getIdentifier("building." + faction->getJsonKey(), node.Vector()[0]).value_or(-1));
  67. });
  68. }
  69. }
  70. bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const
  71. {
  72. const auto * town = dynamic_cast<const CGTownInstance *>(object);
  73. auto buildTest = [&](const BuildingID & id)
  74. {
  75. return town->hasBuilt(id);
  76. };
  77. return filters.count(templ->stringID) != 0 && filters.at(templ->stringID).test(buildTest);
  78. }
  79. void CTownInstanceConstructor::initializeObject(CGTownInstance * obj) const
  80. {
  81. obj->tempOwner = PlayerColor::NEUTRAL;
  82. }
  83. void CTownInstanceConstructor::randomizeObject(CGTownInstance * object, vstd::RNG & rng) const
  84. {
  85. auto templ = getOverride(object->cb->getTile(object->pos)->getTerrainID(), object);
  86. if(templ)
  87. object->appearance = templ;
  88. }
  89. bool CTownInstanceConstructor::hasNameTextID() const
  90. {
  91. return true;
  92. }
  93. std::string CTownInstanceConstructor::getNameTextID() const
  94. {
  95. return faction->getNameTextID();
  96. }
  97. void CHeroInstanceConstructor::initTypeData(const JsonNode & input)
  98. {
  99. VLC->identifiers()->requestIdentifier(
  100. "heroClass",
  101. input["heroClass"],
  102. [&](si32 index) { heroClass = HeroClassID(index).toHeroClass(); });
  103. for (const auto & [name, config] : input["filters"].Struct())
  104. {
  105. HeroFilter filter;
  106. filter.allowFemale = config["female"].Bool();
  107. filter.allowMale = config["male"].Bool();
  108. filters[name] = filter;
  109. if (!config["hero"].isNull())
  110. {
  111. VLC->identifiers()->requestIdentifier( "hero", config["hero"], [this, templateName = name](si32 index) {
  112. filters.at(templateName).fixedHero = HeroTypeID(index);
  113. });
  114. }
  115. }
  116. }
  117. std::shared_ptr<const ObjectTemplate> CHeroInstanceConstructor::getOverride(TerrainId terrainType, const CGObjectInstance * object) const
  118. {
  119. const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
  120. std::vector<std::shared_ptr<const ObjectTemplate>> allTemplates = getTemplates();
  121. std::shared_ptr<const ObjectTemplate> candidateFullMatch;
  122. std::shared_ptr<const ObjectTemplate> candidateGenderMatch;
  123. std::shared_ptr<const ObjectTemplate> candidateBase;
  124. assert(hero->gender != EHeroGender::DEFAULT);
  125. for (const auto & templ : allTemplates)
  126. {
  127. if (filters.count(templ->stringID))
  128. {
  129. const auto & filter = filters.at(templ->stringID);
  130. if (filter.fixedHero.hasValue())
  131. {
  132. if (filter.fixedHero == hero->getHeroTypeID())
  133. candidateFullMatch = templ;
  134. }
  135. else if (filter.allowMale)
  136. {
  137. if (hero->gender == EHeroGender::MALE)
  138. candidateGenderMatch = templ;
  139. }
  140. else if (filter.allowFemale)
  141. {
  142. if (hero->gender == EHeroGender::FEMALE)
  143. candidateGenderMatch = templ;
  144. }
  145. else
  146. {
  147. candidateBase = templ;
  148. }
  149. }
  150. else
  151. {
  152. candidateBase = templ;
  153. }
  154. }
  155. if (candidateFullMatch)
  156. return candidateFullMatch;
  157. if (candidateGenderMatch)
  158. return candidateGenderMatch;
  159. return candidateBase;
  160. }
  161. void CHeroInstanceConstructor::randomizeObject(CGHeroInstance * object, vstd::RNG & rng) const
  162. {
  163. }
  164. bool CHeroInstanceConstructor::hasNameTextID() const
  165. {
  166. return true;
  167. }
  168. std::string CHeroInstanceConstructor::getNameTextID() const
  169. {
  170. return heroClass->getNameTextID();
  171. }
  172. void BoatInstanceConstructor::initTypeData(const JsonNode & input)
  173. {
  174. layer = EPathfindingLayer::SAIL;
  175. int pos = vstd::find_pos(NPathfindingLayer::names, input["layer"].String());
  176. if(pos != -1)
  177. layer = EPathfindingLayer(pos);
  178. else
  179. logMod->error("Unknown layer %s found in boat!", input["layer"].String());
  180. onboardAssaultAllowed = input["onboardAssaultAllowed"].Bool();
  181. onboardVisitAllowed = input["onboardVisitAllowed"].Bool();
  182. actualAnimation = AnimationPath::fromJson(input["actualAnimation"]);
  183. overlayAnimation = AnimationPath::fromJson(input["overlayAnimation"]);
  184. for(int i = 0; i < flagAnimations.size() && i < input["flagAnimations"].Vector().size(); ++i)
  185. flagAnimations[i] = AnimationPath::fromJson(input["flagAnimations"].Vector()[i]);
  186. bonuses = JsonRandom::loadBonuses(input["bonuses"]);
  187. }
  188. void BoatInstanceConstructor::initializeObject(CGBoat * boat) const
  189. {
  190. boat->layer = layer;
  191. boat->actualAnimation = actualAnimation;
  192. boat->overlayAnimation = overlayAnimation;
  193. boat->flagAnimations = flagAnimations;
  194. boat->onboardAssaultAllowed = onboardAssaultAllowed;
  195. boat->onboardVisitAllowed = onboardVisitAllowed;
  196. for(auto & b : bonuses)
  197. boat->addNewBonus(std::make_shared<Bonus>(b));
  198. }
  199. AnimationPath BoatInstanceConstructor::getBoatAnimationName() const
  200. {
  201. return actualAnimation;
  202. }
  203. void MarketInstanceConstructor::initTypeData(const JsonNode & input)
  204. {
  205. if (!input["description"].isNull())
  206. {
  207. description = input["description"].String();
  208. VLC->generaltexth->registerString(input.getModScope(), TextIdentifier(getBaseTextID(), "description"), description);
  209. }
  210. for(auto & element : input["modes"].Vector())
  211. {
  212. if(MappedKeys::MARKET_NAMES_TO_TYPES.count(element.String()))
  213. marketModes.insert(MappedKeys::MARKET_NAMES_TO_TYPES.at(element.String()));
  214. }
  215. marketEfficiency = input["efficiency"].isNull() ? 5 : input["efficiency"].Integer();
  216. predefinedOffer = input["offer"];
  217. title = input["title"].String();
  218. speech = input["speech"].String();
  219. }
  220. bool MarketInstanceConstructor::hasDescription() const
  221. {
  222. return !description.empty();
  223. }
  224. CGMarket * MarketInstanceConstructor::createObject(IGameCallback * cb) const
  225. {
  226. if(marketModes.size() == 1)
  227. {
  228. switch(*marketModes.begin())
  229. {
  230. case EMarketMode::ARTIFACT_RESOURCE:
  231. case EMarketMode::RESOURCE_ARTIFACT:
  232. return new CGBlackMarket(cb);
  233. case EMarketMode::RESOURCE_SKILL:
  234. return new CGUniversity(cb);
  235. }
  236. }
  237. return new CGMarket(cb);
  238. }
  239. void MarketInstanceConstructor::initializeObject(CGMarket * market) const
  240. {
  241. market->marketEfficiency = marketEfficiency;
  242. if(auto university = dynamic_cast<CGUniversity*>(market))
  243. {
  244. university->title = market->getObjectName();
  245. if(!title.empty())
  246. university->title = VLC->generaltexth->translate(title);
  247. if(!speech.empty())
  248. university->speech = VLC->generaltexth->translate(speech);
  249. }
  250. }
  251. const std::set<EMarketMode> & MarketInstanceConstructor::availableModes() const
  252. {
  253. return marketModes;
  254. }
  255. void MarketInstanceConstructor::randomizeObject(CGMarket * object, vstd::RNG & rng) const
  256. {
  257. JsonRandom randomizer(object->cb);
  258. JsonRandom::Variables emptyVariables;
  259. if(auto * university = dynamic_cast<CGUniversity *>(object))
  260. {
  261. for(auto skill : randomizer.loadSecondaries(predefinedOffer, rng, emptyVariables))
  262. university->skills.push_back(skill.first);
  263. }
  264. }
  265. VCMI_LIB_NAMESPACE_END