CMapGenOptions.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #include "StdInc.h"
  2. #include "CMapGenOptions.h"
  3. #include "../GameConstants.h"
  4. #include "../CRandomGenerator.h"
  5. #include "../VCMI_Lib.h"
  6. #include "../CTownHandler.h"
  7. CMapGenOptions::CMapGenOptions() : width(72), height(72), hasTwoLevels(true),
  8. playersCnt(RANDOM_SIZE), teamsCnt(RANDOM_SIZE), compOnlyPlayersCnt(0), compOnlyTeamsCnt(RANDOM_SIZE),
  9. waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM)
  10. {
  11. }
  12. si32 CMapGenOptions::getWidth() const
  13. {
  14. return width;
  15. }
  16. void CMapGenOptions::setWidth(si32 value)
  17. {
  18. if(value > 0)
  19. {
  20. width = value;
  21. }
  22. else
  23. {
  24. throw std::runtime_error("A map width lower than 1 is not allowed.");
  25. }
  26. }
  27. si32 CMapGenOptions::getHeight() const
  28. {
  29. return height;
  30. }
  31. void CMapGenOptions::setHeight(si32 value)
  32. {
  33. if(value > 0)
  34. {
  35. height = value;
  36. }
  37. else
  38. {
  39. throw std::runtime_error("A map height lower than 1 is not allowed.");
  40. }
  41. }
  42. bool CMapGenOptions::getHasTwoLevels() const
  43. {
  44. return hasTwoLevels;
  45. }
  46. void CMapGenOptions::setHasTwoLevels(bool value)
  47. {
  48. hasTwoLevels = value;
  49. }
  50. si8 CMapGenOptions::getPlayersCnt() const
  51. {
  52. return playersCnt;
  53. }
  54. void CMapGenOptions::setPlayersCnt(si8 value)
  55. {
  56. if((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE)
  57. {
  58. playersCnt = value;
  59. resetPlayersMap();
  60. }
  61. else
  62. {
  63. throw std::runtime_error("Players count of RMG options should be between 1 and " +
  64. boost::lexical_cast<std::string>(PlayerColor::PLAYER_LIMIT) + " or CMapGenOptions::RANDOM_SIZE for random.");
  65. }
  66. }
  67. si8 CMapGenOptions::getTeamsCnt() const
  68. {
  69. return teamsCnt;
  70. }
  71. void CMapGenOptions::setTeamsCnt(si8 value)
  72. {
  73. if(playersCnt == RANDOM_SIZE || (value >= 0 && value < playersCnt) || value == RANDOM_SIZE)
  74. {
  75. teamsCnt = value;
  76. }
  77. else
  78. {
  79. throw std::runtime_error("Teams count of RMG options should be between 0 and <" +
  80. boost::lexical_cast<std::string>(playersCnt) + "(players count) - 1> or CMapGenOptions::RANDOM_SIZE for random.");
  81. }
  82. }
  83. si8 CMapGenOptions::getCompOnlyPlayersCnt() const
  84. {
  85. return compOnlyPlayersCnt;
  86. }
  87. void CMapGenOptions::setCompOnlyPlayersCnt(si8 value)
  88. {
  89. if(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playersCnt))
  90. {
  91. compOnlyPlayersCnt = value;
  92. resetPlayersMap();
  93. }
  94. else
  95. {
  96. throw std::runtime_error(std::string("Computer only players count of RMG options should be ") +
  97. "between 0 and <PlayerColor::PLAYER_LIMIT - " + boost::lexical_cast<std::string>(playersCnt) +
  98. "(playersCount)> or CMapGenOptions::RANDOM_SIZE for random.");
  99. }
  100. }
  101. si8 CMapGenOptions::getCompOnlyTeamsCnt() const
  102. {
  103. return compOnlyTeamsCnt;
  104. }
  105. void CMapGenOptions::setCompOnlyTeamsCnt(si8 value)
  106. {
  107. if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayersCnt - 1, 0)))
  108. {
  109. compOnlyTeamsCnt = value;
  110. }
  111. else
  112. {
  113. throw std::runtime_error(std::string("Computer only teams count of RMG options should be ") +
  114. "between 0 and <" + boost::lexical_cast<std::string>(compOnlyPlayersCnt) +
  115. "(compOnlyPlayersCnt) - 1> or CMapGenOptions::RANDOM_SIZE for random.");
  116. }
  117. }
  118. EWaterContent::EWaterContent CMapGenOptions::getWaterContent() const
  119. {
  120. return waterContent;
  121. }
  122. void CMapGenOptions::setWaterContent(EWaterContent::EWaterContent value)
  123. {
  124. waterContent = value;
  125. }
  126. EMonsterStrength::EMonsterStrength CMapGenOptions::getMonsterStrength() const
  127. {
  128. return monsterStrength;
  129. }
  130. void CMapGenOptions::setMonsterStrength(EMonsterStrength::EMonsterStrength value)
  131. {
  132. monsterStrength = value;
  133. }
  134. void CMapGenOptions::resetPlayersMap()
  135. {
  136. players.clear();
  137. int realPlayersCnt = playersCnt == RANDOM_SIZE ? PlayerColor::PLAYER_LIMIT_I : playersCnt;
  138. int realCompOnlyPlayersCnt = compOnlyPlayersCnt == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayersCnt;
  139. for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color)
  140. {
  141. CPlayerSettings player;
  142. player.setColor(PlayerColor(color));
  143. player.setPlayerType((color >= playersCnt) ? EPlayerType::COMP_ONLY : EPlayerType::AI);
  144. players[PlayerColor(color)] = player;
  145. }
  146. }
  147. const std::map<PlayerColor, CMapGenOptions::CPlayerSettings> & CMapGenOptions::getPlayersSettings() const
  148. {
  149. return players;
  150. }
  151. void CMapGenOptions::setStartingTownForPlayer(PlayerColor color, si32 town)
  152. {
  153. auto it = players.find(color);
  154. if(it == players.end()) throw std::runtime_error(boost::str(boost::format("Cannot set starting town for the player with the color '%i'.") % color));
  155. it->second.setStartingTown(town);
  156. }
  157. void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType)
  158. {
  159. auto it = players.find(color);
  160. if(it == players.end()) throw std::runtime_error(boost::str(boost::format("Cannot set player type for the player with the color '%i'.") % color));
  161. if(playerType == EPlayerType::COMP_ONLY) throw std::runtime_error("Cannot set player type computer only to a standard player.");
  162. it->second.setPlayerType(playerType);
  163. }
  164. void CMapGenOptions::finalize()
  165. {
  166. CRandomGenerator gen;
  167. finalize(gen);
  168. }
  169. void CMapGenOptions::finalize(CRandomGenerator & gen)
  170. {
  171. if(playersCnt == RANDOM_SIZE)
  172. {
  173. // 1 human is required at least
  174. auto humanPlayers = countHumanPlayers();
  175. if(humanPlayers == 0) humanPlayers = 1;
  176. playersCnt = gen.getInteger(humanPlayers, PlayerColor::PLAYER_LIMIT_I);
  177. // Remove AI players only from the end of the players map if necessary
  178. for(auto itrev = players.end(); itrev != players.begin();)
  179. {
  180. auto it = itrev;
  181. --it;
  182. if(players.size() == playersCnt) break;
  183. if(it->second.getPlayerType() == EPlayerType::AI)
  184. {
  185. players.erase(it);
  186. }
  187. else
  188. {
  189. --itrev;
  190. }
  191. }
  192. }
  193. if(teamsCnt == RANDOM_SIZE)
  194. {
  195. teamsCnt = gen.getInteger(0, playersCnt - 1);
  196. }
  197. if(compOnlyPlayersCnt == RANDOM_SIZE)
  198. {
  199. compOnlyPlayersCnt = gen.getInteger(0, 8 - playersCnt);
  200. auto totalPlayersCnt = playersCnt + compOnlyPlayersCnt;
  201. // Remove comp only players only from the end of the players map if necessary
  202. for(auto itrev = players.end(); itrev != players.begin();)
  203. {
  204. auto it = itrev;
  205. --it;
  206. if(players.size() <= totalPlayersCnt) break;
  207. if(it->second.getPlayerType() == EPlayerType::COMP_ONLY)
  208. {
  209. players.erase(it);
  210. }
  211. else
  212. {
  213. --itrev;
  214. }
  215. }
  216. // Add some comp only players if necessary
  217. auto compOnlyPlayersToAdd = totalPlayersCnt - players.size();
  218. for(int i = 0; i < compOnlyPlayersToAdd; ++i)
  219. {
  220. CPlayerSettings pSettings;
  221. pSettings.setPlayerType(EPlayerType::COMP_ONLY);
  222. pSettings.setColor(getNextPlayerColor());
  223. players[pSettings.getColor()] = pSettings;
  224. }
  225. }
  226. if(compOnlyTeamsCnt == RANDOM_SIZE)
  227. {
  228. compOnlyTeamsCnt = gen.getInteger(0, std::max(compOnlyPlayersCnt - 1, 0));
  229. }
  230. // There should be at least 2 players (1-player-maps aren't allowed)
  231. if(playersCnt + compOnlyPlayersCnt < 2)
  232. {
  233. CPlayerSettings pSettings;
  234. pSettings.setPlayerType(EPlayerType::AI);
  235. pSettings.setColor(getNextPlayerColor());
  236. players[pSettings.getColor()] = pSettings;
  237. playersCnt = 2;
  238. }
  239. // 1 team isn't allowed
  240. if(teamsCnt == 1 && compOnlyPlayersCnt == 0)
  241. {
  242. teamsCnt = 0;
  243. }
  244. if(waterContent == EWaterContent::RANDOM)
  245. {
  246. waterContent = static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2));
  247. }
  248. if(monsterStrength == EMonsterStrength::RANDOM)
  249. {
  250. monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2));
  251. }
  252. }
  253. int CMapGenOptions::countHumanPlayers() const
  254. {
  255. return static_cast<int>(boost::count_if(players, [](const std::pair<PlayerColor, CPlayerSettings> & pair)
  256. {
  257. return pair.second.getPlayerType() == EPlayerType::HUMAN;
  258. }));
  259. }
  260. PlayerColor CMapGenOptions::getNextPlayerColor() const
  261. {
  262. for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1))
  263. {
  264. if(!players.count(i))
  265. {
  266. return i;
  267. }
  268. }
  269. throw std::runtime_error("Shouldn't happen. No free player color exists.");
  270. }
  271. CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
  272. {
  273. }
  274. PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
  275. {
  276. return color;
  277. }
  278. void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
  279. {
  280. if(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT)
  281. {
  282. color = value;
  283. }
  284. else
  285. {
  286. throw std::runtime_error("The color of the player is not in a valid range.");
  287. }
  288. }
  289. si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
  290. {
  291. return startingTown;
  292. }
  293. void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
  294. {
  295. if(value >= -1 && value < static_cast<int>(VLC->townh->towns.size()))
  296. {
  297. startingTown = value;
  298. }
  299. else
  300. {
  301. throw std::runtime_error("The starting town of the player is not in a valid range.");
  302. }
  303. }
  304. EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
  305. {
  306. return playerType;
  307. }
  308. void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
  309. {
  310. playerType = value;
  311. }