loseconditions.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. case EventCondition::IS_HUMAN:
  95. break; //ignore because always applicable for defeat conditions
  96. }
  97. };
  98. }
  99. }
  100. }
  101. }
  102. }
  103. void LoseConditions::update()
  104. {
  105. //loss messages
  106. bool customMessage = true;
  107. //loss conditions
  108. EventCondition defeatCondition(EventCondition::DAYS_WITHOUT_TOWN);
  109. defeatCondition.value = 7;
  110. //Loss condition - 7 days without town
  111. TriggeredEvent standardDefeat;
  112. standardDefeat.effect.type = EventEffect::DEFEAT;
  113. standardDefeat.effect.toOtherMessage.appendTextID("core.genrltxt.8");
  114. standardDefeat.identifier = "standardDefeat";
  115. standardDefeat.description.clear(); // TODO: display in quest window
  116. standardDefeat.onFulfill.appendTextID("core.genrltxt.7");
  117. standardDefeat.trigger = EventExpression(defeatCondition);
  118. //DEFEAT
  119. if(ui->loseComboBox->currentIndex() == 0)
  120. {
  121. controller->map()->triggeredEvents.push_back(standardDefeat);
  122. controller->map()->defeatIconIndex = 3;
  123. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.0");
  124. customMessage = false;
  125. }
  126. else
  127. {
  128. int lossCondition = ui->loseComboBox->currentIndex() - 1;
  129. TriggeredEvent specialDefeat;
  130. specialDefeat.effect.type = EventEffect::DEFEAT;
  131. specialDefeat.identifier = "specialDefeat";
  132. specialDefeat.description.clear(); // TODO: display in quest window
  133. controller->map()->defeatIconIndex = lossCondition;
  134. switch(lossCondition)
  135. {
  136. case 0: {
  137. EventExpression::OperatorNone noneOf;
  138. EventCondition cond(EventCondition::CONTROL);
  139. cond.objectType = Obj(Obj::TOWN);
  140. assert(loseTypeWidget);
  141. int townIdx = loseTypeWidget->currentData().toInt();
  142. cond.position = controller->map()->objects[townIdx]->pos;
  143. noneOf.expressions.push_back(cond);
  144. specialDefeat.onFulfill.appendTextID("core.genrltxt.251");
  145. specialDefeat.trigger = EventExpression(noneOf);
  146. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.1");
  147. customMessage = false;
  148. break;
  149. }
  150. case 1: {
  151. EventExpression::OperatorNone noneOf;
  152. EventCondition cond(EventCondition::CONTROL);
  153. cond.objectType = Obj(Obj::HERO);
  154. assert(loseTypeWidget);
  155. int townIdx = loseTypeWidget->currentData().toInt();
  156. cond.position = controller->map()->objects[townIdx]->pos;
  157. noneOf.expressions.push_back(cond);
  158. specialDefeat.onFulfill.appendTextID("core.genrltxt.253");
  159. specialDefeat.trigger = EventExpression(noneOf);
  160. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.2");
  161. customMessage = false;
  162. break;
  163. }
  164. case 2: {
  165. EventCondition cond(EventCondition::DAYS_PASSED);
  166. assert(loseValueWidget);
  167. cond.value = expiredDate(loseValueWidget->text());
  168. specialDefeat.onFulfill.appendTextID("core.genrltxt.254");
  169. specialDefeat.trigger = EventExpression(cond);
  170. controller->map()->defeatMessage = MetaString::createFromTextID("core.lcdesc.3");
  171. customMessage = false;
  172. break;
  173. }
  174. case 3: {
  175. EventCondition cond(EventCondition::DAYS_WITHOUT_TOWN);
  176. assert(loseValueWidget);
  177. cond.value = loseValueWidget->text().toInt();
  178. specialDefeat.onFulfill.appendTextID("core.genrltxt.7");
  179. specialDefeat.trigger = EventExpression(cond);
  180. break;
  181. }
  182. }
  183. EventExpression::OperatorAll allOf;
  184. EventCondition isHuman(EventCondition::IS_HUMAN);
  185. isHuman.value = 1;
  186. allOf.expressions.push_back(specialDefeat.trigger.get());
  187. allOf.expressions.push_back(isHuman);
  188. specialDefeat.trigger = EventExpression(allOf);
  189. if(ui->standardLoseCheck->isChecked())
  190. {
  191. controller->map()->triggeredEvents.push_back(standardDefeat);
  192. }
  193. controller->map()->triggeredEvents.push_back(specialDefeat);
  194. }
  195. if(customMessage)
  196. {
  197. controller->map()->defeatMessage = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller->map(), TextIdentifier("header", "defeatMessage"), ui->defeatMessageEdit->text().toStdString()));
  198. }
  199. }
  200. void LoseConditions::on_loseComboBox_currentIndexChanged(int index)
  201. {
  202. delete loseTypeWidget;
  203. delete loseValueWidget;
  204. delete loseSelectWidget;
  205. delete pickObjectButton;
  206. loseTypeWidget = nullptr;
  207. loseValueWidget = nullptr;
  208. loseSelectWidget = nullptr;
  209. pickObjectButton = nullptr;
  210. if(index == 0)
  211. {
  212. ui->standardLoseCheck->setChecked(true);
  213. ui->standardLoseCheck->setEnabled(false);
  214. return;
  215. }
  216. ui->standardLoseCheck->setEnabled(true);
  217. int loseCondition = index - 1;
  218. switch(loseCondition)
  219. {
  220. case 0: { //EventCondition::CONTROL (Obj::TOWN)
  221. loseTypeWidget = new QComboBox;
  222. ui->loseParamsLayout->addWidget(loseTypeWidget);
  223. for(int i : getObjectIndexes<const CGTownInstance>(*controller->map()))
  224. loseTypeWidget->addItem(QString::fromStdString(getTownName(*controller->map(), i).c_str()), QVariant::fromValue(i));
  225. pickObjectButton = new QToolButton;
  226. connect(pickObjectButton, &QToolButton::clicked, this, &LoseConditions::onObjectSelect);
  227. ui->loseParamsLayout->addWidget(pickObjectButton);
  228. break;
  229. }
  230. case 1: { //EventCondition::CONTROL (Obj::HERO)
  231. loseTypeWidget = new QComboBox;
  232. ui->loseParamsLayout->addWidget(loseTypeWidget);
  233. for(int i : getObjectIndexes<const CGHeroInstance>(*controller->map()))
  234. loseTypeWidget->addItem(QString::fromStdString(getHeroName(*controller->map(), i).c_str()), QVariant::fromValue(i));
  235. pickObjectButton = new QToolButton;
  236. connect(pickObjectButton, &QToolButton::clicked, this, &LoseConditions::onObjectSelect);
  237. ui->loseParamsLayout->addWidget(pickObjectButton);
  238. break;
  239. }
  240. case 2: { //EventCondition::DAYS_PASSED
  241. loseValueWidget = new QLineEdit;
  242. ui->loseParamsLayout->addWidget(loseValueWidget);
  243. loseValueWidget->setText("2m 1w 1d");
  244. break;
  245. }
  246. case 3: { //EventCondition::DAYS_WITHOUT_TOWN
  247. loseValueWidget = new QLineEdit;
  248. ui->loseParamsLayout->addWidget(loseValueWidget);
  249. loseValueWidget->setText("7");
  250. break;
  251. }
  252. }
  253. }
  254. void LoseConditions::onObjectSelect()
  255. {
  256. int loseCondition = ui->loseComboBox->currentIndex() - 1;
  257. for(int lvl : {0, 1})
  258. {
  259. auto & l = controller->scene(lvl)->objectPickerView;
  260. switch(loseCondition)
  261. {
  262. case 0: { //EventCondition::CONTROL (Obj::TOWN)
  263. l.highlight<const CGTownInstance>();
  264. break;
  265. }
  266. case 1: { //EventCondition::CONTROL (Obj::HERO)
  267. l.highlight<const CGHeroInstance>();
  268. break;
  269. }
  270. default:
  271. return;
  272. }
  273. l.update();
  274. QObject::connect(&l, &ObjectPickerLayer::selectionMade, this, &LoseConditions::onObjectPicked);
  275. }
  276. controller->settingsDialog->hide();
  277. }
  278. void LoseConditions::onObjectPicked(const CGObjectInstance * obj)
  279. {
  280. controller->settingsDialog->show();
  281. for(int lvl : {0, 1})
  282. {
  283. auto & l = controller->scene(lvl)->objectPickerView;
  284. l.clear();
  285. l.update();
  286. QObject::disconnect(&l, &ObjectPickerLayer::selectionMade, this, &LoseConditions::onObjectPicked);
  287. }
  288. if(!obj) //discarded
  289. return;
  290. for(int i = 0; i < loseTypeWidget->count(); ++i)
  291. {
  292. auto data = controller->map()->objects.at(loseTypeWidget->itemData(i).toInt());
  293. if(data == obj)
  294. {
  295. loseTypeWidget->setCurrentIndex(i);
  296. break;
  297. }
  298. }
  299. }