Crossfire Server, Trunk
CREMainWindow.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2022 the Crossfire Development Team
5  *
6  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
7  * welcome to redistribute it under certain conditions. For details, please
8  * see COPYING and LICENSE.
9  *
10  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
11  */
12 
13 #include <Qt>
14 #include <QtWidgets>
15 #include <memory>
16 
17 #include <CREMainWindow.h>
18 #include <CREResourcesWindow.h>
20 #include "CREExperienceWindow.h"
21 #include "MessageManager.h"
22 #include "CREReportDisplay.h"
23 #include "CREPixmap.h"
24 #include "CRESmoothFaceMaker.h"
25 #include "CREHPBarMaker.h"
26 #include "ResourcesManager.h"
27 #include "CRECombatSimulator.h"
28 #include "CREHPBarMaker.h"
30 #include "FaceMakerDialog.h"
31 #include "EditMonstersDialog.h"
32 #include "random_maps/RandomMap.h"
33 
34 #include "global.h"
35 #include "sproto.h"
36 #include "image.h"
37 #include "assets.h"
38 #include "AssetsManager.h"
39 #include "CRESettings.h"
40 #include "LicenseManager.h"
41 #include "AllAssets.h"
42 #include "assets/AssetModel.h"
43 #include "ChangesDock.h"
44 #include "HelpManager.h"
45 #include "MonsterResistances.h"
46 
47 const char *AssetWrapper::tipProperty = "_cre_internal";
48 
49 CREMainWindow::CREMainWindow(const QString &helpRoot)
50 {
51  myArea = new QMdiArea();
52  setCentralWidget(myArea);
53  myArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
54  myArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
55 
58 
59  myMessageManager = new MessageManager(nullptr);
61  myScriptManager = new ScriptFileManager(nullptr);
62 
64  connect(myMapManager, SIGNAL(browsingMap(const QString&)), this, SLOT(browsingMap(const QString&)));
65  connect(myMapManager, SIGNAL(finished()), this, SLOT(browsingFinished()));
68 
70 
72  myModel = new AssetModel(myAssets, this);
75 
76  myHelpManager = new HelpManager(helpRoot);
77 
78  createActions();
79  createMenus();
80 
81  statusBar()->showMessage(tr("Ready"));
82  myMapBrowseStatus = new QLabel(tr("Browsing maps..."));
83  statusBar()->addPermanentWidget(myMapBrowseStatus);
84 
85  setWindowTitle(tr("Crossfire Resource Editor"));
86 
87  fillFacesets();
88 
89  myChanges = new ChangesDock(myHelpManager, this);
90  addDockWidget(Qt::RightDockWidgetArea, myChanges);
91 
93  myHelpManager->setupData();
94 
96  if (settings.storeWindowsState()) {
97  restoreGeometry(settings.mainWindowGeometry());
98 
99  int count = settings.subWindowCount();
100  for (int idx = 0; idx < count; idx++) {
101  int type = settings.subWindowType(idx);
102  if (type == -2) {
103  onOpenExperience(settings.subWindowPosition(idx));
104  } else {
105  doResourceWindow(type, settings.subWindowPosition(idx));
106  }
107  }
108  }
109 }
110 
112 {
114  if (QMessageBox::question(this, "Discard changes?", "You have unsaved changes, really discard them?") != QMessageBox::Yes) {
115  event->ignore();
116  return;
117  }
118  }
119 
121  if (settings.storeWindowsState()) {
122  auto windows = myArea->subWindowList();
123  settings.setSubWindowCount(windows.size());
124  for (int idx = 0; idx < windows.size(); idx++) {
125  settings.setSubWindowPosition(idx, windows[idx]->saveGeometry());
126  auto widget = windows[idx]->widget();
127  auto crew = dynamic_cast<CREResourcesWindow *>(widget);
128  if (crew != nullptr) {
129  settings.setSubWindowType(idx, crew->rootIndex());
130  }
131  auto ew = dynamic_cast<CREExperienceWindow *>(widget);
132  if (ew) {
133  settings.setSubWindowType(idx, -2);
134  }
135  }
136  settings.setMainWindowGeometry(saveGeometry());
137  }
138 
139  myArea->closeAllSubWindows();
140  delete myArea;
141  QMainWindow::closeEvent(event);
142 
143  myMapManager->cancel();
144  delete myMapManager;
145  delete myMessageManager;
146  delete myResourcesManager;
147  cleanup();
148 }
149 
150 QAction *CREMainWindow::createAction(const QString &title, const QString &statusTip) {
151  auto action = new QAction(title, this);
152  action->setStatusTip(statusTip);
153  return action;
154 }
155 
156 QAction *CREMainWindow::createAction(const QString &title, const QString &statusTip, QObject *target, const char *slot) {
157  auto action = createAction(title, statusTip);
158  connect(action, SIGNAL(triggered()), target, slot);
159  return action;
160 }
161 
163 {
164  mySaveFormulae = new QAction(tr("Formulae"), this);
165  mySaveFormulae->setEnabled(false);
166  connect(mySaveFormulae, SIGNAL(triggered()), this, SLOT(onSaveFormulae()));
167 
168  myReportPlayer = new QAction(tr("Player vs monsters"), this);
169  myReportPlayer->setStatusTip(tr("Compute statistics related to player vs monster combat."));
170  // can't use that while map browsing is running ; will be enabled in browsingFinished()
171  myReportPlayer->setEnabled(false);
172  connect(myReportPlayer, SIGNAL(triggered()), this, SLOT(onReportPlayer()));
173 
174  myReportShops = new QAction(tr("Shop specialization"), this);
175  myReportShops->setStatusTip(tr("Display the list of shops and their specialization for items."));
176  // can't use that while map browsing is running ; will be enabled in browsingFinished()
177  myReportShops->setEnabled(false);
178  connect(myReportShops, SIGNAL(triggered()), this, SLOT(onReportShops()));
179 
180  myReportQuests = new QAction(tr("Quest solved by players"), this);
181  myReportQuests->setStatusTip(tr("Display quests the players have solved."));
182  // can't use that while map browsing is running ; will be enabled in browsingFinished()
183  myReportQuests->setEnabled(false);
184  connect(myReportQuests, SIGNAL(triggered()), this, SLOT(onReportQuests()));
185 
186  myReportArchetypes = new QAction(tr("Unused archetypes"), this);
187  myReportArchetypes->setStatusTip(tr("Display all archetypes which seem unused."));
188  myReportArchetypes->setEnabled(false);
189  connect(myReportArchetypes, SIGNAL(triggered()), this, SLOT(onReportArchetypes()));
190 
191  myClearMapCache = new QAction(tr("Clear map cache"), this);
192  myClearMapCache->setStatusTip(tr("Force a refresh of all map information at next start."));
193  connect(myClearMapCache, SIGNAL(triggered()), this, SLOT(onClearCache()));
194  /* can't clear map cache while collecting information */
195  myClearMapCache->setEnabled(false);
196 
197  myToolFacesetUseFallback = new QAction("Use set fallback for missing faces", this);
198  connect(myToolFacesetUseFallback, SIGNAL(triggered()), this, SLOT(onToolFacesetUseFallback()));
199  myToolFacesetUseFallback->setCheckable(true);
200  myToolFacesetUseFallback->setChecked(true);
201 }
202 
204 {
205  myOpenMenu = menuBar()->addMenu(tr("&Open"));
206 
207  auto add = [this] (int index, const QString &name, const QString &tip) {
208  QAction* action = new QAction(name, this);
209  action->setStatusTip(tip);
210  action->setData(static_cast<int>(index));
211  connect(action, &QAction::triggered, [this, index] () { doResourceWindow(index); });
212  myOpenMenu->addAction(action);
213  };
214  add(-1, "Assets", tr("Display all defined assets, except the experience table."));
215  for (int asset = 0; asset < myAssets->childrenCount(); asset++) {
216  add(asset, myAssets->child(asset)->displayName(), myAssets->child(asset)->property(AssetWrapper::tipProperty).toString());
217  }
218 
219  myOpenMenu->addAction(createAction(tr("Experience"), tr("Display the experience table."), this, SLOT(onOpenExperience())));
220 
221  myOpenMenu->addSeparator();
222  QAction* exit = myOpenMenu->addAction(tr("&Exit"));
223  exit->setStatusTip(tr("Close the application."));
224  connect(exit, SIGNAL(triggered()), this, SLOT(close()));
225 
226  mySaveMenu = menuBar()->addMenu(tr("&Save"));
227  mySaveMenu->addAction(mySaveFormulae);
228  mySaveMenu->addAction(createAction(tr("Quests"), tr("Save all modified quests to disk."), this, SLOT(onSaveQuests())));
229  mySaveMenu->addAction(createAction(tr("Dialogs"), tr("Save all modified NPC dialogs."), this, SLOT(onSaveMessages())));
230  mySaveMenu->addAction(createAction(tr("Archetypes"), tr("Save all modified archetypes."), myResourcesManager, SLOT(saveArchetypes())));
231  mySaveMenu->addAction(createAction(tr("Treasures"), tr("Save all modified treasures."), myResourcesManager, SLOT(saveTreasures())));
232  mySaveMenu->addAction(createAction(tr("General messages"), tr("Save all modified general messages."), myResourcesManager, SLOT(saveGeneralMessages())));
233  mySaveMenu->addAction(createAction(tr("Artifacts"), tr("Save all modified artifacts."), myResourcesManager, SLOT(saveArtifacts())));
234 
235  QMenu* reportMenu = menuBar()->addMenu("&Reports");
236  reportMenu->addAction(createAction(tr("Faces and animations report"), tr("Show faces and animations which are used by multiple archetypes, or not used."), this, SLOT(onReportDuplicate())));
237  reportMenu->addAction(createAction(tr("Spell damage"), tr("Display spell damage by level (bullet spells only for now)"), this, SLOT(onReportSpellDamage())));
238  reportMenu->addAction(createAction(tr("Alchemy"), tr("Display alchemy formulae, in a table."), this, SLOT(onReportAlchemy())));
239  reportMenu->addAction(createAction(tr("Alchemy graph"), tr("Export alchemy relationship as a DOT file."), this, SLOT(onReportAlchemyGraph())));
240  reportMenu->addAction(createAction(tr("Spells"), tr("Display all spells, in a table."), this, SLOT(onReportSpells())));
241  reportMenu->addAction(myReportPlayer);
242  reportMenu->addAction(createAction(tr("Summoned pets statistics"), tr("Display wc, hp, speed and other statistics for summoned pets."), this, SLOT(onReportSummon())));
243  reportMenu->addAction(myReportShops);
244  reportMenu->addAction(myReportQuests);
245  reportMenu->addAction(createAction(tr("Materials"), tr("Display all materials with their properties."), this, SLOT(onReportMaterials())));
246  reportMenu->addAction(myReportArchetypes);
247  reportMenu->addAction(createAction(tr("Licenses checks"), tr("Check for licenses inconsistencies."), this, SLOT(onReportLicenses())));
248 
249  myToolsMenu = menuBar()->addMenu("&Tools");
250  myToolsMenu->addAction(createAction(tr("Edit monsters"), tr("Edit monsters in a table."), this, SLOT(onToolEditMonsters())));
251  auto resist = createAction(tr("Monster resistances overview"), tr("Display an overview of resistances of monsters"));
252  connect(resist, &QAction::triggered, [&] {
253  MonsterResistances dlg(this);
254  dlg.exec();
255  });
256  myToolsMenu->addAction(resist);
257  myToolsMenu->addAction(createAction(tr("Generate smooth face base"), tr("Generate the basic smoothed picture for a face."), this, SLOT(onToolSmooth())));
258  myToolsMenu->addAction(createAction(tr("Generate HP bar"), tr("Generate faces for a HP bar."), this, SLOT(onToolBarMaker())));
259  myToolsMenu->addAction(createAction(tr("Combat simulator"), tr("Simulate fighting between two objects."), this, SLOT(onToolCombatSimulator())));
260  myToolsMenu->addAction(createAction(tr("Generate face variants"), tr("Generate faces by changing colors of existing faces."), this, SLOT(onToolFaceMaker())));
261  myToolsMenu->addAction(myClearMapCache);
262  myToolsMenu->addAction(createAction(tr("Reload assets"), tr("Reload all assets from the data directory."), this, SLOT(onToolReloadAssets())));
263 
264  CRESettings set;
265 
266  myWindows = menuBar()->addMenu(tr("&Windows"));
267  connect(myWindows, SIGNAL(aboutToShow()), this, SLOT(onWindowsShowing()));
268  auto store = createAction(tr("Restore windows positions at launch"), tr("If enabled then opened windows are automatically opened again when the application starts"));
269  store->setCheckable(true);
270  store->setChecked(set.storeWindowsState());
271  myWindows->addAction(store);
272  connect(store, &QAction::triggered, [store] {
273  CRESettings set;
274  set.setStoreWindowState(store->isChecked());
275  } );
276 
277  myWindows->addAction(createAction(tr("Close current window"), tr("Close the currently focused window"), myArea, SLOT(closeActiveSubWindow())));
278  myWindows->addAction(createAction(tr("Close all windows"), tr("Close all opened windows"), myArea, SLOT(closeAllSubWindows())));
279  myWindows->addAction(createAction(tr("Tile windows"), tr("Tile all windows"), myArea, SLOT(tileSubWindows())));
280  myWindows->addAction(createAction(tr("Cascade windows"), tr("Cascade all windows"), myArea, SLOT(cascadeSubWindows())));
281 
282  auto sep = new QAction(this);
283  sep->setSeparator(true);
284  myWindows->addAction(sep);
285 
286  auto helpMenu = menuBar()->addMenu(tr("&Help"));
287  auto help = createAction(tr("Help"), tr("CRE Help"));
288  help->setShortcut(Qt::Key_F1);
289  helpMenu->addAction(help);
290  connect(help, &QAction::triggered, myHelpManager, &HelpManager::displayHelp);
291 
292  auto about = createAction(tr("About"), tr("About CRE"));
293  helpMenu->addAction(about);
294  connect(about, &QAction::triggered, [=] () { QMessageBox::about(this, tr("About CRE"), tr("Crossfire Resource Editor")); });
295 
297  auto show = createAction(tr("Show changes after updating"), tr("If checked, then show latest changes at first startup after an update"));
298  show->setCheckable(true);
299  show->setChecked(settings.showChanges());
300  helpMenu->addAction(show);
301  connect(show, &QAction::triggered, [&] (bool checked) {
303  settings.setShowChanges(checked);
304  });
305 
306  auto changes = createAction(tr("Changes"), tr("Display CRE changes"));
307  helpMenu->addAction(changes);
308  connect(changes, &QAction::triggered, [=] () { myChanges->setVisible(true); });
309 }
310 
311 void CREMainWindow::doResourceWindow(int assets, const QByteArray& position)
312 {
313  QModelIndex root;
314  if (assets != -1) {
315  root = myModel->index(assets, 0, QModelIndex());
316  }
317 
319  resources->setAttribute(Qt::WA_DeleteOnClose);
320  connect(this, SIGNAL(updateFilters()), resources, SLOT(updateFilters()));
321  connect(resources, SIGNAL(filtersModified()), this, SLOT(onFiltersModified()));
322  connect(this, SIGNAL(updateReports()), resources, SLOT(updateReports()));
323  connect(resources, SIGNAL(reportsModified()), this, SLOT(onReportsModified()));
324  auto widget = myArea->addSubWindow(resources);
325  widget->setAttribute(Qt::WA_DeleteOnClose);
326  if (position.isEmpty()) {
327  if (myArea->subWindowList().size() == 1) {
328  widget->setWindowState(Qt::WindowMaximized);
329  }
330  } else {
331  widget->restoreGeometry(position);
332  }
333  resources->show();
334 }
335 
336 void CREMainWindow::onOpenExperience(const QByteArray& position)
337 {
338  QWidget* experience = new CREExperienceWindow();
339  auto widget = myArea->addSubWindow(experience);
340  if (!position.isEmpty()) {
341  widget->restoreGeometry(position);
342  }
343  experience->show();
344 }
345 
347 {
349  const QString select = settings.facesetToDisplay();
350  const bool use = settings.facesetUseFallback();
351 
352  QMenu *fs = myToolsMenu->addMenu("Facesets");
353  myFacesetsGroup = new QActionGroup(this);
354  connect(myFacesetsGroup, SIGNAL(triggered(QAction*)), this, SLOT(onToolFaceset(QAction*)));
355  getManager()->facesets()->each([&fs, &select, this] (face_sets *f)
356  {
357  QAction *a = new QAction(f->fullname, fs);
358  a->setCheckable(true);
359  a->setData(f->prefix);
360  fs->addAction(a);
361  myFacesetsGroup->addAction(a);
362  if (select == f->prefix)
363  a->setChecked(true);
364  });
365  fs->addSeparator();
366  fs->addAction(myToolFacesetUseFallback);
367  myToolFacesetUseFallback->setChecked(use);
368 }
369 
371 {
372 }
373 
375 {
377 }
378 
380 {
382 }
383 
384 void CREMainWindow::browsingMap(const QString& path)
385 {
386  myMapBrowseStatus->setText(tr("Browsing map %1").arg(path));
387 }
388 
390 {
391  statusBar()->showMessage(tr("Finished browsing maps."), 5000);
392  myMapBrowseStatus->setVisible(false);
393  myReportPlayer->setEnabled(true);
394  myReportShops->setEnabled(true);
395  myReportQuests->setEnabled(true);
396  myReportArchetypes->setEnabled(true);
397  myClearMapCache->setEnabled(true);
398 }
399 
401 {
402  emit updateFilters();
403 }
404 
406 {
407  emit updateReports();
408 }
409 
417 {
418  QHash<QString, QStringList> faces, anims;
419 
420  // browse all archetypes
421  getManager()->archetypes()->each([&faces, &anims] (const auto arch)
422  {
423  if (arch->head)
424  {
425  return;
426  }
427  // if there is an animation, don't consider the face, since it's part of the animation anyway (hopefully, see lower for report on that)
428  if (arch->clone.animation == NULL)
429  {
430  if (arch->clone.face) {
431  faces[QString::fromLatin1(arch->clone.face->name)].append(QString(arch->name) + " (arch)");
432  sstring key = object_get_value(&arch->clone, "identified_face");
433  if (key)
434  {
435  faces[QString(key)].append(QString(arch->name) + " (arch)");
436  }
437  }
438  }
439  else
440  {
441  anims[arch->clone.animation->name].append(QString(arch->name) + " (arch)");
442  sstring key = object_get_value(&arch->clone, "identified_animation");
443  if (key)
444  {
445  anims[QString(key)].append(QString(arch->name) + " (arch)");
446  }
447  }
448  });
449 
450  // list faces in animations
451  getManager()->animations()->each([&faces] (const auto anim)
452  {
453  QStringList done;
454  for (int i = 0; i < anim->num_animations; i++)
455  {
456  // don't list animation twice if they use the same face
457  if (!done.contains(QString::fromLatin1(anim->faces[i]->name)))
458  {
459  faces[QString::fromLatin1(anim->faces[i]->name)].append(QString(anim->name) + " (animation)");
460  done.append(QString::fromLatin1(anim->faces[i]->name));
461  }
462  }
463  });
464 
465  // list faces and animations for artifacts
467  artifact* art;
468  for (list = first_artifactlist; list != NULL; list = list->next)
469  {
470  for (art = list->items; art != NULL; art = art->next)
471  {
472  if (art->item->animation == 0)
473  {
474  if (art->item->face) {
475  faces[QString::fromLatin1(art->item->face->name)].append(QString(art->item->name) + " (art)");
476  sstring key = object_get_value(art->item, "identified_face");
477  if (key)
478  {
479  faces[QString(key)].append(QString(art->item->name) + " (art)");
480  }
481  }
482  }
483  else
484  {
485  anims[art->item->animation->name].append(QString(art->item->name) + " (art)");
486  sstring key = object_get_value(art->item, "identified_animation");
487  if (key)
488  {
489  anims[QString(key)].append(QString(art->item->name) + " (arch)");
490  }
491  }
492  }
493  }
494 
495  getManager()->quests()->each([&] (auto quest) {
496  if (quest->face != nullptr)
497  {
498  faces[quest->face->name].append(QString(quest->quest_code) + " (quest)");
499  }
500  });
501 
503  {
504  if (message->face != nullptr)
505  {
506  faces[message->face->name].append(QString(message->identifier) + " (message)");
507  }
508  });
509 
510  for (const auto map : myMapManager->allMaps())
511  {
512  for (const auto face : map->faces())
513  {
514  faces[face].append(QString(map->path()) + " (map)");
515  }
516  for (const auto animation : map->animations())
517  {
518  anims[animation].append(map->path() + " (map)");
519  }
520  }
521 
522  QString report("<p><strong>Warning:</strong> this list doesn't take into account faces for all artifacts, especially the 'animation_suffix' ones.</p><h1>Faces used multiple times:</h1><ul>");
523 
524  QStringList keys = faces.keys();
525  keys.sort();
526  foreach(QString name, keys)
527  {
528  if (faces[name].size() <= 1 || name.compare("blank.111") == 0)
529  continue;
530 
531  faces[name].sort();
532  report += "<li>" + name + ": ";
533  report += faces[name].join(", ");
534  report += "</li>";
535  }
536 
537  report += "</ul>";
538 
539  report += "<h1>Unused faces:</h1><ul>";
540  getManager()->faces()->each([&faces, &report] (const auto face)
541  {
542  if (faces[face->name].size() > 0)
543  return;
544  report += QString("<li>") + face->name + "</li>";
545  });
546  report += "</ul>";
547 
548  report += "<h1>Animations used multiple times:</h1><ul>";
549  keys = anims.keys();
550  keys.sort();
551  foreach(QString name, keys)
552  {
553  if (anims[name].size() <= 1)
554  continue;
555 
556  anims[name].sort();
557  report += "<li>" + name + ": ";
558  report += anims[name].join(", ");
559  report += "</li>";
560  }
561  report += "</ul>";
562 
563  report += "<h1>Unused animations:</h1><ul>";
564  getManager()->animations()->each([&anims, &report] (const auto anim)
565  {
566  if (anims[anim->name].size() > 0 || !strcmp(anim->name, "###none"))
567  return;
568  report += QString("<li>") + anim->name + "</li>";
569  });
570  report += "</ul>";
571 
572  // Find faces used for an object having an animation not including this face
573  report += "<h1>Objects having a face not part of their animation:</h1><ul>";
574 
576  // if there is an animation, don't consider the face, since it's part of the animation anyway (hopefully)
577  if (arch->clone.animation == NULL || arch->clone.face == NULL) {
578  return;
579  }
580  bool included = false;
581  for (int f = 0; f < arch->clone.animation->num_animations && !included; f++) {
582  if (arch->clone.animation->faces[f] == arch->clone.face) {
583  included = true;
584  }
585  }
586  if (!included) {
587  report += QString("<li>%1 (%2) has face %3 not in animation %4</li>\n").arg(arch->name, arch->clone.name, arch->clone.face->name, arch->clone.animation->name);
588  }
589  });
590 
591  CREReportDisplay show(report, "Faces and animations report");
592  show.exec();
593 }
594 
596 {
597  QStringList spell;
598  QList<QStringList> damage;
599 
600  object* caster = create_archetype("orc");
601 
602  getManager()->archetypes()->each([&caster, &spell, &damage] (archetype *arch)
603  {
604  if (arch->clone.type == SPELL && arch->clone.subtype == SP_BULLET && arch->clone.skill && strcmp(arch->clone.skill, "praying") == 0)
605  {
606  spell.append(arch->clone.name);
607  QStringList dam;
608  for (int l = 0; l < settings.max_level; l++)
609  {
610  caster->level = l;
611  int dm = arch->clone.stats.dam + SP_level_dam_adjust(caster, &arch->clone);
612  int cost = SP_level_spellpoint_cost(caster, &arch->clone, SPELL_GRACE);
613  dam.append(tr("%1 [%2]").arg(dm).arg(cost));
614  }
615  damage.append(dam);
616  }
617  });
618 
620 
621  QString report("<table><thead><tr><th>level</th>");
622 
623  for (int i = 0; i < spell.size(); i++)
624  {
625  report += "<th>" + spell[i] + "</th>";
626  }
627 
628  report += "</tr></thead><tbody>";
629 
630  for (int l = 0; l < settings.max_level; l++)
631  {
632  report += "<tr><td>" + QString::number(l) + "</td>";
633  for (int s = 0; s < spell.size(); s++)
634  report += "<td>" + damage[s][l] + "</td>";
635  report += "</tr>";
636  }
637 
638  report += "</tbody></table>";
639 
640  CREReportDisplay show(report, "Spell damage");
641  show.exec();
642 }
643 
644 static QString alchemyTable(const QString& skill, QStringList& noChance, std::vector<std::pair<QString, int>> &allIngredients)
645 {
646  int count = 0;
647 
648  QHash<int, QStringList> recipes;
649 
650  const recipelist* list;
651  const recipe* recipe;
652 
653  for (int ing = 1; ; ing++)
654  {
655  list = get_formulalist(ing);
656  if (!list)
657  break;
658 
659  for (recipe = list->items; recipe; recipe = recipe->next)
660  {
661  if (skill == recipe->skill)
662  {
663  if (recipe->arch_names == 0)
664  // hu?
665  continue;
666 
668  if (arch == NULL) {
669  continue;
670  }
671 
672  QString name;
673  if (strcmp(recipe->title, "NONE") == 0)
674  {
675  if (arch->clone.title == NULL)
676  name = arch->clone.name;
677  else
678  name = QString("%1 %2").arg(arch->clone.name, arch->clone.title);
679  }
680  else
681  {
682  name = QString("%1 of %2").arg(arch->clone.name, recipe->title);
683  }
684 
685  QStringList ingredients;
686  for (const linked_char* ingred = recipe->ingred; ingred != NULL; ingred = ingred->next)
687  {
688  ingredients.append(ingred->name);
689  const char* name = ingred->name;
690  if (isdigit(ingred->name[0])) {
691  name = strchr(ingred->name, ' ') + 1;
692  }
693  auto ing = std::find_if(allIngredients.begin(), allIngredients.end(), [&] (auto i) { return i.first == name; } );
694  if (ing != allIngredients.end()) {
695  (*ing).second++;
696  } else {
697  allIngredients.push_back(std::make_pair(name, 1));;
698  }
699  }
700 
701  recipes[recipe->diff].append(QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>").arg(name).arg(recipe->diff).arg(recipe->ingred_count).arg(recipe->exp).arg(ingredients.join(", ")));
702  count++;
703 
704  if (recipe->chance == 0) {
705  noChance.append(name);
706  }
707  }
708  }
709  }
710 
711  if (count == 0)
712  return QString();
713 
714  QString report = QString("<h2>%1 (%2 recipes)</h2><table><thead><tr><th>product</th><th>difficulty</th><th>ingredients count</th><th>experience</th><th>Ingredients</th>").arg(skill).arg(count);
715  report += "</tr></thead><tbody>";
716 
717  QList<int> difficulties = recipes.keys();
718  qSort(difficulties);
719  foreach(int difficulty, difficulties)
720  {
721  QStringList line = recipes[difficulty];
722  qSort(line);
723  report += line.join("\n");
724  }
725 
726  report += "</tbody></table>";
727 
728  return report;
729 }
730 
731 static void doIngredients(const std::vector<std::pair<QString, int>> &allIngredients, const QString &criteria, QString &report) {
732  report += QString("<h1>All items used as ingredients (%1)</h1>").arg(criteria);
733  report += "<ul>";
734  for (auto ing : allIngredients) {
735  report += QString("<li>%1 (%2 recipes)</li>").arg(ing.first).arg(ing.second);
736  }
737  report += "</ul>";
738 }
739 
741 {
742  QStringList skills;
743 
744  getManager()->archetypes()->each([&skills] (const auto arch)
745  {
746  if (arch->clone.type == SKILL)
747  skills.append(arch->clone.name);
748  });
749  skills.sort();
750 
751  QString report("<h1>Alchemy formulae</h1>");
752  QStringList noChance;
753  std::vector<std::pair<QString, int>> allIngredients;
754 
755  foreach(const QString skill, skills)
756  {
757  report += alchemyTable(skill, noChance, allIngredients);
758  }
759 
760  qSort(noChance);
761  report += tr("<h1>Formulae with chance of 0</h1>");
762  report += "<table><th>";
763  foreach(const QString& name, noChance) {
764  report += "<tr><td>" + name + "</td></tr>";
765  }
766  report += "</th></table>";
767 
768  std::sort(allIngredients.begin(), allIngredients.end(), [] (auto i1, auto i2) {
769  return i1.first.toLower() < i2.first.toLower();
770  });
771  doIngredients(allIngredients, "alphabetical order", report);
772 
773  std::sort(allIngredients.begin(), allIngredients.end(), [] (auto i1, auto i2) {
774  if (i1.second == i2.second) {
775  return i1.first.toLower() < i2.first.toLower();
776  }
777  return i1.second > i2.second;
778  });
779  doIngredients(allIngredients, "count of uses", report);
780 
781  CREReportDisplay show(report, "Alchemy formulae");
782  show.exec();
783 }
784 
786 {
787  QString output = QFileDialog::getSaveFileName(this, tr("Destination file"), "", tr("Dot files (*.dot);;All files (*.*)"));
788  if (output.isEmpty()) {
789  return;
790  }
791 
792  QFile file(output);
793  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
794  QMessageBox::critical(this, "Write error", tr("Unable to write to %1").arg(output));
795  return;
796  }
797  QTextStream out(&file);
798 
799  out << "digraph alchemy {\n";
800 
801  QVector<const recipe*> recipes;
802  QHash<const recipe*, QString> names;
803  QHash<QString, QVector<const recipe*> > products;
804 
805  for (int ing = 1; ; ing++)
806  {
807  const recipelist* list = get_formulalist(ing);
808  if (!list)
809  break;
810 
811  for (const recipe* recipe = list->items; recipe; recipe = recipe->next)
812  {
813  QString product("???");
814  for (size_t idx = 0; idx < recipe->arch_names; idx++) {
815  auto arch = getManager()->archetypes()->find(recipe->arch_name[idx]);
816  if (!arch) {
817  continue;
818  }
819  if (recipe->title && strcmp(recipe->title, "NONE")) {
820  product = tr("%1 of %2").arg(arch->clone.name, recipe->title);
821  } else {
822  product = arch->clone.name;
823  }
824  products[product].append(recipe);
825  }
826  names[recipe] = product;
827  recipes.append(recipe);
828  }
829  }
830 
831  QHash<const recipe*, bool> added;
832 
833  foreach (const recipe* rec, recipes) {
834  for (linked_char* ing = rec->ingred; ing; ing = ing->next) {
835  const char* name = ing->name;
836  if (isdigit(name[0]) && strchr(name, ' ')) {
837  name = strchr(name, ' ') + 1;
838  }
839  QHash<QString, QVector<const recipe*> >::iterator item = products.find(name);
840  if (item != products.end()) {
841  if (!added[rec]) {
842  out << tr("alchemy_%1 [label=\"%2\"]\n").arg(recipes.indexOf(rec)).arg(names[rec]);
843  added[rec] = true;
844  }
845  for (auto r = item->begin(); r != item->end(); r++) {
846  if (!added[*r]) {
847  out << tr("alchemy_%1 [label=\"%2\"]\n").arg(recipes.indexOf(*r)).arg(names[*r]);
848  added[*r] = true;
849  }
850  out << tr("alchemy_%1 -> alchemy_%2\n").arg(recipes.indexOf(*r)).arg(recipes.indexOf(rec));
851  }
852  }
853  }
854  }
855 
856  int ignored = 0;
857  foreach (const recipe* rec, recipes) {
858  if (!added[rec]) {
859  ignored++;
860  }
861  }
862  out << "graph [labelloc=\"b\" labeljust=\"c\" label=\"Alchemy graph, formulae producing ingredients of other formulae";
863  if (ignored) {
864  out << tr(" (%1 formulae not displayed)").arg(ignored);
865  }
866  out << "\"]\n";
867 
868  out << "}\n";
869 }
870 
871 static QString spellsTable(const QString& skill)
872 {
873  bool one = false;
874 
875  QString report = QString("<h2>%1</h2><table><thead><tr><th>Spell</th><th>Level</th>").arg(skill);
876  report += "</tr></thead><tbody>";
877 
878  QHash<int, QStringList> spells;
879 
880  getManager()->archetypes()->each([&skill, &spells, &one] (const archetype *spell) {
881  if (spell->clone.type == SPELL && spell->clone.skill == skill)
882  {
883  spells[spell->clone.level].append(QString("<tr><td>%1</td><td>%2</td></tr>").arg(spell->clone.name).arg(spell->clone.level));
884  one = true;
885  }
886  });
887 
888  if (!one)
889  return QString();
890 
891  QList<int> levels = spells.keys();
892  qSort(levels);
893  foreach(int level, levels)
894  {
895  spells[level].sort();
896  report += spells[level].join("\n");
897  }
898 
899  report += "</tbody></table>";
900 
901  return report;
902 }
903 
905 {
906  QStringList skills;
907 
908  getManager()->archetypes()->each([&skills] (const archt *arch)
909  {
910  if (arch->clone.type == SKILL)
911  skills.append(arch->clone.name);
912  });
913 
914  skills.sort();
915 
916  QString report("<h1>Spell list</h1>");
917 
918  foreach(const QString skill, skills)
919  {
920  report += spellsTable(skill);
921  }
922 
923  CREReportDisplay show(report, "Spell list");
924  show.exec();
925 }
926 
936 static int monsterFight(archetype* monster, archetype* skill, int level)
937 {
938  int limit = 50, result = 1;
939  player pl;
940  socket_struct sock;
941  memset(&pl, 0, sizeof(player));
942  memset(&sock, 0, sizeof(sock));
943  strncpy(pl.savebed_map, "/HallOfSelection", MAX_BUF);
944  pl.bed_x = 5;
945  pl.bed_y = 5;
946  pl.socket = &sock;
947  std::unique_ptr<uint8_t[]> faces(new uint8_t[get_faces_count()]);
948  sock.faces_sent = faces.get();
949 
950  archetype *dwarf_player_arch = find_archetype("dwarf_player");
951  if (dwarf_player_arch == NULL) {
952  return 0;
953  }
954  object* obfirst = object_create_arch(dwarf_player_arch);
955  obfirst->level = level;
956  obfirst->contr = &pl;
957  pl.ob = obfirst;
958  object* obskill = object_create_arch(skill);
959  obskill->level = level;
960  SET_FLAG(obskill, FLAG_APPLIED);
961  object_insert_in_ob(obskill, obfirst);
962  archetype *skill_arch = find_archetype((skill->clone.subtype == SK_TWO_HANDED_WEAPON) ? "sword_3" : "sword");
963  if (skill_arch == NULL) {
964  return 0;
965  }
966  object* sword = object_create_arch(skill_arch);
967  SET_FLAG(sword, FLAG_APPLIED);
968  object_insert_in_ob(sword, obfirst);
969  fix_object(obfirst);
970  obfirst->stats.hp = obfirst->stats.maxhp;
971 
972  object* obsecond = object_create_arch(monster);
973  tag_t tagfirst = obfirst->count;
974  tag_t tagsecond = obsecond->count;
975 
976  // make a big map so large monsters are ok in map
977  mapstruct* test_map = get_empty_map(50, 50);
978 
979  obfirst = object_insert_in_map_at(obfirst, test_map, NULL, 0, 0, 0);
980  obsecond = object_insert_in_map_at(obsecond, test_map, NULL, 0, 1 + monster->tail_x, monster->tail_y);
981 
982  if (!obsecond || object_was_destroyed(obsecond, tagsecond))
983  {
984  qDebug() << "second removed??";
985  }
986 
987  while (limit-- > 0 && obfirst->stats.hp >= 0 && obsecond->stats.hp >= 0)
988  {
989  if (obfirst->weapon_speed_left > 0) {
990  --obfirst->weapon_speed_left;
991  do_some_living(obfirst);
992 
993  move_player(obfirst, 3);
994  if (object_was_destroyed(obsecond, tagsecond))
995  break;
996 
997  /* the player may have been killed (acid for instance), so check here */
998  if (object_was_destroyed(obfirst, tagfirst) || (obfirst->map != test_map))
999  {
1000  result = 0;
1001  break;
1002  }
1003  }
1004 
1005  if (obsecond->speed_left > 0) {
1006  --obsecond->speed_left;
1007  monster_do_living(obsecond);
1008 
1009  attack_ob(obfirst, obsecond);
1010  /* when player is killed, she is teleported to bed of reality -> check map */
1011  if (object_was_destroyed(obfirst, tagfirst) || (obfirst->map != test_map))
1012  {
1013  result = 0;
1014  break;
1015  }
1016  }
1017 
1018  obfirst->weapon_speed_left += obfirst->weapon_speed;
1019  if (obfirst->weapon_speed_left > 1.0)
1020  obfirst->weapon_speed_left = 1.0;
1021  if (obsecond->speed_left <= 0)
1022  obsecond->speed_left += FABS(obsecond->speed);
1023  }
1024 
1025  if (!object_was_destroyed(obfirst, tagfirst))
1026  {
1027  object_remove(obfirst);
1029  }
1030  if (!object_was_destroyed(obsecond, tagsecond))
1031  {
1032  object_remove(obsecond);
1034  }
1036 
1037  return result;
1038 }
1039 
1050 static int monsterFight(archetype* monster, archetype* skill, int level, int count)
1051 {
1052  int victory = 0;
1053  while (count-- > 0)
1054  victory += monsterFight(monster, skill, level);
1055 
1056  return victory;
1057 }
1058 
1068 static QString monsterFight(archetype* monster, archetype* skill)
1069 {
1070  qDebug() << "monsterFight:" << monster->clone.name << skill->clone.name;
1071  int ret, min = settings.max_level + 1, half = settings.max_level + 1, count = 5, level;
1072  int first = 1, max = settings.max_level;
1073 
1074  while (first != max)
1075  {
1076  level = (max + first) / 2;
1077  if (level < first)
1078  level = first;
1079  if (first > max)
1080  first = max;
1081 
1082  ret = monsterFight(monster, skill, level, count);
1083  if (ret > 0)
1084  {
1085  if (level < min)
1086  min = level;
1087  if (ret > (count / 2) && (level < half))
1088  half = level;
1089 
1090  max = level;
1091  }
1092  else
1093  {
1094  if (first == level)
1095  break;
1096  first = level;
1097  }
1098  }
1099 
1100  //qDebug() << " result:" << min << half;
1101 
1102  // if player was killed, then HallOfSelection was loaded, so clean it now.
1103  // This speeds up various checks, like in free_all_objects().
1104  mapstruct* hos = has_been_loaded("/HallOfSelection");
1105  if (hos)
1106  {
1107  hos->reset_time = 1;
1108  hos->in_memory = MAP_IN_MEMORY;
1109  delete_map(hos);
1110  }
1111  /*
1112  extern int nroffreeobjects;
1113  extern int nrofallocobjects;
1114  qDebug() << "free: " << nroffreeobjects << ", all: " << nrofallocobjects;
1115  */
1116 
1117  if (min == settings.max_level + 1)
1118  return "<td colspan=\"2\">-</td>";
1119  return "<td>" + QString::number(min) + "</td><td>" + ((half != 0) ? QString::number(half) : "") + "</td>";
1120 }
1121 
1128 static QString monsterTable(archetype* monster, QList<archetype*> skills)
1129 {
1130  QString line = "<tr>";
1131 
1132  line += "<td>" + QString(monster->clone.name) + "</td>";
1133  line += "<td>" + QString::number(monster->clone.level) + "</td>";
1134  line += "<td>" + QString::number(monster->clone.speed) + "</td>";
1135  line += "<td>" + QString::number(monster->clone.stats.wc) + "</td>";
1136  line += "<td>" + QString::number(monster->clone.stats.dam) + "</td>";
1137  line += "<td>" + QString::number(monster->clone.stats.ac) + "</td>";
1138  line += "<td>" + QString::number(monster->clone.stats.hp) + "</td>";
1139  line += "<td>" + QString::number(monster->clone.stats.Con) + "</td>";
1140 
1141  foreach(archetype* skill, skills)
1142  {
1143  line += monsterFight(monster, skill);
1144  }
1145  line += "</tr>\n";
1146 
1147  return line;
1148 }
1149 
1155 {
1156  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1157 
1158  QStringList names;
1159  QMap<QString, archetype*> monsters;
1160  QList<archetype*> skills;
1161 
1162  getManager()->archetypes()->each([&names, &monsters, &skills] (archetype *arch)
1163  {
1164  if (QUERY_FLAG(&arch->clone, FLAG_MONSTER) && arch->clone.stats.hp > 0 && arch->head == NULL)
1165  {
1166  QString name(QString(arch->clone.name).toLower());
1167  if (monsters.contains(name))
1168  {
1169  int suffix = 1;
1170  do
1171  {
1172  name = QString(arch->clone.name).toLower() + "_" + QString::number(suffix);
1173  suffix++;
1174  } while (monsters.contains(name));
1175  }
1176 
1177  monsters[name] = arch;
1178  }
1179  if (arch->clone.type == SKILL && IS_COMBAT_SKILL(arch->clone.subtype))
1180  {
1181  if (strcmp(arch->name, "skill_missile_weapon") == 0 || strcmp(arch->name, "skill_throwing") == 0)
1182  return;
1183  skills.append(arch);
1184  }
1185  });
1186 
1187  names = monsters.keys();
1188  names.sort();
1189 
1190  QString report(tr("<h1>Player vs monsters</h1><p><strong>fv</strong> is the level at which the first victory happened, <strong>hv</strong> is the level at which at least 50% of fights were victorious.</p>\n")), line;
1191  report += "<table border=\"1\"><tbody>\n";
1192  report += "<tr>";
1193  report += "<th rowspan=\"2\">Monster</th>";
1194  report += "<th rowspan=\"2\">level</th>";
1195  report += "<th rowspan=\"2\">speed</th>";
1196  report += "<th rowspan=\"2\">wc</th>";
1197  report += "<th rowspan=\"2\">dam</th>";
1198  report += "<th rowspan=\"2\">ac</th>";
1199  report += "<th rowspan=\"2\">hp</th>";
1200  report += "<th rowspan=\"2\">regen</th>";
1201 
1202  line = "<tr>";
1203  foreach(archetype* skill, skills)
1204  {
1205  report += "<th colspan=\"2\">" + QString(skill->clone.name) + "</th>";
1206  line += "<th>fv</th><th>hv</th>";
1207  }
1208  report += "</tr>\n" + line + "</tr>\n";
1209 
1210  int limit = 500;
1211  foreach(const QString name, names)
1212  {
1213  report += monsterTable(monsters[name], skills);
1214  if (limit-- <= 0)
1215  break;
1216  }
1217 
1218  report += "</tbody></table>\n";
1219 
1220  CREReportDisplay show(report, "Player vs monsters (hand to hand)");
1221  QApplication::restoreOverrideCursor();
1222  show.exec();
1223 }
1224 
1225 static QString reportSummon(const archetype* summon, const object* other, QString name)
1226 {
1227  QString report;
1228  int level, wc_adj = 0;
1229 
1230  const object* spell = &summon->clone;
1231  sstring rate = object_get_value(spell, "wc_increase_rate");
1232  if (rate != NULL) {
1233  wc_adj = atoi(rate);
1234  }
1235 
1236  // hp, dam, speed, wc
1237 
1238  QString ac("<tr><td>ac</td>");
1239  QString hp("<tr><td>hp</td>");
1240  QString dam("<tr><td>dam</td>");
1241  QString speed("<tr><td>speed</td>");
1242  QString wc("<tr><td>wc</td>");
1243  int ihp, idam, iwc, diff;
1244  float fspeed;
1245 
1246  for (level = 1; level < 120; level += 10)
1247  {
1248  if (level < spell->level)
1249  {
1250  ac += "<td></td>";
1251  hp += "<td></td>";
1252  dam += "<td></td>";
1253  speed += "<td></td>";
1254  wc += "<td></td>";
1255  continue;
1256  }
1257 
1258  diff = level - spell->level;
1259 
1260  ihp = other->stats.hp + spell->duration + (spell->duration_modifier != 0 ? (diff / spell->duration_modifier) : 0);
1261  idam = (spell->stats.dam ? spell->stats.dam : other->stats.dam) + (spell->dam_modifier != 0 ? (diff / spell->dam_modifier) : 0);
1262  fspeed = MIN(1.0, FABS(other->speed) + .02 * (spell->range_modifier != 0 ? (diff / spell->range_modifier) : 0));
1263  iwc = other->stats.wc;
1264  if (wc_adj > 0)
1265  iwc -= (diff / wc_adj);
1266 
1267  ac += "<td>" + QString::number(other->stats.ac) + "</td>";
1268  hp += "<td>" + QString::number(ihp) + "</td>";
1269  dam += "<td>" + QString::number(idam) + "</td>";
1270  speed += "<td>" + QString::number(fspeed) + "</td>";
1271  wc += "<td>" + QString::number(iwc) + "</td>";
1272  }
1273 
1274  report += "<tr><td colspan=\"13\"><strong>" + name + "</strong></td></tr>\n";
1275 
1276  report += ac + "</tr>\n" + hp + "</tr>\n" + dam + "</tr>\n" + speed + "</tr>\n" + wc + "</tr>\n\n";
1277 
1278  return report;
1279 }
1280 
1282 {
1283  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1284 
1285  int level;
1286 
1287  QString report(tr("<h1>Summoned pet statistics</h1>\n")), line;
1288  report += "<table border=\"1\">\n<thead>\n";
1289  report += "<tr>";
1290  report += "<th rowspan=\"2\">Spell</th>";
1291  report += "<th colspan=\"12\">Level</th>";
1292  report += "</tr>\n";
1293  report += "<tr>";
1294 
1295  for (level = 1; level < 120; level += 10)
1296  {
1297  report += "<th>" + QString::number(level) + "</th>";
1298  }
1299  report += "</tr>\n</thead>\n<tbody>\n";
1300 
1301  QMap<QString, QString> spells;
1302 
1303  getManager()->archetypes()->each([&spells] (archetype *summon)
1304  {
1305  if (summon->clone.type != SPELL || summon->clone.subtype != SP_SUMMON_GOLEM)
1306  return;
1307  if (summon->clone.other_arch != NULL)
1308  {
1309  spells[summon->clone.name] = reportSummon(summon, &summon->clone.other_arch->clone, QString(summon->clone.name));
1310  return;
1311  }
1312 
1313  // god-based summoning
1314  getManager()->archetypes()->each([&summon, &spells] (archetype *god)
1315  {
1316  if (god->clone.type != GOD)
1317  return;
1318 
1319  QString name(QString(summon->clone.name) + " (" + QString(god->name) + ")");
1320  archetype* holy = determine_holy_arch(&god->clone, summon->clone.race);
1321  if (holy == NULL)
1322  return;
1323 
1324  spells[name] = reportSummon(summon, &holy->clone, name);
1325  });
1326  });
1327 
1328  QStringList keys = spells.keys();
1329  keys.sort();
1330  foreach(QString key, keys)
1331  {
1332  report += spells[key];
1333  }
1334 
1335  report += "</tbody>\n</table>\n";
1336 
1337  CREReportDisplay show(report, "Summoned pet statistics");
1338  QApplication::restoreOverrideCursor();
1339  show.exec();
1340 }
1341 
1342 static QString buildShopReport(const QString& title, const QStringList& types, const QList<CREMapInformation*>& maps, QStringList& items)
1343 {
1344  QString report("<h2>" + title + "</h2>");
1345  report += "<table border=\"1\">\n<thead>\n";
1346  report += "<tr>";
1347  report += "<th>Shop</th>";
1348  report += "<th>Greed</th>";
1349  report += "<th>Race</th>";
1350  report += "<th>Min</th>";
1351  report += "<th>Max</th>";
1352  foreach (QString item, types)
1353  {
1354  report += "<th>" + item + "</th>";
1355  items.removeAll(item);
1356  }
1357  report += "</tr>\n</thead><tbody>";
1358 
1359  foreach(const CREMapInformation* map, maps)
1360  {
1361  QString line;
1362  bool keep = false;
1363 
1364  if (map->shopItems().size() == 0)
1365  continue;
1366 
1367  line += "<tr>";
1368 
1369  line += "<td>" + map->name() + " " + map->path() + "</td>";
1370  line += "<td>" + QString::number(map->shopGreed()) + "</td>";
1371  line += "<td>" + map->shopRace() + "</td>";
1372  line += "<td>" + (map->shopMin() != 0 ? QString::number(map->shopMin()) : "") + "</td>";
1373  line += "<td>" + (map->shopMax() != 0 ? QString::number(map->shopMax()) : "") + "</td>";
1374 
1375  foreach(const QString item, types)
1376  {
1377  if (map->shopItems()[item] == 0)
1378  {
1379  if (map->shopItems()["*"] == 0)
1380  line += "<td></td>";
1381  else
1382  line += "<td>" + QString::number(map->shopItems()["*"]) + "</td>";
1383  continue;
1384  }
1385  keep = true;
1386  line += "<td>" + QString::number(map->shopItems()[item]) + "</td>";
1387  }
1388 
1389  line += "</tr>";
1390  if (keep)
1391  report += line;
1392  }
1393 
1394  report += "</tbody></table>";
1395  return report;
1396 }
1397 
1399 {
1400  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1401 
1402  QString report(tr("<h1>Shop information</h1>\n"));
1403 
1404  QList<CREMapInformation*> maps = myMapManager->allMaps();
1405  QStringList items;
1406  foreach(const CREMapInformation* map, maps)
1407  {
1408  QStringList add = map->shopItems().keys();
1409  foreach(const QString item, add)
1410  {
1411  if (!items.contains(item))
1412  items.append(item);
1413  }
1414  }
1415  qSort(items);
1416 
1417  QStringList part;
1418 
1419  part << "weapon" << "weapon improver" << "bow" << "arrow";
1420  report += buildShopReport("Weapons", part, maps, items);
1421 
1422  part.clear();
1423  part << "armour" << "armour improver" << "boots" << "bracers" << "cloak" << "girdle" << "gloves" << "helmet" << "shield";
1424  report += buildShopReport("Armour", part, maps, items);
1425 
1426  part.clear();
1427  part << "amulet" << "potion" << "power_crystal" << "ring" << "rod" << "scroll" << "skillscroll" << "spellbook" << "wand";
1428  report += buildShopReport("Magical", part, maps, items);
1429 
1430  part.clear();
1431  part << "container" << "food" << "key" << "lamp" << "skill tool" << "special key";
1432  report += buildShopReport("Equipment", part, maps, items);
1433 
1434  if (!items.isEmpty())
1435  {
1436 
1437  part = items;
1438  report += buildShopReport("Others", part, maps, items);
1439  }
1440 
1441  CREReportDisplay show(report, "Shop information");
1442  QApplication::restoreOverrideCursor();
1443  show.exec();
1444 }
1445 
1446 void readDirectory(const QString& path, QHash<QString, QHash<QString, bool> >& states)
1447 {
1448  QDir dir(path);
1449  QStringList subdirs = dir.entryList(QStringList("*"), QDir::Dirs | QDir::NoDotAndDotDot);
1450  foreach(QString subdir, subdirs)
1451  {
1452  readDirectory(path + QDir::separator() + subdir, states);
1453  }
1454 
1455  QStringList quests = dir.entryList(QStringList("*.quest"), QDir::Files);
1456  foreach(QString file, quests)
1457  {
1458  qDebug() << "read quest:" << path << file;
1459  QString name = file.left(file.length() - 6);
1460  QFile read(path + QDir::separator() + file);
1461  read.open(QFile::ReadOnly);
1462  QTextStream stream(&read);
1463  QString line, code;
1464  bool completed;
1465  while (!(line = stream.readLine(0)).isNull())
1466  {
1467  if (line.startsWith("quest "))
1468  {
1469  code = line.mid(6);
1470  completed = false;
1471  continue;
1472  }
1473  if (code.isEmpty())
1474  continue;
1475  if (line == "end_quest")
1476  {
1477  states[code][name] = completed;
1478  code.clear();
1479  continue;
1480  }
1481  if (line.startsWith("state "))
1482  continue;
1483  if (line == "completed 1")
1484  completed = true;
1485  }
1486  }
1487 }
1488 
1490 {
1491  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1492 
1493  QHash<QString, QHash<QString, bool> > states;
1494  QString directory(settings.localdir);
1495  directory += QDir::separator();
1496  directory += settings.playerdir;
1497  readDirectory(directory, states);
1498 
1499  QStringList codes;
1500  getManager()->quests()->each([&] (const auto quest) {
1501  codes.append(quest->quest_code);
1502  });
1503 
1504  QString report("<html><body>\n<h1>Quests</h1>\n");
1505 
1506  QStringList keys = states.keys();
1507  keys.sort();
1508 
1509  foreach(QString key, keys)
1510  {
1511  codes.removeAll(key);
1512  const auto quest = getManager()->quests()->get(key.toStdString());
1513  report += "<h2>Quest: " + (quest != NULL ? quest->quest_title : (key + " ???")) + "</h2>\n";
1514  report += "<p>";
1515  QHash<QString, bool> done = states[key];
1516  QStringList players = done.keys();
1517  players.sort();
1518  int completed = 0;
1519  QString sep;
1520  foreach(QString player, players)
1521  {
1522  report += sep;
1523  sep = ", ";
1524  if (done[player])
1525  {
1526  completed++;
1527  report += "<strong>" + player + "</strong>";
1528  }
1529  else
1530  {
1531  report += player;
1532  }
1533  }
1534  report += "</p>\n";
1535  report += "<p>" + tr("%1 completed out of %2 (%3%)").arg(completed).arg(players.size()).arg(completed * 100 / players.size()) + "</p>\n";
1536  }
1537 
1538  if (codes.length() > 0)
1539  {
1540  codes.sort();
1541  QString sep;
1542  report += "<h2>Quests never done</h2>\n<p>\n";
1543  foreach(QString code, codes)
1544  {
1545  report += sep;
1546  sep = ", ";
1547  const auto quest = getManager()->quests()->find(code.toStdString());
1548  report += (quest != NULL ? quest->quest_title : (code + " ???"));
1549  }
1550  report += "</p>\n";
1551  }
1552 
1553  report += "</body>\n</html>\n";
1554 
1555  CREReportDisplay show(report, "Quests report");
1556  QApplication::restoreOverrideCursor();
1557  show.exec();
1558 }
1559 
1561 {
1562  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1563 
1564  QString report;
1565  report += "<html>";
1566 
1567  report += "<h1>Materials</h1>";
1568  report += "<table><tr><th>Name</th><th>Description</th></tr>";
1569  auto mat = materialt;
1570  while (mat) {
1571  report += tr("<tr><td>%1</td><td>%2</td></tr>").arg(mat->name, mat->description);
1572  mat = mat->next;
1573  }
1574  report += "</table>";
1575 
1576  for (int s = 0; s < 2; s++) {
1577  QString name(s == 0 ? "Saves" : "Resistances");
1578  report += tr("<h1>%1</h1>").arg(name);
1579  report += tr("<tr><th rowspan='2'>Name</th><th colspan='%1'>%2</th></tr>").arg(NROFATTACKS).arg(name);
1580  report += "<tr>";
1581  for (int r = 0; r < NROFATTACKS; r++) {
1582  report += "<th>" + QString(attacktype_desc[r]) + "</th>";
1583  }
1584  report += "</tr>";
1585 
1586  mat = materialt;
1587  while (mat) {
1588  report += tr("<tr><td>%1</td>").arg(mat->name);
1589  for (int r = 0; r < NROFATTACKS; r++) {
1590  report += tr("<td>%1</td>").arg(s == 0 ? mat->save[r] : mat->mod[r]);
1591  }
1592  report += "</tr>";
1593  mat = mat->next;
1594  }
1595  report += "</table>";
1596  }
1597 
1598  report += "</html>";
1599 
1600  CREReportDisplay show(report, "Materials report");
1601  QApplication::restoreOverrideCursor();
1602  show.exec();
1603 }
1604 
1606 {
1607  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1608 
1609  QString report;
1610  report += "<html>";
1611 
1612  report += "<h1>Apparently unused archetypes</h1>";
1613  report += "<h3>Warning: this list contains skills, items on style maps, and other things which are actually used.</h3>";
1614  report += "<table>";
1615  report += "<tr><th>Image</th><th>Archetype name</th><th>Item name</th><th>Type</th></tr>";
1616 
1617  getManager()->archetypes()->each([this, &report] (const archt* arch)
1618  {
1619  if (arch->head || arch->clone.type == PLAYER || arch->clone.type == MAP || arch->clone.type == EVENT_CONNECTOR)
1620  return;
1621  if (strstr(arch->name, "hpbar") != nullptr)
1622  return;
1623 
1624  bool used = false;
1626  (ArchetypeUse, const archt*, const treasurelist*, const CREMapInformation*, const recipe*) -> bool
1627  {
1628  used = true;
1629  return false;
1630  });
1631 
1632  if (!used)
1633  {
1634  QImage image(CREPixmap::getIcon(arch->clone.face->number).pixmap(32,32).toImage());
1635  QByteArray byteArray;
1636  QBuffer buffer(&byteArray);
1637  image.save(&buffer, "PNG");
1638  QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data());
1639  auto td = get_typedata(arch->clone.type);
1640  report += tr("<tr><td><img src='data:image/png;base64,%1'></td><td>%2</td><td>%3</td><td>%4</td></tr>")
1641  .arg(iconBase64, arch->name, arch->clone.name, td ? td->name : tr("unknown: %1").arg(arch->clone.type));
1642  }
1643  });
1644 
1645  report += "</table>";
1646  report += "</html>";
1647 
1648  CREReportDisplay show(report, "Unused archetypes report");
1649  QApplication::restoreOverrideCursor();
1650  show.exec();
1651 }
1652 
1654 {
1655  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1656 
1657  QString report;
1658  report += "<html>";
1659 
1660  auto all = myResourcesManager->licenseManager()->getAll();
1661  std::set<std::string> faces, facesets;
1662 
1663  for (auto item : all)
1664  {
1665  faces.insert(item.first);
1666  for (auto fs : item.second)
1667  {
1668  facesets.insert(fs.first);
1669  }
1670  }
1671 
1672  getManager()->facesets()->each([&facesets] (const face_sets *fs)
1673  {
1674  facesets.erase(fs->prefix);
1675  });
1676  getManager()->faces()->each([&faces] (const Face *face)
1677  {
1679  });
1680 
1681  if (facesets.empty())
1682  {
1683  report += "<h1>No invalid faceset</h1>\n";
1684  }
1685  else
1686  {
1687  report += "<h1>Invalid faceset found</h1>\n";
1688  report += "<p>The faceset of the license file doesn't match any defined facesets.</p>";
1689  report += "<ul>\n";
1690  for (auto fs : facesets)
1691  {
1692  report += "<li>" + QString(fs.c_str()) + "</li>\n";
1693  }
1694  report += "</ul>\n";
1695  }
1696 
1697  if (faces.empty())
1698  {
1699  report += "<h1>No invalid face name</h1>\n";
1700  }
1701  else
1702  {
1703  report += "<h1>Invalid face names found</h1>\n";
1704  report += "<p>The face name from the license file doesn't match any defined face.</p>";
1705  report += "<ul>\n";
1706  for (auto f : faces)
1707  {
1708  report += "<li>" + QString(f.c_str()) + "</li>\n";
1709  }
1710  report += "</ul>\n";
1711  }
1712 
1713  report += "</html>";
1714  CREReportDisplay show(report, "Licenses checks");
1715  QApplication::restoreOverrideCursor();
1716  show.exec();
1717 }
1718 
1720 {
1722  edit.exec();
1723 }
1724 
1726 {
1727  CRESmoothFaceMaker smooth;
1728  smooth.exec();
1729 }
1730 
1732 {
1733  CRECombatSimulator simulator;
1734  simulator.exec();
1735 }
1736 
1738 {
1739  CREHPBarMaker maker;
1740  maker.exec();
1741 }
1742 
1744 {
1745  FaceMakerDialog maker(this, myResourcesManager);
1746  maker.exec();
1747 }
1748 
1750 {
1751  QMessageBox confirm;
1752  confirm.setWindowTitle(tr("Crossfire Resource Editor"));
1753  confirm.setText("Really clear map cache?");
1754  confirm.setInformativeText("This will force cache rebuild at next application start.");
1755  confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1756  confirm.setDefaultButton(QMessageBox::No);
1757  confirm.setIcon(QMessageBox::Question);
1758  if (confirm.exec() == QMessageBox::Yes)
1759  {
1761  }
1762 }
1763 
1765 {
1766  CREPixmap::setFaceset(action->data().toString());
1767 }
1768 
1770 {
1772 }
1773 
1775 {
1776  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1780  QApplication::restoreOverrideCursor();
1781  QMessageBox::information(this, "Reload complete", "Assets reload complete, you may need to change the selected item to see updated versions.");
1782 }
1783 
1785  auto windows = myArea->subWindowList();
1786  bool hasWindows = !windows.empty();
1787 
1788  while (myWindows->actions().size() > 6) {
1789  myWindows->removeAction(myWindows->actions()[6]);
1790  }
1791  for (auto a : myWindows->actions()) {
1792  if (a->isSeparator()) {
1793  a->setVisible(hasWindows);
1794  } else if (a != myWindows->actions()[0]) {
1795  a->setEnabled(hasWindows);
1796  }
1797  }
1798 
1799  for (int i = 0; i < windows.size(); ++i) {
1800  QMdiSubWindow *mdiSubWindow = windows.at(i);
1801 
1802  QString title(mdiSubWindow->widget()->windowTitle());
1803  if (i < 9) {
1804  title = tr("&%1 %2").arg(i + 1).arg(title);
1805  } else {
1806  title = tr("%1 %2").arg(i + 1).arg(title);
1807  }
1808  QAction *action = myWindows->addAction(title, mdiSubWindow, [this, mdiSubWindow] () {
1809  myArea->setActiveSubWindow(mdiSubWindow);
1810  });
1811  action->setCheckable(true);
1812  action ->setChecked(mdiSubWindow == myArea->activeSubWindow());
1813  }
1814 }
1815 
1817  auto reg = get_region_by_name(map->region().toLocal8Bit().data());
1818  map->setDisplayParent(myResourcesManager->wrap(reg, myAssets->regions()));
1819  for (auto rm : map->randomMaps()) {
1820  rm->setDisplayParent(myAssets->randomMaps());
1821  }
1822 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
obj::weapon_speed
float weapon_speed
Definition: object.h:334
recipestruct::arch_names
size_t arch_names
Definition: recipe.h:12
Face::name
sstring name
Definition: face.h:19
materialt
materialtype_t * materialt
Definition: init.cpp:128
ScriptFileManager
Definition: ScriptFileManager.h:26
CREPixmap::setFaceset
static void setFaceset(const QString &prefix)
Definition: CREPixmap.cpp:44
Face
Definition: face.h:14
MonsterResistances
Definition: MonsterResistances.h:24
PLAYER
@ PLAYER
Definition: object.h:107
CREMainWindow::onSaveFormulae
void onSaveFormulae()
Definition: CREMainWindow.cpp:370
global.h
make_face_from_files.anims
list anims
Definition: make_face_from_files.py:53
AllAssets::randomMaps
AssetWrapper * randomMaps()
Definition: AllAssets.h:33
CREMainWindow::browsingMap
void browsingMap(const QString &path)
Definition: CREMainWindow.cpp:384
settings
struct Settings settings
Definition: init.cpp:138
liv::dam
int16_t dam
Definition: living.h:46
banquet.l
l
Definition: banquet.py:164
GeneralMessage
Definition: book.h:44
MAP
@ MAP
Definition: object.h:125
get_formulalist
recipelist * get_formulalist(int i)
Definition: recipe.cpp:96
CREMainWindow::closeEvent
void closeEvent(QCloseEvent *event)
Definition: CREMainWindow.cpp:111
ResourcesManager::licenseManager
LicenseManager * licenseManager()
Definition: ResourcesManager.h:146
CREMainWindow::onReportAlchemyGraph
void onReportAlchemyGraph()
Definition: CREMainWindow.cpp:785
Settings::max_level
int16_t max_level
Definition: global.h:300
CREMainWindow::myClearMapCache
QAction * myClearMapCache
Definition: CREMainWindow.h:70
obj::face
const Face * face
Definition: object.h:336
ChangesDock.h
FABS
#define FABS(x)
Definition: define.h:22
CREMainWindow::onFiltersModified
void onFiltersModified()
Definition: CREMainWindow.cpp:400
maps
static std::unordered_map< std::string, mapzone * > maps
Definition: citylife.cpp:92
EVENT_CONNECTOR
@ EVENT_CONNECTOR
Definition: object.h:227
monsterFight
static int monsterFight(archetype *monster, archetype *skill, int level)
Definition: CREMainWindow.cpp:936
CREMainWindow::myReportQuests
QAction * myReportQuests
Definition: CREMainWindow.h:65
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.cpp:869
ResourcesManager::archetypeUse
static void archetypeUse(const archt *item, CREMapInformationManager *store, AssetUseCallback callback)
Definition: ResourcesManager.cpp:115
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
test_map
mapstruct * test_map
Definition: comet_perf.cpp:74
AssetsManager::messages
Messages * messages()
Definition: AssetsManager.h:59
get_region_by_name
region * get_region_by_name(const char *region_name)
Definition: region.cpp:46
CREResourcesWindow
Definition: CREResourcesWindow.h:31
spellsTable
static QString spellsTable(const QString &skill)
Definition: CREMainWindow.cpp:871
ScriptFileManager.h
obj::count
tag_t count
Definition: object.h:302
obj::map
struct mapdef * map
Definition: object.h:300
CREPixmap::setUseFacesetFallback
static void setUseFacesetFallback(bool use)
Definition: CREPixmap.cpp:52
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
MessageManager.h
ResourcesManager
Definition: ResourcesManager.h:80
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
obj::race
sstring race
Definition: object.h:321
AssetsManager.h
archt::tail_x
int8_t tail_x
Definition: object.h:475
types
type_definition ** types
Definition: gridarta-types-convert.c:56
liv::wc
int8_t wc
Definition: living.h:37
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Definition: map.cpp:78
socket_struct
Definition: newserver.h:89
CREMapInformationManager::start
void start()
Definition: CREMapInformationManager.cpp:85
Settings::datadir
const char * datadir
Definition: global.h:246
MessageManager::loadMessages
void loadMessages()
Definition: MessageManager.cpp:34
disinfect.a
a
Definition: disinfect.py:13
FaceMakerDialog.h
liv::maxhp
int16_t maxhp
Definition: living.h:41
pl
Definition: player.h:105
cleanup
void cleanup(void)
Definition: server.cpp:1257
CREMapInformationManager::clearCache
void clearCache()
Definition: CREMapInformationManager.cpp:787
guildoracle.list
list
Definition: guildoracle.py:87
report.report
def report(pl)
Definition: report.py:6
AssetsManager::animations
AllAnimations * animations()
Definition: AssetsManager.h:49
ResourcesManager::wrap
ArchetypeWrapper * wrap(archt *arch, AssetWrapper *parent)
Definition: ResourcesManager.h:125
AssetWrapper::setDisplayParent
void setDisplayParent(AssetWrapper *parent)
Definition: AssetWrapper.h:46
liv::hp
int16_t hp
Definition: living.h:40
CREPixmap::getIcon
static QIcon getIcon(uint16_t faceNumber)
Definition: CREPixmap.cpp:65
CRESettings::storeWindowsState
bool storeWindowsState() const
Definition: CRESettings.cpp:120
CREMainWindow::createMenus
void createMenus()
Definition: CREMainWindow.cpp:203
ArchetypeUse
ArchetypeUse
Definition: ResourcesManager.h:66
obj::range_modifier
uint8_t range_modifier
Definition: object.h:411
root
static char root[500]
Definition: mapper.cpp:306
AllAssets.h
mapdef::in_memory
uint32_t in_memory
Definition: map.h:338
CREMainWindow::myReportPlayer
QAction * myReportPlayer
Definition: CREMainWindow.h:63
mad_mage_user.file
file
Definition: mad_mage_user.py:15
recipestruct::title
sstring title
Definition: recipe.h:11
MIN
#define MIN(x, y)
Definition: compat.h:21
move_player
int move_player(object *op, int dir)
Definition: player.cpp:2916
pl::ob
object * ob
Definition: player.h:176
hall_of_fame.keys
keys
Definition: hall_of_fame.py:43
archt::tail_y
int8_t tail_y
Definition: object.h:475
SKILL
@ SKILL
Definition: object.h:143
monster_do_living
void monster_do_living(object *op)
Definition: monster.cpp:721
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
CREMapInformationManager::allMaps
QList< CREMapInformation * > allMaps()
Definition: CREMapInformationManager.cpp:364
LicenseManager::reset
void reset()
Definition: LicenseManager.h:52
guildbuy.players
list players
Definition: guildbuy.py:17
CREMainWindow::onSaveQuests
void onSaveQuests()
Definition: CREMainWindow.cpp:374
RandomMap.h
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
curse_on_apply.ac
ac
Definition: curse_on_apply.py:4
ResourcesManager::saveQuests
void saveQuests()
Definition: ResourcesManager.cpp:203
CREMainWindow::onReportMaterials
void onReportMaterials()
Definition: CREMainWindow.cpp:1560
recipestruct::ingred_count
int ingred_count
Definition: recipe.h:23
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4328
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
AssetWrapper::tipProperty
static const char * tipProperty
Definition: AssetWrapper.h:33
getManager
AssetsManager * getManager()
Definition: assets.cpp:333
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2840
recipestruct::chance
int chance
Definition: recipe.h:14
face_sets::prefix
char * prefix
Definition: image.h:19
AssetsCollection::find
T * find(const Key &name)
Definition: AssetsCollection.h:107
CREMainWindow::myMapBrowseStatus
QLabel * myMapBrowseStatus
Definition: CREMainWindow.h:72
CREMainWindow::onReportLicenses
void onReportLicenses()
Definition: CREMainWindow.cpp:1653
obj::duration_modifier
uint8_t duration_modifier
Definition: object.h:409
obj::duration
int16_t duration
Definition: object.h:408
LicenseManager.h
CREMainWindow::onReportSpellDamage
void onReportSpellDamage()
Definition: CREMainWindow.cpp:595
linked_char
Definition: global.h:89
CREMainWindow::myResourcesManager
ResourcesManager * myResourcesManager
Definition: CREMainWindow.h:75
archt
Definition: object.h:470
quest
Definition: quest.py:1
CREMapInformation
Definition: CREMapInformation.h:27
CREMainWindow::onSaveMessages
void onSaveMessages()
Definition: CREMainWindow.cpp:379
recipestruct
Definition: recipe.h:10
pl::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:110
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:131
CREMainWindow::onToolCombatSimulator
void onToolCombatSimulator()
Definition: CREMainWindow.cpp:1731
CREHPBarMaker
Definition: CREHPBarMaker.h:22
CREMainWindow::myModel
AssetModel * myModel
Definition: CREMainWindow.h:53
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1549
CREMainWindow::updateReports
void updateReports()
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
SP_BULLET
#define SP_BULLET
Definition: spells.h:79
disinfect.map
map
Definition: disinfect.py:4
titlestruct
Definition: readable.cpp:107
obj::name
sstring name
Definition: object.h:314
EditMonstersDialog.h
SK_TWO_HANDED_WEAPON
@ SK_TWO_HANDED_WEAPON
Definition: skills.h:56
CREExperienceWindow.h
rotate-tower.result
bool result
Definition: rotate-tower.py:13
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:320
buildShopReport
static QString buildShopReport(const QString &title, const QStringList &types, const QList< CREMapInformation * > &maps, QStringList &items)
Definition: CREMainWindow.cpp:1342
alchemyTable
static QString alchemyTable(const QString &skill, QStringList &noChance, std::vector< std::pair< QString, int >> &allIngredients)
Definition: CREMainWindow.cpp:644
CREMainWindow::doResourceWindow
void doResourceWindow(int assets, const QByteArray &position=QByteArray())
Definition: CREMainWindow.cpp:311
CREMainWindow::onToolFaceset
void onToolFaceset(QAction *action)
Definition: CREMainWindow.cpp:1764
ResourcesManager::load
void load()
Definition: ResourcesManager.cpp:54
levels
int64_t * levels
Definition: exp.cpp:26
ResourcesManager::setMapInformationManager
void setMapInformationManager(CREMapInformationManager *mapInformationManager)
Definition: ResourcesManager.h:88
CREMainWindow::CREMainWindow
CREMainWindow(const QString &helpRoot)
Definition: CREMainWindow.cpp:49
artifactstruct::next
struct artifactstruct * next
Definition: artifact.h:18
HelpManager.h
CRECombatSimulator.h
CREMainWindow::onWindowsShowing
void onWindowsShowing()
Definition: CREMainWindow.cpp:1784
recipestruct::arch_name
char ** arch_name
Definition: recipe.h:13
CRESettings.h
obj::speed_left
float speed_left
Definition: object.h:333
python_init.path
path
Definition: python_init.py:8
done
int done
Definition: readable.cpp:1611
CREMainWindow::onToolFacesetUseFallback
void onToolFacesetUseFallback()
Definition: CREMainWindow.cpp:1769
convert.action
action
Definition: convert.py:25
doIngredients
static void doIngredients(const std::vector< std::pair< QString, int >> &allIngredients, const QString &criteria, QString &report)
Definition: CREMainWindow.cpp:731
AssetsManager::quests
Quests * quests()
Definition: AssetsManager.h:71
AssetsManager::faces
Faces * faces()
Definition: AssetsManager.h:39
CREMainWindow::browsingFinished
void browsingFinished()
Definition: CREMainWindow.cpp:389
CREMainWindow::fillFacesets
void fillFacesets()
Definition: CREMainWindow.cpp:346
LicenseManager::licenseNameFromFaceName
static std::string licenseNameFromFaceName(const std::string &face)
Definition: LicenseManager.cpp:79
recipestruct::exp
int exp
Definition: recipe.h:17
AssetModel
Definition: AssetModel.h:29
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:299
CREReportDisplay.h
linked_char::next
struct linked_char * next
Definition: global.h:91
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1581
artifactliststruct
Definition: artifact.h:26
obj::other_arch
struct archt * other_arch
Definition: object.h:418
CREMainWindow::onToolReloadAssets
void onToolReloadAssets()
Definition: CREMainWindow.cpp:1774
CREMainWindow::createActions
void createActions()
Definition: CREMainWindow.cpp:162
CREMainWindow::createAction
QAction * createAction(const QString &title, const QString &statusTip)
Definition: CREMainWindow.cpp:150
player
struct pl player
AssetModel.h
sstring
const typedef char * sstring
Definition: global.h:43
disinfect.count
int count
Definition: disinfect.py:7
obj::speed
float speed
Definition: object.h:332
say.max
dictionary max
Definition: say.py:148
MessageManager
Definition: MessageManager.h:25
tag_t
uint32_t tag_t
Definition: object.h:12
liv::Con
int8_t Con
Definition: living.h:36
CREMainWindow::myScriptManager
ScriptFileManager * myScriptManager
Definition: CREMainWindow.h:76
AssetsCollection::get
T * get(const Key &name)
Definition: AssetsCollection.h:88
sproto.h
recipeliststruct
Definition: recipe.h:37
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:157
animate.anim
string anim
Definition: animate.py:20
IS_COMBAT_SKILL
#define IS_COMBAT_SKILL(num)
Definition: skills.h:91
mapdef
Definition: map.h:317
CREMainWindow::myAssets
AllAssets * myAssets
Definition: CREMainWindow.h:54
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1722
AssetsManager::facesets
Facesets * facesets()
Definition: AssetsManager.h:65
CREMainWindow::mySaveMenu
QMenu * mySaveMenu
Definition: CREMainWindow.h:60
CREMainWindow::myMapManager
CREMapInformationManager * myMapManager
Definition: CREMainWindow.h:73
ChangesDock
Definition: ChangesDock.h:24
CREMainWindow::myChanges
ChangesDock * myChanges
Definition: CREMainWindow.h:77
obj::animation
const Animations * animation
Definition: object.h:421
CREMainWindow::onToolEditMonsters
void onToolEditMonsters()
Definition: CREMainWindow.cpp:1719
image.h
pl::bed_x
int16_t bed_x
Definition: player.h:111
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2087
ASSETS_ALL
#define ASSETS_ALL
Definition: assets.h:32
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
recipestruct::ingred
linked_char * ingred
Definition: recipe.h:22
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
MAX_BUF
#define MAX_BUF
Definition: define.h:35
artifactstruct
Definition: artifact.h:14
CREMapInformationManager.h
CREMainWindow::onReportSpells
void onReportSpells()
Definition: CREMainWindow.cpp:904
CREMainWindow::onReportAlchemy
void onReportAlchemy()
Definition: CREMainWindow.cpp:740
ResourcesManager.h
CREMainWindow::myArea
QMdiArea * myArea
Definition: CREMainWindow.h:52
CREMainWindow::onReportDuplicate
void onReportDuplicate()
Definition: CREMainWindow.cpp:416
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:279
CREMainWindow::myFacesetsGroup
QActionGroup * myFacesetsGroup
Definition: CREMainWindow.h:68
CREMainWindow::mySaveFormulae
QAction * mySaveFormulae
Definition: CREMainWindow.h:62
Settings::playerdir
const char * playerdir
Definition: global.h:248
CREMainWindow::onReportsModified
void onReportsModified()
Definition: CREMainWindow.cpp:405
CREMainWindow::myToolsMenu
QMenu * myToolsMenu
Definition: CREMainWindow.h:67
recipestruct::skill
sstring skill
Definition: recipe.h:26
MonsterResistances.h
animations_struct::name
sstring name
Definition: face.h:26
pl::bed_y
int16_t bed_y
Definition: player.h:111
diamondslots.message
string message
Definition: diamondslots.py:57
CRESmoothFaceMaker
Definition: CRESmoothFaceMaker.h:23
make_face_from_files.out
out
Definition: make_face_from_files.py:75
obj::type
uint8_t type
Definition: object.h:343
HelpManager
Definition: HelpManager.h:23
obj::stats
living stats
Definition: object.h:373
attacktype_desc
const char *const attacktype_desc[NROFATTACKS]
Definition: init.cpp:39
report
Definition: report.py:1
archt::clone
object clone
Definition: object.h:474
obj::contr
struct pl * contr
Definition: object.h:279
powerbroker.confirm
def confirm(text, action)
Definition: powerbroker.py:97
item
Definition: item.py:1
AllAssets
Definition: AllAssets.h:22
readDirectory
void readDirectory(const QString &path, QHash< QString, QHash< QString, bool > > &states)
Definition: CREMainWindow.cpp:1446
CREMainWindow::onReportSummon
void onReportSummon()
Definition: CREMainWindow.cpp:1281
guildbuy.names
list names
Definition: guildbuy.py:18
CRESettings
Definition: CRESettings.h:21
CREExperienceWindow
Definition: CREExperienceWindow.h:18
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:282
help
static void help(void)
Definition: init.cpp:1163
obj::weapon_speed_left
float weapon_speed_left
Definition: object.h:335
CREMainWindow::onReportShops
void onReportShops()
Definition: CREMainWindow.cpp:1398
EditMonstersDialog
Definition: EditMonstersDialog.h:25
HelpManager::displayHelp
void displayHelp()
Definition: HelpManager.cpp:50
CREMainWindow::myHelpManager
HelpManager * myHelpManager
Definition: CREMainWindow.h:78
CREMainWindow::myMessageManager
MessageManager * myMessageManager
Definition: CREMainWindow.h:74
assets.h
npc_dialog.index
int index
Definition: npc_dialog.py:102
mapdef::reset_time
uint32_t reset_time
Definition: map.h:324
CREMapInformationManager::cancel
void cancel()
Definition: CREMapInformationManager.cpp:358
recipestruct::next
struct recipestruct * next
Definition: recipe.h:24
dragon_attune.faces
dictionary faces
Definition: dragon_attune.py:31
CREMainWindow::updateFilters
void updateFilters()
obj::subtype
uint8_t subtype
Definition: object.h:344
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
recipestruct::diff
int diff
Definition: recipe.h:16
CREHPBarMaker.h
AllAssets::childrenCount
virtual int childrenCount() const
Definition: AllAssets.h:28
level
int level
Definition: readable.cpp:1608
first_artifactlist
artifactlist * first_artifactlist
Definition: init.cpp:108
AllAssets::regions
AssetWrapper * regions()
Definition: AllAssets.h:32
artifactstruct::item
object * item
Definition: artifact.h:15
castle_read.key
key
Definition: castle_read.py:64
CREPixmap::init
static void init()
Definition: CREPixmap.cpp:32
liv::ac
int8_t ac
Definition: living.h:38
obj::skill
sstring skill
Definition: object.h:324
object_remove
void object_remove(object *op)
Definition: object.cpp:1822
CREMainWindow::myReportArchetypes
QAction * myReportArchetypes
Definition: CREMainWindow.h:66
animate.event
event
DIALOGCHECK MINARGS 1 MAXARGS 2
Definition: animate.py:17
CREMainWindow::myOpenMenu
QMenu * myOpenMenu
Definition: CREMainWindow.h:59
monsterTable
static QString monsterTable(archetype *monster, QList< archetype * > skills)
Definition: CREMainWindow.cpp:1128
CREMainWindow::myToolFacesetUseFallback
QAction * myToolFacesetUseFallback
Definition: CREMainWindow.h:69
CREMainWindow::onReportArchetypes
void onReportArchetypes()
Definition: CREMainWindow.cpp:1605
face_sets::fullname
char * fullname
Definition: image.h:20
do_some_living
void do_some_living(object *op)
Definition: player.cpp:3240
SP_SUMMON_GOLEM
#define SP_SUMMON_GOLEM
Definition: spells.h:86
CREMainWindow::onReportPlayer
void onReportPlayer()
Definition: CREMainWindow.cpp:1154
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:531
archt::name
sstring name
Definition: object.h:471
CREMainWindow.h
assets_collect
void assets_collect(const char *datadir, int what)
Definition: assets.cpp:115
say.item
dictionary item
Definition: say.py:149
reportSummon
static QString reportSummon(const archetype *summon, const object *other, QString name)
Definition: CREMainWindow.cpp:1225
attack_ob
int attack_ob(object *op, object *hitter)
Definition: attack.cpp:919
connect
Definition: connect.py:1
CREPixmap::clearFaceCache
static void clearFaceCache()
Definition: CREPixmap.cpp:60
CRESettings::setStoreWindowState
void setStoreWindowState(bool store)
Definition: CRESettings.cpp:124
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:317
CREMainWindow::mapAdded
void mapAdded(CREMapInformation *map)
Definition: CREMainWindow.cpp:1816
CRESmoothFaceMaker.h
CREMainWindow::onToolBarMaker
void onToolBarMaker()
Definition: CREMainWindow.cpp:1737
AssetModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const override
Definition: AssetModel.cpp:30
CREMapInformationManager
Definition: CREMapInformationManager.h:27
face_sets
Definition: image.h:17
FaceMakerDialog
Definition: FaceMakerDialog.h:26
CREResourcesWindow.h
SPELL
@ SPELL
Definition: object.h:214
quests
static struct_quest ** quests
Definition: mapper.cpp:916
title
struct titlestruct title
CREMainWindow::onOpenExperience
void onOpenExperience(const QByteArray &position=QByteArray())
Definition: CREMainWindow.cpp:336
ResourcesManager::hasPendingChanges
bool hasPendingChanges() const
Definition: ResourcesManager.h:115
pl::socket
socket_struct * socket
Definition: player.h:107
CREPixmap.h
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
CREReportDisplay
Definition: CREReportDisplay.h:19
CREMainWindow::myWindows
QMenu * myWindows
Definition: CREMainWindow.h:71
if
if(!(yy_init))
Definition: loader.c:2626
LicenseManager::getAll
std::map< std::string, LicenseItems > getAll() const
Definition: LicenseManager.h:47
CREMainWindow::onReportQuests
void onReportQuests()
Definition: CREMainWindow.cpp:1489
AllAssets::child
virtual AssetWrapper * child(int index)
Definition: AllAssets.h:29
CRECombatSimulator
Definition: CRECombatSimulator.h:27
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
CREMainWindow::onClearCache
void onClearCache()
Definition: CREMainWindow.cpp:1749
MessageManager::saveMessages
void saveMessages()
Definition: MessageManager.cpp:43
obj::level
int16_t level
Definition: object.h:356
GOD
@ GOD
Definition: object.h:148
treasureliststruct
Definition: treasure.h:85
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
spell_arrow.spells
spells
Definition: spell_arrow.py:6
determine_holy_arch
archetype * determine_holy_arch(const object *god, const char *type)
Definition: gods.cpp:675
AssetWrapper::displayName
virtual QString displayName() const =0
give.name
name
Definition: give.py:27
CREMainWindow::onToolSmooth
void onToolSmooth()
Definition: CREMainWindow.cpp:1725
obj::dam_modifier
uint8_t dam_modifier
Definition: object.h:412
CREMainWindow::myReportShops
QAction * myReportShops
Definition: CREMainWindow.h:64
CREMainWindow::onToolFaceMaker
void onToolFaceMaker()
Definition: CREMainWindow.cpp:1743
recipe
struct recipestruct recipe
level
Definition: level.py:1
Settings::localdir
const char * localdir
Definition: global.h:247