windownewmap.cpp 12 KB

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