RandomMapTab.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*
  2. * RandomMapTab.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 "RandomMapTab.h"
  12. #include "CSelectionBase.h"
  13. #include "../CGameInfo.h"
  14. #include "../CServerHandler.h"
  15. #include "../gui/CAnimation.h"
  16. #include "../gui/CGuiHandler.h"
  17. #include "../widgets/CComponent.h"
  18. #include "../widgets/Buttons.h"
  19. #include "../widgets/MiscWidgets.h"
  20. #include "../widgets/ObjectLists.h"
  21. #include "../widgets/TextControls.h"
  22. #include "../windows/GUIClasses.h"
  23. #include "../windows/InfoWindows.h"
  24. #include "../../lib/CGeneralTextHandler.h"
  25. #include "../../lib/mapping/CMapInfo.h"
  26. #include "../../lib/rmg/CMapGenOptions.h"
  27. #include "../../lib/CModHandler.h"
  28. #include "../../lib/rmg/CRmgTemplateStorage.h"
  29. RandomMapTab::RandomMapTab():
  30. InterfaceObjectConfigurable()
  31. {
  32. recActions = 0;
  33. mapGenOptions = std::make_shared<CMapGenOptions>();
  34. const JsonNode config(ResourceID("config/windows/randomMapTab.json"));
  35. addCallback("toggleMapSize", [&](int btnId)
  36. {
  37. auto mapSizeVal = getPossibleMapSizes();
  38. mapGenOptions->setWidth(mapSizeVal[btnId]);
  39. mapGenOptions->setHeight(mapSizeVal[btnId]);
  40. updateMapInfoByHost();
  41. });
  42. addCallback("toggleTwoLevels", [&](bool on)
  43. {
  44. mapGenOptions->setHasTwoLevels(on);
  45. setTemplate(mapGenOptions->getMapTemplate());
  46. updateMapInfoByHost();
  47. });
  48. addCallback("setPlayersCount", [&](int btnId)
  49. {
  50. mapGenOptions->setPlayerCount(btnId);
  51. setMapGenOptions(mapGenOptions);
  52. //validatePlayersCnt(btnId);
  53. updateMapInfoByHost();
  54. });
  55. addCallback("setTeamsCount", [&](int btnId)
  56. {
  57. mapGenOptions->setTeamCount(btnId);
  58. updateMapInfoByHost();
  59. });
  60. addCallback("setCompOnlyPlayers", [&](int btnId)
  61. {
  62. mapGenOptions->setCompOnlyPlayerCount(btnId);
  63. setMapGenOptions(mapGenOptions);
  64. //validateCompOnlyPlayersCnt(btnId);
  65. updateMapInfoByHost();
  66. });
  67. addCallback("setCompOnlyTeams", [&](int btnId)
  68. {
  69. mapGenOptions->setCompOnlyTeamCount(btnId);
  70. updateMapInfoByHost();
  71. });
  72. addCallback("setWaterContent", [&](int btnId)
  73. {
  74. mapGenOptions->setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
  75. updateMapInfoByHost();
  76. });
  77. addCallback("setMonsterStrength", [&](int btnId)
  78. {
  79. if(btnId < 0)
  80. mapGenOptions->setMonsterStrength(EMonsterStrength::RANDOM);
  81. else
  82. mapGenOptions->setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId)); //value 2 to 4
  83. updateMapInfoByHost();
  84. });
  85. //new callbacks available only from mod
  86. addCallback("templateSelection", [&](int)
  87. {
  88. GH.pushInt(std::make_shared<TemplatesDropBox>(this));
  89. });
  90. init(config);
  91. updateMapInfoByHost();
  92. }
  93. void RandomMapTab::updateMapInfoByHost()
  94. {
  95. if(CSH->isGuest())
  96. return;
  97. // Generate header info
  98. mapInfo = std::make_shared<CMapInfo>();
  99. mapInfo->isRandomMap = true;
  100. mapInfo->mapHeader = make_unique<CMapHeader>();
  101. mapInfo->mapHeader->version = EMapFormat::SOD;
  102. mapInfo->mapHeader->name = CGI->generaltexth->allTexts[740];
  103. mapInfo->mapHeader->description = CGI->generaltexth->allTexts[741];
  104. mapInfo->mapHeader->difficulty = 1; // Normal
  105. mapInfo->mapHeader->height = mapGenOptions->getHeight();
  106. mapInfo->mapHeader->width = mapGenOptions->getWidth();
  107. mapInfo->mapHeader->twoLevel = mapGenOptions->getHasTwoLevels();
  108. // Generate player information
  109. mapInfo->mapHeader->players.clear();
  110. int playersToGen = PlayerColor::PLAYER_LIMIT_I;
  111. if(mapGenOptions->getPlayerCount() != CMapGenOptions::RANDOM_SIZE)
  112. {
  113. if(mapGenOptions->getCompOnlyPlayerCount() != CMapGenOptions::RANDOM_SIZE)
  114. playersToGen = mapGenOptions->getPlayerCount() + mapGenOptions->getCompOnlyPlayerCount();
  115. else
  116. playersToGen = mapGenOptions->getPlayerCount();
  117. }
  118. mapInfo->mapHeader->howManyTeams = playersToGen;
  119. for(int i = 0; i < playersToGen; ++i)
  120. {
  121. PlayerInfo player;
  122. player.isFactionRandom = true;
  123. player.canComputerPlay = true;
  124. if(mapGenOptions->getCompOnlyPlayerCount() != CMapGenOptions::RANDOM_SIZE && i >= mapGenOptions->getPlayerCount())
  125. {
  126. player.canHumanPlay = false;
  127. }
  128. else
  129. {
  130. player.canHumanPlay = true;
  131. }
  132. player.team = TeamID(i);
  133. player.hasMainTown = true;
  134. player.generateHeroAtMainTown = true;
  135. mapInfo->mapHeader->players.push_back(player);
  136. }
  137. mapInfoChanged(mapInfo, mapGenOptions);
  138. }
  139. void RandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
  140. {
  141. mapGenOptions = opts;
  142. //prepare allowed options
  143. for(int i = 0; i <= PlayerColor::PLAYER_LIMIT_I; ++i)
  144. {
  145. playerCountAllowed.insert(i);
  146. compCountAllowed.insert(i);
  147. playerTeamsAllowed.insert(i);
  148. compTeamsAllowed.insert(i);
  149. }
  150. auto * tmpl = mapGenOptions->getMapTemplate();
  151. if(tmpl)
  152. {
  153. playerCountAllowed = tmpl->getPlayers().getNumbers();
  154. compCountAllowed = tmpl->getCpuPlayers().getNumbers();
  155. }
  156. if(mapGenOptions->getPlayerCount() != CMapGenOptions::RANDOM_SIZE)
  157. {
  158. vstd::erase_if(compCountAllowed,
  159. [opts](int el){
  160. return PlayerColor::PLAYER_LIMIT_I - opts->getPlayerCount() < el;
  161. });
  162. vstd::erase_if(playerTeamsAllowed,
  163. [opts](int el){
  164. return PlayerColor::PLAYER_LIMIT_I - opts->getPlayerCount() < el + 1;
  165. });
  166. }
  167. if(mapGenOptions->getCompOnlyPlayerCount() != CMapGenOptions::RANDOM_SIZE)
  168. {
  169. vstd::erase_if(playerCountAllowed,
  170. [opts](int el){
  171. return PlayerColor::PLAYER_LIMIT_I - opts->getCompOnlyPlayerCount() < el;
  172. });
  173. vstd::erase_if(compTeamsAllowed,
  174. [opts](int el){
  175. return PlayerColor::PLAYER_LIMIT_I - opts->getCompOnlyPlayerCount() < el + 1;
  176. });
  177. }
  178. if(auto w = widget<CToggleGroup>("groupMapSize"))
  179. w->setSelected(vstd::find_pos(getPossibleMapSizes(), opts->getWidth()));
  180. if(auto w = widget<CToggleButton>("buttonTwoLevels"))
  181. w->setSelected(opts->getHasTwoLevels());
  182. if(auto w = widget<CToggleGroup>("groupMaxPlayers"))
  183. {
  184. w->setSelected(opts->getPlayerCount());
  185. deactivateButtonsFrom(*w, playerCountAllowed);
  186. }
  187. if(auto w = widget<CToggleGroup>("groupMaxTeams"))
  188. {
  189. w->setSelected(opts->getTeamCount());
  190. deactivateButtonsFrom(*w, playerCountAllowed);
  191. }
  192. if(auto w = widget<CToggleGroup>("groupCompOnlyPlayers"))
  193. {
  194. w->setSelected(opts->getCompOnlyPlayerCount());
  195. deactivateButtonsFrom(*w, playerTeamsAllowed);
  196. }
  197. if(auto w = widget<CToggleGroup>("groupCompOnlyTeams"))
  198. {
  199. w->setSelected(opts->getCompOnlyTeamCount());
  200. deactivateButtonsFrom(*w, compTeamsAllowed);
  201. }
  202. if(auto w = widget<CToggleGroup>("groupWaterContent"))
  203. {
  204. w->setSelected(opts->getWaterContent());
  205. if(opts->getMapTemplate())
  206. {
  207. std::set<int> allowedWater(opts->getMapTemplate()->getWaterContentAllowed().begin(), opts->getMapTemplate()->getWaterContentAllowed().end());
  208. deactivateButtonsFrom(*w, allowedWater);
  209. }
  210. else
  211. deactivateButtonsFrom(*w, {-1});
  212. }
  213. if(auto w = widget<CToggleGroup>("groupMonsterStrength"))
  214. w->setSelected(opts->getMonsterStrength());
  215. }
  216. void RandomMapTab::setTemplate(const CRmgTemplate * tmpl)
  217. {
  218. mapGenOptions->setMapTemplate(tmpl);
  219. setMapGenOptions(mapGenOptions);
  220. if(auto w = widget<CButton>("templateButton"))
  221. {
  222. if(tmpl)
  223. w->addTextOverlay(tmpl->getName(), EFonts::FONT_SMALL);
  224. else
  225. w->addTextOverlay("default", EFonts::FONT_SMALL);
  226. }
  227. updateMapInfoByHost();
  228. }
  229. void RandomMapTab::deactivateButtonsFrom(CToggleGroup & group, int startAllowed, int endAllowed)
  230. {
  231. logGlobal->debug("Blocking all buttons except %d - %d", startAllowed, endAllowed);
  232. for(auto toggle : group.buttons)
  233. {
  234. if(auto button = std::dynamic_pointer_cast<CToggleButton>(toggle.second))
  235. {
  236. if(toggle.first == CMapGenOptions::RANDOM_SIZE
  237. || (startAllowed == CMapGenOptions::RANDOM_SIZE && endAllowed == CMapGenOptions::RANDOM_SIZE)
  238. || (toggle.first >= startAllowed
  239. && (endAllowed == CMapGenOptions::RANDOM_SIZE || toggle.first <= endAllowed)))
  240. {
  241. //button->block(false);
  242. }
  243. else
  244. {
  245. button->block(true);
  246. }
  247. }
  248. }
  249. }
  250. void RandomMapTab::deactivateButtonsFrom(CToggleGroup & group, const std::set<int> & allowed)
  251. {
  252. logGlobal->debug("Blocking buttons");
  253. for(auto toggle : group.buttons)
  254. {
  255. if(auto button = std::dynamic_pointer_cast<CToggleButton>(toggle.second))
  256. {
  257. if(allowed.count(CMapGenOptions::RANDOM_SIZE)
  258. || allowed.count(toggle.first)
  259. || toggle.first == CMapGenOptions::RANDOM_SIZE)
  260. {
  261. button->block(false);
  262. }
  263. else
  264. {
  265. button->block(true);
  266. }
  267. }
  268. }
  269. }
  270. void RandomMapTab::validatePlayersCnt(int playersCnt)
  271. {
  272. if(playersCnt == CMapGenOptions::RANDOM_SIZE)
  273. {
  274. return;
  275. }
  276. /*if(mapGenOptions->getTeamCount() >= playersCnt)
  277. {
  278. mapGenOptions->setTeamCount(playersCnt - 1);
  279. if(auto w = widget<CToggleGroup>("groupMaxTeams"))
  280. w->setSelected(mapGenOptions->getTeamCount());
  281. }
  282. // total players should not exceed PlayerColor::PLAYER_LIMIT_I (8 in homm3)
  283. if(mapGenOptions->getCompOnlyPlayerCount() + playersCnt > PlayerColor::PLAYER_LIMIT_I)
  284. {
  285. mapGenOptions->setCompOnlyPlayerCount(PlayerColor::PLAYER_LIMIT_I - playersCnt);
  286. if(auto w = widget<CToggleGroup>("groupCompOnlyPlayers"))
  287. w->setSelected(mapGenOptions->getCompOnlyPlayerCount());
  288. }*/
  289. validateCompOnlyPlayersCnt(mapGenOptions->getCompOnlyPlayerCount());
  290. }
  291. void RandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
  292. {
  293. if(compOnlyPlayersCnt == CMapGenOptions::RANDOM_SIZE)
  294. {
  295. return;
  296. }
  297. /*if(mapGenOptions->getCompOnlyTeamCount() >= compOnlyPlayersCnt)
  298. {
  299. int compOnlyTeamCount = compOnlyPlayersCnt == 0 ? 0 : compOnlyPlayersCnt - 1;
  300. mapGenOptions->setCompOnlyTeamCount(compOnlyTeamCount);
  301. updateMapInfoByHost();
  302. if(auto w = widget<CToggleGroup>("groupCompOnlyTeams"))
  303. w->setSelected(compOnlyTeamCount);
  304. }*/
  305. }
  306. std::vector<int> RandomMapTab::getPossibleMapSizes()
  307. {
  308. return {CMapHeader::MAP_SIZE_SMALL, CMapHeader::MAP_SIZE_MIDDLE, CMapHeader::MAP_SIZE_LARGE, CMapHeader::MAP_SIZE_XLARGE, CMapHeader::MAP_SIZE_HUGE, CMapHeader::MAP_SIZE_XHUGE, CMapHeader::MAP_SIZE_GIANT};
  309. }
  310. TemplatesDropBox::ListItem::ListItem(TemplatesDropBox * _dropBox, Point position)
  311. : CIntObject(LCLICK | HOVER, position),
  312. dropBox(_dropBox)
  313. {
  314. OBJ_CONSTRUCTION;
  315. labelName = std::make_shared<CLabel>(0, 0, FONT_SMALL, EAlignment::TOPLEFT, Colors::WHITE);
  316. labelName->setAutoRedraw(false);
  317. hoverImage = std::make_shared<CPicture>("List10Sl", 0, 0);
  318. hoverImage->visible = false;
  319. pos.w = hoverImage->pos.w;
  320. pos.h = hoverImage->pos.h;
  321. type |= REDRAW_PARENT;
  322. }
  323. void TemplatesDropBox::ListItem::updateItem(int idx, const CRmgTemplate * _item)
  324. {
  325. item = _item;
  326. if(item)
  327. {
  328. labelName->setText(item->getName());
  329. }
  330. else
  331. {
  332. if(idx)
  333. labelName->setText("");
  334. else
  335. labelName->setText("default");
  336. }
  337. }
  338. void TemplatesDropBox::ListItem::hover(bool on)
  339. {
  340. if(labelName->getText().empty())
  341. {
  342. hovered = false;
  343. hoverImage->visible = false;
  344. }
  345. else
  346. {
  347. hoverImage->visible = on;
  348. }
  349. redraw();
  350. }
  351. void TemplatesDropBox::ListItem::clickLeft(tribool down, bool previousState)
  352. {
  353. if(down && hovered)
  354. {
  355. dropBox->setTemplate(item);
  356. }
  357. }
  358. TemplatesDropBox::TemplatesDropBox(RandomMapTab * randomMapTab):
  359. CIntObject(LCLICK | HOVER),
  360. randomMapTab(randomMapTab)
  361. {
  362. curItems = VLC->tplh->getTemplates();
  363. curItems.insert(curItems.begin(), nullptr); //default template
  364. OBJ_CONSTRUCTION;
  365. background = std::make_shared<CPicture>("List10Bk", 158, 76);
  366. int positionsToShow = 10;
  367. for(int i = 0; i < positionsToShow; i++)
  368. listItems.push_back(std::make_shared<ListItem>(this, Point(158, 76 + i * 25)));
  369. slider = std::make_shared<CSlider>(Point(212 + 158, 76), 252, std::bind(&TemplatesDropBox::sliderMove, this, _1), positionsToShow, (int)curItems.size(), 0, false, CSlider::BLUE);
  370. updateListItems();
  371. pos = background->pos;
  372. }
  373. void TemplatesDropBox::sliderMove(int slidPos)
  374. {
  375. if(!slider)
  376. return; // ignore spurious call when slider is being created
  377. updateListItems();
  378. redraw();
  379. }
  380. void TemplatesDropBox::hover(bool on)
  381. {
  382. hovered = on;
  383. }
  384. void TemplatesDropBox::clickLeft(tribool down, bool previousState)
  385. {
  386. if(down && !hovered)
  387. {
  388. assert(GH.topInt().get() == this);
  389. GH.popInt(GH.topInt());
  390. }
  391. }
  392. void TemplatesDropBox::updateListItems()
  393. {
  394. int elemIdx = slider->getValue();
  395. for(auto item : listItems)
  396. {
  397. if(elemIdx < curItems.size())
  398. {
  399. item->updateItem(elemIdx, curItems[elemIdx]);
  400. elemIdx++;
  401. }
  402. else
  403. {
  404. item->updateItem(elemIdx);
  405. }
  406. }
  407. }
  408. void TemplatesDropBox::setTemplate(const CRmgTemplate * tmpl)
  409. {
  410. randomMapTab->setTemplate(tmpl);
  411. assert(GH.topInt().get() == this);
  412. GH.popInt(GH.topInt());
  413. }