BuildingManager.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * BuildingManager.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 "BuildingManager.h"
  12. #include "../../CCallback.h"
  13. #include "../../lib/mapObjects/MapObjects.h"
  14. bool BuildingManager::tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays)
  15. {
  16. if (maxDays == 0)
  17. {
  18. logAi->warn("Request to build building %d in 0 days!", building.toEnum());
  19. return false;
  20. }
  21. if (!vstd::contains(t->town->buildings, building))
  22. return false; // no such building in town
  23. if (t->hasBuilt(building)) //Already built? Shouldn't happen in general
  24. return true;
  25. const CBuilding * buildPtr = t->town->buildings.at(building);
  26. auto toBuild = buildPtr->requirements.getFulfillmentCandidates([&](const BuildingID & buildID)
  27. {
  28. return t->hasBuilt(buildID);
  29. });
  30. toBuild.push_back(building);
  31. for (BuildingID buildID : toBuild)
  32. {
  33. EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
  34. if (canBuild == EBuildingState::HAVE_CAPITAL || canBuild == EBuildingState::FORBIDDEN || canBuild == EBuildingState::NO_WATER)
  35. return false; //we won't be able to build this
  36. }
  37. if (maxDays && toBuild.size() > maxDays)
  38. return false;
  39. //TODO: calculate if we have enough resources to build it in maxDays?
  40. for (const auto & buildID : toBuild)
  41. {
  42. const CBuilding * b = t->town->buildings.at(buildID);
  43. EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
  44. if (canBuild == EBuildingState::ALLOWED)
  45. {
  46. <<<<<<< HEAD
  47. =======
  48. >>>>>>> 079ea69b43b0faabece4e9703ee089eb34486ff2
  49. PotentialBuilding pb;
  50. pb.bid = buildID;
  51. pb.price = t->getBuildingCost(buildID);
  52. immediateBuildings.push_back(pb); //these are checked again in try
  53. return true;
  54. }
  55. else if (canBuild == EBuildingState::PREREQUIRES)
  56. {
  57. // can happen when dependencies have their own missing dependencies
  58. if (tryBuildThisStructure(t, buildID, maxDays - 1))
  59. return true;
  60. }
  61. else if (canBuild == EBuildingState::MISSING_BASE)
  62. {
  63. if (tryBuildThisStructure(t, b->upgrade, maxDays - 1))
  64. return true;
  65. }
  66. else if (canBuild == EBuildingState::NO_RESOURCES)
  67. {
  68. //we may need to gather resources for those
  69. PotentialBuilding pb;
  70. pb.bid = buildID;
  71. pb.price = t->getBuildingCost(buildID);
  72. expensiveBuildings.push_back(pb); //these are checked again in try
  73. return false;
  74. }
  75. else
  76. return false;
  77. }
  78. return false;
  79. }
  80. bool BuildingManager::tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
  81. {
  82. for (const auto & building : buildList)
  83. {
  84. if (t->hasBuilt(building))
  85. continue;
  86. return tryBuildThisStructure(t, building, maxDays);
  87. }
  88. return false; //Can't build anything
  89. }
  90. <<<<<<< HEAD
  91. =======
  92. >>>>>>> 079ea69b43b0faabece4e9703ee089eb34486ff2
  93. boost::optional<BuildingID> BuildingManager::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
  94. {
  95. for (const auto & building : buildList)
  96. {
  97. if (t->hasBuilt(building))
  98. continue;
  99. if (cb->canBuildStructure(t, building))
  100. return boost::optional<BuildingID>(building);
  101. }
  102. return boost::optional<BuildingID>(); //Can't build anything
  103. }
  104. bool BuildingManager::tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
  105. {
  106. for (const auto & building : buildList)
  107. {
  108. if (t->hasBuilt(building))
  109. continue;
  110. return tryBuildThisStructure(t, building, maxDays);
  111. }
  112. return false; //Nothing to build
  113. }
  114. void BuildingManager::setCB(CPlayerSpecificInfoCallback * CB)
  115. {
  116. cb = CB;
  117. }
  118. void BuildingManager::setAI(VCAI * AI)
  119. {
  120. ai = AI;
  121. }
  122. //Set of buildings for different goals. Does not include any prerequisites.
  123. static const BuildingID essential[] = { BuildingID::TAVERN, BuildingID::TOWN_HALL };
  124. static const BuildingID goldSource[] = { BuildingID::TOWN_HALL, BuildingID::CITY_HALL, BuildingID::CAPITOL };
  125. static const BuildingID capitolRequirements[] = { BuildingID::FORT, BuildingID::CITADEL };
  126. static const BuildingID unitsSource[] = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
  127. BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7 };
  128. static const BuildingID unitsUpgrade[] = { BuildingID::DWELL_LVL_1_UP, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP,
  129. BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP };
  130. static const BuildingID unitGrowth[] = { BuildingID::FORT, BuildingID::CITADEL, BuildingID::CASTLE, BuildingID::HORDE_1,
  131. BuildingID::HORDE_1_UPGR, BuildingID::HORDE_2, BuildingID::HORDE_2_UPGR };
  132. static const BuildingID _spells[] = { BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3,
  133. BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5 };
  134. static const BuildingID extra[] = { BuildingID::RESOURCE_SILO, BuildingID::SPECIAL_1, BuildingID::SPECIAL_2, BuildingID::SPECIAL_3,
  135. BuildingID::SPECIAL_4, BuildingID::SHIPYARD }; // all remaining buildings
  136. bool BuildingManager::getBuildingOptions(const CGTownInstance * t)
  137. {
  138. //TODO make *real* town development system
  139. //TODO: faction-specific development: use special buildings, build dwellings in better order, etc
  140. //TODO: build resource silo, defences when needed
  141. //Possible - allow "locking" on specific building (build prerequisites and then building itself)
  142. immediateBuildings.clear();
  143. expensiveBuildings.clear();
  144. //below algorithm focuses on economy growth at start of the game.
  145. TResources currentRes = cb->getResourceAmount();
  146. TResources currentIncome = t->dailyIncome();
  147. if (tryBuildAnyStructure(t, std::vector<BuildingID>(essential, essential + ARRAY_COUNT(essential))))
  148. return true;
  149. //the more gold the better and less problems later
  150. if (tryBuildNextStructure(t, std::vector<BuildingID>(goldSource, goldSource + ARRAY_COUNT(goldSource))))
  151. return true;
  152. //workaround for mantis #2696 - build fort and citadel - building castle will be handled without bug
  153. if (vstd::contains(t->builtBuildings, BuildingID::CITY_HALL) &&
  154. cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::HAVE_CAPITAL)
  155. {
  156. if (cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::FORBIDDEN)
  157. {
  158. if (tryBuildNextStructure(t, std::vector<BuildingID>(capitolRequirements,
  159. capitolRequirements + ARRAY_COUNT(capitolRequirements))))
  160. return true;
  161. }
  162. }
  163. //TODO: save money for capitol or city hall if capitol unavailable
  164. //do not build other things (unless gold source buildings are disabled in map editor)
  165. if (cb->getDate(Date::DAY_OF_WEEK) > 6) // last 2 days of week - try to focus on growth
  166. {
  167. if (tryBuildNextStructure(t, std::vector<BuildingID>(unitGrowth, unitGrowth + ARRAY_COUNT(unitGrowth)), 2))
  168. return true;
  169. }
  170. // first in-game week or second half of any week: try build dwellings
  171. if (cb->getDate(Date::DAY) < 7 || cb->getDate(Date::DAY_OF_WEEK) > 3)
  172. {
  173. if (tryBuildAnyStructure(t, std::vector<BuildingID>(unitsSource,
  174. unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK)))
  175. return true;
  176. }
  177. //try to upgrade dwelling
  178. for (int i = 0; i < ARRAY_COUNT(unitsUpgrade); i++)
  179. {
  180. if (t->hasBuilt(unitsSource[i]) && !t->hasBuilt(unitsUpgrade[i]))
  181. {
  182. if (tryBuildThisStructure(t, unitsUpgrade[i]))
  183. return true;
  184. }
  185. }
  186. //remaining tasks
  187. if (tryBuildNextStructure(t, std::vector<BuildingID>(_spells, _spells + ARRAY_COUNT(_spells))))
  188. return true;
  189. if (tryBuildAnyStructure(t, std::vector<BuildingID>(extra, extra + ARRAY_COUNT(extra))))
  190. return true;
  191. //at the end, try to get and build any extra buildings with nonstandard slots (for example HotA 3rd level dwelling)
  192. std::vector<BuildingID> extraBuildings;
  193. for (auto buildingInfo : t->town->buildings)
  194. {
  195. if (buildingInfo.first > 43)
  196. extraBuildings.push_back(buildingInfo.first);
  197. }
  198. if (tryBuildAnyStructure(t, extraBuildings))
  199. return true;
  200. return false;
  201. <<<<<<< HEAD
  202. =======
  203. >>>>>>> 079ea69b43b0faabece4e9703ee089eb34486ff2
  204. }
  205. boost::optional<PotentialBuilding> BuildingManager::immediateBuilding() const
  206. {
  207. if (immediateBuildings.size())
  208. return boost::optional<PotentialBuilding>(immediateBuildings.front()); //back? whatever
  209. else
  210. return boost::optional<PotentialBuilding>();
  211. }
  212. boost::optional<PotentialBuilding> BuildingManager::expensiveBuilding() const
  213. {
  214. if (expensiveBuildings.size())
  215. return boost::optional<PotentialBuilding>(expensiveBuildings.front());
  216. else
  217. return boost::optional<PotentialBuilding>();
  218. }
  219. <<<<<<< HEAD
  220. =======
  221. >>>>>>> 079ea69b43b0faabece4e9703ee089eb34486ff2