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