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