mapsettings.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. /*
  2. * mapsettings.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 "mapsettings.h"
  11. #include "ui_mapsettings.h"
  12. #include "mainwindow.h"
  13. #include "../lib/CSkillHandler.h"
  14. #include "../lib/spells/CSpellHandler.h"
  15. #include "../lib/CArtHandler.h"
  16. #include "../lib/CHeroHandler.h"
  17. #include "../lib/CGeneralTextHandler.h"
  18. #include "../lib/mapObjects/CGHeroInstance.h"
  19. #include "../lib/mapObjects/MiscObjects.h"
  20. #include "../lib/StringConstants.h"
  21. #include "inspector/townbulidingswidget.h" //to convert BuildingID to string
  22. //parses date for lose condition (1m 1w 1d)
  23. int expiredDate(const QString & date)
  24. {
  25. int result = 0;
  26. for(auto component : date.split(" "))
  27. {
  28. int days = component.left(component.lastIndexOf('d')).toInt();
  29. int weeks = component.left(component.lastIndexOf('w')).toInt();
  30. int months = component.left(component.lastIndexOf('m')).toInt();
  31. result += days > 0 ? days - 1 : 0;
  32. result += (weeks > 0 ? weeks - 1 : 0) * 7;
  33. result += (months > 0 ? months - 1 : 0) * 28;
  34. }
  35. return result;
  36. }
  37. QString expiredDate(int date)
  38. {
  39. QString result;
  40. int m = date / 28;
  41. int w = (date % 28) / 7;
  42. int d = date % 7;
  43. if(m)
  44. result += QString::number(m) + "m";
  45. if(w)
  46. {
  47. if(!result.isEmpty())
  48. result += " ";
  49. result += QString::number(w) + "w";
  50. }
  51. if(d)
  52. {
  53. if(!result.isEmpty())
  54. result += " ";
  55. result += QString::number(d) + "d";
  56. }
  57. return result;
  58. }
  59. int3 posFromJson(const JsonNode & json)
  60. {
  61. return int3(json.Vector()[0].Integer(), json.Vector()[1].Integer(), json.Vector()[2].Integer());
  62. }
  63. std::vector<JsonNode> linearJsonArray(const JsonNode & json)
  64. {
  65. std::vector<JsonNode> result;
  66. if(json.getType() == JsonNode::JsonType::DATA_STRUCT)
  67. result.push_back(json);
  68. if(json.getType() == JsonNode::JsonType::DATA_VECTOR)
  69. {
  70. for(auto & node : json.Vector())
  71. {
  72. auto subvector = linearJsonArray(node);
  73. result.insert(result.end(), subvector.begin(), subvector.end());
  74. }
  75. }
  76. return result;
  77. }
  78. MapSettings::MapSettings(MapController & ctrl, QWidget *parent) :
  79. QDialog(parent),
  80. ui(new Ui::MapSettings),
  81. controller(ctrl)
  82. {
  83. ui->setupUi(this);
  84. assert(controller.map());
  85. ui->mapNameEdit->setText(tr(controller.map()->name.c_str()));
  86. ui->mapDescriptionEdit->setPlainText(tr(controller.map()->description.c_str()));
  87. show();
  88. for(int i = 0; i < controller.map()->allowedAbilities.size(); ++i)
  89. {
  90. auto * item = new QListWidgetItem(QString::fromStdString(VLC->skillh->objects[i]->getNameTranslated()));
  91. item->setData(Qt::UserRole, QVariant::fromValue(i));
  92. item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
  93. item->setCheckState(controller.map()->allowedAbilities[i] ? Qt::Checked : Qt::Unchecked);
  94. ui->listAbilities->addItem(item);
  95. }
  96. for(int i = 0; i < controller.map()->allowedSpell.size(); ++i)
  97. {
  98. auto * item = new QListWidgetItem(QString::fromStdString(VLC->spellh->objects[i]->getNameTranslated()));
  99. item->setData(Qt::UserRole, QVariant::fromValue(i));
  100. item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
  101. item->setCheckState(controller.map()->allowedSpell[i] ? Qt::Checked : Qt::Unchecked);
  102. ui->listSpells->addItem(item);
  103. }
  104. for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
  105. {
  106. auto * item = new QListWidgetItem(QString::fromStdString(VLC->arth->objects[i]->getNameTranslated()));
  107. item->setData(Qt::UserRole, QVariant::fromValue(i));
  108. item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
  109. item->setCheckState(controller.map()->allowedArtifact[i] ? Qt::Checked : Qt::Unchecked);
  110. ui->listArts->addItem(item);
  111. }
  112. for(int i = 0; i < controller.map()->allowedHeroes.size(); ++i)
  113. {
  114. auto * item = new QListWidgetItem(QString::fromStdString(VLC->heroh->objects[i]->getNameTranslated()));
  115. item->setData(Qt::UserRole, QVariant::fromValue(i));
  116. item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
  117. item->setCheckState(controller.map()->allowedHeroes[i] ? Qt::Checked : Qt::Unchecked);
  118. ui->listHeroes->addItem(item);
  119. }
  120. //set difficulty
  121. switch(controller.map()->difficulty)
  122. {
  123. case 0:
  124. ui->diffRadio1->setChecked(true);
  125. break;
  126. case 1:
  127. ui->diffRadio2->setChecked(true);
  128. break;
  129. case 2:
  130. ui->diffRadio3->setChecked(true);
  131. break;
  132. case 3:
  133. ui->diffRadio4->setChecked(true);
  134. break;
  135. case 4:
  136. ui->diffRadio5->setChecked(true);
  137. break;
  138. };
  139. //victory & loss messages
  140. ui->victoryMessageEdit->setText(QString::fromStdString(controller.map()->victoryMessage));
  141. ui->defeatMessageEdit->setText(QString::fromStdString(controller.map()->defeatMessage));
  142. //victory & loss conditions
  143. const std::array<std::string, 8> conditionStringsWin = {
  144. QT_TR_NOOP("No special victory"),
  145. QT_TR_NOOP("Have artifact"),
  146. QT_TR_NOOP("Have creatures"),
  147. QT_TR_NOOP("Have resources"),
  148. QT_TR_NOOP("Have building"),
  149. QT_TR_NOOP("Capture city"),
  150. QT_TR_NOOP("Beat hero"),
  151. QT_TR_NOOP("Transport artifact")
  152. };
  153. const std::array<std::string, 5> conditionStringsLose = {
  154. QT_TR_NOOP("No special loss"),
  155. QT_TR_NOOP("Lose castle"),
  156. QT_TR_NOOP("Lose hero"),
  157. QT_TR_NOOP("Time expired"),
  158. QT_TR_NOOP("Days without town")
  159. };
  160. for(auto & s : conditionStringsWin)
  161. {
  162. ui->victoryComboBox->addItem(QString::fromStdString(s));
  163. }
  164. ui->standardVictoryCheck->setChecked(false);
  165. ui->onlyForHumansCheck->setChecked(false);
  166. for(auto & s : conditionStringsLose)
  167. {
  168. ui->loseComboBox->addItem(QString::fromStdString(s));
  169. }
  170. ui->standardLoseCheck->setChecked(false);
  171. auto conditionToJson = [](const EventCondition & event) -> JsonNode
  172. {
  173. JsonNode result;
  174. result["condition"].Integer() = event.condition;
  175. result["value"].Integer() = event.value;
  176. result["objectType"].Integer() = event.objectType;
  177. result["objectSubytype"].Integer() = event.objectSubtype;
  178. result["objectInstanceName"].String() = event.objectInstanceName;
  179. result["metaType"].Integer() = (ui8)event.metaType;
  180. {
  181. auto & position = result["position"].Vector();
  182. position.resize(3);
  183. position[0].Float() = event.position.x;
  184. position[1].Float() = event.position.y;
  185. position[2].Float() = event.position.z;
  186. }
  187. return result;
  188. };
  189. for(auto & ev : controller.map()->triggeredEvents)
  190. {
  191. if(ev.effect.type == EventEffect::VICTORY)
  192. {
  193. if(ev.identifier == "standardVictory")
  194. ui->standardVictoryCheck->setChecked(true);
  195. if(ev.identifier == "specialVictory")
  196. {
  197. auto readjson = ev.trigger.toJson(conditionToJson);
  198. auto linearNodes = linearJsonArray(readjson);
  199. for(auto & json : linearNodes)
  200. {
  201. switch(json["condition"].Integer())
  202. {
  203. case EventCondition::HAVE_ARTIFACT: {
  204. ui->victoryComboBox->setCurrentIndex(1);
  205. assert(victoryTypeWidget);
  206. victoryTypeWidget->setCurrentIndex(json["objectType"].Integer());
  207. break;
  208. }
  209. case EventCondition::HAVE_CREATURES: {
  210. ui->victoryComboBox->setCurrentIndex(2);
  211. assert(victoryTypeWidget);
  212. assert(victoryValueWidget);
  213. auto idx = victoryTypeWidget->findData(int(json["objectType"].Integer()));
  214. victoryTypeWidget->setCurrentIndex(idx);
  215. victoryValueWidget->setText(QString::number(json["value"].Integer()));
  216. break;
  217. }
  218. case EventCondition::HAVE_RESOURCES: {
  219. ui->victoryComboBox->setCurrentIndex(3);
  220. assert(victoryTypeWidget);
  221. assert(victoryValueWidget);
  222. auto idx = victoryTypeWidget->findData(int(json["objectType"].Integer()));
  223. victoryTypeWidget->setCurrentIndex(idx);
  224. victoryValueWidget->setText(QString::number(json["value"].Integer()));
  225. break;
  226. }
  227. case EventCondition::HAVE_BUILDING: {
  228. ui->victoryComboBox->setCurrentIndex(4);
  229. assert(victoryTypeWidget);
  230. assert(victorySelectWidget);
  231. auto idx = victoryTypeWidget->findData(int(json["objectType"].Integer()));
  232. victoryTypeWidget->setCurrentIndex(idx);
  233. int townIdx = getObjectByPos<CGTownInstance>(posFromJson(json["position"]));
  234. if(townIdx >= 0)
  235. {
  236. auto idx = victorySelectWidget->findData(townIdx);
  237. victorySelectWidget->setCurrentIndex(idx);
  238. }
  239. break;
  240. }
  241. case EventCondition::CONTROL: {
  242. ui->victoryComboBox->setCurrentIndex(5);
  243. assert(victoryTypeWidget);
  244. if(json["objectType"].Integer() == Obj::TOWN)
  245. {
  246. int townIdx = getObjectByPos<CGTownInstance>(posFromJson(json["position"]));
  247. if(townIdx >= 0)
  248. {
  249. auto idx = victoryTypeWidget->findData(townIdx);
  250. victoryTypeWidget->setCurrentIndex(idx);
  251. }
  252. }
  253. //TODO: support control other objects (dwellings, mines)
  254. break;
  255. }
  256. case EventCondition::DESTROY: {
  257. ui->victoryComboBox->setCurrentIndex(6);
  258. assert(victoryTypeWidget);
  259. if(json["objectType"].Integer() == Obj::HERO)
  260. {
  261. int heroIdx = getObjectByPos<CGHeroInstance>(posFromJson(json["position"]));
  262. if(heroIdx >= 0)
  263. {
  264. auto idx = victoryTypeWidget->findData(heroIdx);
  265. victoryTypeWidget->setCurrentIndex(idx);
  266. }
  267. }
  268. //TODO: support control other objects (monsters)
  269. break;
  270. }
  271. case EventCondition::TRANSPORT: {
  272. ui->victoryComboBox->setCurrentIndex(7);
  273. assert(victoryTypeWidget);
  274. assert(victorySelectWidget);
  275. victoryTypeWidget->setCurrentIndex(json["objectType"].Integer());
  276. int townIdx = getObjectByPos<CGTownInstance>(posFromJson(json["position"]));
  277. if(townIdx >= 0)
  278. {
  279. auto idx = victorySelectWidget->findData(townIdx);
  280. victorySelectWidget->setCurrentIndex(idx);
  281. }
  282. break;
  283. }
  284. case EventCondition::IS_HUMAN: {
  285. ui->onlyForHumansCheck->setChecked(true);
  286. break;
  287. }
  288. };
  289. }
  290. }
  291. }
  292. if(ev.effect.type == EventEffect::DEFEAT)
  293. {
  294. if(ev.identifier == "standardDefeat")
  295. ui->standardLoseCheck->setChecked(true);
  296. if(ev.identifier == "specialDefeat")
  297. {
  298. auto readjson = ev.trigger.toJson(conditionToJson);
  299. auto linearNodes = linearJsonArray(readjson);
  300. for(auto & json : linearNodes)
  301. {
  302. switch(json["condition"].Integer())
  303. {
  304. case EventCondition::CONTROL: {
  305. if(json["objectType"].Integer() == Obj::TOWN)
  306. {
  307. ui->loseComboBox->setCurrentIndex(1);
  308. assert(loseTypeWidget);
  309. int townIdx = getObjectByPos<CGTownInstance>(posFromJson(json["position"]));
  310. if(townIdx >= 0)
  311. {
  312. auto idx = loseTypeWidget->findData(townIdx);
  313. loseTypeWidget->setCurrentIndex(idx);
  314. }
  315. }
  316. if(json["objectType"].Integer() == Obj::HERO)
  317. {
  318. ui->loseComboBox->setCurrentIndex(2);
  319. assert(loseTypeWidget);
  320. int heroIdx = getObjectByPos<CGHeroInstance>(posFromJson(json["position"]));
  321. if(heroIdx >= 0)
  322. {
  323. auto idx = loseTypeWidget->findData(heroIdx);
  324. loseTypeWidget->setCurrentIndex(idx);
  325. }
  326. }
  327. break;
  328. }
  329. case EventCondition::DAYS_PASSED: {
  330. ui->loseComboBox->setCurrentIndex(3);
  331. assert(loseValueWidget);
  332. loseValueWidget->setText(expiredDate(json["value"].Integer()));
  333. break;
  334. }
  335. case EventCondition::DAYS_WITHOUT_TOWN: {
  336. ui->loseComboBox->setCurrentIndex(4);
  337. assert(loseValueWidget);
  338. loseValueWidget->setText(QString::number(json["value"].Integer()));
  339. break;
  340. case EventCondition::IS_HUMAN:
  341. break; //ignore because always applicable for defeat conditions
  342. }
  343. };
  344. }
  345. }
  346. }
  347. }
  348. }
  349. MapSettings::~MapSettings()
  350. {
  351. delete ui;
  352. }
  353. std::string MapSettings::getTownName(int townObjectIdx)
  354. {
  355. std::string name;
  356. if(auto town = dynamic_cast<CGTownInstance*>(controller.map()->objects[townObjectIdx].get()))
  357. {
  358. auto * ctown = town->town;
  359. if(!ctown)
  360. ctown = VLC->townh->randomTown;
  361. name = ctown->faction ? town->getObjectName() : town->getNameTranslated() + ", (random)";
  362. }
  363. return name;
  364. }
  365. std::string MapSettings::getHeroName(int townObjectIdx)
  366. {
  367. std::string name;
  368. if(auto hero = dynamic_cast<CGHeroInstance*>(controller.map()->objects[townObjectIdx].get()))
  369. {
  370. name = hero->getNameTranslated();
  371. }
  372. return name;
  373. }
  374. std::string MapSettings::getMonsterName(int monsterObjectIdx)
  375. {
  376. std::string name;
  377. if(auto monster = dynamic_cast<CGCreature*>(controller.map()->objects[monsterObjectIdx].get()))
  378. {
  379. //TODO: get proper name
  380. //name = hero->name;
  381. MAYBE_UNUSED(monster);
  382. }
  383. return name;
  384. }
  385. void MapSettings::on_pushButton_clicked()
  386. {
  387. controller.map()->name = ui->mapNameEdit->text().toStdString();
  388. controller.map()->description = ui->mapDescriptionEdit->toPlainText().toStdString();
  389. controller.commitChangeWithoutRedraw();
  390. for(int i = 0; i < controller.map()->allowedAbilities.size(); ++i)
  391. {
  392. auto * item = ui->listAbilities->item(i);
  393. controller.map()->allowedAbilities[i] = item->checkState() == Qt::Checked;
  394. }
  395. for(int i = 0; i < controller.map()->allowedSpell.size(); ++i)
  396. {
  397. auto * item = ui->listSpells->item(i);
  398. controller.map()->allowedSpell[i] = item->checkState() == Qt::Checked;
  399. }
  400. for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
  401. {
  402. auto * item = ui->listArts->item(i);
  403. controller.map()->allowedArtifact[i] = item->checkState() == Qt::Checked;
  404. }
  405. for(int i = 0; i < controller.map()->allowedHeroes.size(); ++i)
  406. {
  407. auto * item = ui->listHeroes->item(i);
  408. controller.map()->allowedHeroes[i] = item->checkState() == Qt::Checked;
  409. }
  410. //set difficulty
  411. if(ui->diffRadio1->isChecked()) controller.map()->difficulty = 0;
  412. if(ui->diffRadio2->isChecked()) controller.map()->difficulty = 1;
  413. if(ui->diffRadio3->isChecked()) controller.map()->difficulty = 2;
  414. if(ui->diffRadio4->isChecked()) controller.map()->difficulty = 3;
  415. if(ui->diffRadio5->isChecked()) controller.map()->difficulty = 4;
  416. //victory & loss messages
  417. controller.map()->victoryMessage = ui->victoryMessageEdit->text().toStdString();
  418. controller.map()->defeatMessage = ui->defeatMessageEdit->text().toStdString();
  419. //victory & loss conditions
  420. EventCondition victoryCondition(EventCondition::STANDARD_WIN);
  421. EventCondition defeatCondition(EventCondition::DAYS_WITHOUT_TOWN);
  422. defeatCondition.value = 7;
  423. //Victory condition - defeat all
  424. TriggeredEvent standardVictory;
  425. standardVictory.effect.type = EventEffect::VICTORY;
  426. standardVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[5];
  427. standardVictory.identifier = "standardVictory";
  428. standardVictory.description.clear(); // TODO: display in quest window
  429. standardVictory.onFulfill = VLC->generaltexth->allTexts[659];
  430. standardVictory.trigger = EventExpression(victoryCondition);
  431. //Loss condition - 7 days without town
  432. TriggeredEvent standardDefeat;
  433. standardDefeat.effect.type = EventEffect::DEFEAT;
  434. standardDefeat.effect.toOtherMessage = VLC->generaltexth->allTexts[8];
  435. standardDefeat.identifier = "standardDefeat";
  436. standardDefeat.description.clear(); // TODO: display in quest window
  437. standardDefeat.onFulfill = VLC->generaltexth->allTexts[7];
  438. standardDefeat.trigger = EventExpression(defeatCondition);
  439. controller.map()->triggeredEvents.clear();
  440. //VICTORY
  441. if(ui->victoryComboBox->currentIndex() == 0)
  442. {
  443. controller.map()->triggeredEvents.push_back(standardVictory);
  444. controller.map()->victoryIconIndex = 11;
  445. controller.map()->victoryMessage = VLC->generaltexth->victoryConditions[0];
  446. }
  447. else
  448. {
  449. int vicCondition = ui->victoryComboBox->currentIndex() - 1;
  450. TriggeredEvent specialVictory;
  451. specialVictory.effect.type = EventEffect::VICTORY;
  452. specialVictory.identifier = "specialVictory";
  453. specialVictory.description.clear(); // TODO: display in quest window
  454. controller.map()->victoryIconIndex = vicCondition;
  455. controller.map()->victoryMessage = VLC->generaltexth->victoryConditions[size_t(vicCondition) + 1];
  456. switch(vicCondition)
  457. {
  458. case 0: {
  459. EventCondition cond(EventCondition::HAVE_ARTIFACT);
  460. assert(victoryTypeWidget);
  461. cond.objectType = victoryTypeWidget->currentData().toInt();
  462. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[281];
  463. specialVictory.onFulfill = VLC->generaltexth->allTexts[280];
  464. specialVictory.trigger = EventExpression(cond);
  465. break;
  466. }
  467. case 1: {
  468. EventCondition cond(EventCondition::HAVE_CREATURES);
  469. assert(victoryTypeWidget);
  470. cond.objectType = victoryTypeWidget->currentData().toInt();
  471. cond.value = victoryValueWidget->text().toInt();
  472. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[277];
  473. specialVictory.onFulfill = VLC->generaltexth->allTexts[276];
  474. specialVictory.trigger = EventExpression(cond);
  475. break;
  476. }
  477. case 2: {
  478. EventCondition cond(EventCondition::HAVE_RESOURCES);
  479. assert(victoryTypeWidget);
  480. cond.objectType = victoryTypeWidget->currentData().toInt();
  481. cond.value = victoryValueWidget->text().toInt();
  482. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[279];
  483. specialVictory.onFulfill = VLC->generaltexth->allTexts[278];
  484. specialVictory.trigger = EventExpression(cond);
  485. break;
  486. }
  487. case 3: {
  488. EventCondition cond(EventCondition::HAVE_BUILDING);
  489. assert(victoryTypeWidget);
  490. cond.objectType = victoryTypeWidget->currentData().toInt();
  491. int townIdx = victorySelectWidget->currentData().toInt();
  492. if(townIdx > -1)
  493. cond.position = controller.map()->objects[townIdx]->pos;
  494. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[283];
  495. specialVictory.onFulfill = VLC->generaltexth->allTexts[282];
  496. specialVictory.trigger = EventExpression(cond);
  497. break;
  498. }
  499. case 4: {
  500. EventCondition cond(EventCondition::CONTROL);
  501. assert(victoryTypeWidget);
  502. cond.objectType = Obj::TOWN;
  503. int townIdx = victoryTypeWidget->currentData().toInt();
  504. cond.position = controller.map()->objects[townIdx]->pos;
  505. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[250];
  506. specialVictory.onFulfill = VLC->generaltexth->allTexts[249];
  507. specialVictory.trigger = EventExpression(cond);
  508. break;
  509. }
  510. case 5: {
  511. EventCondition cond(EventCondition::DESTROY);
  512. assert(victoryTypeWidget);
  513. cond.objectType = Obj::HERO;
  514. int heroIdx = victoryTypeWidget->currentData().toInt();
  515. cond.position = controller.map()->objects[heroIdx]->pos;
  516. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[253];
  517. specialVictory.onFulfill = VLC->generaltexth->allTexts[252];
  518. specialVictory.trigger = EventExpression(cond);
  519. break;
  520. }
  521. case 6: {
  522. EventCondition cond(EventCondition::TRANSPORT);
  523. assert(victoryTypeWidget);
  524. cond.objectType = victoryTypeWidget->currentData().toInt();
  525. int townIdx = victorySelectWidget->currentData().toInt();
  526. if(townIdx > -1)
  527. cond.position = controller.map()->objects[townIdx]->pos;
  528. specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[293];
  529. specialVictory.onFulfill = VLC->generaltexth->allTexts[292];
  530. specialVictory.trigger = EventExpression(cond);
  531. break;
  532. }
  533. }
  534. // if condition is human-only turn it into following construction: AllOf(human, condition)
  535. if(ui->onlyForHumansCheck->isChecked())
  536. {
  537. EventExpression::OperatorAll oper;
  538. EventCondition notAI(EventCondition::IS_HUMAN);
  539. notAI.value = 1;
  540. oper.expressions.push_back(notAI);
  541. oper.expressions.push_back(specialVictory.trigger.get());
  542. specialVictory.trigger = EventExpression(oper);
  543. }
  544. // if normal victory allowed - add one more quest
  545. if(ui->standardVictoryCheck->isChecked())
  546. {
  547. controller.map()->victoryMessage += " / ";
  548. controller.map()->victoryMessage += VLC->generaltexth->victoryConditions[0];
  549. controller.map()->triggeredEvents.push_back(standardVictory);
  550. }
  551. controller.map()->triggeredEvents.push_back(specialVictory);
  552. }
  553. //DEFEAT
  554. if(ui->loseComboBox->currentIndex() == 0)
  555. {
  556. controller.map()->triggeredEvents.push_back(standardDefeat);
  557. controller.map()->defeatIconIndex = 3;
  558. controller.map()->defeatMessage = VLC->generaltexth->lossCondtions[0];
  559. }
  560. else
  561. {
  562. int lossCondition = ui->loseComboBox->currentIndex() - 1;
  563. TriggeredEvent specialDefeat;
  564. specialDefeat.effect.type = EventEffect::DEFEAT;
  565. specialDefeat.identifier = "specialDefeat";
  566. specialDefeat.description.clear(); // TODO: display in quest window
  567. controller.map()->defeatIconIndex = lossCondition;
  568. controller.map()->defeatMessage = VLC->generaltexth->lossCondtions[size_t(lossCondition) + 1];
  569. switch(lossCondition)
  570. {
  571. case 0: {
  572. EventExpression::OperatorNone noneOf;
  573. EventCondition cond(EventCondition::CONTROL);
  574. cond.objectType = Obj::TOWN;
  575. assert(loseTypeWidget);
  576. int townIdx = loseTypeWidget->currentData().toInt();
  577. cond.position = controller.map()->objects[townIdx]->pos;
  578. noneOf.expressions.push_back(cond);
  579. specialDefeat.onFulfill = VLC->generaltexth->allTexts[251];
  580. specialDefeat.trigger = EventExpression(noneOf);
  581. break;
  582. }
  583. case 1: {
  584. EventExpression::OperatorNone noneOf;
  585. EventCondition cond(EventCondition::CONTROL);
  586. cond.objectType = Obj::HERO;
  587. assert(loseTypeWidget);
  588. int townIdx = loseTypeWidget->currentData().toInt();
  589. cond.position = controller.map()->objects[townIdx]->pos;
  590. noneOf.expressions.push_back(cond);
  591. specialDefeat.onFulfill = VLC->generaltexth->allTexts[253];
  592. specialDefeat.trigger = EventExpression(noneOf);
  593. break;
  594. }
  595. case 2: {
  596. EventCondition cond(EventCondition::DAYS_PASSED);
  597. assert(loseValueWidget);
  598. cond.value = expiredDate(loseValueWidget->text());
  599. specialDefeat.onFulfill = VLC->generaltexth->allTexts[254];
  600. specialDefeat.trigger = EventExpression(cond);
  601. break;
  602. }
  603. case 3: {
  604. EventCondition cond(EventCondition::DAYS_WITHOUT_TOWN);
  605. assert(loseValueWidget);
  606. cond.value = loseValueWidget->text().toInt();
  607. specialDefeat.onFulfill = VLC->generaltexth->allTexts[7];
  608. specialDefeat.trigger = EventExpression(cond);
  609. break;
  610. }
  611. }
  612. EventExpression::OperatorAll allOf;
  613. EventCondition isHuman(EventCondition::IS_HUMAN);
  614. isHuman.value = 1;
  615. allOf.expressions.push_back(specialDefeat.trigger.get());
  616. allOf.expressions.push_back(isHuman);
  617. specialDefeat.trigger = EventExpression(allOf);
  618. if(ui->standardLoseCheck->isChecked())
  619. {
  620. controller.map()->triggeredEvents.push_back(standardDefeat);
  621. }
  622. controller.map()->triggeredEvents.push_back(specialDefeat);
  623. }
  624. close();
  625. }
  626. void MapSettings::on_victoryComboBox_currentIndexChanged(int index)
  627. {
  628. delete victoryTypeWidget;
  629. delete victoryValueWidget;
  630. delete victorySelectWidget;
  631. victoryTypeWidget = nullptr;
  632. victoryValueWidget = nullptr;
  633. victorySelectWidget = nullptr;
  634. if(index == 0)
  635. {
  636. ui->standardVictoryCheck->setChecked(true);
  637. ui->standardVictoryCheck->setEnabled(false);
  638. ui->onlyForHumansCheck->setChecked(false);
  639. ui->onlyForHumansCheck->setEnabled(false);
  640. return;
  641. }
  642. ui->onlyForHumansCheck->setEnabled(true);
  643. ui->standardVictoryCheck->setEnabled(true);
  644. int vicCondition = index - 1;
  645. switch(vicCondition)
  646. {
  647. case 0: { //EventCondition::HAVE_ARTIFACT
  648. victoryTypeWidget = new QComboBox;
  649. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  650. for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
  651. victoryTypeWidget->addItem(QString::fromStdString(VLC->arth->objects[i]->getNameTranslated()), QVariant::fromValue(i));
  652. break;
  653. }
  654. case 1: { //EventCondition::HAVE_CREATURES
  655. victoryTypeWidget = new QComboBox;
  656. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  657. for(int i = 0; i < VLC->creh->objects.size(); ++i)
  658. victoryTypeWidget->addItem(QString::fromStdString(VLC->creh->objects[i]->getNamePluralTranslated()), QVariant::fromValue(i));
  659. victoryValueWidget = new QLineEdit;
  660. ui->victoryParamsLayout->addWidget(victoryValueWidget);
  661. victoryValueWidget->setText("1");
  662. break;
  663. }
  664. case 2: { //EventCondition::HAVE_RESOURCES
  665. victoryTypeWidget = new QComboBox;
  666. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  667. {
  668. for(int resType = 0; resType < GameConstants::RESOURCE_QUANTITY; ++resType)
  669. {
  670. auto resName = QString::fromStdString(GameConstants::RESOURCE_NAMES[resType]);
  671. victoryTypeWidget->addItem(resName, QVariant::fromValue(resType));
  672. }
  673. }
  674. victoryValueWidget = new QLineEdit;
  675. ui->victoryParamsLayout->addWidget(victoryValueWidget);
  676. victoryValueWidget->setText("1");
  677. break;
  678. }
  679. case 3: { //EventCondition::HAVE_BUILDING
  680. victoryTypeWidget = new QComboBox;
  681. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  682. auto * ctown = VLC->townh->randomTown;
  683. for(int bId : ctown->getAllBuildings())
  684. victoryTypeWidget->addItem(QString::fromStdString(defaultBuildingIdConversion(BuildingID(bId))), QVariant::fromValue(bId));
  685. victorySelectWidget = new QComboBox;
  686. ui->victoryParamsLayout->addWidget(victorySelectWidget);
  687. victorySelectWidget->addItem("Any town", QVariant::fromValue(-1));
  688. for(int i : getObjectIndexes<CGTownInstance>())
  689. victorySelectWidget->addItem(getTownName(i).c_str(), QVariant::fromValue(i));
  690. break;
  691. }
  692. case 4: { //EventCondition::CONTROL (Obj::TOWN)
  693. victoryTypeWidget = new QComboBox;
  694. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  695. for(int i : getObjectIndexes<CGTownInstance>())
  696. victoryTypeWidget->addItem(tr(getTownName(i).c_str()), QVariant::fromValue(i));
  697. break;
  698. }
  699. case 5: { //EventCondition::DESTROY (Obj::HERO)
  700. victoryTypeWidget = new QComboBox;
  701. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  702. for(int i : getObjectIndexes<CGHeroInstance>())
  703. victoryTypeWidget->addItem(tr(getHeroName(i).c_str()), QVariant::fromValue(i));
  704. break;
  705. }
  706. case 6: { //EventCondition::TRANSPORT (Obj::ARTEFACT)
  707. victoryTypeWidget = new QComboBox;
  708. ui->victoryParamsLayout->addWidget(victoryTypeWidget);
  709. for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
  710. victoryTypeWidget->addItem(QString::fromStdString(VLC->arth->objects[i]->getNameTranslated()), QVariant::fromValue(i));
  711. victorySelectWidget = new QComboBox;
  712. ui->victoryParamsLayout->addWidget(victorySelectWidget);
  713. for(int i : getObjectIndexes<CGTownInstance>())
  714. victorySelectWidget->addItem(tr(getTownName(i).c_str()), QVariant::fromValue(i));
  715. break;
  716. }
  717. //TODO: support this vectory type
  718. // in order to do that, need to implement finding creature by position
  719. // selecting from map would be the best user experience
  720. /*case 7: { //EventCondition::DESTROY (Obj::MONSTER)
  721. victoryTypeWidget = new QComboBox;
  722. ui->loseParamsLayout->addWidget(victoryTypeWidget);
  723. for(int i : getObjectIndexes<CGCreature>())
  724. victoryTypeWidget->addItem(tr(getMonsterName(i).c_str()), QVariant::fromValue(i));
  725. break;
  726. }*/
  727. }
  728. }
  729. void MapSettings::on_loseComboBox_currentIndexChanged(int index)
  730. {
  731. delete loseTypeWidget;
  732. delete loseValueWidget;
  733. delete loseSelectWidget;
  734. loseTypeWidget = nullptr;
  735. loseValueWidget = nullptr;
  736. loseSelectWidget = nullptr;
  737. if(index == 0)
  738. {
  739. ui->standardLoseCheck->setChecked(true);
  740. ui->standardLoseCheck->setEnabled(false);
  741. return;
  742. }
  743. ui->standardLoseCheck->setEnabled(true);
  744. int loseCondition = index - 1;
  745. switch(loseCondition)
  746. {
  747. case 0: { //EventCondition::CONTROL (Obj::TOWN)
  748. loseTypeWidget = new QComboBox;
  749. ui->loseParamsLayout->addWidget(loseTypeWidget);
  750. for(int i : getObjectIndexes<CGTownInstance>())
  751. loseTypeWidget->addItem(tr(getTownName(i).c_str()), QVariant::fromValue(i));
  752. break;
  753. }
  754. case 1: { //EventCondition::CONTROL (Obj::HERO)
  755. loseTypeWidget = new QComboBox;
  756. ui->loseParamsLayout->addWidget(loseTypeWidget);
  757. for(int i : getObjectIndexes<CGHeroInstance>())
  758. loseTypeWidget->addItem(tr(getHeroName(i).c_str()), QVariant::fromValue(i));
  759. break;
  760. }
  761. case 2: { //EventCondition::DAYS_PASSED
  762. loseValueWidget = new QLineEdit;
  763. ui->loseParamsLayout->addWidget(loseValueWidget);
  764. loseValueWidget->setText("2m 1w 1d");
  765. break;
  766. }
  767. case 3: { //EventCondition::DAYS_WITHOUT_TOWN
  768. loseValueWidget = new QLineEdit;
  769. ui->loseParamsLayout->addWidget(loseValueWidget);
  770. loseValueWidget->setText("7");
  771. break;
  772. }
  773. }
  774. }