inspector.cpp 30 KB

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