windownewmap.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * windownewmap.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 "../lib/mapping/CMap.h"
  12. #include "../lib/rmg/CRmgTemplateStorage.h"
  13. #include "../lib/rmg/CRmgTemplate.h"
  14. #include "../lib/rmg/CMapGenerator.h"
  15. #include "../lib/VCMI_Lib.h"
  16. #include "../lib/mapping/CMapEditManager.h"
  17. #include "../lib/mapping/MapFormat.h"
  18. #include "../lib/CGeneralTextHandler.h"
  19. #include "../lib/serializer/JsonSerializer.h"
  20. #include "../lib/serializer/JsonDeserializer.h"
  21. #include "jsonutils.h"
  22. #include "windownewmap.h"
  23. #include "ui_windownewmap.h"
  24. #include "mainwindow.h"
  25. #include "generatorprogress.h"
  26. WindowNewMap::WindowNewMap(QWidget *parent) :
  27. QDialog(parent),
  28. ui(new Ui::WindowNewMap)
  29. {
  30. ui->setupUi(this);
  31. setAttribute(Qt::WA_DeleteOnClose);
  32. setWindowModality(Qt::ApplicationModal);
  33. for(auto * combo : {ui->humanCombo, ui->cpuCombo, ui->humanTeamsCombo, ui->cpuTeamsCombo})
  34. combo->clear();
  35. //prepare human players combo box
  36. for(int i = 0; i <= PlayerColor::PLAYER_LIMIT_I; ++i)
  37. {
  38. ui->humanCombo->addItem(!i ? randomString : QString::number(players.at(i)));
  39. ui->humanCombo->setItemData(i, QVariant(players.at(i)));
  40. ui->cpuCombo->addItem(!i ? randomString : QString::number(cpuPlayers.at(i)));
  41. ui->cpuCombo->setItemData(i, QVariant(cpuPlayers.at(i)));
  42. ui->humanTeamsCombo->addItem(!i ? randomString : QString::number(cpuPlayers.at(i)));
  43. ui->humanTeamsCombo->setItemData(i, QVariant(cpuPlayers.at(i)));
  44. ui->cpuTeamsCombo->addItem(!i ? randomString : QString::number(cpuPlayers.at(i)));
  45. ui->cpuTeamsCombo->setItemData(i, QVariant(cpuPlayers.at(i)));
  46. }
  47. bool useLoaded = loadUserSettings();
  48. if (!useLoaded)
  49. {
  50. for(auto * combo : {ui->humanCombo, ui->cpuCombo, ui->humanTeamsCombo, ui->cpuTeamsCombo})
  51. combo->setCurrentIndex(0);
  52. }
  53. show();
  54. if (!useLoaded)
  55. {
  56. //setup initial parameters
  57. int width = ui->widthTxt->text().toInt();
  58. int height = ui->heightTxt->text().toInt();
  59. mapGenOptions.setWidth(width ? width : 1);
  60. mapGenOptions.setHeight(height ? height : 1);
  61. bool twoLevel = ui->twoLevelCheck->isChecked();
  62. mapGenOptions.setHasTwoLevels(twoLevel);
  63. updateTemplateList();
  64. }
  65. }
  66. WindowNewMap::~WindowNewMap()
  67. {
  68. delete ui;
  69. }
  70. bool WindowNewMap::loadUserSettings()
  71. {
  72. bool ret = false;
  73. CRmgTemplate * templ = nullptr;
  74. QSettings s(Ui::teamName, Ui::appName);
  75. auto generateRandom = s.value(newMapGenerateRandom);
  76. if (generateRandom.isValid())
  77. {
  78. ui->randomMapCheck->setChecked(generateRandom.toBool());
  79. }
  80. auto settings = s.value(newMapWindow);
  81. if (settings.isValid())
  82. {
  83. auto node = JsonUtils::toJson(settings);
  84. JsonDeserializer handler(nullptr, node);
  85. handler.serializeStruct("lastSettings", mapGenOptions);
  86. templ = const_cast<CRmgTemplate*>(mapGenOptions.getMapTemplate()); // Remember for later
  87. ui->widthTxt->setText(QString::number(mapGenOptions.getWidth()));
  88. ui->heightTxt->setText(QString::number(mapGenOptions.getHeight()));
  89. for(const auto & sz : mapSizes)
  90. {
  91. if(sz.second.first == mapGenOptions.getWidth() &&
  92. sz.second.second == mapGenOptions.getHeight())
  93. {
  94. ui->sizeCombo->setCurrentIndex(sz.first);
  95. break;
  96. }
  97. }
  98. ui->twoLevelCheck->setChecked(mapGenOptions.getHasTwoLevels());
  99. ui->humanCombo->setCurrentIndex(mapGenOptions.getHumanOrCpuPlayerCount());
  100. ui->cpuCombo->setCurrentIndex(mapGenOptions.getCompOnlyPlayerCount());
  101. ui->humanTeamsCombo->setCurrentIndex(mapGenOptions.getTeamCount());
  102. ui->cpuTeamsCombo->setCurrentIndex(mapGenOptions.getCompOnlyTeamCount());
  103. switch (mapGenOptions.getWaterContent())
  104. {
  105. case EWaterContent::RANDOM:
  106. ui->waterOpt1->setChecked(true); break;
  107. case EWaterContent::NONE:
  108. ui->waterOpt2->setChecked(true); break;
  109. case EWaterContent::NORMAL:
  110. ui->waterOpt3->setChecked(true); break;
  111. case EWaterContent::ISLANDS:
  112. ui->waterOpt4->setChecked(true); break;
  113. }
  114. switch (mapGenOptions.getMonsterStrength())
  115. {
  116. case EMonsterStrength::RANDOM:
  117. ui->monsterOpt1->setChecked(true); break;
  118. case EMonsterStrength::GLOBAL_WEAK:
  119. ui->monsterOpt2->setChecked(true); break;
  120. case EMonsterStrength::GLOBAL_NORMAL:
  121. ui->monsterOpt3->setChecked(true); break;
  122. case EMonsterStrength::GLOBAL_STRONG:
  123. ui->monsterOpt4->setChecked(true); break;
  124. }
  125. ret = true;
  126. }
  127. updateTemplateList();
  128. mapGenOptions.setMapTemplate(templ); // Can be null
  129. if (templ)
  130. {
  131. std::string name = templ->getName();
  132. for (size_t i = 0; i < ui->templateCombo->count(); i++)
  133. {
  134. if (ui->templateCombo->itemText(i).toStdString() == name)
  135. {
  136. ui->templateCombo->setCurrentIndex(i);
  137. break;
  138. }
  139. }
  140. ret = true;
  141. }
  142. return ret;
  143. }
  144. void WindowNewMap::saveUserSettings()
  145. {
  146. QSettings s(Ui::teamName, Ui::appName);
  147. JsonNode data;
  148. JsonSerializer ser(nullptr, data);
  149. ser.serializeStruct("lastSettings", mapGenOptions);
  150. auto variant = JsonUtils::toVariant(data);
  151. s.setValue(newMapWindow, variant);
  152. s.setValue(newMapGenerateRandom, ui->randomMapCheck->isChecked());
  153. }
  154. void WindowNewMap::on_cancelButton_clicked()
  155. {
  156. saveUserSettings();
  157. close();
  158. }
  159. void generateRandomMap(CMapGenerator & gen, MainWindow * window)
  160. {
  161. window->controller.setMap(gen.generate());
  162. }
  163. std::unique_ptr<CMap> generateEmptyMap(CMapGenOptions & options)
  164. {
  165. auto map = std::make_unique<CMap>(nullptr);
  166. map->version = EMapFormat::VCMI;
  167. map->creationDateTime = std::time(nullptr);
  168. map->width = options.getWidth();
  169. map->height = options.getHeight();
  170. map->twoLevel = options.getHasTwoLevels();
  171. map->initTerrain();
  172. map->getEditManager()->clearTerrain(&CRandomGenerator::getDefault());
  173. return map;
  174. }
  175. void WindowNewMap::on_okButton_clicked()
  176. {
  177. EWaterContent::EWaterContent water = EWaterContent::RANDOM;
  178. EMonsterStrength::EMonsterStrength monster = EMonsterStrength::RANDOM;
  179. if(ui->waterOpt1->isChecked())
  180. water = EWaterContent::RANDOM;
  181. if(ui->waterOpt2->isChecked())
  182. water = EWaterContent::NONE;
  183. if(ui->waterOpt3->isChecked())
  184. water = EWaterContent::NORMAL;
  185. if(ui->waterOpt4->isChecked())
  186. water = EWaterContent::ISLANDS;
  187. if(ui->monsterOpt1->isChecked())
  188. monster = EMonsterStrength::RANDOM;
  189. if(ui->monsterOpt2->isChecked())
  190. monster = EMonsterStrength::GLOBAL_WEAK;
  191. if(ui->monsterOpt3->isChecked())
  192. monster = EMonsterStrength::GLOBAL_NORMAL;
  193. if(ui->monsterOpt4->isChecked())
  194. monster = EMonsterStrength::GLOBAL_STRONG;
  195. mapGenOptions.setWaterContent(water);
  196. mapGenOptions.setMonsterStrength(monster);
  197. saveUserSettings();
  198. std::unique_ptr<CMap> nmap;
  199. if(ui->randomMapCheck->isChecked())
  200. {
  201. //verify map template
  202. if(mapGenOptions.getPossibleTemplates().empty())
  203. {
  204. QMessageBox::warning(this, tr("No template"), tr("No template for parameters specified. Random map cannot be generated."));
  205. return;
  206. }
  207. int seed = std::time(nullptr);
  208. if(ui->checkSeed->isChecked() && !ui->lineSeed->text().isEmpty())
  209. seed = ui->lineSeed->text().toInt();
  210. CMapGenerator generator(mapGenOptions, nullptr, seed);
  211. auto progressBarWnd = new GeneratorProgress(generator, this);
  212. progressBarWnd->show();
  213. try
  214. {
  215. auto f = std::async(std::launch::async, &CMapGenerator::generate, &generator);
  216. progressBarWnd->update();
  217. nmap = f.get();
  218. }
  219. catch(const std::exception & e)
  220. {
  221. QMessageBox::critical(this, tr("RMG failure"), e.what());
  222. }
  223. }
  224. else
  225. {
  226. auto f = std::async(std::launch::async, &::generateEmptyMap, std::ref(mapGenOptions));
  227. nmap = f.get();
  228. }
  229. nmap->mods = MapController::modAssessmentAll();
  230. static_cast<MainWindow*>(parent())->controller.setMap(std::move(nmap));
  231. static_cast<MainWindow*>(parent())->initializeMap(true);
  232. close();
  233. }
  234. void WindowNewMap::on_sizeCombo_activated(int index)
  235. {
  236. ui->widthTxt->setText(QString::number(mapSizes.at(index).first));
  237. ui->heightTxt->setText(QString::number(mapSizes.at(index).second));
  238. }
  239. void WindowNewMap::on_twoLevelCheck_stateChanged(int arg1)
  240. {
  241. bool twoLevel = ui->twoLevelCheck->isChecked();
  242. mapGenOptions.setHasTwoLevels(twoLevel);
  243. updateTemplateList();
  244. }
  245. void WindowNewMap::on_humanCombo_activated(int index)
  246. {
  247. int humans = ui->humanCombo->currentData().toInt();
  248. if(humans > PlayerColor::PLAYER_LIMIT_I)
  249. {
  250. humans = PlayerColor::PLAYER_LIMIT_I;
  251. ui->humanCombo->setCurrentIndex(humans);
  252. }
  253. mapGenOptions.setHumanOrCpuPlayerCount(humans);
  254. int teams = mapGenOptions.getTeamCount();
  255. if(teams > humans - 1)
  256. {
  257. teams = humans > 0 ? humans - 1 : CMapGenOptions::RANDOM_SIZE;
  258. ui->humanTeamsCombo->setCurrentIndex(teams + 1); //skip one element because first is random
  259. }
  260. int cpu = mapGenOptions.getCompOnlyPlayerCount();
  261. if(cpu > PlayerColor::PLAYER_LIMIT_I - humans)
  262. {
  263. cpu = PlayerColor::PLAYER_LIMIT_I - humans;
  264. ui->cpuCombo->setCurrentIndex(cpu + 1); //skip one element because first is random
  265. }
  266. int cpuTeams = mapGenOptions.getCompOnlyTeamCount(); //comp only players - 1
  267. if(cpuTeams > cpu - 1)
  268. {
  269. cpuTeams = cpu > 0 ? cpu - 1 : CMapGenOptions::RANDOM_SIZE;
  270. ui->cpuTeamsCombo->setCurrentIndex(cpuTeams + 1); //skip one element because first is random
  271. }
  272. updateTemplateList();
  273. }
  274. void WindowNewMap::on_cpuCombo_activated(int index)
  275. {
  276. int humans = mapGenOptions.getHumanOrCpuPlayerCount();
  277. int cpu = ui->cpuCombo->currentData().toInt();
  278. // FIXME: Use mapGenOption method only to calculate actual number of players for current template
  279. if(cpu > PlayerColor::PLAYER_LIMIT_I - humans)
  280. {
  281. cpu = PlayerColor::PLAYER_LIMIT_I - humans;
  282. ui->cpuCombo->setCurrentIndex(cpu + 1); //skip one element because first is random
  283. }
  284. mapGenOptions.setCompOnlyPlayerCount(cpu);
  285. int cpuTeams = mapGenOptions.getCompOnlyTeamCount(); //comp only players - 1
  286. if(cpuTeams > cpu - 1)
  287. {
  288. cpuTeams = cpu > 0 ? cpu - 1 : CMapGenOptions::RANDOM_SIZE;
  289. ui->cpuTeamsCombo->setCurrentIndex(cpuTeams + 1); //skip one element because first is random
  290. }
  291. updateTemplateList();
  292. }
  293. void WindowNewMap::on_randomMapCheck_stateChanged(int arg1)
  294. {
  295. randomMap = ui->randomMapCheck->isChecked();
  296. ui->templateCombo->setEnabled(randomMap);
  297. updateTemplateList();
  298. }
  299. void WindowNewMap::on_templateCombo_activated(int index)
  300. {
  301. if(index == 0)
  302. {
  303. mapGenOptions.setMapTemplate(nullptr);
  304. return;
  305. }
  306. auto * templ = data_cast<const CRmgTemplate>(ui->templateCombo->currentData().toLongLong());
  307. mapGenOptions.setMapTemplate(templ);
  308. }
  309. void WindowNewMap::on_widthTxt_textChanged(const QString &arg1)
  310. {
  311. int sz = arg1.toInt();
  312. if(sz > 1)
  313. {
  314. mapGenOptions.setWidth(arg1.toInt());
  315. updateTemplateList();
  316. }
  317. }
  318. void WindowNewMap::on_heightTxt_textChanged(const QString &arg1)
  319. {
  320. int sz = arg1.toInt();
  321. if(sz > 1)
  322. {
  323. mapGenOptions.setHeight(arg1.toInt());
  324. updateTemplateList();
  325. }
  326. }
  327. void WindowNewMap::updateTemplateList()
  328. {
  329. ui->templateCombo->clear();
  330. ui->templateCombo->setCurrentIndex(-1);
  331. if(!randomMap)
  332. return;
  333. mapGenOptions.setMapTemplate(nullptr);
  334. auto templates = mapGenOptions.getPossibleTemplates();
  335. if(templates.empty())
  336. return;
  337. ui->templateCombo->addItem("[default]", 0);
  338. for(auto * templ : templates)
  339. {
  340. ui->templateCombo->addItem(QString::fromStdString(templ->getName()), data_cast(templ));
  341. }
  342. ui->templateCombo->setCurrentIndex(0);
  343. }
  344. void WindowNewMap::on_checkSeed_toggled(bool checked)
  345. {
  346. ui->lineSeed->setEnabled(checked);
  347. }
  348. void WindowNewMap::on_humanTeamsCombo_activated(int index)
  349. {
  350. int humans = mapGenOptions.getHumanOrCpuPlayerCount();
  351. int teams = ui->humanTeamsCombo->currentData().toInt();
  352. if(teams >= humans)
  353. {
  354. teams = humans > 0 ? humans - 1 : CMapGenOptions::RANDOM_SIZE;
  355. ui->humanTeamsCombo->setCurrentIndex(teams + 1); //skip one element because first is random
  356. }
  357. mapGenOptions.setTeamCount(teams);
  358. updateTemplateList();
  359. }
  360. void WindowNewMap::on_cpuTeamsCombo_activated(int index)
  361. {
  362. int cpu = mapGenOptions.getCompOnlyPlayerCount();
  363. int cpuTeams = ui->cpuTeamsCombo->currentData().toInt();
  364. if(cpuTeams >= cpu)
  365. {
  366. cpuTeams = cpu > 0 ? cpu - 1 : CMapGenOptions::RANDOM_SIZE;
  367. ui->cpuTeamsCombo->setCurrentIndex(cpuTeams + 1); //skip one element because first is random
  368. }
  369. mapGenOptions.setCompOnlyTeamCount(cpuTeams);
  370. updateTemplateList();
  371. }