loseconditions.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * loseconditions.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 "loseconditions.h"
  12. #include "ui_loseconditions.h"
  13. #include "../mapcontroller.h"
  14. #include "../lib/texts/CGeneralTextHandler.h"
  15. LoseConditions::LoseConditions(QWidget *parent) :
  16. AbstractSettings(parent),
  17. ui(new Ui::LoseConditions)
  18. {
  19. ui->setupUi(this);
  20. }
  21. LoseConditions::~LoseConditions()
  22. {
  23. delete ui;
  24. }
  25. void LoseConditions::initialize(MapController & c)
  26. {
  27. AbstractSettings::initialize(c);
  28. //loss messages
  29. ui->defeatMessageEdit->setText(QString::fromStdString(controller->map()->defeatMessage.toString()));
  30. //loss conditions
  31. const std::array<std::string, 5> conditionStringsLose = {
  32. QT_TR_NOOP("No special loss"),
  33. QT_TR_NOOP("Lose castle"),
  34. QT_TR_NOOP("Lose hero"),
  35. QT_TR_NOOP("Time expired"),
  36. QT_TR_NOOP("Days without town")
  37. };
  38. for(auto & s : conditionStringsLose)
  39. {
  40. ui->loseComboBox->addItem(tr(s.c_str()));
  41. }
  42. ui->standardLoseCheck->setChecked(false);
  43. for(auto & ev : controller->map()->triggeredEvents)
  44. {
  45. if(ev.effect.type == EventEffect::DEFEAT)
  46. {
  47. if(ev.identifier == "standardDefeat")
  48. ui->standardLoseCheck->setChecked(true);
  49. if(ev.identifier == "specialDefeat")
  50. {
  51. auto readjson = ev.trigger.toJson(AbstractSettings::conditionToJson);
  52. auto linearNodes = linearJsonArray(readjson);
  53. for(auto & json : linearNodes)
  54. {
  55. switch(json["condition"].Integer())
  56. {
  57. case EventCondition::CONTROL: {
  58. auto objectType = MapObjectID::decode(json["objectType"].String());
  59. if(objectType == Obj::TOWN)
  60. {
  61. ui->loseComboBox->setCurrentIndex(1);
  62. assert(loseTypeWidget);
  63. int townIdx = getObjectByPos<const CGTownInstance>(*controller->map(), posFromJson(json["position"]));
  64. if(townIdx >= 0)
  65. {
  66. auto idx = loseTypeWidget->findData(townIdx);
  67. loseTypeWidget->setCurrentIndex(idx);
  68. }
  69. }
  70. if(objectType == Obj::HERO)
  71. {
  72. ui->loseComboBox->setCurrentIndex(2);
  73. assert(loseTypeWidget);
  74. int heroIdx = getObjectByPos<const CGHeroInstance>(*controller->map(), posFromJson(json["position"]));
  75. if(heroIdx >= 0)
  76. {
  77. auto idx = loseTypeWidget->findData(heroIdx);
  78. loseTypeWidget->setCurrentIndex(idx);
  79. }
  80. }
  81. break;
  82. }
  83. case EventCondition::DAYS_PASSED: {
  84. ui->loseComboBox->setCurrentIndex(3);
  85. assert(loseValueWidget);
  86. loseValueWidget->setText(expiredDate(json["value"].Integer()));
  87. break;
  88. }
  89. case EventCondition::DAYS_WITHOUT_TOWN: {
  90. ui->loseComboBox->setCurrentIndex(4);
  91. assert(loseValueWidget);
  92. loseValueWidget->setText(QString::number(json["value"].Integer()));
  93. break;
  94. }
  95. case EventCondition::IS_HUMAN: {
  96. break; //ignore because always applicable for defeat conditions
  97. }
  98. };
  99. }
  100. }
  101. }
  102. }
  103. }
  104. void LoseConditions::update()
  105. {
  106. //loss messages
  107. bool customMessage = true;
  108. //loss conditions
  109. EventCondition defeatCondition(EventCondition::DAYS_WITHOUT_TOWN);
  110. defeatCondition.value = 7;
  111. //Loss condition - 7 days without town
  112. TriggeredEvent standardDefeat;
  113. standardDefeat.effect.type = EventEffect::DEFEAT;
  114. standardDefeat.effect.toOtherMessage.appendTextID("core.genrltxt.8");
  115. standardDefeat.identifier = "standardDefeat";
  116. standardDefeat.description.clear(); // TODO: display in quest window
  117. standardDefeat.onFulfill.appendTextID("core.genrltxt.7");
  118. standardDefeat.trigger = EventExpression(defeatCondition);
  119. //DEFEAT
  120. if(ui->loseComboBox->currentIndex() == 0)
  121. {
  122. controller->map()->triggeredEvents.push_back(standardDefeat);
  123. controller->map()->defeatIconIndex = 3;
  124. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.0");
  125. customMessage = false;
  126. }
  127. else
  128. {
  129. int lossCondition = ui->loseComboBox->currentIndex() - 1;
  130. TriggeredEvent specialDefeat;
  131. specialDefeat.effect.type = EventEffect::DEFEAT;
  132. specialDefeat.identifier = "specialDefeat";
  133. specialDefeat.description.clear(); // TODO: display in quest window
  134. controller->map()->defeatIconIndex = lossCondition;
  135. switch(lossCondition)
  136. {
  137. case 0: {
  138. EventExpression::OperatorNone noneOf;
  139. EventCondition cond(EventCondition::CONTROL);
  140. cond.objectType = Obj(Obj::TOWN);
  141. assert(loseTypeWidget);
  142. int townIdx = loseTypeWidget->currentData().toInt();
  143. cond.position = controller->map()->objects[townIdx]->pos;
  144. noneOf.expressions.push_back(cond);
  145. specialDefeat.onFulfill.appendTextID("core.genrltxt.251");
  146. specialDefeat.trigger = EventExpression(noneOf);
  147. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.1");
  148. customMessage = false;
  149. break;
  150. }
  151. case 1: {
  152. EventExpression::OperatorNone noneOf;
  153. EventCondition cond(EventCondition::CONTROL);
  154. cond.objectType = Obj(Obj::HERO);
  155. assert(loseTypeWidget);
  156. int townIdx = loseTypeWidget->currentData().toInt();
  157. cond.position = controller->map()->objects[townIdx]->pos;
  158. noneOf.expressions.push_back(cond);
  159. specialDefeat.onFulfill.appendTextID("core.genrltxt.253");
  160. specialDefeat.trigger = EventExpression(noneOf);
  161. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.2");
  162. customMessage = false;
  163. break;
  164. }
  165. case 2: {
  166. EventCondition cond(EventCondition::DAYS_PASSED);
  167. assert(loseValueWidget);
  168. cond.value = expiredDate(loseValueWidget->text());
  169. specialDefeat.onFulfill.appendTextID("core.genrltxt.254");
  170. specialDefeat.trigger = EventExpression(cond);
  171. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.3");
  172. customMessage = false;
  173. break;
  174. }
  175. case 3: {
  176. EventCondition cond(EventCondition::DAYS_WITHOUT_TOWN);
  177. assert(loseValueWidget);
  178. cond.value = loseValueWidget->text().toInt();
  179. specialDefeat.onFulfill.appendTextID("core.genrltxt.7");
  180. specialDefeat.trigger = EventExpression(cond);
  181. break;
  182. }
  183. }
  184. EventExpression::OperatorAll allOf;
  185. EventCondition isHuman(EventCondition::IS_HUMAN);
  186. isHuman.value = 1;
  187. allOf.expressions.push_back(specialDefeat.trigger.get());
  188. allOf.expressions.push_back(isHuman);
  189. specialDefeat.trigger = EventExpression(allOf);
  190. if(ui->standardLoseCheck->isChecked())
  191. {
  192. controller->map()->triggeredEvents.push_back(standardDefeat);
  193. }
  194. controller->map()->triggeredEvents.push_back(specialDefeat);
  195. }
  196. if(customMessage)
  197. {
  198. controller->map()->defeatMessage = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller->map(), TextIdentifier("header", "defeatMessage"), ui->defeatMessageEdit->text().toStdString()));
  199. }
  200. }
  201. void LoseConditions::on_loseComboBox_currentIndexChanged(int index)
  202. {
  203. delete loseTypeWidget;
  204. delete loseValueWidget;
  205. delete loseSelectWidget;
  206. delete pickObjectButton;
  207. loseTypeWidget = nullptr;
  208. loseValueWidget = nullptr;
  209. loseSelectWidget = nullptr;
  210. pickObjectButton = nullptr;
  211. if(index == 0)
  212. {
  213. ui->standardLoseCheck->setChecked(true);
  214. ui->standardLoseCheck->setEnabled(false);
  215. return;
  216. }
  217. ui->standardLoseCheck->setEnabled(true);
  218. int loseCondition = index - 1;
  219. switch(loseCondition)
  220. {
  221. case 0: { //EventCondition::CONTROL (Obj::TOWN)
  222. loseTypeWidget = new QComboBox;
  223. ui->loseParamsLayout->addWidget(loseTypeWidget);
  224. for(int i : getObjectIndexes<const CGTownInstance>(*controller->map()))
  225. loseTypeWidget->addItem(QString::fromStdString(getTownName(*controller->map(), i).c_str()), QVariant::fromValue(i));
  226. pickObjectButton = new QToolButton;
  227. connect(pickObjectButton, &QToolButton::clicked, this, &LoseConditions::onObjectSelect);
  228. ui->loseParamsLayout->addWidget(pickObjectButton);
  229. break;
  230. }
  231. case 1: { //EventCondition::CONTROL (Obj::HERO)
  232. loseTypeWidget = new QComboBox;
  233. ui->loseParamsLayout->addWidget(loseTypeWidget);
  234. for(int i : getObjectIndexes<const CGHeroInstance>(*controller->map()))
  235. loseTypeWidget->addItem(QString::fromStdString(getHeroName(*controller->map(), i).c_str()), QVariant::fromValue(i));
  236. pickObjectButton = new QToolButton;
  237. connect(pickObjectButton, &QToolButton::clicked, this, &LoseConditions::onObjectSelect);
  238. ui->loseParamsLayout->addWidget(pickObjectButton);
  239. break;
  240. }
  241. case 2: { //EventCondition::DAYS_PASSED
  242. loseValueWidget = new QLineEdit;
  243. ui->loseParamsLayout->addWidget(loseValueWidget);
  244. loseValueWidget->setText("2m 1w 1d");
  245. break;
  246. }
  247. case 3: { //EventCondition::DAYS_WITHOUT_TOWN
  248. loseValueWidget = new QLineEdit;
  249. ui->loseParamsLayout->addWidget(loseValueWidget);
  250. loseValueWidget->setText("7");
  251. break;
  252. }
  253. }
  254. }
  255. void LoseConditions::onObjectSelect()
  256. {
  257. int loseCondition = ui->loseComboBox->currentIndex() - 1;
  258. for(int lvl : {0, 1})
  259. {
  260. auto & l = controller->scene(lvl)->objectPickerView;
  261. switch(loseCondition)
  262. {
  263. case 0: { //EventCondition::CONTROL (Obj::TOWN)
  264. l.highlight<const CGTownInstance>();
  265. break;
  266. }
  267. case 1: { //EventCondition::CONTROL (Obj::HERO)
  268. l.highlight<const CGHeroInstance>();
  269. break;
  270. }
  271. default:
  272. return;
  273. }
  274. l.update();
  275. QObject::connect(&l, &ObjectPickerLayer::selectionMade, this, &LoseConditions::onObjectPicked);
  276. }
  277. controller->settingsDialog->hide();
  278. }
  279. void LoseConditions::onObjectPicked(const CGObjectInstance * obj)
  280. {
  281. controller->settingsDialog->show();
  282. for(int lvl : {0, 1})
  283. {
  284. auto & l = controller->scene(lvl)->objectPickerView;
  285. l.clear();
  286. l.update();
  287. QObject::disconnect(&l, &ObjectPickerLayer::selectionMade, this, &LoseConditions::onObjectPicked);
  288. }
  289. if(!obj) //discarded
  290. return;
  291. for(int i = 0; i < loseTypeWidget->count(); ++i)
  292. {
  293. auto data = controller->map()->objects.at(loseTypeWidget->itemData(i).toInt());
  294. if(data.get() == obj)
  295. {
  296. loseTypeWidget->setCurrentIndex(i);
  297. break;
  298. }
  299. }
  300. }