inspector.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /*
  2. * inspector.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 "inspector.h"
  12. #include "../lib/ArtifactUtils.h"
  13. #include "../lib/CArtHandler.h"
  14. #include "../lib/entities/hero/CHeroClass.h"
  15. #include "../lib/entities/hero/CHeroHandler.h"
  16. #include "../lib/spells/CSpellHandler.h"
  17. #include "../lib/CRandomGenerator.h"
  18. #include "../lib/mapObjectConstructors/AObjectTypeHandler.h"
  19. #include "../lib/mapObjectConstructors/CObjectClassesHandler.h"
  20. #include "../lib/mapObjects/ObjectTemplate.h"
  21. #include "../lib/mapping/CMap.h"
  22. #include "../lib/constants/StringConstants.h"
  23. #include "../lib/texts/CGeneralTextHandler.h"
  24. #include "townbuildingswidget.h"
  25. #include "towneventswidget.h"
  26. #include "townspellswidget.h"
  27. #include "armywidget.h"
  28. #include "messagewidget.h"
  29. #include "rewardswidget.h"
  30. #include "questwidget.h"
  31. #include "heroartifactswidget.h"
  32. #include "heroskillswidget.h"
  33. #include "herospellwidget.h"
  34. #include "portraitwidget.h"
  35. #include "PickObjectDelegate.h"
  36. #include "../mapcontroller.h"
  37. static QList<std::pair<QString, QVariant>> CharacterIdentifiers
  38. {
  39. {QObject::tr("Compliant"), QVariant::fromValue(int(CGCreature::Character::COMPLIANT))},
  40. {QObject::tr("Friendly"), QVariant::fromValue(int(CGCreature::Character::FRIENDLY))},
  41. {QObject::tr("Aggressive"), QVariant::fromValue(int(CGCreature::Character::AGGRESSIVE))},
  42. {QObject::tr("Hostile"), QVariant::fromValue(int(CGCreature::Character::HOSTILE))},
  43. {QObject::tr("Savage"), QVariant::fromValue(int(CGCreature::Character::SAVAGE))},
  44. };
  45. // multiple times used translation strings
  46. enum ReusedKey { ARMY, OWNER, SAME_AS_TOWN, REMOVABLE_UNITS, PLACEHOLDER_TYPE, POWER_RANK, HERO_TYPE, EXPERIENCE, MALE, FEMALE, GENDER, NAME, BIOGRAPHY, SPELLS, NO_PATROL, PATROL_RADIUS, TOWN_NAME, MESSAGE, SPELL, PRODUCTIVITY, AMOUNT, CHARACTER, NEVER_FLEES, NOT_GROWING, REWARD, REMOVE_AFTER, HUMAN_TRIGGER, CPU_TRIGGER, FIRST_VISIT_TEXT, NEXT_VISIT_TEXT, COMPLETED_TEXT, REPEAT_QUEST, TIME_LIMIT };
  47. static const QHash<ReusedKey, QString> trReused =
  48. {
  49. { ARMY, QObject::tr("Army") },
  50. { OWNER, QObject::tr("Owner") },
  51. { SAME_AS_TOWN, QObject::tr("Same as town") },
  52. { REMOVABLE_UNITS, QObject::tr("Removable units") },
  53. { PLACEHOLDER_TYPE, QObject::tr("Placeholder type") },
  54. { POWER_RANK, QObject::tr("Power rank") },
  55. { HERO_TYPE, QObject::tr("Hero type") },
  56. { EXPERIENCE, QObject::tr("Experience") },
  57. { MALE, QObject::tr("MALE") },
  58. { FEMALE, QObject::tr("FEMALE") },
  59. { GENDER, QObject::tr("Gender") },
  60. { NAME, QObject::tr("Name") },
  61. { BIOGRAPHY, QObject::tr("Biography") },
  62. { SPELLS, QObject::tr("Spells") },
  63. { NO_PATROL, QObject::tr("No patrol") },
  64. { PATROL_RADIUS, QObject::tr("Patrol radius") },
  65. { TOWN_NAME, QObject::tr("Town name") },
  66. { MESSAGE, QObject::tr("Message") },
  67. { SPELL, QObject::tr("Spell") },
  68. { PRODUCTIVITY, QObject::tr("Productivity") },
  69. { AMOUNT, QObject::tr("Amount") },
  70. { CHARACTER, QObject::tr("Character") },
  71. { NEVER_FLEES, QObject::tr("Never flees") },
  72. { NOT_GROWING, QObject::tr("Not growing") },
  73. { REWARD, QObject::tr("Reward") },
  74. { REMOVE_AFTER, QObject::tr("Remove after") },
  75. { HUMAN_TRIGGER, QObject::tr("Human trigger") },
  76. { CPU_TRIGGER, QObject::tr("Cpu trigger") },
  77. { FIRST_VISIT_TEXT, QObject::tr("First visit text") },
  78. { NEXT_VISIT_TEXT, QObject::tr("Next visit text") },
  79. { COMPLETED_TEXT, QObject::tr("Completed text") },
  80. { REPEAT_QUEST, QObject::tr("Repeat quest") },
  81. { TIME_LIMIT, QObject::tr("Time limit") },
  82. };
  83. //===============IMPLEMENT OBJECT INITIALIZATION FUNCTIONS================
  84. Initializer::Initializer(CGObjectInstance * o, const PlayerColor & pl) : defaultPlayer(pl)
  85. {
  86. logGlobal->info("New object instance initialized");
  87. ///IMPORTANT! initialize order should be from base objects to derived objects
  88. INIT_OBJ_TYPE(CGResource);
  89. INIT_OBJ_TYPE(CGArtifact);
  90. INIT_OBJ_TYPE(CArmedInstance);
  91. INIT_OBJ_TYPE(CGShipyard);
  92. INIT_OBJ_TYPE(CGGarrison);
  93. INIT_OBJ_TYPE(CGMine);
  94. INIT_OBJ_TYPE(CGDwelling);
  95. INIT_OBJ_TYPE(CGTownInstance);
  96. INIT_OBJ_TYPE(CGCreature);
  97. INIT_OBJ_TYPE(CGHeroPlaceholder);
  98. INIT_OBJ_TYPE(CGHeroInstance);
  99. INIT_OBJ_TYPE(CGSignBottle);
  100. INIT_OBJ_TYPE(FlaggableMapObject);
  101. //INIT_OBJ_TYPE(CRewardableObject);
  102. //INIT_OBJ_TYPE(CGPandoraBox);
  103. //INIT_OBJ_TYPE(CGEvent);
  104. //INIT_OBJ_TYPE(CGSeerHut);
  105. }
  106. void Initializer::initialize(CArmedInstance * o)
  107. {
  108. if(!o) return;
  109. }
  110. void Initializer::initialize(CGSignBottle * o)
  111. {
  112. if(!o) return;
  113. }
  114. void Initializer::initialize(CGCreature * o)
  115. {
  116. if(!o) return;
  117. o->character = CGCreature::Character::HOSTILE;
  118. if(!o->hasStackAtSlot(SlotID(0)))
  119. o->putStack(SlotID(0), new CStackInstance(CreatureID(o->subID), 0, false));
  120. }
  121. void Initializer::initialize(CGDwelling * o)
  122. {
  123. if(!o) return;
  124. o->tempOwner = defaultPlayer;
  125. if(o->ID == Obj::RANDOM_DWELLING || o->ID == Obj::RANDOM_DWELLING_LVL || o->ID == Obj::RANDOM_DWELLING_FACTION)
  126. {
  127. o->randomizationInfo = CGDwellingRandomizationInfo();
  128. if(o->ID == Obj::RANDOM_DWELLING_LVL)
  129. {
  130. o->randomizationInfo->minLevel = o->subID;
  131. o->randomizationInfo->maxLevel = o->subID;
  132. }
  133. if(o->ID == Obj::RANDOM_DWELLING_FACTION)
  134. {
  135. o->randomizationInfo->allowedFactions.insert(FactionID(o->subID));
  136. }
  137. }
  138. }
  139. void Initializer::initialize(CGGarrison * o)
  140. {
  141. if(!o) return;
  142. o->tempOwner = defaultPlayer;
  143. o->removableUnits = true;
  144. }
  145. void Initializer::initialize(CGShipyard * o)
  146. {
  147. if(!o) return;
  148. o->tempOwner = defaultPlayer;
  149. }
  150. void Initializer::initialize(FlaggableMapObject * o)
  151. {
  152. if(!o) return;
  153. o->tempOwner = defaultPlayer;
  154. }
  155. void Initializer::initialize(CGHeroPlaceholder * o)
  156. {
  157. if(!o) return;
  158. o->tempOwner = defaultPlayer;
  159. if(!o->powerRank.has_value() && !o->heroType.has_value())
  160. o->powerRank = 0;
  161. if(o->powerRank.has_value() && o->heroType.has_value())
  162. o->powerRank.reset();
  163. }
  164. void Initializer::initialize(CGHeroInstance * o)
  165. {
  166. if(!o)
  167. return;
  168. o->tempOwner = defaultPlayer;
  169. if(o->ID == Obj::PRISON)
  170. {
  171. o->subID = 0;
  172. o->tempOwner = PlayerColor::NEUTRAL;
  173. }
  174. if(o->ID == Obj::HERO)
  175. {
  176. for(auto const & t : VLC->heroh->objects)
  177. {
  178. if(t->heroClass->getId() == HeroClassID(o->subID))
  179. {
  180. o->subID = t->getId();
  181. break;
  182. }
  183. }
  184. }
  185. if(o->getHeroTypeID().hasValue())
  186. {
  187. o->gender = o->getHeroType()->gender;
  188. o->randomizeArmy(o->getFactionID());
  189. }
  190. }
  191. void Initializer::initialize(CGTownInstance * o)
  192. {
  193. if(!o) return;
  194. const std::vector<std::string> castleLevels{"village", "fort", "citadel", "castle", "capitol"};
  195. int lvl = vstd::find_pos(castleLevels, o->appearance->stringID);
  196. o->addBuilding(BuildingID::DEFAULT);
  197. if(lvl > -1) o->addBuilding(BuildingID::TAVERN);
  198. if(lvl > 0) o->addBuilding(BuildingID::FORT);
  199. if(lvl > 1) o->addBuilding(BuildingID::CITADEL);
  200. if(lvl > 2) o->addBuilding(BuildingID::CASTLE);
  201. if(lvl > 3) o->addBuilding(BuildingID::CAPITOL);
  202. if(o->possibleSpells.empty())
  203. {
  204. for(auto const & spellId : VLC->spellh->getDefaultAllowed()) //add all regular spells to town
  205. {
  206. o->possibleSpells.push_back(spellId);
  207. }
  208. }
  209. }
  210. void Initializer::initialize(CGArtifact * o)
  211. {
  212. if(!o) return;
  213. if(o->ID == Obj::SPELL_SCROLL)
  214. {
  215. std::vector<SpellID> out;
  216. for(auto const & spell : VLC->spellh->objects) //spellh size appears to be greater (?)
  217. {
  218. if(VLC->spellh->getDefaultAllowed().count(spell->id) != 0)
  219. {
  220. out.push_back(spell->id);
  221. }
  222. }
  223. auto a = ArtifactUtils::createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
  224. o->storedArtifact = a;
  225. }
  226. }
  227. void Initializer::initialize(CGMine * o)
  228. {
  229. if(!o) return;
  230. o->tempOwner = defaultPlayer;
  231. if(o->isAbandoned())
  232. {
  233. for(auto r = GameResID(0); r < GameResID::COUNT; ++r)
  234. o->abandonedMineResources.insert(r);
  235. }
  236. else
  237. {
  238. o->producedResource = GameResID(o->subID);
  239. o->producedQuantity = o->defaultResProduction();
  240. }
  241. }
  242. void Initializer::initialize(CGResource * o)
  243. {
  244. if(!o) return;
  245. o->amount = CGResource::RANDOM_AMOUNT;
  246. }
  247. //===============IMPLEMENT PROPERTIES SETUP===============================
  248. void Inspector::updateProperties(CArmedInstance * o)
  249. {
  250. if(!o) return;
  251. auto * delegate = new ArmyDelegate(*o);
  252. addProperty(trReused[ARMY], PropertyEditorPlaceholder(), delegate, false);
  253. }
  254. void Inspector::updateProperties(CGDwelling * o)
  255. {
  256. if(!o) return;
  257. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller), false);
  258. if (o->ID == Obj::RANDOM_DWELLING || o->ID == Obj::RANDOM_DWELLING_LVL)
  259. {
  260. auto * delegate = new PickObjectDelegate(controller, PickObjectDelegate::typedFilter<CGTownInstance>);
  261. addProperty(trReused[SAME_AS_TOWN], PropertyEditorPlaceholder(), delegate, false);
  262. }
  263. }
  264. void Inspector::updateProperties(FlaggableMapObject * o)
  265. {
  266. if(!o) return;
  267. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller), false);
  268. }
  269. void Inspector::updateProperties(CGGarrison * o)
  270. {
  271. if(!o) return;
  272. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller), false);
  273. addProperty(trReused[REMOVABLE_UNITS], o->removableUnits, false);
  274. }
  275. void Inspector::updateProperties(CGShipyard * o)
  276. {
  277. if(!o) return;
  278. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller), false);
  279. }
  280. void Inspector::updateProperties(CGHeroPlaceholder * o)
  281. {
  282. if(!o) return;
  283. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller), false);
  284. bool type = false;
  285. if(o->heroType.has_value())
  286. type = true;
  287. else if(!o->powerRank.has_value())
  288. assert(0); //one of values must be initialized
  289. {
  290. auto * delegate = new InspectorDelegate;
  291. delegate->options = {{QObject::tr("POWER RANK"), QVariant::fromValue(false)}, {QObject::tr("HERO TYPE"), QVariant::fromValue(true)}};
  292. addProperty(trReused[PLACEHOLDER_TYPE], delegate->options[type].first, delegate, false);
  293. }
  294. addProperty(trReused[POWER_RANK], o->powerRank.has_value() ? o->powerRank.value() : 0, type);
  295. {
  296. auto * delegate = new InspectorDelegate;
  297. for(int i = 0; i < VLC->heroh->objects.size(); ++i)
  298. {
  299. delegate->options.push_back({QObject::tr(VLC->heroh->objects[i]->getNameTranslated().c_str()), QVariant::fromValue(VLC->heroh->objects[i]->getId().getNum())});
  300. }
  301. addProperty(trReused[HERO_TYPE], o->heroType.has_value() ? VLC->heroh->getById(o->heroType.value())->getNameTranslated() : "", delegate, !type);
  302. }
  303. }
  304. void Inspector::updateProperties(CGHeroInstance * o)
  305. {
  306. if(!o) return;
  307. auto isPrison = o->ID == Obj::PRISON;
  308. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller, isPrison), isPrison); //field is not editable for prison
  309. addProperty<int>(trReused[EXPERIENCE], o->exp, false);
  310. addProperty(QObject::tr("Hero class"), o->getHeroClassID().hasValue() ? o->getHeroClass()->getNameTranslated() : "", true);
  311. { //Gender
  312. auto * delegate = new InspectorDelegate;
  313. delegate->options = {{trReused[MALE], QVariant::fromValue(int(EHeroGender::MALE))}, {trReused[FEMALE], QVariant::fromValue(int(EHeroGender::FEMALE))}};
  314. addProperty<std::string>(trReused[GENDER], (o->gender == EHeroGender::FEMALE ? trReused[FEMALE] : trReused[MALE]).toStdString(), delegate , false);
  315. }
  316. addProperty(trReused[NAME], o->getNameTranslated(), false);
  317. addProperty(trReused[BIOGRAPHY], o->getBiographyTranslated(), new MessageDelegate, false);
  318. addProperty(QObject::tr("Portrait"), PropertyEditorPlaceholder(), new PortraitDelegate(*o), false);
  319. auto * delegate = new HeroSkillsDelegate(*o);
  320. addProperty(QObject::tr("Skills"), PropertyEditorPlaceholder(), delegate, false);
  321. addProperty(trReused[SPELLS], PropertyEditorPlaceholder(), new HeroSpellDelegate(*o), false);
  322. addProperty(QObject::tr("Artifacts"), PropertyEditorPlaceholder(), new HeroArtifactsDelegate(*o), false);
  323. if(o->getHeroTypeID().hasValue() || o->ID == Obj::PRISON)
  324. { //Hero type
  325. auto * delegate = new InspectorDelegate;
  326. for(const auto & heroPtr : VLC->heroh->objects)
  327. {
  328. if(controller.map()->allowedHeroes.count(heroPtr->getId()) != 0)
  329. {
  330. if(o->ID == Obj::PRISON || heroPtr->heroClass->getIndex() == o->getHeroClassID())
  331. {
  332. delegate->options.push_back({QObject::tr(heroPtr->getNameTranslated().c_str()), QVariant::fromValue(heroPtr->getIndex())});
  333. }
  334. }
  335. }
  336. addProperty(trReused[HERO_TYPE], o->getHeroTypeID().hasValue() ? o->getHeroType()->getNameTranslated() : "", delegate, false);
  337. }
  338. {
  339. const int maxRadius = 60;
  340. auto * patrolDelegate = new InspectorDelegate;
  341. patrolDelegate->options = { {QObject::tr("No patrol"), QVariant::fromValue(CGHeroInstance::NO_PATROLLING)} };
  342. for(int i = 0; i <= maxRadius; ++i)
  343. patrolDelegate->options.push_back({ QObject::tr("%n tile(s)", "", i), QVariant::fromValue(i)});
  344. auto patrolRadiusText = o->patrol.patrolling ? QObject::tr("%n tile(s)", "", o->patrol.patrolRadius) : QObject::tr("No patrol");
  345. addProperty(trReused[PATROL_RADIUS], patrolRadiusText, patrolDelegate, false);
  346. }
  347. }
  348. void Inspector::updateProperties(CGTownInstance * o)
  349. {
  350. if(!o) return;
  351. addProperty(trReused[TOWN_NAME], o->getNameTranslated(), false);
  352. auto * delegate = new TownBuildingsDelegate(*o);
  353. addProperty(QObject::tr("Buildings"), PropertyEditorPlaceholder(), delegate, false);
  354. addProperty(trReused[SPELLS], PropertyEditorPlaceholder(), new TownSpellsDelegate(*o), false);
  355. addProperty(QObject::tr("Events"), PropertyEditorPlaceholder(), new TownEventsDelegate(*o, controller), false);
  356. }
  357. void Inspector::updateProperties(CGArtifact * o)
  358. {
  359. if(!o) return;
  360. addProperty(trReused[MESSAGE], o->message, false);
  361. CArtifactInstance * instance = o->storedArtifact;
  362. if(instance)
  363. {
  364. SpellID spellId = instance->getScrollSpellID();
  365. if(spellId != SpellID::NONE)
  366. {
  367. auto * delegate = new InspectorDelegate;
  368. for(auto const & spell : VLC->spellh->objects)
  369. {
  370. if(controller.map()->allowedSpells.count(spell->id) != 0)
  371. delegate->options.push_back({QObject::tr(spell->getNameTranslated().c_str()), QVariant::fromValue(int(spell->getId()))});
  372. }
  373. addProperty(trReused[SPELL], VLC->spellh->getById(spellId)->getNameTranslated(), delegate, false);
  374. }
  375. }
  376. }
  377. void Inspector::updateProperties(CGMine * o)
  378. {
  379. if(!o) return;
  380. addProperty(trReused[OWNER], o->tempOwner, new OwnerDelegate(controller), false);
  381. addProperty(QObject::tr("Resource"), o->producedResource);
  382. addProperty(trReused[PRODUCTIVITY], o->producedQuantity);
  383. }
  384. void Inspector::updateProperties(CGResource * o)
  385. {
  386. if(!o) return;
  387. addProperty(trReused[AMOUNT], o->amount, false);
  388. addProperty(trReused[MESSAGE], o->message, false);
  389. }
  390. void Inspector::updateProperties(CGSignBottle * o)
  391. {
  392. if(!o) return;
  393. addProperty(trReused[MESSAGE], o->message, new MessageDelegate, false);
  394. }
  395. void Inspector::updateProperties(CGCreature * o)
  396. {
  397. if(!o) return;
  398. addProperty(trReused[MESSAGE], o->message, false);
  399. { //Character
  400. auto * delegate = new InspectorDelegate;
  401. delegate->options = CharacterIdentifiers;
  402. addProperty<CGCreature::Character>("Character", (CGCreature::Character)o->character, delegate, false);
  403. }
  404. addProperty(trReused[NEVER_FLEES], o->neverFlees, false);
  405. addProperty(trReused[NOT_GROWING], o->notGrowingTeam, false);
  406. addProperty(QObject::tr("Artifact reward"), o->gainedArtifact); //TODO: implement in setProperty
  407. addProperty(trReused[ARMY], PropertyEditorPlaceholder(), true);
  408. addProperty(trReused[AMOUNT], o->stacks[SlotID(0)]->count, false);
  409. //addProperty(QObject::tr("Resources reward"), o->resources); //TODO: implement in setProperty
  410. }
  411. void Inspector::updateProperties(CRewardableObject * o)
  412. {
  413. if(!o) return;
  414. auto * delegate = new RewardsDelegate(*controller.map(), *o);
  415. addProperty(trReused[REWARD], PropertyEditorPlaceholder(), delegate, false);
  416. }
  417. void Inspector::updateProperties(CGPandoraBox * o)
  418. {
  419. if(!o) return;
  420. addProperty(trReused[MESSAGE], o->message, new MessageDelegate, false);
  421. }
  422. void Inspector::updateProperties(CGEvent * o)
  423. {
  424. if(!o) return;
  425. addProperty(trReused[REMOVE_AFTER], o->removeAfterVisit, false);
  426. addProperty(trReused[HUMAN_TRIGGER], o->humanActivate, false);
  427. addProperty(trReused[CPU_TRIGGER], o->computerActivate, false);
  428. //ui8 availableFor; //players whom this event is available for
  429. }
  430. void Inspector::updateProperties(CGSeerHut * o)
  431. {
  432. if(!o || !o->quest) return;
  433. addProperty(trReused[FIRST_VISIT_TEXT], o->quest->firstVisitText, new MessageDelegate, false);
  434. addProperty(trReused[NEXT_VISIT_TEXT], o->quest->nextVisitText, new MessageDelegate, false);
  435. addProperty(trReused[COMPLETED_TEXT], o->quest->completedText, new MessageDelegate, false);
  436. addProperty(trReused[REPEAT_QUEST], o->quest->repeatedQuest, false);
  437. addProperty(trReused[TIME_LIMIT], o->quest->lastDay, false);
  438. { //Quest
  439. auto * delegate = new QuestDelegate(controller, *o->quest);
  440. addProperty(QObject::tr("Quest"), PropertyEditorPlaceholder(), delegate, false);
  441. }
  442. }
  443. void Inspector::updateProperties(CGQuestGuard * o)
  444. {
  445. if(!o || !o->quest) return;
  446. addProperty(trReused[REWARD], PropertyEditorPlaceholder(), nullptr, true);
  447. addProperty(trReused[REPEAT_QUEST], o->quest->repeatedQuest, true);
  448. }
  449. void Inspector::updateProperties()
  450. {
  451. if(!obj)
  452. return;
  453. table->setRowCount(0); //cleanup table
  454. addProperty(QObject::tr("Identifier"), obj);
  455. addProperty(QObject::tr("ID"), obj->ID.getNum());
  456. addProperty(QObject::tr("SubID"), obj->subID);
  457. addProperty(QObject::tr("InstanceName"), obj->instanceName);
  458. if(obj->ID != Obj::HERO_PLACEHOLDER && !dynamic_cast<CGHeroInstance*>(obj))
  459. {
  460. auto factory = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID);
  461. addProperty(QObject::tr("IsStatic"), factory->isStaticObject());
  462. }
  463. addProperty(trReused[OWNER], obj->tempOwner, new OwnerDelegate(controller), true);
  464. UPDATE_OBJ_PROPERTIES(CArmedInstance);
  465. UPDATE_OBJ_PROPERTIES(CGResource);
  466. UPDATE_OBJ_PROPERTIES(CGArtifact);
  467. UPDATE_OBJ_PROPERTIES(CGMine);
  468. UPDATE_OBJ_PROPERTIES(CGGarrison);
  469. UPDATE_OBJ_PROPERTIES(CGShipyard);
  470. UPDATE_OBJ_PROPERTIES(CGDwelling);
  471. UPDATE_OBJ_PROPERTIES(CGTownInstance);
  472. UPDATE_OBJ_PROPERTIES(CGCreature);
  473. UPDATE_OBJ_PROPERTIES(CGHeroPlaceholder);
  474. UPDATE_OBJ_PROPERTIES(CGHeroInstance);
  475. UPDATE_OBJ_PROPERTIES(CGSignBottle);
  476. UPDATE_OBJ_PROPERTIES(FlaggableMapObject);
  477. UPDATE_OBJ_PROPERTIES(CRewardableObject);
  478. UPDATE_OBJ_PROPERTIES(CGPandoraBox);
  479. UPDATE_OBJ_PROPERTIES(CGEvent);
  480. UPDATE_OBJ_PROPERTIES(CGSeerHut);
  481. UPDATE_OBJ_PROPERTIES(CGQuestGuard);
  482. table->show();
  483. }
  484. //===============IMPLEMENT PROPERTY UPDATE================================
  485. void Inspector::setProperty(const QString & key, const QTableWidgetItem * item)
  486. {
  487. if(!item->data(Qt::UserRole).isNull())
  488. {
  489. setProperty(key, item->data(Qt::UserRole));
  490. return;
  491. }
  492. if(item->flags() & Qt::ItemIsUserCheckable)
  493. {
  494. setProperty(key, QVariant::fromValue(item->checkState() == Qt::Checked));
  495. return;
  496. }
  497. setProperty(key, item->text());
  498. }
  499. void Inspector::setProperty(const QString & key, const QVariant & value)
  500. {
  501. if(!obj)
  502. return;
  503. if(key == trReused[OWNER])
  504. obj->tempOwner = PlayerColor(value.toInt());
  505. SET_PROPERTIES(CArmedInstance);
  506. SET_PROPERTIES(CGTownInstance);
  507. SET_PROPERTIES(CGArtifact);
  508. SET_PROPERTIES(CGMine);
  509. SET_PROPERTIES(CGResource);
  510. SET_PROPERTIES(CGDwelling);
  511. SET_PROPERTIES(CGGarrison);
  512. SET_PROPERTIES(CGCreature);
  513. SET_PROPERTIES(CGHeroPlaceholder);
  514. SET_PROPERTIES(CGHeroInstance);
  515. SET_PROPERTIES(CGShipyard);
  516. SET_PROPERTIES(CGSignBottle);
  517. SET_PROPERTIES(FlaggableMapObject);
  518. SET_PROPERTIES(CRewardableObject);
  519. SET_PROPERTIES(CGPandoraBox);
  520. SET_PROPERTIES(CGEvent);
  521. SET_PROPERTIES(CGSeerHut);
  522. SET_PROPERTIES(CGQuestGuard);
  523. }
  524. void Inspector::setProperty(CArmedInstance * o, const QString & key, const QVariant & value)
  525. {
  526. if(!o) return;
  527. }
  528. void Inspector::setProperty(FlaggableMapObject * o, const QString & key, const QVariant & value)
  529. {
  530. if(!o) return;
  531. }
  532. void Inspector::setProperty(CRewardableObject * o, const QString & key, const QVariant & value)
  533. {
  534. if(!o) return;
  535. }
  536. void Inspector::setProperty(CGPandoraBox * o, const QString & key, const QVariant & value)
  537. {
  538. if(!o) return;
  539. if(key == trReused[MESSAGE])
  540. o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  541. TextIdentifier("guards", o->instanceName, "message"), value.toString().toStdString()));
  542. }
  543. void Inspector::setProperty(CGEvent * o, const QString & key, const QVariant & value)
  544. {
  545. if(!o) return;
  546. if(key == trReused[REMOVE_AFTER])
  547. o->removeAfterVisit = value.toBool();
  548. if(key == trReused[HUMAN_TRIGGER])
  549. o->humanActivate = value.toBool();
  550. if(key == trReused[CPU_TRIGGER])
  551. o->computerActivate = value.toBool();
  552. }
  553. void Inspector::setProperty(CGTownInstance * o, const QString & key, const QVariant & value)
  554. {
  555. if(!o) return;
  556. if(key == trReused[TOWN_NAME])
  557. o->setNameTextId(mapRegisterLocalizedString("map", *controller.map(),
  558. TextIdentifier("town", o->instanceName, "name"), value.toString().toStdString()));
  559. }
  560. void Inspector::setProperty(CGSignBottle * o, const QString & key, const QVariant & value)
  561. {
  562. if(!o) return;
  563. if(key == trReused[MESSAGE])
  564. o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  565. TextIdentifier("sign", o->instanceName, "message"), value.toString().toStdString()));
  566. }
  567. void Inspector::setProperty(CGMine * o, const QString & key, const QVariant & value)
  568. {
  569. if(!o) return;
  570. if(key == trReused[PRODUCTIVITY])
  571. o->producedQuantity = value.toString().toInt();
  572. }
  573. void Inspector::setProperty(CGArtifact * o, const QString & key, const QVariant & value)
  574. {
  575. if(!o) return;
  576. if(key == trReused[MESSAGE])
  577. o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  578. TextIdentifier("guards", o->instanceName, "message"), value.toString().toStdString()));
  579. if(o->storedArtifact && key == trReused[SPELL])
  580. {
  581. o->storedArtifact = ArtifactUtils::createScroll(SpellID(value.toInt()));
  582. }
  583. }
  584. void Inspector::setProperty(CGDwelling * o, const QString & key, const QVariant & value)
  585. {
  586. if(!o) return;
  587. if(key == trReused[SAME_AS_TOWN])
  588. {
  589. if (!o->randomizationInfo.has_value())
  590. o->randomizationInfo = CGDwellingRandomizationInfo();
  591. o->randomizationInfo->instanceId = "";
  592. if(CGTownInstance * town = data_cast<CGTownInstance>(value.toLongLong()))
  593. o->randomizationInfo->instanceId = town->instanceName;
  594. }
  595. }
  596. void Inspector::setProperty(CGGarrison * o, const QString & key, const QVariant & value)
  597. {
  598. if(!o) return;
  599. if(key == trReused[REMOVABLE_UNITS])
  600. o->removableUnits = value.toBool();
  601. }
  602. void Inspector::setProperty(CGHeroPlaceholder * o, const QString & key, const QVariant & value)
  603. {
  604. if(!o) return;
  605. if(key == trReused[PLACEHOLDER_TYPE])
  606. {
  607. if(value.toBool())
  608. {
  609. if(!o->heroType.has_value())
  610. o->heroType = HeroTypeID(0);
  611. o->powerRank.reset();
  612. }
  613. else
  614. {
  615. if(!o->powerRank.has_value())
  616. o->powerRank = 0;
  617. o->heroType.reset();
  618. }
  619. updateProperties();
  620. }
  621. if(key == trReused[POWER_RANK])
  622. o->powerRank = value.toInt();
  623. if(key == trReused[HERO_TYPE])
  624. {
  625. o->heroType = HeroTypeID(value.toInt());
  626. }
  627. }
  628. void Inspector::setProperty(CGHeroInstance * o, const QString & key, const QVariant & value)
  629. {
  630. if(!o) return;
  631. if(key == trReused[GENDER])
  632. o->gender = EHeroGender(value.toInt());
  633. if(key == trReused[NAME])
  634. o->nameCustomTextId = mapRegisterLocalizedString("map", *controller.map(),
  635. TextIdentifier("hero", o->instanceName, "name"), value.toString().toStdString());
  636. if(key == trReused[BIOGRAPHY])
  637. o->biographyCustomTextId = mapRegisterLocalizedString("map", *controller.map(),
  638. TextIdentifier("hero", o->instanceName, "biography"), value.toString().toStdString());
  639. if(key == trReused[EXPERIENCE])
  640. o->exp = value.toString().toInt();
  641. if(key == trReused[HERO_TYPE])
  642. {
  643. for(auto const & t : VLC->heroh->objects)
  644. {
  645. if(t->getId() == value.toInt())
  646. o->subID = value.toInt();
  647. }
  648. o->gender = o->getHeroType()->gender;
  649. o->randomizeArmy(o->getHeroType()->heroClass->faction);
  650. updateProperties(); //updating other properties after change
  651. }
  652. if(key == trReused[PATROL_RADIUS])
  653. {
  654. auto radius = value.toInt();
  655. o->patrol.patrolRadius = radius;
  656. o->patrol.patrolling = radius != CGHeroInstance::NO_PATROLLING;
  657. }
  658. }
  659. void Inspector::setProperty(CGShipyard * o, const QString & key, const QVariant & value)
  660. {
  661. if(!o) return;
  662. }
  663. void Inspector::setProperty(CGResource * o, const QString & key, const QVariant & value)
  664. {
  665. if(!o) return;
  666. if(key == trReused[AMOUNT])
  667. o->amount = value.toString().toInt();
  668. }
  669. void Inspector::setProperty(CGCreature * o, const QString & key, const QVariant & value)
  670. {
  671. if(!o) return;
  672. if(key == trReused[MESSAGE])
  673. o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  674. TextIdentifier("monster", o->instanceName, "message"), value.toString().toStdString()));
  675. if(key == trReused[CHARACTER])
  676. o->character = CGCreature::Character(value.toInt());
  677. if(key == trReused[NEVER_FLEES])
  678. o->neverFlees = value.toBool();
  679. if(key == trReused[NOT_GROWING])
  680. o->notGrowingTeam = value.toBool();
  681. if(key == trReused[AMOUNT])
  682. o->stacks[SlotID(0)]->count = value.toString().toInt();
  683. }
  684. void Inspector::setProperty(CGSeerHut * o, const QString & key, const QVariant & value)
  685. {
  686. if(!o) return;
  687. if(key == trReused[FIRST_VISIT_TEXT])
  688. o->quest->firstVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  689. TextIdentifier("quest", o->instanceName, "firstVisit"), value.toString().toStdString()));
  690. if(key == trReused[NEXT_VISIT_TEXT])
  691. o->quest->nextVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  692. TextIdentifier("quest", o->instanceName, "nextVisit"), value.toString().toStdString()));
  693. if(key == trReused[COMPLETED_TEXT])
  694. o->quest->completedText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
  695. TextIdentifier("quest", o->instanceName, "completed"), value.toString().toStdString()));
  696. if(key == trReused[REPEAT_QUEST])
  697. o->quest->repeatedQuest = value.toBool();
  698. if(key == trReused[TIME_LIMIT])
  699. o->quest->lastDay = value.toString().toInt();
  700. }
  701. void Inspector::setProperty(CGQuestGuard * o, const QString & key, const QVariant & value)
  702. {
  703. if(!o) return;
  704. }
  705. //===============IMPLEMENT PROPERTY VALUE TYPE============================
  706. QTableWidgetItem * Inspector::addProperty(CGObjectInstance * value)
  707. {
  708. auto * item = new QTableWidgetItem(QString::number(data_cast<CGObjectInstance>(value)));
  709. item->setFlags(Qt::NoItemFlags);
  710. return item;
  711. }
  712. QTableWidgetItem * Inspector::addProperty(Inspector::PropertyEditorPlaceholder value)
  713. {
  714. auto item = new QTableWidgetItem("...");
  715. item->setFlags(Qt::NoItemFlags);
  716. return item;
  717. }
  718. QTableWidgetItem * Inspector::addProperty(unsigned int value)
  719. {
  720. auto * item = new QTableWidgetItem(QString::number(value));
  721. item->setFlags(Qt::NoItemFlags);
  722. //item->setData(Qt::UserRole, QVariant::fromValue(value));
  723. return item;
  724. }
  725. QTableWidgetItem * Inspector::addProperty(int value)
  726. {
  727. auto * item = new QTableWidgetItem(QString::number(value));
  728. item->setFlags(Qt::NoItemFlags);
  729. //item->setData(Qt::UserRole, QVariant::fromValue(value));
  730. return item;
  731. }
  732. QTableWidgetItem * Inspector::addProperty(bool value)
  733. {
  734. auto item = new QTableWidgetItem;
  735. item->setFlags(Qt::ItemIsUserCheckable);
  736. item->setCheckState(value ? Qt::Checked : Qt::Unchecked);
  737. return item;
  738. }
  739. QTableWidgetItem * Inspector::addProperty(const std::string & value)
  740. {
  741. return addProperty(QString::fromStdString(value));
  742. }
  743. QTableWidgetItem * Inspector::addProperty(const TextIdentifier & value)
  744. {
  745. return addProperty(VLC->generaltexth->translate(value.get()));
  746. }
  747. QTableWidgetItem * Inspector::addProperty(const MetaString & value)
  748. {
  749. return addProperty(value.toString());
  750. }
  751. QTableWidgetItem * Inspector::addProperty(const QString & value)
  752. {
  753. auto * item = new QTableWidgetItem(value);
  754. item->setFlags(Qt::NoItemFlags);
  755. return item;
  756. }
  757. QTableWidgetItem * Inspector::addProperty(const int3 & value)
  758. {
  759. auto * item = new QTableWidgetItem(QString("(%1, %2, %3)").arg(value.x, value.y, value.z));
  760. item->setFlags(Qt::NoItemFlags);
  761. return item;
  762. }
  763. QTableWidgetItem * Inspector::addProperty(const PlayerColor & value)
  764. {
  765. auto str = QObject::tr("UNFLAGGABLE");
  766. if(value == PlayerColor::NEUTRAL)
  767. str = QObject::tr("neutral");
  768. MetaString playerStr;
  769. playerStr.appendName(value);
  770. if(value.isValidPlayer())
  771. str = QString::fromStdString(playerStr.toString());
  772. auto * item = new QTableWidgetItem(str);
  773. item->setFlags(Qt::NoItemFlags);
  774. item->setData(Qt::UserRole, QVariant::fromValue(value.getNum()));
  775. return item;
  776. }
  777. QTableWidgetItem * Inspector::addProperty(const GameResID & value)
  778. {
  779. MetaString str;
  780. str.appendName(value);
  781. auto * item = new QTableWidgetItem(QString::fromStdString(str.toString()));
  782. item->setFlags(Qt::NoItemFlags);
  783. item->setData(Qt::UserRole, QVariant::fromValue(value.getNum()));
  784. return item;
  785. }
  786. QTableWidgetItem * Inspector::addProperty(CGCreature::Character value)
  787. {
  788. auto * item = new QTableWidgetItem;
  789. item->setFlags(Qt::NoItemFlags);
  790. item->setData(Qt::UserRole, QVariant::fromValue(int(value)));
  791. for(auto & i : CharacterIdentifiers)
  792. {
  793. if(i.second.toInt() == value)
  794. {
  795. item->setText(i.first);
  796. break;
  797. }
  798. }
  799. return item;
  800. }
  801. //========================================================================
  802. Inspector::Inspector(MapController & c, CGObjectInstance * o, QTableWidget * t): obj(o), table(t), controller(c)
  803. {
  804. }
  805. /*
  806. * Delegates
  807. */
  808. QWidget * InspectorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
  809. {
  810. return new QComboBox(parent);
  811. }
  812. void InspectorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
  813. {
  814. if(QComboBox *ed = qobject_cast<QComboBox *>(editor))
  815. {
  816. for(auto & i : options)
  817. {
  818. ed->addItem(i.first);
  819. ed->setItemData(ed->count() - 1, i.second);
  820. }
  821. }
  822. else
  823. {
  824. QStyledItemDelegate::setEditorData(editor, index);
  825. }
  826. }
  827. void InspectorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
  828. {
  829. if(QComboBox *ed = qobject_cast<QComboBox *>(editor))
  830. {
  831. if(!options.isEmpty())
  832. {
  833. QMap<int, QVariant> data;
  834. data[Qt::DisplayRole] = options[ed->currentIndex()].first;
  835. data[Qt::UserRole] = options[ed->currentIndex()].second;
  836. model->setItemData(index, data);
  837. }
  838. }
  839. else
  840. {
  841. QStyledItemDelegate::setModelData(editor, model, index);
  842. }
  843. }
  844. OwnerDelegate::OwnerDelegate(MapController & controller, bool addNeutral)
  845. {
  846. if(addNeutral)
  847. options.push_back({QObject::tr("neutral"), QVariant::fromValue(PlayerColor::NEUTRAL.getNum()) });
  848. for(int p = 0; p < controller.map()->players.size(); ++p)
  849. if(controller.map()->players[p].canAnyonePlay())
  850. {
  851. MetaString str;
  852. str.appendName(PlayerColor(p));
  853. options.push_back({QString::fromStdString(str.toString()), QVariant::fromValue(PlayerColor(p).getNum()) });
  854. }
  855. }